Подтвердить что ты не робот

Основной рендеринг проекции 3D-перспективы на 2D-экран с камерой (без opengl)

Скажем, у меня есть структура данных, такая как:

Camera {
   double x, y, z

   /** ideally the camera angle is positioned to aim at the 0,0,0 point */
   double angleX, angleY, angleZ;
}

SomePointIn3DSpace {
   double x, y, z
}

ScreenData {
   /** Convert from some point 3d space to 2d space, end up with x, y */
   int x_screenPositionOfPt, y_screenPositionOfPt

   double zFar = 100;

   int width=640, height=480
}

...

Без отсечения экрана или большей части чего-либо еще, как бы я вычислил положение x, y на экране некоторой точки, заданной некоторой трехмерной точкой в ​​пространстве. Я хочу проецировать эту трехмерную точку на экран 2d.

Camera.x = 0
Camera.y = 10;
Camera.z = -10;


/** ideally, I want the camera to point at the ground at 3d space 0,0,0 */
Camera.angleX = ???;
Camera.angleY = ????
Camera.angleZ = ????;

SomePointIn3DSpace.x = 5;
SomePointIn3DSpace.y = 5;
SomePointIn3DSpace.z = 5;

ScreenData.x и y - это позиция экрана x трехмерной точки в пространстве. Как рассчитать эти значения?

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

http://en.wikipedia.org/wiki/3D_projection

4b9b3361

Ответ 1

"Как это делается" - использовать гомогенные преобразования и координаты. Вы занимаете точку в пространстве и:

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

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

Гомогенные векторы, точки, преобразования

В 3D однородная точка будет матрицей столбцов вида [x, y, z, 1]. Конечным компонентом является "w", коэффициент масштабирования, который для векторов равен 0: это означает, что вы не можете переводить векторы, что является математически корректным. Мы туда не поедем, мы говорим о точках.

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

Существует 3 первичных однородных преобразования:

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

Орфографическая и перспектива

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

  • Орфографический, обычно используемый для 2D и CAD.
  • Перспектива, хороша для игр и 3D-сред.

Структура орфографической проекции строится следующим образом:

An orthographic projection matrix, courtesy of Wikipedia.

Если параметры включают:

  • Верх: координата Y верхнего края видимого пространства.
  • Внизу: координата Y нижнего края видимого пространства.
  • Слева: координата X левого края видимого пространства.
  • Правильно: координата X правого края видимого пространства.

Я думаю, что это довольно просто. То, что вы устанавливаете, - это область пространства, которая появится на экране, которую вы можете обрезать. Здесь просто, потому что область видимого пространства - это прямоугольник. Обрезка в перспективе сложнее, потому что область, которая появляется на экране или объем просмотра, является frustrum.

Если вам сложно провести время с википедией на перспективной проекции, вот код для создания подходящей матрицы, любезность geeks3D

void BuildPerspProjMat(float *m, float fov, float aspect,
float znear, float zfar)
{
  float xymax = znear * tan(fov * PI_OVER_360);
  float ymin = -xymax;
  float xmin = -xymax;

  float width = xymax - xmin;
  float height = xymax - ymin;

  float depth = zfar - znear;
  float q = -(zfar + znear) / depth;
  float qn = -2 * (zfar * znear) / depth;

  float w = 2 * znear / width;
  w = w / aspect;
  float h = 2 * znear / height;

  m[0]  = w;
  m[1]  = 0;
  m[2]  = 0;
  m[3]  = 0;

  m[4]  = 0;
  m[5]  = h;
  m[6]  = 0;
  m[7]  = 0;

  m[8]  = 0;
  m[9]  = 0;
  m[10] = q;
  m[11] = -1;

  m[12] = 0;
  m[13] = 0;
  m[14] = qn;
  m[15] = 0;
}

Переменные:

  • fov: поле зрения, pi/4 радия - хорошее значение.
  • аспект: отношение высоты к ширине.
  • znear, zfar: используется для отсечения, я проигнорирую их.

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

0   4   8  12
1   5   9  13
2   6  10  14
3   7  11  15

Трансформация видового экрана, координаты экрана

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

Таким образом, для точки p мы бы:

  • Выполните матрицу трансформации модели * p, в результате получим pm.
  • Выполните проекционную матрицу * pm, в результате получив pp.
  • Обрезание pp против объема просмотра.
  • Выполнить матрицу преобразования viewport * pp, в результате получится ps: point on screen.

Резюме

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

Я связался с этим выше, но я настоятельно рекомендую вам прочитать это и загрузить двоичный файл. Это отличный инструмент для дальнейшего понимания преобразований тезисов и того, как он получает точки на экране:

http://www.songho.ca/opengl/gl_transform.html

Что касается фактической работы, вам необходимо реализовать матричный класс 4x4 для однородных преобразований, а также однородный точечный класс, который вы можете умножить на него для применения преобразований (помните, [x, y, z, 1]), Вам нужно будет генерировать преобразования, как описано выше, и в ссылках. Это не так сложно, как только вы понимаете процедуру. Удачи:).

Ответ 2

@BerlinBrown, как общий комментарий, вы не должны хранить поворот камеры как углы X, Y, Z, так как это может привести к двусмысленности.

Например, x = 60degrees совпадает с -300 градусов. При использовании x, y и z число неоднозначных возможностей очень велико.

Вместо этого попробуйте использовать две точки в трехмерном пространстве: x1, y1, z1 для местоположения камеры и x2, y2, z2 для камеры "target". Углы могут быть пересчитаны в/из местоположения/цели, но, на мой взгляд, это не рекомендуется. Использование местоположения/цели камеры позволяет вам создать вектор "LookAt", который является единичным вектором в направлении камеры (v '). Из этого вы также можете построить матрицу LookAt, которая представляет собой матрицу 4x4, используемую для проецирования объектов в 3D-пространстве на пиксели в 2D-пространстве.

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

Учитывая, что вектор вашей камеры нацелен, v = xi, yj, zk
Нормализовать вектор, v '= xi, yj, zk/sqrt (xi ^ 2 + yj ^ 2 + zk ^ 2)
Пусть U = глобальный глобальный вектор вверх u = 0, 0, 1
Затем мы можем вычислить R = горизонтальный вектор, параллельный направлению просмотра камеры R = v '^ U,
где ^ - поперечное произведение, заданное формулой  a ^ b = (a2b3 - a3b2) я + (a3b1 - a1b3) j + (a1b2 - a2b1) k

Это даст вам вектор, который выглядит так.

Computing a vector orthogonal to the camera

Это может быть полезно для вашего вопроса, так как однажды у вас есть вектор LookAt Vector v ', ортогональный вектор R, который вы можете начать проектировать из точки в 3D-пространстве на плоскость камеры.

В основном все эти проблемы с 3D-манипуляцией сводятся к преобразованию точки в мировом пространстве в локальное пространство, где локальные оси x, y, z находятся в ориентации с камерой. Имеет ли это смысл? Итак, если у вас есть точка, Q = x, y, z и вы знаете R и v '(оси камеры), вы можете проецировать ее на "экран" с помощью простых векторных манипуляций. Углы могут быть обнаружены с помощью оператора точечного произведения на векторах.

Projecting Q onto the screen

Ответ 3

Следуя википедии, сначала вычислите "d":

http://upload.wikimedia.org/wikipedia/en/math/6/0/b/60b64ec331ba2493a2b93e8829e864b6.png

Чтобы сделать это, создайте эти матрицы в коде. Отображения от ваших примеров к их переменным:

θ = Camera.angle*

a = SomePointIn3DSpace

c = Camera.x | y | z

Или просто выполните уравнения отдельно без использования матриц, ваш выбор:

http://upload.wikimedia.org/wikipedia/en/math/1/c/8/1c89722619b756d05adb4ea38ee6f62b.png

Теперь мы вычисляем "b", двумерную точку:

http://upload.wikimedia.org/wikipedia/en/math/2/5/6/256a0e12b8e6cc7cd71fa9495c0c3668.png

В этом случае ex и ey являются позицией зрителя, я считаю, что в большинстве графических систем половина размера экрана (0,5) используется по умолчанию (0, 0) по центру экрана, но вы можете использовать любое значение (поиграть). ez - это поле зрения. Это единственное, чего вам не хватало. Выберите угол fov и вычислите ez как:

ez = 1/tan (fov/2)

Наконец, чтобы получить bx и фактические пиксели, вы должны масштабироваться в зависимости от размера экрана. Например, если b отображает от (0, 0) до (1, 1), вы можете просто масштабировать x на 1920 и y на 1080 для дисплея 1920 x 1080. Таким образом, любой размер экрана будет показывать одно и то же. Конечно, есть много других факторов, связанных с реальной 3D-графикой, но это базовая версия.

Ответ 4

Преобразование точек в 3D-пространстве в двумерную точку на экране просто производится с помощью матрицы . Используйте матрицу для расчета положения экрана вашей точки, это экономит вам много работы.

При работе с камерами вы должны использовать look-at-matrix и умножить матрицу на матрицу проекции.

Ответ 5

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

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

Ответ 6

Предполагая, что камера находится на (0, 0, 0) и направлена ​​прямо вперед, уравнения будут:

ScreenData.x = SomePointIn3DSpace.x / SomePointIn3DSpace.z * constant;
ScreenData.y = SomePointIn3DSpace.y / SomePointIn3DSpace.z * constant;

где "константа" - некоторое положительное значение. Установка его на ширину экрана в пикселях обычно дает хорошие результаты. Если вы установите его выше, то сцена будет выглядеть более "увеличенной" и наоборот.

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

В основном вы вычисляете точку пересечения между линией, проходящей через камеру и 3D-точку, и вертикальной плоскостью, которая немного плавает перед камерой.

Ответ 7

Вы хотите преобразовать свою сцену с матрицей, подобной OpenGL gluLookAt, а затем вычислить проекцию с использованием матрицы проекций, аналогичной OpenGL gluPerspective.

Вы можете попытаться просто вычислить матрицы и выполнить умножение в программном обеспечении.

Ответ 8

Запустите его через трассировщик лучей:

Ray Tracer в С# - Некоторые из объектов, которые он имеет, будут вам знакомы; -)

И только для того, чтобы пинать LINQ version.

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

Если ваше приложение просто пытается нарисовать всю сцену, это будет здорово.

Решение проблемы # 1. Неисправные точки не будут проецироваться.
Решение. Хотя я не видел ничего о прозрачности или прозрачности на странице блога, вы, вероятно, могли бы добавить эти свойства и код для обработки одного луча, который отскакивал (как обычно), и один, который продолжался (для "прозрачности" ).

Решение проблемы №2. Для проецирования одного пикселя потребуется дорогостоящая трассировка полного изображения всех пикселей.
Очевидно, если вы просто хотите нарисовать объекты, используйте трассировщик лучей для чего! Но если вы хотите искать тысячи пикселей на изображении, из случайных частей случайных объектов (почему?), Выполнение полной трассы лучей для каждого запроса будет огромной собакой производительности.

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

Если вы не знакомы с трассировкой лучей, прочитайте запись в блоге - я думаю, это объясняет, как вещи действительно работают в обратном направлении от каждого 2D-пикселя, к объектам, а затем огни, которые определяют значение пикселя.

Вы можете добавить код так, чтобы были сделаны пересечения с объектами, вы строите списки, индексированные пересекающимися точками объектов, причем элемент является текущим 2d-пикселем.

Затем, когда вы хотите проецировать точку, перейдите в этот список объектов, найдите ближайшую точку к той, которую вы хотите спроектировать, и посмотрите на 2d-пиксель, о котором вы заботитесь. Математика будет гораздо более минимальной, чем уравнения в ваших статьях. К сожалению, используя, например, словарь для сопоставления структуры объекта + точки в 2d пикселей, я не уверен, как найти ближайшую точку на объекте, не просматривая весь список отображаемых точек. Хотя это не было бы самой медленной вещью в мире, и вы, вероятно, могли бы это понять, у меня просто нет времени об этом думать. Кто-нибудь?

удача!

"Кроме того, я не понимаю в записи wiki, что такое позиция зрителя в сравнении с позицией камеры"... Я на 99% уверен, что это то же самое.