Значение Z всегда 1 или -1 при использовании `glm :: перспектива` - PullRequest
4 голосов
/ 04 октября 2019

Я пытаюсь научить себя способам 3D-программирования с OpenGL, но я борюсь с некоторыми вещами, особенно с проекционными матрицами.

Я определил некоторые вершины для куба и успешно передал их моей графикепроцессор. Куб переходит от xyz -0.5 к xyz 0.5 соответственно, что хорошо отображается.

Чтобы переместить его в мою мировую систему координат, я использую эту матрицу модели:

auto model = glm::mat4(
    glm::vec4(1, 0, 0, 0),
    glm::vec4(0, 1, 0, 0),
    glm::vec4(0, 0, 1, 0),
    glm::vec4(0, 0, 0, 1)
);
model = glm::translate(model, glm::vec3(0.f, 0.f, 495.f));
model = glm::scale(model, glm::vec3(100.f, 100.f, 100.f));

Это успешноперемещает мой куб на (-50, -50, 445) -> (50, 50, 545), так что теперь он центрирован в мировых координатах 200x200x1000, которые я определил для себя.

Моя матрица камеры / вида имеет вид

auto view = glm::lookAt(
    glm::vec3(0.f, 0.f, 5.f),
    glm::vec3(0.f, 0.f, 0.f),
    glm::vec3(0.f, 1.f, 0.f)
);

, что немного смещает куб, изменяя егокоординаты z до 440 и 540 соответственно. Я не понимаю, почему это происходит, но я думаю это как-то связано с тем, что glm ожидает правую систему координат, когда я работаю с левой? Хотя я пишу этот вопрос не по этой причине, я был бы рад, если бы кто-нибудь прояснил его для меня.

Теперь к моей реальной проблеме: я пытаюсь использовать glm::perspective. Я называю это так:

auto perspective = glm::perspective(glm::radians(55.f), 1.f, 0.f, 1000.f);

Если я не ошибаюсь, при значении az 440 я могу ожидать, что область отсечения увеличится примерно с -229 до 229, поэтому я ожидаю, чтонижняя правая вершина куба в (-50,-50) видна. Я рассчитал это, нарисовав усеченную фигуру в 2D, когда заметил, что I должен иметь возможность рассчитать высоту любого расстояния до камеры, используя tan(alpha / 2) * distToCamera = maxVisibleCoordinate (работая с соотношением сторон 1: 1). Это правильное предположение? Вот мой ужасный рисунок, может быть, вы можете сказать, что у меня с ним что-то не так:

I hope you can see what I was trying to do

На последнем шаге я пытаюсьсоберите все это вместе в моем вершинном шейдере, используя

gl_Position = projection * view * model * vec4(pos.x, pos.y, pos.z, 1.0);

, который дает совершенно разумный результат для значений x и y, но значение z всегда равно -1, что, насколько я знаю, является правильнымза то, что не отображается.

Для моей передней-нижней-левой вершины куба (-0.5, -0.5, -0.5) результат равен (-96.04, -96.04, -440, -440), нормализован до (-0.218, -0.218, -1).

Для моей задней-верхней-правой вершины куба(0.5, 0.5, 0.5) результат равен (96.04, 96.04, -550, -550), нормализован до (0.218, 0.218, -1).

В чем я ошибаюсь, что мое значение z потеряно и вместо него просто установлено -1? При игре с положением камеры лучшее, что я могу получить, это установить ее на 1, что также приводит к появлению пустого окна и определенно не того, чего я ожидал.

Ответы [ 2 ]

5 голосов
/ 04 октября 2019

Матрица проекции выглядит следующим образом:

enter image description here

На рисунке f обозначает zfar, а n обозначает znear.

Как видите, если вы поставите znear = 0, термин в 4-м столбце станет нулевым, что неверно. Также, -(f+n)/(f-n) = -1, что тоже неверно.

Итак, вывод таков: znear не может быть нулем. Обычно это небольшое значение, например, 0,1

3 голосов
/ 04 октября 2019

Поскольку Amadeus уже правильно ответил на вопрос, я просто воспользуюсь этим пробелом, чтобы добавить поясняющую информацию о том, почему он правильный.

Мы можем обратиться к предоставленной вами диаграмме, чтобы объяснить, в чем проблемаесть: у вас есть две плоскости, ближняя и дальняя, представляющие диапазон, на котором вы можете просматривать объекты. Что делает «Матрица перспективы», так это то, что она берет все между этими двумя плоскостями в пределах определенного вами Frustrum (математически конус, но наши мониторы имеют прямоугольную форму, так что ...) и отображает их на плоскую ближнюю плоскость, чтобы создатьокончательное изображение. В некотором смысле вы можете думать о ближней плоскости как о представлении монитора.

Итак, учитывая этот контекст, если вы установите расстояние в ближней плоскости равным 0, то есть оно будет идентично камере, что произойдет? Что ж, в конусе он установил бы плоскость в одну точку, а в усечке - то же самое. Вы не можете просматривать объекты, нарисованные в одной точке. Для рисования вам нужна поверхность с фактической площадью поверхности.

Вот почему нецелесообразно устанавливать близкое значение равным 0. Это превратит поверхность рисования в одну точку, и вы не сможете математически визуализировать какие-либо объекты. на одной точке. Следовательно, почему основные математические формулы, лежащие в основе матрицы, сломаются и приведут к плохим результатам, если вы все равно попытаетесь это сделать.

...