главная страница статьи файлы о сайте ссылки |
Пример вместе с исходниками: rad8.zip - 173kb - запускать только в режиме 32bpp. Интересная реализация Radiosity с использованием glOrtho. Георгий Мошкин Сначала об алгоритме. Смысл алгоритма прост: ХРАНЕНИЕ ДАННЫХ 1) У каждого полигона есть три текстуры: первая MaterialTexture - материал Также у каждого полигона есть два массива (почти как текстуры): первый - Peredacha передача цветов (размер
W3 x H3) 2) Третяя текстура (цветовой индекс) формируется следующим образом: [code] То есть всего 255 полигонов (пиксель[i,j].R=0..254)
и один зарезервирован 3) В первую текстуру грузится материал, вторая тектсура заполняется чёрным цветом. 4) В программе есть массивы image1, image2, zbuffer1, zbuffer2 для чтения буфера с экрана: image1,image2 - чтение отрендеренной "картинки"
(W5 x H5) 5) Есть переменная текущей итерации (просто одно число типа integer);
Один проход включает следующие пункты: A) Процедурой glOrtho включается параллельное проецирование вместо перспективного [code] Процедурой glViewPort устанавливаются размеры
W5 x H5 [code] B) Выбирается случайная точка в пространстве (eye.x, eye.y, eye.z) C) Выбирается случайное направление в пространстве (napr.x, napr.y, napr.z) D) Процедурой gluLookAt камера ставится в
точку (eye.x, eye.y, eye.z) E) Рендерится сцена с наложением текстуры IndexTexture. Другие текстуры (материал, лайтмап) не накладываются. F) Процедурой glReadPixels считывается первая "картинка" и z-buffer (буфер глубины): [code] G) Потом стирается содержимое экрана (буферов): [code] H) И начинается рендеринг в обратном направлении
(-napr.x, -napr.y, -napr.z). I) Рендерится сцена с наложением текстуры IndexTexture. Другие текстуры (материал, лайтмап) не накладываются. То есть как и в пункте (E). J) Процедурой glReadPixels считывается image2 и zbuffer2: [code] K) Начинается анализ содержимого массивов image1, image2, zbuffer1, zbuffer2: - анализируется цвет в массиве image1 и image 2 В цвете закодирован номер полигона и текстурные
координаты lightmap-а [code] N2:=image2[i,j].R; [b]w5-1-j[/b] - меняем верх/низ местами (из-за того, что картинка image2 получена рендерингом в обратную сторону) Теперь мы знаем, что серез точку I,J проходит луч, который с одной стороны упирается в полигон N1, а с другой - в полигон N2. Всего у нас W5 x H5 = ... таких лучей Но мы знаем не только номера полигонов, с которыми пересекается каждый луч. Мы ещё знаем тектурные координаты, в который попадает луч. Таким образом, мы знаем, что луч [i,j] проходит между точкой (U1,V1) текстуры полигона N1 и точкой (U2,V2) текстуры полигона N2. Уже сейчас мы можем просто "перебросить" цвета между этими точками (прямо из лайтмапов). Обратиться к лайтмапу LightmapTexture и массивам Peredacha и Nakoplenie можно так: [code] Или так: [code] Так же мы можем узнать нормали полигонов, с которыми пересекается луч [i,j]: [code] и [code] Используя данные массивов буфера глубины, мы можем найти расстояние между точкой (U1,V1) и (U2,V2). Для луча [i,j]: [code] То есть у нас есть пучок параллельных лучей.
Всего W5 x H5 лучей. Для каждого луча есть даннные: [code] U1:=image1[i,j].G; RASST:=2-(zbuffer1[i,j]+zbuffer2[i,w5-1-j]); L) Происходит некоторый обмен между цветами: Если image1[i,j].R=255 или image2[i,j].R=255, то обмена не происходит (это соответствует белому цвету, что означает отсутствие полигонов). - определяется два угла (угол между нормалью первого полигона и направлением луча и угол между нормалью второго полигона и противоположным направлением луча): [code] - учитывается влияние углов на затухание: [code] [i]меньше всего, если направление луча совпадёт с нормалью обоих полигонов cos(0)*cos(0)=1[/i] - учитывается затухание из-за расстояния между точками: [code] - и общее затухание: [code] - обмен цветами/энергиями (в зависимости от полноты реализации radiosity) между точками. Если упрощенно, то сразу между точками лайтмапа: [code] // --- считываем пиксели из лайтмапов --- // --- считываем пиксели из текстур --- // --- передача "света" --- temp:=round(TempColorA.R*Zatuhanie*TextureColorB.R/255); // --- учёт "попадания" луча в
точки лайтмапов --- (!!!) Особенности рендеринга (пункты E и
I): [code] Обратные стороны полигонов прорисовываются белым цветом. Для этого все полигоны рендерятся ещё раз: [code] Render; glFrontFace(GL_CCW); // возвращаем в исходное
состояние Таким образом, один проход алгоритма включает четыре вызова рендеринга: два в пункте E и два в пункте I.
(!!!) Зачем нужна закраска белым цветом: Источкниками света являются любые лайтмапы или, в зависимости от реализации, массивы хранения света/цвета. Для этого у всех источников света они заполняются нужным цветом/ ненулевой энергией. В некотором радиусе случайным образом (или по определённым формулам) "болтается" невидимая плоскость параллельного процеирования. Процедура создания пучка вызывается параллельно с общим игровым циклом. Пучёк лучей соединяет параллельными лучами различные точки в сцене. Параллельно с этим мы наращиваем общий счётчик кадров и счётчики "попадания" лучей в точки текстур (зависит от реализации). При этом можно постоянно корректировать значения цветов, основываясь на данных счётчиков. Если ничего не понятно, то попробуйте прочитать пояснение. |