c++ opengl line sdl pixel

c++ - OpenGL Scale Single Pixel Line



sdl (2)

Me gustaría hacer un juego que sea internamente 320x240, pero que se muestre en la pantalla con múltiplos enteros de este (640x480, 960,720, etc.). Voy por gráficos retro de píxeles 2D.

He logrado esto configurando la resolución interna a través de glOrtho ():

glOrtho(0, 320, 240, 0, 0, 1);

Y luego escalo la resolución de salida en un factor de 3, así:

glViewport(0,0,960,720); window = SDL_CreateWindow("Title", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 960, 720, SDL_WINDOW_OPENGL);

Dibujo rectángulos como este:

glBegin(GL_LINE_LOOP); glVertex2f(rect_x, rect_y); glVertex2f(rect_x + rect_w, rect_y); glVertex2f(rect_x + dst_w, dst_y + dst_h); glVertex2f(rect_x, rect_y + rect_h); glEnd();

Funciona perfectamente a 320x240 (sin escala):

Cuando escalo hasta 960x720, ¡la representación de píxeles funciona bien! Sin embargo, parece que GL_Line_Loop no se dibuja en un lienzo de 320x240 y se amplía, sino que se dibuja en el lienzo final de 960x720. El resultado son líneas de 1 px en un mundo de 3 px :(

¿Cómo dibujo líneas al lienzo glOrtho 320x240, en lugar del lienzo de salida 960x720?


Como mencioné en mi comentario, los controladores Intel OpenGL tienen problemas con el renderizado directo a la textura y no conozco ninguna solución alternativa que esté funcionando. En tal caso, la única forma de evitar esto es usar glReadPixels para copiar el contenido de la pantalla en la memoria de la CPU y luego volver a copiarlo en la GPU como textura. De grueso que es mucho más lento que el renderizado directo a textura. Así que aquí está el trato:

  1. establecer vista de baja resolución

    no cambie la resolución de su ventana solo los valores de glViewport . Luego renderice su escena en baja resolución (en solo una fracción del espacio de la pantalla)

  2. copia la pantalla renderizada en textura

  3. establecer vista de resolución objetivo
  4. renderizar la textura

    no olvides usar el filtro GL_NEAREST . ¡Lo más importante es que intercambie los buffers solo después de esto, no antes! De lo contrario, habría parpadeo.

Aquí la fuente de C ++ para esto:

void gl_draw() { // render resolution and multiplier const int xs=320,ys=200,m=2; // [low res render pass] glViewport(0,0,xs,ys); glClearColor(0.0,0.0,0.0,1.0); glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDisable(GL_DEPTH_TEST); glDisable(GL_TEXTURE_2D); // 50 random lines RandSeed=0x12345678; glColor3f(1.0,1.0,1.0); glBegin(GL_LINES); for (int i=0;i<100;i++) glVertex2f(2.0*Random()-1.0,2.0*Random()-1.0); glEnd(); // [multiply resiolution render pass] static bool _init=true; GLuint txrid=0; // texture id BYTE map[xs*ys*3]; // RGB // init texture if (_init) // you should also delte the texture on exit of app ... { // create texture _init=false; glGenTextures(1,&txrid); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,txrid); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST); // must be nearest !!! glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_COPY); glDisable(GL_TEXTURE_2D); } // copy low res screen to CPU memory glReadPixels(0,0,xs,ys,GL_RGB,GL_UNSIGNED_BYTE,map); // and then to GPU texture glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,txrid); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, xs, ys, 0, GL_RGB, GL_UNSIGNED_BYTE, map); // set multiplied resolution view glViewport(0,0,m*xs,m*ys); glClear(GL_COLOR_BUFFER_BIT); // render low res screen as texture glBegin(GL_QUADS); glTexCoord2f(0.0,0.0); glVertex2f(-1.0,-1.0); glTexCoord2f(0.0,1.0); glVertex2f(-1.0,+1.0); glTexCoord2f(1.0,1.0); glVertex2f(+1.0,+1.0); glTexCoord2f(1.0,0.0); glVertex2f(+1.0,-1.0); glEnd(); glDisable(GL_TEXTURE_2D); glFlush(); SwapBuffers(hdc); // swap buffers only here !!! }

Y vista previa:

Probé esto en algunos gráficos Intel HD (Dios sabe qué versión) tengo a mi disposición y funciona (mientras que los enfoques estándar de renderizado a textura no lo son).


No hay un "lienzo glOrtho de 320x240". Solo existe la resolución real de la ventana: 960x720.

Todo lo que está haciendo es ampliar las coordenadas de las primitivas que renderiza. Entonces, su código dice que renderice una línea desde, por ejemplo, (20, 20) a (40, 40). Y OpenGL (eventualmente) escala esas coordenadas en 3 en cada dimensión: (60, 60) y (120x120).

Pero eso solo se trata de los puntos finales . Lo que sucede en el medio todavía se basa en el hecho de que está renderizando con la resolución real de la ventana.

Incluso si empleó glLineWidth para cambiar el ancho de sus líneas, eso solo solucionaría los anchos de línea. No solucionaría el hecho de que la rasterización de líneas se basa en la resolución real a la que está renderizando. Por lo tanto, las líneas diagonales no tendrán la apariencia pixelada que probablemente desee.

La única forma de hacerlo correctamente es, bueno, hacerlo correctamente. Renderice a una imagen que sea real 320x240, luego dibuje a la resolución real de la ventana.

Tendrás que crear una textura de ese tamaño, luego adjuntarla a un objeto framebuffer . Enlace el FBO para renderizar y renderizar a él (con la ventana gráfica configurada al tamaño de la imagen). Luego, desenlaza el FBO y dibuja esa textura en la ventana (con la ventana gráfica configurada con la resolución de la ventana).