Войти
ПрограммированиеСтатьи

Статичный лайт-меп.

Автор: BoogeMan


Сегодня, многоуважаемый читатель/геймдевелопер, мы поговорим о картах освещенности (на буржуйском - лайт-меп). На текущее время любой достаточно большой проект не может обойтись без эффектов освещения. Одним из этих эффектов и является лайт-меп (прежде всего для игр от первого/третьего лица). С помощью карт освещенности можно добиться невероятно приятных глазу эффектов, например, представьте спроецированный на пол и стены рисунок посредством прохождения света через разноцветное окно, или просто статичные тени. Ну что, заинтриговал? Тогда приступим!


Пример без лайт-мепа:
Изображение
Убого... неправда ли?


Пример с лайт-мепом(без теней):
Изображение
Тоже убого ;) но уже лучше :)

Определение (придуманное автором;)

Лайт-меп - это дополнительная текстура, которая (посредством мультитекстурирования или многопроходности) накладываясь на полигон вместе с основной текстурой придает ему эффект освещенности.... т.е. для КАЖДОГО!!! полигона нашей сцены необходимо создать свой лайт-меп (индивидуальную текстуру) непосредственно при загрузке самой сцены.

Расчет карт освещенности для точечного источника.

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

Прежде всего, нам надо задать текстурные координаты для карты освещенности:


Изображение
Рис. 1

Как видно из этого рисунка первую вершину полигона я поместил в точку (0;0), третью - в точку (1;0), а координаты второй я нашел относительно длин сторон треугольника (они строго пропорциональны длинам сторон исходного треугольника в 3D).

Далее нам необходимо получить uv вектора в 3D (в ненормализованном виде): т.к. координаты 1-ой и 3-ей точек в пространстве нам известны, то нахождение вектора u не вызовет у вас особых проблем... на нем останавливаться не будем.


Изображение
Рис. 2

С вектором v будет немного сложнее: как видно из второго рисунка, вектор v перпендикулярен вектору u и вектору нормали полигона, поэтому найти его можно при помощи векторного произведения (Нормаль можно найти по этой же формуле, перемножив вектора u и n1):


v.x = u.y*нормаль.z - u.z*нормаль.y;
v.y = u.z*нормаль.x - u.x*нормаль.z;
v.z = u.x*нормаль.y - u.y*нормаль.x;

Полученный вектор необходимо нормализовать:


v.x = v.x/длинна вектора;
v.y = v.y/длинна вектора;
v.z = v.z/длинна вектора;

и умножить на высоту полигона к основанию, которое принадлежит вектору v.

Теперь, имея эти векторы, мы можем найти координаты (в 3D) любого текселя на текстуре:


тексель.x = 1.x + (u.x*тексель.u) + (v.x*тексель.v);
тексель.y = 1.y + (u.y*тексель.u) + (v.y*тексель.v);
тексель.z = 1.z + (u.z*тексель.u) + (v.z*тексель.v);

Поочередно перебирая все тексели текстуры (методом трассировки лучей), мы должны рассчитать затененность каждого из них и запихнуть результаты наших вычислений в текстуру (сам лайт-меп). Для расчета освещенности текселя можно воспользоваться несколькими методами (все зависит от вашей фантазии):

Метод первый (его я изобрел методом тыка):
Осв. текселя = Рад. источника + расстояние от источника до текселя * яркость источника; т.е.  для этой реализации нам нужно рассчитать расстояние от источника до точки... самой простой метод, который я когда-либо видел :)

Метод второй (подсказан мне Storm-ом, за что ему большое спасибище):
Осв. текселя = (косинус между нормалью и вектором до источника)*(яркость фонаря)/(квадрат расстояния до источника); тут расчетов уже побольше - косинус между нормалью и вектором до источника мы рассчитаем с помощью скалярного произведения векторов:

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

Нормализуем нормаль и вектор от текселя до источника (аналогично вектору v), находим скалярное произведение этих векторов (вектор от текселя до источника я буду называть - "v1"):

dot pr.:= нормаль.x*v1.x + нормаль.y*v1.y + нормаль.z*v1.z;

Больше проблем тут по-моему нет...

Расчет карт освещенности для направленного источника:

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

Расчет освещенности для направленного источника ничем не отличается от расчета для точечного, кроме как учетом самого направления света: Если косинус угла между вектором направления источника и вектором от источника до текселя, будет меньше косинуса угла разброса, то тексель не будет освещен этим источником вообще!!!

Тени на картах освещенности:

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

Возможная оптимизация:

Во-первых, советую использовать возможности bsp (если вы вообще собираетесь его использовать). Так же можно просто отбрасывать те полигоны, которые не повернуты к источнику света лицевой стороной.

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

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

P.S. Если у вас будут дополнения/предложения/поправки, то просьба сообщить об этом мне на мыл :).

15 июня 2002

Комментарии [7]