Почему фигура не отображается, если смотреть на нее сверху? - PullRequest
2 голосов
/ 09 мая 2020

Я изменил tutorial04. cpp немного из http://www.opengl-tutorial.org/beginners-tutorials/tutorial-4-a-colored-cube/

Я сделал форму пирамиды, и я хотел поместить камеру над пирамидой и посмотреть вниз на нем, но я обнаружил, что когда камера находится прямо над пирамидой, она вообще не отображает. Если я изменю свое значение X на любое другое значение, кроме 0, оно будет отображаться нормально.

Pyramid when camera is located at 1, 10, 0

Если я установил для X значение -0.0000001f или 0.0000001f, он также будет отображаться нормально .

Приведенный ниже код не работает.

glm::mat4 View = glm::lookAt(
    glm::vec3(0,10,0), // Camera
    glm::vec3(0,0,0), // and looks at the origin
    glm::vec3(0,1,0)  // Head is up (set to 0,-1,0 to look upside-down)
);

Этот код работает нормально

glm::mat4 View = glm::lookAt(
    glm::vec3(1,10,0), // Camera
    glm::vec3(0,0,0), // and looks at the origin
    glm::vec3(0,1,0)  // Head is up (set to 0,-1,0 to look upside-down)
);

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

a: 0,1,0

b: 1,0, -1

c: 1,0,1

d: -1 , 0,1

e: -1,0, -1

Треугольник 1: a, b, c

Треугольник 2: a, c, d

Треугольник 3: a, e, b

Треугольник 4: a, e, b

Треугольник 5: b, d, c

Треугольник 6: d, b, e

static const GLfloat g_vertex_buffer_data[] = {
0,1,0,
1,0,-1,
1,0,1,//a,b,c
0,1,0,
1,0,1,
-1,0,1,//a,c,d
0,1,0,
-1,0,1,
-1,0,-1,//a,d,e
0,1,0,
-1,0,-1,
1,0,-1,//a,e,b
1,0,-1,
-1,0,1,
1,0,1,//b,d,c
-1,0,1,
1,0,-1,
-1,0,-1//4,2,5
};

1 Ответ

4 голосов
/ 11 мая 2020

Вы не первый, кто попался на этот эффект: ссылка

Есть два решения:

  • либо не использовать lookAt функционируют вообще и представляют повороты вашей камеры с помощью кватерниона;
  • или отслеживают и никогда не применяют «прямо вверх» (0, X, 0) или «прямо вниз» (0, -X, 0 ) направление взгляда для вашей камеры.

В чем именно проблема? Я попытался вникнуть в код glm, и вот как lookAt выглядит как

    template<typename T, qualifier Q>
    GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtLH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up)
    {
        vec<3, T, Q> const f(normalize(center - eye));
        vec<3, T, Q> const s(normalize(cross(up, f)));
        vec<3, T, Q> const u(cross(f, s));

        mat<4, 4, T, Q> Result(1);
        Result[0][0] = s.x;
        Result[1][0] = s.y;
        Result[2][0] = s.z;
        Result[0][1] = u.x;
        Result[1][1] = u.y;
        Result[2][1] = u.z;
        Result[0][2] = f.x;
        Result[1][2] = f.y;
        Result[2][2] = f.z;
        Result[3][0] = -dot(s, eye);
        Result[3][1] = -dot(u, eye);
        Result[3][2] = -dot(f, eye);
        return Result;
    }

Если ваша камера смотрит прямо вверх или вниз, то f будет (0,1,0), s всегда будет (0,0,0), потому что up и f коллинеарны, поэтому их перекрестное произведение равно нулю, а u тоже (0,0,0), потому что s является. Итак, матрица результатов, которую вы получите:

[0 0 0 0]
[0 0 1 0]
[0 0 0 0]
[0 0 0 1]

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

Это также может быть неявным частным случаем Gimbal Lock - эффект, когда интуитивное "XYZ" вращение может привести к потере 1 или более степеней свободы, что сделает невозможным "открутить". "пространство назад. Вот где появляются кватернионы, они не страдают от Gimbal Lock, им требуется меньше памяти для хранения по сравнению с mat4, они быстрее вычисляются, их сложнее объяснить и понять (но glm имеет реализацию это, так что используйте это). Имейте в виду, что вы не должны изменять компоненты кватерниона самостоятельно, иначе он станет недействительным, поэтому вместо этого используйте только функции, которые знают, как их изменять).

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

...