Criando um HUD / GUI com OpenGL (LWJGL)

15

Estou no estágio de desenvolvimento de jogos em que preciso criar um HUD ou GUI. Eu nunca cheguei a essa parte, então não sei como é feito. Tentei renderizar um quad simples em uma posição fixa na tela, mas há um problema. Para fazer minha câmera funcionar com ortografia, eu uso o seguinte:

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);
}

Não vejo como seria capaz de corrigir algo na tela usando esse método? Alguma maneira de contornar isso? Obrigado :)

smoth190
fonte
Não responderei porque isso é da perspectiva do Direct3D, mas se você usar as coordenadas ([0...1], [0...1], 0, 1)sem projeção, exibição ou matriz mundial, elas sempre aparecerão no espaço da tela.
11137 Jonathan Dickinson
stackoverflow.com/questions/5467218/opengl-2d-hud-over-3d
Ciro Santilli新疆改造中心法轮功六四事件

Respostas:

13

Isso é de um antigo mecanismo de jogo baseado em OpenGL que eu estava tentando escrever há cerca de sete anos, escrito em C ++ tão nu comigo, enquanto tentava explicar como lidei com o mundo 3D e as operações de renderização da GUI 2D dentro dele. Eu usei quatro métodos principais dentro da minha classe de renderizador OpenGL (OGLRender), dos quais são:

  • ready3D () para preparar o OpenGL para renderizar a cena mundial em 3D.
  • ready2D () para preparar o OpenGL para renderizar a GUI 2D.
  • render3D () para o desenho real da cena mundial em 3D.
  • render2D () para o desenho real da 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 ...
    }

E então, no loop principal do thread, eu basicamente chamava os métodos na seguinte ordem:

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

    SDL_GL_SwapBuffers(); // make drawn frame visible
}

Então, o que estou fazendo é desenhar minha cena mundial em 3D primeiro e depois desenhar minha GUI por último, para que a GUI esteja sempre no topo da cena mundial. O método ready3D () prepara a projeção do mundo 3D para o desenho da cena mundial e o método ready2D () prepara a cena orto 2D pronta para o desenho da GUI. m_Setup.widthe m_Setup.heightsão apenas as dimensões da tela da porta de visualização.

O que há de especial no método ready2D () é que a gluOrtho2D()função é chamada com argumentos que informam que, quando desenhamos as primitivas da GUI, as desenhamos nas coordenadas da tela especificadas para corresponder ao Windows, Mac e outros sistemas de coordenadas da tela da área de trabalho. Como no canto superior esquerdo, é (0,0) no formato (X, Y), enquanto no canto inferior direito (ViewportWidth-1, ViewportHeight-1). E glTranslatef()é usado para corrigir o posicionamento preciso por pixel. Assim, quando traçarmos uma linha de (0,0) a (0,9), a linha será realmente desenhada do canto superior esquerdo e direto para baixo, totalizando dez pixels de comprimento e largura de um pixel.

No geral, você provavelmente só está interessado no que o método ready2D () está fazendo. Forneci os exemplos de código-fonte dos outros métodos para dar uma idéia geral de como a maioria dos jogos faz cena do mundo 3D e ordem de desenho da GUI.

NAM TRON
fonte
Obrigado, eu simplesmente não sabia se alternar entre orto e perspectiva seria ruim para o desempenho, porque para mim parece uma grande operação (é claro que eu mal sei como o OpenGL funciona ... ainda estou aprendendo!), Mas em todos os lugares que eu visto, e o que você disse, sugira fazer isso. Então eu acho que vou :)
smoth190
Eu gosto dessa resposta, é o que eu estava pensando em fazer. Eu só estava pensando, porém, se isso poderia ser melhor pressionando a matriz de projeção em cada renderização 2D e depois a exibindo. Isso significa que você pode configurar o 3D uma vez com certeza? Então você só precisará chamar sua configuração 3D novamente para alterar o tamanho da janela, se você cuidar disso.
Lightbulb1