Hacer un HUD / GUI con OpenGL (LWJGL)

15

Estoy en la etapa de desarrollo de mi juego donde necesito hacer un HUD o GUI. Nunca he llegado a esta parte, así que no sé cómo se hace. Intenté renderizar un quad simple en una posición fija en la pantalla, pero hay un problema. Para hacer que mi cámara funcione con ortografía, uso esto:

public void lookThrough()
{
    GL11.glMatrixMode(GL11.GL_PROJECTION);
    GL11.glLoadIdentity();
    GL11.glOrtho(position.x, position.x + Display.getDisplayMode().getWidth()/zoom, position.y + Display.getDisplayMode().getHeight()/zoom, position.y, -1, 1);
    GL11.glMatrixMode(GL11.GL_MODELVIEW);
}

No veo cómo podría hacer que algo arreglado en la pantalla con este método. ¿Alguna forma de evitar esto? Gracias :)

smoth190
fuente
No responderé porque esto es desde una perspectiva Direct3D, pero si usa las coordenadas ([0...1], [0...1], 0, 1)sin proyección, vista o matriz mundial, siempre aterrizarán en el espacio de la pantalla.
Jonathan Dickinson
stackoverflow.com/questions/5467218/opengl-2d-hud-over-3d
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Respuestas:

13

Esto es de un viejo motor de juegos basado en OpenGL que estaba tratando de escribir hace siete años, escrito en C ++, tan claro conmigo mientras trato de explicar cómo manejé las operaciones de renderizado 3D GUI y mundo 2D dentro de él. Usé cuatro métodos principales dentro de mi clase de renderizador OpenGL (OGLRender) de los cuales son:

  • ready3D () para preparar OpenGL para representar la escena mundial en 3D.
  • ready2D () para preparar OpenGL para representar la GUI 2D.
  • render3D () para el dibujo real de la escena mundial en 3D.
  • render2D () para el actual dibujo GUI 2D.

    void OGLRender::ready3D()
    {
        glViewport(0, 0, m_Setup.width, m_Setup.height);
        glMatrixMode(GL_PROJECTION);
    
        glLoadIdentity();
        gluPerspective(45, (float) m_Setup.width / m_Setup.height, 0.1, 5000.0);
    
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
    
        glDepthFunc(GL_LEQUAL);
        glEnable(GL_DEPTH_TEST);
    }
    
    void OGLRender::ready2D()
    {
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
    
        gluOrtho2D(0.0f, m_Setup.width, m_Setup.height, 0.0f);
    
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0.375, 0.375, 0.0);
    
        glDisable(GL_DEPTH_TEST);
    }
    
    void OGLRender::render3D()
    {
        this->ready3D();
    
        // ... draw 3D world scene here ...
    }
    
    void OGLRender::render2D()
    {
        this->ready2D();
    
        // ... draw GUI here ...
    }

Y luego, en el bucle de hilo principal, básicamente llamaría a los métodos en el siguiente orden:

while(m_drawFrame)
{
    gm_Render->render3D(); // draw 3D scene
    gm_Render->render2D(); // draw GUI

    SDL_GL_SwapBuffers(); // make drawn frame visible
}

Entonces, lo que estoy haciendo es dibujar primero mi escena mundial en 3D y luego dibujar mi GUI al final de esa manera, la GUI siempre está en la cima de la escena mundial. El método ready3D () prepara la proyección del mundo 3D para el dibujo de la escena mundial y el método ready2D () prepara la escena orto 2D para el dibujo de la GUI. m_Setup.widthy m_Setup.heightson solo las dimensiones de la pantalla del puerto de vista.

Lo que es especial sobre el método ready2D () es que gluOrtho2D()se llama a la función con argumentos que le indican que cuando dibujamos las primitivas de GUI las dibujamos en las coordenadas de pantalla especificadas para que coincidan con Windows, Mac y otros sistemas de coordenadas de pantalla de escritorio. Tal como la parte superior izquierda es (0,0) en formato (X, Y) mientras que la parte inferior derecha es (ViewportWidth-1, ViewportHeight-1). Y glTranslatef()se utiliza para corregir el posicionamiento preciso por píxel. De modo que cuando dibujamos una línea desde (0,0) hasta (0,9), la línea realmente dibujará desde la parte superior izquierda y hacia abajo diez píxeles en total de longitud y un ancho de píxel.

En general, lo más probable es que solo te interese lo que está haciendo el método ready2D () . Proporcioné los ejemplos de código fuente de los otros métodos para darle una idea de cómo generalmente la mayoría de los juegos hacen la escena mundial 3D y el orden de dibujo de la GUI.

NAM TRON
fuente
Gracias, simplemente no sabía si cambiar entre orto y perspectiva sería malo para el rendimiento, porque para mí parece una gran operación (por supuesto, apenas sé cómo funciona OpenGL ... ¡todavía estoy aprendiendo!), Pero en todas partes he visto, y lo que dijiste, sugiere hacer esto. Así que supongo que lo haré :)
smoth190
Me gusta esta respuesta, es un poco lo que estaba pensando hacer. Sin embargo, me preguntaba si podría hacerse mejor presionando la matriz de proyección en cada render 2D y luego apareciéndola. ¿Eso significaría que solo podrías configurar 3D una vez? Entonces solo necesitaría llamar a su configuración 3D nuevamente para cambios de tamaño de ventana si maneja eso.
Bombilla1