Почему соседние треугольники имеют тенденцию исчезать?

8

Я только что включил отбраковку спины и замечаю странное поведение: когда все вершины моего треугольника находятся вне поля зрения, и 2 из них находятся позади меня (я думаю), треугольник исчезает.

Чтобы увидеть это, вот GIF.

введите описание изображения здесь

Я подозреваю, что проекционная матрица меняет порядок двух вершин, когда они отстают от меня, и меняет намотку моего треугольника.

Но непонятно, почему треугольники исчезают, только если все вершины не видны ...

Как я могу обойти эту проблему, если это возможно?

Я разрабатываю на Linux, если это имеет значение.

ОБНОВИТЬ:

Указано, что это может быть не из-за выбраковки задней поверхности. Я отключил это, и я действительно могу воспроизвести это. Кубики имеют размер 20 × 20, а вертикальный обзор поля составляет 90 °. Его вертикальный видимый размер примерно заполняет окно.

ОБНОВЛЕНИЕ 2:

Хорошо, я опубликую соответствующую часть кода, матрицы проекции и представления настроены с использованием моих собственных функций:

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

Матрица проекции, настроенная с помощью этого вызова:

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

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

Уровень рисования просто:

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

Кубики отрисовываются стена за стеной (оптимизация будет другой историей):

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

Вершинный шейдер:

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

Фрагмент шейдера:

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

Буфер глубины просто настраивается путем его включения.

Calmarius
источник
Я не могу понять, о каком треугольнике ты говоришь, здесь.
Тревор Пауэлл
@TrevorPowell Квадратные грани куба состоят из 2 треугольников, половина квадрата исчезает на втором рисунке.
Кальмарий
Я понял это. Но на какую площадь вы ссылаетесь? Я не могу сказать, на какой бит второго изображения я должен смотреть, и какие вершины на втором изображении соответствуют каким вершинам на первом. Может быть, это похоже на то, что самая правая синяя стена прорезает ближайшую плоскость обрезки? Или вы говорите о самой правой белой стене? Или что?
Тревор Пауэлл
1
Не могли бы вы показать нам код, который вызывает это?
akaltar
1
Таким образом, похоже, что треугольники исчезают в тот момент, когда вершина внизу экрана исчезает из поля зрения. Это определенно начало происходить только тогда, когда вы включили отбраковку лица назад, или возможно, вы просто заметили это потом? Являются ли грани куба очень большими относительно той части, которую мы видим (я думаю о возможном арифметическом переполнении)? Есть ли шанс попробовать его на другом оборудовании (это может быть ошибка драйвера)?
GuyRT

Ответы:

6

Хотя подобные проблемы часто вызваны отсечкой, ближняя плоскость здесь не является проблемой. Если это произойдет, исчезновение будет за пиксель, а не за треугольник.

В вашей анимации треугольники точно исчезают в тот момент, когда все его три вершины выходят за пределы экрана. Ваш алгоритм может быть основан на ложном предположении, что треугольники скрыты, когда скрыты все их вершины.

Вот статья, рассказывающая о хорошей реализации отбраковки frustum.

Данияр
источник
Треугольник не всегда исчезает, когда все вершины не видны. Разве это не обрезает задачу OpenGL?
Кальмарий
@ Калмариус, что говорит Данияр, в том, что это проблема в вашем алгоритме отбраковки усеченного конуса, который, я думаю, вы даже не выполняете, не так ли? Если честно, я думаю, что это проблема с драйверами.
concept3d
@ Calmarius concept3d может быть прав, вы используете Mesa, и это может быть ошибка, которая вызывает вашу проблему. Можете ли вы запустить свой код на машине с официальным драйвером Nvidia или AMD?
Данияр
@danijar Может быть позже, когда я вернусь на работу после отпуска. Я использую старые сломанные компьютеры, в которых нет дополнительной видеокарты, встроенной только в бортовую.
Кальмарий
4

Пока что кажется, что это проблема с драйвером OpenGL. У меня нет другого компьютера, чтобы проверить это, чтобы подтвердить.

Если я форсирую рендеринг программного обеспечения

$ export LIBGL_ALWAYS_SOFTWARE=1

Проблема уходит. Вероятно, мне нужно осмотреть ошибки с Mesa.

Calmarius
источник
Я принимаю это, проблема не возникает ни на моем рабочем столе, ни на других компьютерах.
Кальмариус
-1

это чисто связано с ближней плоскостью отсечения для камеры и не имеет ничего общего с отбраковкой задней поверхности. Вам нужно уменьшить ближнюю плоскость отсечения, и отсечение исчезнет.

Саураб Пассолия
источник
Если вы посмотрите внимательно, вы увидите, что треугольник просто исчезает, это не имеет ничего общего с ближней плоскостью отсечения.
Кальмарий
-1

Треугольники исчезают из-за ближней плоскости камеры. Все, что ближе к камере, чем ближняя плоскость, автоматически обрезается. Вам просто нужно расположить ближний самолет еще ближе к месту расположения камеры. Как вы можете настроить ближнюю плоскость, зависит от вашей графической библиотеки или движка. Например, в OpenGL вы должны установить параметр zNear для gluPerspective :

void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
dsilva.vinicius
источник
да, выглядит так, и не имеет ничего общего с отбраковкой задней поверхности.
concept3d
3
это заставило бы исчезнуть весь треугольник, который пересекает ближнюю плоскость отсечения? не должно ли это просто обрезать некоторые фрагменты ?
3
Я не думаю, что это так; эта камера смотрит прямо вперед, а эти стены вертикальные, что означает, что все, что обрезается при пересечении ближней плоскости отсечения, должно образовывать вертикальную линию на экране, а не эти мелкие углы. Показанные изображения действительно выглядят как треугольник, ошибочно выброшенный.
Тревор Пауэлл
@TrevorPowell Да, я думаю, что вы правы, я отозвал свой голос.
concept3d