Камера. Сетка из линий. Отсечение по передней плоскости просмотра

Загрузить архив с примерами ЗДЕСЬ.

После умножения вершин модели на матрицу вида, координаты модели перемещаются с мирового пространства в пространство вида. В пространстве вида камера имеет координаты (0,0,0), и если после умножения на матрицу вида модель имеет положительные координаты Z - значит она видна зрителю. Если модель имеет отрицательные координаты Z она выводится на экран с искажениями. Поэтому нужно отсекать все вершины модели которые имеют отрицательную координату Z.

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

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

Если все вершины модели имеют отрицательное значение Z то мы просто не рисуем модель на экране (модель находится за камерой).

Если v1 перед плоскостью, и v2 за плоскостью, отсечение линии (или ребра треугольника) производится так:


		if(v2.z < 0)
		{
			float d = v1.z / (v1.z - v2.z);
			v2.x = (v2.x - v1.x) * d + v1.x;
			v2.y = (v2.y - v1.y) * d + v1.y;
			v2.z = 0.1f;
		}

В этом примере мы будем отсекать по передней плоскости линии.

Код примера можно загрузить /src/03.002-draw_field_winapi/Draw_Field_WinAPI.

После запуска примера перемещатся по сцене можно с помощью клавиш W,S,A,D и поворачивать камеру мышей.

Камера. Сетка из линий. Отсечение по передней плоскости просмотра

В этом примере матрицу вида возвращает функция камеры Get_View_Matrix(). Вы можете организовать свой класс в приложении который возвращает матрицу вида. Функция Get_View_Matrix() следит на нажатием клавиш клавиатуры W,S,A,D для перемещения по сцене, и следит на перемещением мыши что бы поворачивать обзор камеры, т.е. куда смотрит камера.

После умножения вершины на матрицу вида вершина попадает в видовое пространство. Что такое видовое пространство. К примеру в мировых координатах вершина имеет координаты V(0,0,-15) т.е. по оси Z размещена -15 единиц. К примеру в мировых координатах наша камера имеет позицию (0,0,0) - т.е. находится в начале центра координатной системы и камера смотрит в мировых коорданатах в отрицательную сторону оси Z, те.е -Z. Нормаль в мировых координатах куда смотрит камера N(0,0,-1). Тогда в поле камеры попадает наша вершина (0,0,-15). Но мировых координатах вершина имеет Z=-15 а в пространстве камеры (видовое пространство) вершина еимеет Z = +15. Это мы могли наблюдать когда рассматривали тему Экперименты с матрицей Вида. Т.е. ось Z камеры всегда имеет положительное направления. Все что видит зритель на сцене имеет положительную координату Z в пространстве камеры. Все что имеет Z меньше нуля в видовом пространстве зритель видеть не может.

По этому поводу существует понятие передней проскости отсечения. Все что находится перед передней проскостью отсечения зритель видит и все что зритель видит имеет положительную координату Z. Так организовано отсечение в этом примере. Мы умножаем координаты линий на матрицу вида, и если окажется что у этой координаты Z меньше нуля значит зритель эту координату не видит - необходимо отсечение, что бы правильно нарисовать линию. Поскольку после этого мы как и положено делим на Z (перспективное делений) Z не может быть равно нулю (делить на ноль нельзя), и мы принимаем небольшое число близкое к ную. Z = 0.1f.


	//50 линий сетка + еще 2 линий в конце
	//одна по горизонтали и одна по вертикали (замыкающие линии)
	for ( int i = 0; i < ( 50 + 2 ); i++ )
	{
		vector3 v1 = vert_buff_transformed[ i * 2 ];
		vector3 v2 = vert_buff_transformed[ i * 2 + 1 ];

		//линия за передней плоскостью отсечения
		if( (v1.z < 0) && (v2.z < 0) )
			continue;

		//первая вершина за передней плоскостью отсечения
		if(v1.z < 0)
		{
			float d = v2.z / (v2.z - v1.z);
			v1.x = (v1.x - v2.x) * d + v2.x;
			v1.y = (v1.y - v2.y) * d + v2.y;
			v1.z = 0.1f;
		}

		//вторая вершина за передней плоскостью отсечения
		if(v2.z < 0)
		{
			float d = v1.z / (v1.z - v2.z);
			v2.x = (v2.x - v1.x) * d + v1.x;
			v2.y = (v2.y - v1.y) * d + v1.y;
			v2.z = 0.1f;
		}



Дальше в коде перспективное деление (деление Z) и знакомый нам код.

В примере используется отсечение по передней плоскости просмотра. Оно осуществляется следующим способом:

Камера. Сетка из линий. Отсечение по передней плоскости просмотра

В данном примере проводится только отсечение по передней плоскости просмотра. Отсечение по левому и правому краю экрана не надо - это делает GDI. Отсечение по верхнему краю нам делать на надо, так как с верхним экраном сетка из линий не пересекается.