Warum verschwinden nahegelegene Dreiecke?

8

Ich habe gerade das Keulen der Rückseite aktiviert und bemerke ein seltsames Verhalten: Wenn sich alle Scheitelpunkte meines Dreiecks außerhalb der Ansicht befinden und zwei von ihnen hinter mir liegen (glaube ich), verschwindet das Dreieck.

Um es zu sehen, hier ist ein GIF.

Geben Sie hier die Bildbeschreibung ein

Ich vermute, dass die Projektionsmatrix die Reihenfolge der beiden Eckpunkte umkehrt, wenn sie hinter mich fallen, und die Wicklung meines Dreiecks ändert.

Es ist jedoch unklar, warum die Dreiecke nur verschwinden, wenn alle Scheitelpunkte nicht sichtbar sind ...

Wie kann ich dieses Problem nach Möglichkeit umgehen?

Ich entwickle unter Linux, wenn das wichtig ist.

AKTUALISIEREN:

Es wird darauf hingewiesen, dass dies möglicherweise nicht auf das Keulen der Rückseite zurückzuführen ist. Ich habe es deaktiviert und kann es tatsächlich reproduzieren. Die Würfel sind 20 × 20 und die vertikale Feldansicht beträgt 90 °. Seine vertikale scheinbare Größe füllt das Fenster ungefähr aus.

UPDATE 2:

Ok, ich werde den relevanten Teil des Codes veröffentlichen. Projektions- und Ansichtsmatrizen werden mit meinen eigenen Funktionen eingerichtet:

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

Mit diesem Aufruf eingerichtete Projektionsmatrix:

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

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

Levelzeichnung ist einfach:

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

Würfel werden Wand für Wand gerendert (dies zu optimieren wird eine andere Geschichte sein):

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

Vertex-Shader:

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

Fragment Shader:

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

Der Tiefenpuffer wird einfach durch Aktivieren eingerichtet.

Calmarius
quelle
Ich kann hier nicht herausfinden, von welchem ​​Dreieck Sie sprechen.
Trevor Powell
@TrevorPowell Die quadratischen Flächen des Würfels bestehen aus 2 Dreiecken. Die Hälfte des Quadrats verschwindet auf dem 2. Bild.
Calmarius
Ich habe das verstanden. Aber auf welches Quadrat beziehen Sie sich? Ich kann nicht sagen, welches Bit des zweiten Bildes ich betrachten soll und welche Scheitelpunkte im zweiten Bild welchen Scheitelpunkten im ersten entsprechen. Es sieht nur so aus, als würde die am weitesten rechts stehende blaue Wand durch die nahe Clip-Ebene schneiden, vielleicht? Oder redest du von der ganz weißen Wand ganz rechts? Oder was?
Trevor Powell
1
Können Sie uns den Code zeigen, der dies verursacht?
Akaltar
1
Es sieht also so aus, als würden die Dreiecke verschwinden, sobald der Scheitelpunkt am unteren Bildschirmrand nicht mehr sichtbar ist. Hat dies definitiv erst begonnen, als Sie das Keulen der Rückseite aktiviert haben, oder ist es möglich, dass Sie es erst später bemerkt haben? Sind die Flächen des Würfels relativ zu dem Teil, den wir sehen können, sehr groß (ich denke an einen möglichen arithmetischen Überlauf)? Gibt es eine Chance, es auf einer anderen Hardware zu versuchen (es könnte ein Treiberfehler sein)?
GuyRT

Antworten:

6

Obwohl ähnliche Probleme häufig durch Abschneiden verursacht werden, ist das nahe Flugzeug hier nicht das Problem. Wenn dies der Fall wäre, würde das Verschwinden pro Pixel und nicht pro Dreieck erfolgen.

In Ihrer Animation verschwinden die Dreiecke genau in dem Moment, in dem alle drei Eckpunkte den Bildschirm verlassen. Ihr Algorithmus basiert möglicherweise auf der falschen Annahme, dass Dreiecke ausgeblendet sind, wenn alle ihre Scheitelpunkte ausgeblendet sind.

In diesem Artikel geht es um eine gute Implementierung von Frustum Culling.

Danijar
quelle
Das Dreieck verschwindet nicht immer, wenn alle Scheitelpunkte nicht sichtbar sind. Beschneidet das nicht die Aufgabe der OpenGL?
Calmarius
@Calmarius Was Danijar sagt, ist, dass es ein Problem in Ihrem Frustum-Culling-Algorithmus ist, den Sie meiner Meinung nach nicht einmal ausführen, oder? Um ehrlich zu sein, denke ich, dass es sich um ein Treiberproblem handelt.
Konzept3d
@Calmarius concept3d könnte richtig sein, Sie verwenden Mesa und es könnte einen Fehler geben, der Ihr Problem verursacht. Können Sie Ihren Code auf einem Computer mit offiziellem Nvidia- oder AMD-Treiber ausführen?
Danijar
@danijar Vielleicht später, wenn ich nach den Ferien wieder zur Arbeit gehe. Ich verwende alte verschrottete Computer, auf denen keine zusätzliche Grafikkarte nur in die integrierte integriert ist.
Calmarius
4

Bisher scheint es sich um ein OpenGL-Treiberproblem zu handeln. Ich habe keinen anderen Computer, auf dem ich dies testen kann, um dies zu bestätigen.

Wenn ich das Rendern von Software erzwinge

$ export LIBGL_ALWAYS_SOFTWARE=1

Das Problem verschwindet. Wahrscheinlich muss ich mich mit Mesa umsehen.

Calmarius
quelle
Ich akzeptiere dies, das Problem tritt weder auf meiner Desktop-Box noch auf anderen Computern auf.
Calmarius
-1

Es ist rein verwandt mit der nahen Clipping-Ebene für die Kamera und hat nichts mit dem Keulen der Rückseite zu tun. Sie müssen die nahe Clipping-Ebene reduzieren, und der Clipping wird ausgelöst.

Saurabh Passolia
quelle
Wenn Sie genau hinschauen, können Sie sehen, dass ein Dreieck einfach verschwindet. Es hat nichts mit der nahen Schnittebene zu tun.
Calmarius
-1

Die Dreiecke verschwinden aufgrund der nahen Ebene des Kamera-Frustrums. Alles, was näher an der Kamera als an der nahen Ebene liegt, wird automatisch abgeschnitten. Sie müssen nur Ihr nahes Flugzeug noch näher an den Kamerastandort bringen. Wie Sie die Near-Ebene konfigurieren können, hängt von Ihrer grafischen Bibliothek oder Engine ab. In OpenGL sollten Sie beispielsweise den Parameter zNear von gluPerspective festlegen :

void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
dsilva.vinicius
quelle
ja sieht so aus und hat nichts mit Backface Culling zu tun.
Konzept3d
3
Würde dies dazu führen, dass das gesamte Dreieck, das die nahe Schnittebene kreuzt, verschwindet? sollte es nicht einfach einige der Fragmente abschneiden ?
3
Ich denke nicht, dass es das ist; Diese Kamera scheint geradeaus zu zeigen, und diese Wände sind vertikal. Dies bedeutet, dass alles, was durch Überqueren der nahen Schnittebene abgeschnitten wird, eine vertikale Linie auf dem Bildschirm bilden sollte, nicht diese flachen Winkel. Die gezeigten Bilder sehen wirklich aus wie ein Dreieck, das fälschlicherweise ausgesondert wird.
Trevor Powell
@TrevorPowell Ja, ich denke du hast Recht, ich habe meine Stimme zurückgezogen.
Konzept3d