И так,Radiosity - один из методов глобального освещения(Global Illumination,GI).
Радиосити даёт довольно реалистичное освещение нежели простые методы.
Есть open-source реализации Global Illumination рендеринга такие как Toxic(найти можно на SourceForge.net).
Единственный минус GI это довольно таки долгий расчёт из за моножества вычислений так что GI в наше время можно юзать как статическое(фоновое) освещение,заранее расчитаное.
Но со скорым выходом NVIDIA RayTrace Engine(Точное название не помню) возможно GI можно будет выбить в риал тайм,есть конечно уже реализация риал тайм GI от ATI на DirectX 10 где юзаются кубмапы,но и там оно не сильно риал тайм,да и у меня на NVIDIA GeForce 9600 GT почемуто не запускается их пример,найти его можно на developer.amd.com.
А ха да что то я уже в дебри полез
,так Radiosity - не юзает рей трейсинг в то время как просто GI его во всю юзает.
И так реализация:
Я раскажу о повершином Radiosity,но правельнее же конечно юзать лайтмеп(но это отдельная тема).
У нас в сцене есть комнота,все её цвета вершин заполнены чёрным цветом(r=0,g=0,b=0) на потолке комнаты есть лампа - меш все её цвета вершины заполнены белым цветом(r=225,g=225,b=225),начинаем проход по всем мешам\сурфейсам мешей\вершинам сурфейсов,ах да в Radiosity юзается такая штука как Form Factors для определения интенсивности освещёности пикселя,генерируется Form Factor'ы так:
const int RQ = 32; // качество радиосити,чем больше тем круче
float formFactors[RQ][RQ]; // двумерный массив форм факторов RQ*RQ
for(int x=0;x<RQ;x++){
for(int y=0;y<RQ;y++){
formFactors[x][y] = sin( float(x)*PI/float(RQ) )*sin( float(y)*PI/float(RQ) );
}
}
Форм факторы сгенерированы,представляют они из себя это:
тоесть будет токой цикл:
for(int i=0;i<num_meshes;i++)
{
Mesh* mesh = meshes[i];
for(int j=0;j<mesh->getNumSurfaces;j++){
Surface* s = mesh->getSurface(j);
Vertex* v = s->getVertex();
for(int k=0;k<s->getNumVertex();k++){
бла бла бла...
}
}
}
Цикл генерации radiosity освещения:
1) Камера перемещается в позицию вершины k,её направление равно нормали вершины k(в блитце можно для этого заюзать AlignToVector),вьюпорт камеры - x=0;y=0;width=RQ;height=RQ;FOV=90 - обязательно 90.
2) Рисуется вся сцена из текущей позиции камеры(желально вырубить режим куллинга)
3) Считывается кусок backbuffer'а - x=0,y=0,w=RQ,h=RQ.
Далее ЦИКЛ:
unsigned char tmp[3];
for( int x = 0;x<RQ;x++ ){
for(int y = 0;y<RQ;y++){
unsigned char r = пиксель[x][y].r;
unsigned char g = пиксель[x][y].g;
unsigned char b = пиксель[x][y].b;
tmp[0] += r * formFactors[x][y];
tmp[1] += g * formFactors[x][y];
tmp[2] += b * formFactors[x][y];
}
}
после делим tmp на RQ*RQ
tmp[0] /= RQ*RQ;
tmp[1] /= RQ*RQ;
tmp[2] /= RQ*RQ;
и прибовляем tmp к цвету вершины k.
ну и так по все вершинам...
Вот как будет выглидеть полностью цикл:
camera->setViewport(0,0,RQ,RQ);
camera->setFov(90);
camera->setAspect(RQ/RQ);
for(int i=0;i<num_meshes;i++)
{
Mesh* mesh = meshes[i];
for(int j=0;j<mesh->getNumSurfaces;j++){
Surface* s = mesh->getSurface(j);
Vertex* v = s->getVertex();
for(int k=0;k<s->getNumVertex();k++){
camera->setPosition(v[k].xyz);
camera->align(v[k].normal);
рендерим мир.
лочим backbuffer.
получаем массив пикселей.
unsigned char tmp[3];
for( int x = 0;x<RQ;x++ ){
for(int y = 0;y<RQ;y++){
unsigned char r = пиксель[x][y].r;
unsigned char g = пиксель[x][y].g;
unsigned char b = пиксель[x][y].b;
tmp[0] += r * formFactors[x][y];
tmp[1] += g * formFactors[x][y];
tmp[2] += b * formFactors[x][y];
}
}
после делим tmp на RQ*RQ
tmp[0] /= RQ*RQ;
tmp[1] /= RQ*RQ;
tmp[2] /= RQ*RQ;
v[k].color.x += tmp[0];
v[k].color.y += tmp[1];
v[k].color.z += tmp[2];
}
}
}
повторяем этот цикл до достижения красивой картинки(обычно это 15-16 итераций)
4 пасса -
16 пассов -
Полезные ссылки:
-
http://freespace.virgin.net/hugo.eli.../radiosity.htm
-
http://democoder.ru/dcdn_article_view.php?dcid=22