Какими бывают координаты вершин

После моделирования 3D модели в пакете моделирования (например 3DS Max, Maya, Blender и т.п.) координаты модели находятся в локальных координатах. После умножения на матрицу мира (т.е. матрицу вращения, масштабирования, перемещения) координаты модели находятся в мировом пространстве (у всех объектов на сцене есть общий центр в т.ч. камера имеет свою позицию в мировых координатах). После умножения на матрицу вида - координаты модели находятся в видовом пространстве (центр сцены v(0,0,0) там где расположена камера, наблюдатель). После умножения на матрицу проекции мы переходим к 4х размерных векторам, и у нас однородные координаты вершины (homogeneous space). После деления на Z (или как в графических API происходит деление на 4й компонент W) у нас есть NDC координаты (normalized device coordinates) - т.е. каждый компонет x,y,z находится в диапазоне от -1.0 до +1.0. И после преобразования в экранное пространство дисплея у нас есть экранные координаты - которые и выводятся на экран.

Любой 3D конвеер рендеринга должен обеспечить проход вершин модели пошагово от локальных координат до экранных координат.

Матрица мира меняется когда объект перемещается, вращается, масштабируется.

Матрица вида меняется когда камера (наблюдатель) меняет позицию, вращается.

Матрица проекции меняется когда окно меняет размеры.

Что такое однородные (гомогенные) координаты - homogeneous space? Пусть у нас есть вектор в декартовой системе координат v(x,y,z) который представляет собой одну вершину модели, и есть матрица mxRes, которая равна произведению матрицы Мира, Вида, Проекции. Тепреь нам нужно перейти от декартовых к однородным координатам, выполнить перспективное деление, и тем самым вернутся обратно к декартовым координатам.


	v(x,y,z)

	mxRes = mxWorld * mxView * mxProjection
	

Теперь согласно ковееру рендеринга вектор v нужно умножить на матрицу mxRes. Матрица проекции расчитывается так что четвертый элемент w равен третьему элементу z. Матрица проекции согласно документации DirectX выглядит так:


	typedef float matrix4x4[4][4];

	float fFov = 3.14f/2.0f; // FOV 90 degree
	float fAspect = 640.0f/480.0f;
	float fZFar = 100.0f;
	float fZNear = 1.0f;

	float    h, w, Q;
	w = (float)(1/tan(fFov*0.5f))/fAspect;
	h = (float)1/tan(fFov*0.5f);
	Q = fZFar/(fZFar - fZNear);

   	matrix4x4 mProj={
	w, 0, 0, 0,
	0, h, 0, 0,
	0, 0, Q, 1,
	0, 0, -Q*fZNear, 0 };
	

Как умножить вектор 3х1 на матрицу 4х4? Необходимо ввести четвертый элемент вектора w = 1: v(x,y,z,1) или v(x,y,z,w). Теперь вектор 4х1 мы можем умножить на матрицу 4х4 по правилам умножения.

После умножения вектора v(x,y,z,1) на матрицу проекции, мы получаем четвертый элемент вектора w = z - это и есть однородная координата, когда мы трехмерный вектор переводим в четырехмерный, условие w не равно 1. Этот четырехмерный ветор и есть однородная координата. После умножения вектора v на матрицу проекции мы выполняем перспективное деление, т.е. деление на z - и этим мы производим переход от однородного пространства обратно к декартовой системе координат.

В результате перспективного деления мы получаем x,y координаты вектора v готовые для перевода в экранные координаты (экранное пространство). И получаем z координату в диапазоне от 0 до 1.0 готовую что бы ее занести в буфер глубины.

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


   	matrix4x4 mProj={
	w, 0, 0, 0,
	0, h, 0, 0,
	0, 0, 1, 0,
	0, 0, 0, 1 };

	

Но в реальных конвеерах рендеринга DirectX/OpenGL гомогенные координаты использутся, так же используется буфер глубины со значениями от 0 до 1.0.

Почему после деления на z (перспективное деление) координаты x и y должны быть в диапазоне от 0 до 1? Потому что так необходимо для дальнейшего преобразования x и y в экранные координаты. Рассмотрим пример, пусть по ширине x экран имеет разрешение 640 пикселей:


	//случай 1 x < z
	z = 4
	x = 2

	//перспективное деление
	x = x / z = 2 / 4 = 0.5

	//экранные координаты в пределах от 0 до 640 по x
	x = x * 640 / 2 + 640/2 = 0.5 * 640/2 + 640/2 = 480

	//случай 2 x > z
	z = 4
	x = 8 

	//перспективное деление 
	x = x / z = 8 / 2 = 2.0

	//экранные координаты в пределах от 0 до 640 по x
	x = x * 640 / 2 + 640/2 = 2 * 640/2 + 640/2 = 960  

Видим что в первом случае мы получили корректное значение экранных координат- 480 лежит в диапазоне от 0 до 640. Во втором случае где x больше z мы получили некорректное значение экранных координат - 960 лежит вне диапазона от 0 до 640. Вывод- после перспективного деления мы должны получить x и y в диапазоне от 0 до 1 для корректного преобразования в экранные координаты.

Таким образом гомогенные координаты получаем после умножения на матрицу проекции. Так же есть NDC Normalized Device Coordinates - Нормализованные координаты устроства - они получаются после деления x и y на z, то есть мы получаем значения от 0 до 1, после перспективного деления, это и есть NDC, которые теперь можно преобразовать в экранные координаты.

Подитожим сказанное.