OpenGL: Como determinar se um ponto 3D (renderizado) é ocluído por outras primitivas 3D (renderizadas) na frente dele?

StackOverflow https://stackoverflow.com/questions/1311869

  •  19-09-2019
  •  | 
  •  

Pergunta

No meu programa OpenGL, estou fazendo o seguinte em sequência:

// Drawing filled polyhedrons
// Drawing points using GL_POINTS
// Displaying information for each above point beside it

Para exibir as informações de ponto (digamos um identificador/número de pontos), converti as coordenadas 3D do ponto para coordenadas de janela 2D usando GluProject(). Eu escrevo o identificador de ponto naquele local da janela 2D usando GLRASTERPOS() e código de renderização de caracteres 2D.

Quando um ponto renderizado é ocluído por outro primitivo, é automaticamente não exibido devido ao teste de oclusão automática e teste de profundidade que acontecem no pipeline do OpenGL. No entanto, o texto do meu identificador de argumento é exibido ao lado do ponto, mesmo quando é ocluído, pois não recebo essas informações de oclusão.

Como determinar se um ponto 3D (renderizado) é ocluído por outras primitivas 3D (renderizadas) na frente dele? Ou existe uma maneira melhor de exibir o texto da informação de ponto ao lado dele Quando não é ocluído?

Nota: Estou ciente dos métodos que exigem um passe extra de renderização. Eu sinto que esses são caros para o meu propósito.

Foi útil?

Solução

Se você não estiver disposto a usar um segundo passe de consulta de oclusão, tente amostrar o Z-Buffer para comparar com o seu ponto de teste.

Como você está adicionando texto ao lado de um ponto, pegue o valor normalizado do tampão Z (digamos usando o GluProject) do ponto e compare esse valor com o valor Z-buffer amostrado (usando GlReadPixels) nesse ponto. Se o seu ponto estiver atrasado (maior que) o valor de profundidade que você amostrou, seu ponto deverá ser ocluído e você pode optar por não desenhar o texto.

É claro que isso exige que você renderize toda a sua geometria antes do texto, mas isso não deve ser um problema.

Código de amostra:

// Assumed to already hold 3D coordinates of point
GLdouble point3DX, point3DY, point3DZ;

// Project 3D point coordinates to 2D
GLdouble point2DX, point2DY, point2DZ;  // 2D coordinates of point
gluProject( point3DX, point3DY, point3DZ,
            mMatrix, pMatrix, vMatrix,      // MVP matrices
            &point2DX, &point2DY, &point2DZ);

// Read depth buffer at 2D coordinates obtained from above
GLfloat bufDepth = 0.0;
glReadPixels(   static_cast<GLint>( point2DX ), static_cast<GLint>( point2DY ),     // Cast 2D coordinates to GLint
                1, 1,                                                               // Reading one pixel
                GL_DEPTH_COMPONENT, GL_FLOAT,
                &bufDepth);

// Compare depth from buffer to 2D coordinate "depth"
GLdouble EPSILON = 0.0001;  // Define your own epsilon
if (fabs(bufDepth - point2DZ) < EPSILON)
    // 3D point is not occluded
else
    // 3D point is occluded by something

Outras dicas

A leitura do Z-Buffer pode ser muito lenta no hardware moderno. É por isso que a consulta de oclusão foi inventada. Procure a extensão ARB-OCCLUST-QUERY. Ele tem alguns quadros de atraso antes que você possa obter os resultados, mas não atingirá seu desempenho.

Se a consulta de oclusão não funcionar por qualquer motivo, a próxima opção de fallback é fazer uma operação de software de raio-intelect no mundo usando uma árvore BSP (que não usa GL).

Além da resposta de Alan, você pode testar matematicamente, projetando um raio da posição da sua câmera ao seu ponto e determinando se ele cruza alguma de sua geometria. Existem muitas referências na internet por fazer testes de interseção de Ray-Object (ver, por exemplo, o Página de interseção de objeto/objeto). Se você tiver muita geometria, pode acelerar as coisas usando volumes delimitadores ou uma árvore BSP.

Como bônus, seu código de oclusão deve ser muito mais fácil de fazer um teste de unidade, porque não depende de extrair valores do OpenGL.

A resposta de Ashwin Nanjappa foi muito útil. Não sou especialista em OpenGL, então demorei um pouco para descobrir como obter matrizes MVP. Estou compartilhando o código aqui para complementar o post dele:

    GLint viewport[4];
    GLdouble modelview[16];
    GLdouble projection[16];
    glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
    glGetDoublev( GL_PROJECTION_MATRIX, projection );
    glGetIntegerv( GL_VIEWPORT, viewport );
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top