Матрицы проекции: на что должна быть нанесена карта глубины? - PullRequest
0 голосов
/ 19 октября 2018

Я сталкиваюсь с противоречиями при попытке построить матрицу проекции для Vulkan, и мне еще предстоит найти объяснение того, как матрица проекции должна отображать Z из входного вектора в выходной.Отобразить x и y просто.Насколько я понимаю, матрицы проекции OpenGL должны отображать ближнюю плоскость усеченного контура в -1, а далеко в +1.Вулкан до 0 и +1 соответственно.Отображение должно быть логарифмическим, что обеспечивает большую точность в ближнем поле.

В приведенных ниже примерах используется near (n) = 1, far (f) = 100. Вот график отображения z с использованием матрицы, которую я построил дляВулкан спец.Он выдает ошибки при рендеринге, но выдает правильный результат, насколько я понимаю:

lambda z: (f / (f-n) * z - f*n/(f-n)) / z enter image description here

График наиболее распространенной проекции OpenGL I 'мы нашли в сети, которая должна отображаться от -1 до +1:

lambda z: ((-f+n)/(f-n)*z - 2*f*n/(f-n))/-z enter image description here

А вот один из сгенерированных мной библиотек для OpenGL(cgmath в Rust): enter image description here

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

1 Ответ

0 голосов
/ 19 октября 2018

Отображение должно быть логарифмическим, что обеспечивает большую точность в ближнем поле.

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

Графикиз наиболее распространенной проекции OpenGL, которую я нашел в сети, которая должна отображаться от -1 до +1:

lambda z: ((-f+n)/(f-n)*z - 2*f*n/(f-n))/-z 

Нет.У вас есть ошибка знака в первом члене, это должно быть

(-(f+n)/(f-n)*z - 2*f*n/(f-n))/-z 

Следовательно, ваш сюжет просто неверен.С исправленной формулой вы получите сюжет, похожий на вашу cgmath библиотеку ржавчины.

Но важная часть - это нечто другое: Вы замышляете не ту вещь !Обратите внимание на -z на знаменателе в этой формуле?Классическим соглашением GL всегда было использование правостороннего глазного пространства, но левостороннего оконного пространства.В результате классическая проекционная матрица GL проецируется в направлении -z.Параметры n и f все же задаются как расстояния вдоль направления просмотра.Это означает, что фактические плоскости отсечения будут в z_eye = -n и z_eye=-f в глазном пространстве.То, что вы наметили на графике, это диапазон позади камеры, и вы увидите вторую ветвь гиперболы, ту, которая обычно обрезана в любом направлении, и которая будет отображаться за пределами интервала [-1,1].

Если вы построите отображение для n = 5 и f = 100, вы получите: plot of hyperbolic Z function

Обратите внимание, что проект OpenGL в направлении -zЧистое соглашение, оно ничем не навязывается, поэтому вы также можете использовать +z матрицу проекций.

Я не могу построить правильную матрицу проекций Vulkan (из которых я не нашел ни одной)через гугл), если я не понимаю, что z должен отображаться.Вот график отображения z с использованием матрицы, которую я построил по спецификации Vulkan.Это приводит к ошибкам в рендеринге, но дает правильный результат, насколько я понимаю:

lambda z: (f / (f-n) * z - f*n/(f-n)) / z 

Не уверен, какие ошибки вы видите с этим, но отображение корректно, если вы

  1. предполагают, что по умолчанию вулкан использует [0,1] z клипов, а
  2. хочет направление проекции вдоль +z в пространстве глаза.

Кстати.Соглашение о клипах vulkans [0,1] также позволяет лучше использовать точность при использовании привязки глубины с плавающей запятой: изменив отображение так, чтобы ближняя плоскость была сопоставлена ​​с 1, а дальняя плоскость была сопоставлена ​​с 0, вы можете значительно повысить точность,Посмотрите эту статью по nvidia devblog для получения более подробной информации.

...