Erro de Instância de Objeto Rápido do OpenGL

8

Eu tenho algum código que percorre um conjunto de objetos e renderiza instâncias desses objetos. A lista de objetos que precisam ser renderizados é armazenada como um std :: map>, onde um objeto da classe MeshResource contém os vértices e índices com os dados reais, e um objeto de classMeshRenderer define o ponto no espaço em que a malha deve ser processado em.

Meu código de renderização é o seguinte:

glDisable(GL_BLEND);
    glEnable(GL_CULL_FACE);
    glDepthMask(GL_TRUE);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);

    for (std::map<MeshResource*, std::vector<MeshRenderer*> >::iterator it = renderables.begin(); it != renderables.end(); it++)
    {
        it->first->setupBeforeRendering();
        cout << "<";
        for (unsigned long i =0; i < it->second.size(); i++)
        {
            //Pass in an identity matrix to the vertex shader- used here only for debugging purposes; the real code correctly inputs any matrix.
            uniformizeModelMatrix(Matrix4::IDENTITY);
            /**
             * StartHere fix rendering problem.
             * Ruled out:
             *  Vertex buffers correctly.
             *  Index buffers correctly.
             *  Matrices correct?
             */
            it->first->render();
        }
        it->first->cleanupAfterRendering();
    }

    geometryPassShader->disable();
    glDepthMask(GL_FALSE);
    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);

A função no MeshResource que lida com a configuração dos uniformes é a seguinte:

void MeshResource::setupBeforeRendering()
{
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);
    glEnableVertexAttribArray(3);
    glEnableVertexAttribArray(4);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);
    glBindBuffer(GL_ARRAY_BUFFER, vboID);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); // Vertex position
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 12); // Vertex normal
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 24); // UV layer 0
    glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 32); // Vertex color
    glVertexAttribPointer(4, 1, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 44); //Material index
}

O código que renderiza o objeto é este:

void MeshResource::render()
{
    glDrawElements(GL_TRIANGLES, geometry->numIndices, GL_UNSIGNED_SHORT, 0);
}

E o código que limpa é este:

void MeshResource::cleanupAfterRendering()
{
    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(2);
    glDisableVertexAttribArray(3);
    glDisableVertexAttribArray(4);
}

O resultado final disso é que eu recebo uma tela preta, embora o final do meu pipeline de renderização após o código de renderização (essencialmente apenas desenhando eixos e linhas na tela) funcione corretamente, por isso tenho certeza de que não é um problema com o passagem de uniformes. Se, no entanto, eu alterar o código levemente para que o código de renderização chame a instalação imediatamente antes da renderização, da seguinte maneira:

void MeshResource::render()
{
    setupBeforeRendering();
    glDrawElements(GL_TRIANGLES, geometry->numIndices, GL_UNSIGNED_SHORT, 0);
}

O programa funciona como desejado. Porém, não quero fazer isso, pois meu objetivo é configurar dados de vértice, material etc. etc. uma vez por tipo de objeto e renderizar cada instância atualizando apenas as informações de transformação.

O uniformizeModelMatrix funciona da seguinte maneira:

void RenderManager::uniformizeModelMatrix(Matrix4 matrix)
{
    glBindBuffer(GL_UNIFORM_BUFFER, globalMatrixUBOID);
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(Matrix4), matrix.ptr());
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
HJ Media Studios
fonte
Eu tenho uma configuração quase idêntica para renderizar meus modelos. Exceto que minha chamada de renderização liga o buffer e define os ponteiros de atributo a cada vez. Você está enfrentando problemas de desempenho com isso? Corre muito rápido para mim.
MichaelHouse
Não tenho problemas de desempenho, a menos que tenha centenas de objetos idênticos na tela, mas ainda assim, não consigo descobrir o que está acontecendo de errado aqui, e seria ótimo saber por que o código não está funcionando como o esperado.
HJ Media Studios
11
Nós só precisamos chamar a atenção de @NicolBolas, ele é o especialista residente em openGL.
MichaelHouse
Pode ser uma boa ideia usar offsetofao especificar atributos de vértice
JBeurer

Respostas:

2

Primeiro, o OpenGL está cheio de coisas estranhas, então um bug de driver, por mais improvável que seja, ainda é uma opção - considere testar o aplicativo em diferentes configurações (nVidia vs. AMD, drivers mais antigos) e outras pequenas modificações de código. Por exemplo, você pode começar removendo o "glBindBuffer (GL_UNIFORM_BUFFER, 0);" linha - parece não estar fazendo nada útil de qualquer maneira.

Como tudo aqui parece estar correto, o problema provavelmente não está aqui. Existem duas opções: gDEBugger e percorrer o código no depurador C ++. Parece que algo está sendo redefinido antes do desenho. No gDEBugger, existe um recurso "histórico de chamadas" que pode ajudá-lo a ver quais chamadas foram feitas antes da chamada de empate e em que ordem.

A propósito, sugiro fortemente que você agrupe todas as chamadas de retorno de erro com uma macro que verifique todos os erros possíveis e os gere. Ele deve ser uma macro para oferecer suporte à depuração estendida (arquivo de impressão, linha e a própria linha de código defeituosa) que pode ser desabilitada nas compilações de versão. Se alguma regra secreta for violada, essa configuração deve avisá-lo disso imediatamente.

snake5
fonte
5
Eu evitaria criar links para o site Gremedy. Essa versão do gDEBugger é antiga, sem suporte e com muitos erros. developer.amd.com/tools/heterogeneous-computing/amd-gdebugger é a versão atualizada atualizada da AMD, com suporte para Windows e Linux (no OS X, infelizmente). Existem também outras ferramentas fantásticas de depuração / perf GL no site da AMD, sem mencionar as ferramentas que a NVIDIA e a Intel oferecem.
Sean Middleditch
0

Tenho certeza de que o atributo deve ser vinculado ao buffer atual, portanto, não há razão para refazer esse negócio com os atributos a cada quadro, a menos que você reconstrua o buffer sempre.

Portanto, você provavelmente deve fazê-lo de uma maneira ou de outra - deixe como está ou reconstrua a coisa toda a cada quadro.

Yudrist
fonte
0

TL; DR: erros de driver.

Nos meus testes a partir de hoje (outubro de 2016), os buffers uniformes não são suportados adequadamente pela maioria dos drivers existentes.

Alguns não respeitam, glUniformBlockBindingoutros não atualizam os dados uniformes ( glBufferSubDatae glBufferData) adequadamente, onde as cópias internas em cache dos shaders / GPU dos referidos buffers não são mantidas coerentes.


Do jeito que eu entendo (e do jeito que a Nvidia também entende)

  • Vincule / mapeie seu Objeto de Buffer Uniforme a uma tabela global compartilhada por todos os shaders dentro do driver / GPU OpenGL usando glBindBufferBaseouglBindBufferRange .
  • Mapeie os acessos de buffer uniforme do shader para uma entrada nessa tabela global usando glUniformBlockBinding(shader_id, shader_ubo_index, global_ubo_index);essa configuração por programa de shader , não compartilhado globalmente.

Nota: global_ubo_index NÃO é o nome do objeto de buffer uniforme, mas um índice nessa tabela global.

Essa "complexidade" (que é um ótimo recurso para compartilhar UBOs entre diferentes sombreadores, como valores de iluminação) parece ser o que a maioria dos drivers OpenGL erra. Para ser justo, a redação da documentação do OpenGL também não é a mais inequívoca.

Eu tive que recorrer ao uso de uniformes velhos comuns para outros motoristas.

Ambas as capturas de tela usando objetos de buffer uniformes, dois drivers diferentes:

Erros de buffer uniformes

Stephane Hockenhull
fonte
Com quais drivers você testou? Qual plataforma?
Akaltar