Вершинное освещение совместно с LightMaps.
Сейчас уже никого не удивишь наличием LightMap'ов в программе. И уж тем более наличием вершинного освещения. Но при всем при этом не надо сразу выбрасывать данную тему на помойку.
Автор: terror
Раньше вершинное освещение не могло давать качественных результатов из-за того, что карты не могли рисовать достаточное количество треугольников на кадр, при которых вершинное освещение имело бы силу. Поэтому и получалось что-то типа того:
На левой части картинки видно, что из-за маленького количества треугольников освещение не получается таким, как на правой части. То есть, не видно светового пятна, а видны лишь плавные переходы цветов между каждой вершиной, а их всего четыре. Чтобы добиться такого же качества света как на правой части картинки, нужно использовать или LightMap'ы или более высокое количество треугольников.
Теперь попробуем сравнить оба метода.
LightMaps.
- + Самое высокое качество получаемого освещения.
+ Не требует высокополигональных сцен.
– Долгий расчет.
– Занимает много видеопамяти.
– Без упаковки LightMap'ов в одну текстуру начинается сильная тормозня из-за большого количества смен текстур.
– При рендере занимает один текстурный юнит, который с успехом мог бы пойти на детализированную текстуру.
VertexLight.
- + Быстрый расчет. При качественной реализации можно создавать в месте с загрузкой карты.
+ Требует мизерное количество видеопамяти.
+ Не занимает текстурный юнит.
+ Работает быстрее, чем LightMap, так как нет необходимости менять текстуры.
+ Может быть немного качественнее LightMap'ов из-за отсутствия текстурных фильтров.
+ Ну и если это можно назвать плюсом - гораздо проще в реализации, чем LightMap'ы.
– Нужны высокополигональные объекты для качественного результата.
– Тени все равно будут хуже, чем у LightMap'ов.
– Иногда расчет может быть не таким уж и быстрым, только из-за того, что используются высокополигональные объекты.
Вывод: LightMap — качество, VertexLight – количество.
Обычно людей больше интересует качество. Лучше один хороший процессор, чем десять 486'ых. В крайнем случае, если будет спрос на 486'ые процессоры, то наладят их производство.
Но не так все и плохо! При использовании вершинного освещения мы убиваем кучу зайцев одним выстрелом. Используем высокополигональные объекты, не занимаем tmu, видеопамять, а также увеличиваем быстродействие.
Вот картинка из примера, прилагаемого к этой статье:
На картинке нарисован чайник, который отбрасывает тень на сцену. При этом свет не проходит через него. Заметьте, что тень нарисована довольно качественно и самое главное - это не LightMap'ы. Это и есть то самое вершинное освещение.
Количество полигонов на чайнике довольно высокое и только поэтому тень на нем смотрится неплохо.
Вывод: при использовании высокополигональных объектов лучше использовать вершинное освещение. При этом LightMap'ы использовать как способ создания качественных теней.
Теперь, что касается примера. Это стандартное glut приложение, сделанное на VC++7.0, никаких особенностей при переводе в другие редакторы нет, кроме #pragma once.
Теперь более подробно разберем самую главную функцию в этом примере:
void InitVertexLight (void ) { int i = 0; vector c; float a,d; for ( int j = 0; j < Obj[1].VertsCount; j++ ) { c.Set ( 130.0f ); if ( lpos.GetDistance ( Obj[1].verts[j] ) > lrad ) continue; if ( RayTrace ( lpos, Obj[1].verts[j] )) { Obj[1].tVertexLight[j].v[0] = ( byte)c.v[0]; Obj[1].tVertexLight[j].v[1] = ( byte)c.v[1]; Obj[1].tVertexLight[j].v[2] = ( byte)c.v[2]; continue; } d = lpos.GetDistance ( Obj[1].verts[j] ); a = 1.0f - ( d / lrad ); c.v[0] += 255.0f * a; c.v[1] += 255.0f * a; c.v[2] += 255.0f * a; if ( c.v[0] > 255 ) c.v[0] = 255; if ( c.v[0] < 0 ) c.v[0] = 0; if ( c.v[1] > 255 ) c.v[1] = 255; if ( c.v[1] < 0 ) c.v[1] = 0; if ( c.v[2] > 255 ) c.v[2] = 255; if ( c.v[2] < 0 ) c.v[2] = 0; Obj[1].tVertexLight[j].v[0] = ( byte)c.v[0]; Obj[1].tVertexLight[j].v[1] = ( byte)c.v[1]; Obj[1].tVertexLight[j].v[2] = ( byte)c.v[2]; } }
Дело все в том, что программа настолько проста, что даже количество объектов в ней фиксированное. То есть при попытке подменить файлы карт, программа, скорее всего не запустится, а если и будут работать, то только первые два объекта. У вас, скорее всего, собственные классы векторов, плоскостей, поэтому я не стал делать из примера супер накрученную программу, в которой черт ногу сломит. Думаю заменить один тип данных на другой не составит труда.
Поэтому в функции InitVertexLight() мы сразу пробегаемся по каждой вершине второго объекта. А дальше алгоритм таков:
1. Ставим цвет тени в 130. Вообще это можно делать и более продвинутыми методами, но и этот сгодится.
2. Так как источник света всего один, то проверяем сразу его. Если расстояние от лампочки больше радиуса освещения, то пропускаем вершину. Хотя и в данном примере это не видно из-за маленькой сцены, но все-таки лучше не пропускать вершину, а назначить ей цвет. Черный или серый.
3. Находим факт о пересечении луча от источника света до вершины.
4. Далее опять находим расстояние от лампочки до вершины. Для оптимизации можно делать всего один раз.
Дальше по формулам, которые не раз упоминались на многих сайтах, находим цвет в вершине исходя из длинны и радиуса. Делаем это так:
- Находим расстояние от источника света до вершины
- Получаем значение attenuation (a) по формуле: 1 - ( d / rad )
Где,
d - расстояние от источника света до вершины,
rad - радиус источника света (радиус освещения)
- Затем находим RGB вершины по формуле: Color * a * b (находится для каждой RGB составляющей)
Где,
Color — цвет источника света (R, G или B)
a — attenuation
b — brightness
Но в нашем примере параметр brightness мы опустили.
5. Проверяем чтобы числа не вылезли за пределы и присваиваем их цвету вершине.
Фишка в том, что цветовые параметры LightMap'а должны совпадать с вершинным цветом, так как в противном случае можно увидеть разницу между двумя методами, разницу в цвете. А это может плохо сказаться на картинке в сторону "глюкавости". Хотя иногда можно и не следить за схожестью цветовых параметров другого освещения. Например, у нас есть стена, а в ней проходят трубы, их, разумеется, видно. Так вот, можно придать трубам дополнительный вид если использовать на них вершинное освещение, а так как трубы находятся в стене, их подсветка не тронет общий цвет стены. Я все это к тому, что вершинное освещение и LightMap'ы не совсем схожи в конечном результате, поэтому нужно следить, чтобы разные объекты находящиеся под одной лампой были освещены одинаково, как LightMap'ами, так и вершинным освещением.
Исходный код к статье: 20030611.zip
11 июня 2003 (Обновление: 17 сен 2009)
Комментарии [6]