Как мне справиться с проекцией трехмерных точек, отсеченных к плоскости просмотра? - PullRequest
3 голосов
/ 16 декабря 2011

Я создаю программный 3D рендерер только для изучения концепций и математики.Это весело, и у меня есть хороший вращающийся куб на сетке, действующий как своего рода пол.Сетка / пол отображается с использованием отрезков.У меня есть виртуальная камера, расположенная и ориентированная с помощью простого преобразования взгляда.Плоскость просмотра произвольно установлена ​​так, чтобы она находилась на расстоянии n от «глаза» или на z = -n.

Все отлично работает (преобразование из объекта в мир в пространство камеры, отбраковка, проект, клип, рендеринг)кроме одной вещи.При рендеринге сетки конечные точки сегмента линии могут охватывать плоскость просмотра виртуальной камеры.Я хочу визуализировать видимую часть, чтобы закрепить ее на плоскости просмотра.Обрезанная конечная точка проецируется на плоскость просмотра.Проекция:

p'(x) = -n * p(x) / p(z)
p'(y) = -n * p(y) / p(z)

Все потенциально видимые точки будут иметь p(z) ≤ -n.Точка, которая была обрезана до плоскости просмотра, имеет p(z) = -n.Таким образом, я имею в виду:

p'(x) = p(x)
p'(y) = p(y)

для такой точки;ортографическая проекция.

Значения здесь могут легко находиться за пределами окна на плоскости просмотра, что заставляет преобразование области просмотра отправлять эти точки далеко за пределы окна ОС.Эффект заключается в том, что я периодически вижу летающие линии.Это ужасно.

Не говоря уже о том, чтобы делать все, как, скажем, OpenGL делает это (я бы просто использовал OpenGL!), Чего мне не хватает?

Спасибо (если вы сделали это так далеко!).

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

Я не делаю никакой выборки (пока).Возможно, я должен?

enter image description here

Ответы [ 2 ]

0 голосов
/ 28 декабря 2016

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

Прежде всего, можно определить ближнюю и дальнюю плоскости, затем отрезать отрезокна этих плоскостях ( см. пример ).

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

Как выясняется, вы можете выполнять обрезку ближней / дальней линии с помощью простой логики.

Умножьте позицию на матрицу перспективы, чтобы получить вектор 4D. Сравните 4-й компонент с расстояниями ближнего / дальнего отсечения. При необходимости обрежьте сегмент.

Это можно оптимизировать, рассчитав 4-й компонент вектора перед вычислением полной проекции.

Это также означает, что вам не нужно повторно вычислять компоненты XYZ после отсечения.

Например: это умножает вектор 4D на матрицу 4x4.

pub fn mul_m4v4(m: &[[f64; 4]; 4], v: &[f64; 4]) -> [f64; 4] {
    [
        v[0] * m[0][0] + v[1] * m[1][0] + v[2] * m[2][0] + m[3][0] * v[3],
        v[0] * m[0][1] + v[1] * m[1][1] + v[2] * m[2][1] + m[3][1] * v[3],
        v[0] * m[0][2] + v[1] * m[1][2] + v[2] * m[2][2] + m[3][2] * v[3],
        v[0] * m[0][3] + v[1] * m[1][3] + v[2] * m[2][3] + m[3][3] * v[3],
    ]
}

Поскольку это трехмерная позиция, мы можем предположить, что 4-й компонент равен 1.0.

pub fn mul_m4v3_as_v4(m: &[[f64; 4]; 4], v: &[f64; 3]) -> [f64; 4] {
    [
        v[0] * m[0][0] + v[1] * m[1][0] + v[2] * m[2][0] + m[3][0],
        v[0] * m[0][1] + v[1] * m[1][1] + v[2] * m[2][1] + m[3][1],
        v[0] * m[0][2] + v[1] * m[1][2] + v[2] * m[2][2] + m[3][2],
        v[0] * m[0][3] + v[1] * m[1][3] + v[2] * m[2][3] + m[3][3],
    ]
}

Чтобы избежать полного расчета, выделите отдельную функцию для получения 4-го компонента.

pub fn mul_project_m4_v3_zfac(m: &[[f64; 4]; 4], v: &[f64; 3]) -> [f64; 4] {
    v[0] * m[0][3] + v[1] * m[1][3] + v[2] * m[2][3] + m[3][3]
}

Вот коммит , который реализует отсечение, как описано выше.

Примечание: матрицы являются основными столбцами (как OpenGL).

0 голосов
/ 09 января 2012

Вы должны быть в состоянии избавиться от этих точек, которые выступают за пределы вашего экранного пространства без необходимости смотреть на объем усеченного конуса. Итак, перед тем, как приступить к выбору усеченного конуса, каков ваш алгоритм ограничения пространства на экране? Посмотрите на эти алгоритмы: http://en.wikipedia.org/wiki/Line_clipping и посмотрите, сможете ли вы извлечь из этого пользу.

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

...