¿Por qué los triángulos cercanos tienden a desaparecer?

8

Acabo de habilitar el sacrificio de la cara posterior y noto un comportamiento extraño: cuando todos los vértices de mi triángulo están fuera de la vista y 2 de ellos están detrás de mí (creo) el triángulo desaparece.

Entonces, para verlo, aquí hay un GIF.

ingrese la descripción de la imagen aquí

Sospecho que la matriz de proyección invierte el orden de los dos vértices cuando caen detrás de mí y cambia el devanado de mi triángulo.

Pero no está claro por qué los triángulos desaparecen solo si todos los vértices están fuera de la vista ...

¿Cómo puedo solucionar este problema, si es posible?

Me desarrollo en Linux si eso importa.

ACTUALIZAR:

Se señaló que podría no ser debido a la eliminación de la cara posterior. Lo deshabilité y de hecho puedo reproducirlo. Los cubos son de 20 × 20 y la vista del campo vertical es de 90 °. Su tamaño aparente vertical llena más o menos la ventana.

ACTUALIZACIÓN 2:

Ok, publicaré la parte relevante del código, la proyección y las matrices de vista se configuran usando mis propias funciones:

void createViewMatrix(
    GLfloat matrix[16],
    const Vector3 *forward,
    const Vector3 *up,
    const Vector3 *pos
)
{
    /* Setting up perpendicular axes */
    Vector3 rright;
    Vector3 rup = *up;
    Vector3 rforward = *forward;

    vbonorm(&rright, &rup, &rforward); /* Orthonormalization (right is computed from scratch) */

    /* Filling the matrix */
    matrix[0] = rright.x;
    matrix[1] = rup.x;
    matrix[2] = -rforward.x;
    matrix[3] = 0;

    matrix[4] = rright.y;
    matrix[5] = rup.y;
    matrix[6] = -rforward.y;
    matrix[7] = 0;

    matrix[8] = rright.z;
    matrix[9] = rup.z;
    matrix[10] = -rforward.z;
    matrix[11] = 0;

    matrix[12] = -vdp(pos, &rright);
    matrix[13] = -vdp(pos, &rup);
    matrix[14] = vdp(pos, &rforward);
    matrix[15] = 1;
}

void createProjectionMatrix(
    GLfloat matrix[16],
    GLfloat vfov,
    GLfloat aspect,
    GLfloat near,
    GLfloat far
)
{
    GLfloat vfovtan = 1 / tan(RAD(vfov * 0.5));

    memset(matrix, 0, sizeof(*matrix) * 16);
    matrix[0] = vfovtan / aspect;
    matrix[5] = vfovtan;
    matrix[10] = (near+far)/(near-far);
    matrix[11] = -1;
    matrix[14] = (2*near*far)/(near-far);
}

Matriz de proyección configurada con esta llamada:

createProjectionMatrix(projMatrix, VERTICAL_FOV, ASPECT_RATIO, Z_NEAR, 10000);

(VERTICAL_FOV = 90, ASPECT_RATIO = 4.0 / 3, Z_NEAR = 1)

El dibujo de nivel es simplemente:

void drawStuff()
{
    GLfloat projectView[16];

    glClearColor(0, 0, 0, 1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    createViewMatrix(viewMatrix, &camera.forward, &camera.up, &camera.pos);

    multiplyMatrix(projectView, viewMatrix, projMatrix); /*< Row mayor multiplication. */

    glUniformMatrix4fv(renderingMatrixId, 1, GL_FALSE, projectView);
    bailOnGlError(__FILE__, __LINE__);

    renderLevel(&testLevel);
}

Los cubos se representan pared por pared (optimizar esta será otra historia):

    for (j = 0; j < 6; j++)
    {
        glBindTexture(GL_TEXTURE_2D, cube->wallTextureIds[j]);
        bailOnGlError(__FILE__, __LINE__);

        glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_INT, (void*)(sizeof(GLuint) * 4 * j));
        bailOnGlError(__FILE__, __LINE__);
        glUniform4f(extraColorId, 1, 1, 1, 1);
        bailOnGlError(__FILE__, __LINE__);
    }

Sombreador de vértices:

#version 110

attribute vec3 position;
attribute vec3 color;
attribute vec2 texCoord;

varying vec4 f_color;
varying vec2 f_texCoord;

uniform mat4 renderingMatrix;

void main()
{
    gl_Position =  renderingMatrix * vec4(position, 1);
    f_color = vec4(color, 1);
    f_texCoord = texCoord;
}

Sombreador de fragmentos:

#version 110

varying vec4 f_color;
varying vec2 f_texCoord;

uniform sampler2D tex;

uniform vec4 extraColor;

void main()
{
    gl_FragColor = texture2D(tex, f_texCoord) * vec4(f_color) * extraColor;
}

El búfer de profundidad simplemente se configura habilitándolo.

Calmarius
fuente
No puedo entender de qué triángulo estás hablando aquí.
Trevor Powell
@TrevorPowell Las caras cuadradas del cubo se componen de 2 triángulos, la mitad del cuadrado desaparece en la segunda foto.
Calmarius
Lo entendí. ¿Pero a qué cuadrado te refieres? No puedo decir qué parte de la segunda imagen se supone que estoy mirando, y qué vértices en la segunda imagen corresponden a qué vértices en la primera. Parece que la pared azul más a la derecha se está recortando a través del plano de recorte cercano, ¿tal vez? ¿O estás hablando de la pared blanca más a la derecha? ¿O que?
Trevor Powell
1
¿Podrías mostrarnos el código que está causando esto?
akaltar
1
Entonces parece que los triángulos desaparecen en el momento en que el vértice en la parte inferior de la pantalla desaparece. ¿Esto definitivamente comenzó a suceder solo cuando habilitó el sacrificio de la cara posterior, o es posible que lo haya notado después? ¿Son las caras del cubo muy grandes en relación con la parte que podemos ver (estoy pensando en un posible desbordamiento aritmético)? ¿Alguna posibilidad de probarlo en un hardware diferente (podría ser un error del controlador)?
GuyRT

Respuestas:

6

Aunque a menudo los problemas similares son causados ​​por el recorte, el plano cercano no es el problema aquí. Si así fuera, la desaparición sería por píxel y no por triángulo.

En su animación, los triángulos desaparecen exactamente en el momento en que sus tres vértices salen de la pantalla. Su algoritmo puede basarse en la suposición falsa de que los triángulos están ocultos cuando todos sus vértices están ocultos.

Aquí hay un artículo que habla sobre una buena implementación de eliminación de frustum.

danijar
fuente
El triángulo no siempre desaparece cuando todos los vértices salen de la vista. ¿No es esto recortar la tarea de OpenGL?
Calmarius
@Calmarius lo que dice danijar es que es un problema en tu algoritmo de eliminación de frustum, que creo que ni siquiera estás realizando, ¿verdad? Para ser honesto, creo que es un problema / error del controlador.
concept3d
@Calmarius concept3d podría estar en lo cierto, está utilizando Mesa y puede tener un error que causa su problema. ¿Puede ejecutar su código en una máquina con controlador oficial Nvidia o AMD?
danijar
@danijar Quizás más tarde, cuando vuelva a trabajar después de las vacaciones. Estoy usando computadoras viejas descartadas que no tienen una tarjeta de video adicional incorporada solo en la de a bordo.
Calmarius
4

Hasta ahora parece que es un problema del controlador OpenGL. No tengo otra computadora para probar esto para confirmar.

Si forzo la representación del software por

$ export LIBGL_ALWAYS_SOFTWARE=1

El problema desaparece. Probablemente necesito mirar los errores con Mesa.

Calmarius
fuente
Acepto esto, el problema no ocurre en mi escritorio ni en otras computadoras.
Calmarius
-1

está puramente relacionado con el plano de recorte cercano para cámara y no tiene nada relacionado con el sacrificio de la cara posterior. U necesita reducir el plano de recorte cercano y el recorte se disparará.

Saurabh Passolia
fuente
Si observa cuidadosamente, puede ver que un triángulo simplemente desaparece, no tiene nada que ver con el plano de recorte cercano.
Calmarius
-1

Los triángulos están desapareciendo debido al plano cercano de la cámara frustrum. Todo lo que esté más cerca de la cámara que el plano cercano se recorta automáticamente. Solo necesita poner su avión cercano aún más cerca de la ubicación de la cámara. Cómo puede configurar el plano cercano depende de su biblioteca gráfica o motor. En OpenGL, por ejemplo, debe establecer el parámetro zNear de gluPerspective :

void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
dsilva.vinicius
fuente
sí, se ve así y no tiene nada que ver con el sacrificio de la cara posterior.
concept3d
3
¿Causaría eso la desaparición de todo el triángulo que cruza el plano de recorte cercano? ¿No debería simplemente recortar algunos de los fragmentos ?
3
No creo que sea esto; esa cámara parece estar orientada hacia adelante, y esas paredes son verticales, lo que significa que cualquier cosa que se corte al cruzar el plano de recorte cercano debería formar una línea vertical en la pantalla, no estos ángulos poco profundos. Las imágenes que se muestran realmente parecen un triángulo que se selecciona erróneamente.
Trevor Powell
@TrevorPowell Sí, creo que tienes razón, me retracté de mi voto.
concept3d