Технология RayCasting: текстуры, освещение, размытие ( Часть 2 )

   Прошел год с небольшим, с тех пор, как я написал первую статью по технологии обратной трассировки лучей, именуемой RayCasting, с которой можно ознакомиться здесь. Настал черед более глубокого изучения этой темы. В данной статье будут рассмотрены вещи, как относящиеся непосредственно к технологии RayCasting, так и нет, например размытие или попросту - Blur.
   Для начала нужно разобраться с эффектом линзы, или как его еще называют эффектом рыбьего глаза. Как известно, в основе RayCasting лежит определение точки пересечения с фигурой, а так же вычисление расстояния от камеры до этой точки, с последующим сравнением этого значения со значением в буфере. Но такой подход может создать ощущение того, что стены кривые и вообще нарушить визуальное восприятие. Непорядок, поэтому чтобы избавиться от такого эффекта нужно просто напросто спроецировать точку пересечения на плоскость экрана. Вот тут необходимо сделать пометку о том, что в данном случае все происходит в 2d, поэтому вместо плоскости будет луч. Теперь, нужно разобраться, что к чему на данном рисунке:

   Нет эффекту линзы!

   Как уже было сказано выше, эффект линзы имеет место при использовании длины отрезка ray, выделенного красным. Для устранения его нужно вычислить длину отрезка projection. Это можно сделать просто спроецировав точку пересечения со стеной на плоскость экрана, затем вычесть из получившейся точки, точку пересечения и т.д. и т.п... Но стоит ли это делать? На самом деле длина projection, есть скалярное произведение направления взляда камеры dir( единичный вектор ) на ray. Вот и все, теперь эффект линзы устранен.


   Текстурирование

   Так как все происходит в 2d, то с осью OY можно схитрить, но обо всем по порядку. Вообще данный алгоритм не претендует на место самого лучшего алгоритма текстурирования, ибо придуман был полностью мной, а это значит является велосипедом.
   Для того, чтобы вычислить координату текстуры в определенной точке отрезка( стены ) нужно проделать следующее: вычислить разность двух точек отрезка( A ), вычислить разность точки пересечения и одной из точек отрезка( B ). По сути достаточно проекции на одну из осей либо OX либо OY. Я выбрал OX. Получив две проекции A и B на OX, можно вычислить координаты текстуры по X:


	// A = конец_отрезка - начало_отрезка;
	// B = точка_пересечения - начало_отрезка;
	xCoordinate = int ( ширина_текстуры * ( ( A - B ) / A ) );
	// ( ( A - B ) / A )  -  вещественное число, от 0 до 1.

   С текстурной координатой X разобрались, самое время двигаться дальше. Y вычислить несколько сложнее, из-за того, что часто на экране видна лишь часть стены, реальная же высота которой больше высоты экрана, поэтому ее приходится обрезать. Для вычисления высоты стены в определенной точке используется банальная формула


	высота_стены = высота_экрана / расстояние_до_точки_пересечения;

   Первое, что мне пришло на ум для вычисления текстурной координаты Y это такая формула:


	yCoordinate = int ( ( высота_текстуры * ( высота_стены - итератор ) ) / высота_стены );
	// итератор меняет значения от 0 до высота_стены, за каждую отрисовку вертикальной линии

   Просто и понятно, но работает при условии если высота вертикальной линии, меньше или равна высоте экрана. В противном случае происходит искривление текстурных координат, но это можно решить, немного отредактировав формулу:

	
	// РВС - реальная_высота_стены, это НЕОБРЕЗАННОЕ по высоте экрана значение
	// то есть РВС может быть больше высоты экрана
	yCoordinate = int ( высота_текстуры * ( ( ( ( высота_стены + РВС ) >> 1 ) - итератор ) ) / РВС );

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


   Блюр

   Нужно циклом пройтись по всем точками изображения и вычислить цвет каждой точки Result. Это можно сделать разными способами, сложить как 4, 5, 8 или даже 9 точек, и разделить на общее количество слагаемых. Советую пользоваться числами степени двойки, ибо потом можно будет смело использовать сдвиг вправо вместо деления. Я воспользовался суммой 4 точек, выделенных на рисунке зеленым.
   С освещением все еще проще:

	
	интенсивность = радиус_источника_света / расстояние_до_точки;
	результирующий_цвет_точки = цвет_точки * интенсивность;

   В случае, когда интенсивность велика может произойти переполнение, поэтому нужно обрезать это значение, в прилагаемой программе происходит обрезание по 255, ибо там используются числа типа unsigned char.
   Уфф, вот вроде и все. Ниже представлен снимок экрана из демонстрационной программы. При нажатии на B включается размытие, при нажатии на L - освещение. Текстура для стен взята из игры Doom 3 - дум, родимый дум.


   Скрин-шот

   Скачать демонстрационную программу и исходники можно з д е с ь

Статью написал faceH0r 03.05.2007
Используются технологии uCoz