Матрица клипов для трехмерной проекции перспективы - PullRequest
5 голосов
/ 30 сентября 2011

Я пытаюсь создать простой движок трехмерной графики и нашел и использовал уравнения, которые я нашел здесь: http://en.wikipedia.org/wiki/3D_projection#cite_note-0. (у меня есть расчеты для Dx, Dy, Dz и Bx, By)

Я работаю, но когда я поворачиваю камеру, достаточно линий начинает летать повсюду, и в конечном итоге вы видите, что полигоны, которые исчезли с экрана, начинают возвращаться на противоположную сторону экрана (вы можете перейти сюда: http://mobile.sheridanc.on.ca/~claassen/3d.html и используйте клавиши W, A, S и D, чтобы повернуть камеру, чтобы увидеть, о чем я говорю)

Я читал это обсуждение: Как преобразовать трехмерную точку в двухмерную перспективную проекцию? , где он говорил об использовании матрицы клипов, но я все еще немного сбит с толку относительно того, как именно ее использовать. Также я не уверен, что использую «однородные координаты», как описано в обсуждении.

Ответы [ 2 ]

22 голосов
/ 25 ноября 2013

После умножения на матрицу перспективной проекции (или матрицу клипов) вы получите однородный 4-вектор [x, y, z, w]. Это называется npc (нормализованные координаты проекции), а также называется координатами клипа. Чтобы получить 2D координаты на экране, вы обычно используете что-то вроде

xscreen = (x/w) * screen_width
yscreen = (y/w) * screen_width

Для точек перед камерой это дает вам то, что вы хотите. Но точки за камерой будут иметь w <0, и вы получите значения, которые соответствуют действительным координатам экрана, даже если точка находится за камерой. Чтобы избежать этого, вам нужно закрепить клип. Любая вершина, имеющая w <0, должна быть обрезана. </p>

Быстрая попытка состоит в том, чтобы просто не рисовать линии, если у любой вершины есть w <0. Это должно исправить странные полигоны, которые появляются в вашей сцене. Но это также удалит некоторые строки, которые должны быть видны. </p>

Чтобы полностью решить проблему, вам нужно обрезать все линии, у которых одна вершина находится перед камерой и одна вершина позади камеры. Отсечение означает разрезать линию пополам и выбросить половину, которая находится позади камеры. Линия «обрезается» плоскостью, проходящей через камеру и параллельной экрану дисплея. Задача состоит в том, чтобы найти точку на линии, которая соответствует этой плоскости (то есть, где линия пересекает плоскость). Это произойдет в точке на линии, где w == 0. Вы можете найти эту точку, но потом при попытке найти координаты экрана

xscreen = (x/w) * screen_width
yscreen = (y/w) * screen_width

В итоге вы делитесь на 0 (w == 0). Это причина "ближнего отсечения самолета". Ближайшая плоскость отсечения также параллельна экрану дисплея, но находится перед камерой (между камерой и сценой). Расстояние между камерой и ближней плоскостью отсечения является «ближним» параметром матрицы проекции:

[    near/width   ][        0        ][         0              ][        0       ]
[        0        ][    near/height  ][         0              ][        0       ]
[        0        ][        0        ][(far+near)/(far-near)   ][        1       ]
[        0        ][        0        ][-(2*near*far)/(far-near)][        0       ]

Чтобы обрезать ближнюю плоскость, вы должны найти точку на линии, которая пересекает ближнюю плоскость отсечения. Это точка, где w == рядом. Так что если у вас есть линия с вершинами v1, v2, где

v1 = [x1, y1, z1, w1]
v2 = [x2, y2, z2, w2]

вам нужно проверить, находится ли каждая вершина перед или позади ближней плоскости отсечения. V1 впереди, если w1> = близко и сзади, если w1 <рядом. Если v1 и v2 оба впереди, то проведите линию. Если v1 и v2 оба позади, тогда не рисуйте линию. Если v1 впереди, а v2 сзади, вам нужно найти vc, где линия пересекает плоскость ближнего клипа: </p>

n = (w1 - near) / (w1 - w2)
xc = (n * x1) + ((1-n) * x2)
yc = (n * y1) + ((1-n) * y2)
zc = (n * z1) + ((1-n) * z2)
wc = near
vc = [xc, yc, zc, wc]

Теперь проведите линию между v1 и vc.

4 голосов
/ 01 октября 2011

Это может быть неправильное понимание терминологии.Матрица клипа более уместно известна как матрица проекции.По крайней мере, в OpenGL матрица проекции преобразует 4D однородные координаты в пространство координат просмотра (VCS) в пространство координат отсечения (CCS) .Для проецирования из CCS в нормализованное пространство устройства (NDCS) требуется перспективное деление, то есть деление каждого компонента на W-компонент.Отсечение правильно сделано перед этим шагом.Таким образом, «матрица отсечения» не устраняет необходимость обрезать геометрию перед проекцией.Надеюсь, я вас понял, и это не звучит снисходительно.

Тем не менее, я думаю, вы, очевидно, правильно поняли матрицу проекции - это работает.Я подозреваю, что вершины, проходящие за глазом , имеют отрицательный W, что означает, что они должны быть обрезаны;но я также подозреваю, что у них отрицательный Z, поэтому деление дает положительное значение Z.Если вы действительно хотите обрезать геометрию, а не отбрасывать целые треугольники, выполните поиск «однородного отсечения».Если вы на самом деле не работаете в однородном пространстве 4D, вы можете начать с рассмотрения 3D-вырезки «Сазерленд-Ходжман».

...