Страницы

воскресенье, 7 августа 2011 г.

Fog with multipass lighting

При использовании многопроходного освещения возникает проблема наложения тумана. Если рассматривать результат аддитивного смешивания, получим следующую формулу (для урощения предположим, что коэффициент наложения тумана при расчете равен 0.7):


C1 = L1 * 0.3 + F * 0.7 // первый проход
C2 = L2 * 0.3 + F * 0.7 // второй проход
C = C1 + C2 = L1 * 0.3 + F * 0.7 + L2 * 0.3 + F * 0.7 = (L1 + L2) * 0.3 + F * 1.4


Где L1 - результат вычисления цвета в первом проходе
L2 - во втором
C1 - суммарный результат освещения с туманом в первом проходе
C2 - во втором

В результате вычислений получили фактор тумана равный 1.4, т.е. туман наложился дважды:


Если выключить туман во втором проходе, результат будет так же неправильный:

C1 = L1 * 0.3 + F * 0.7
C2 = L2
C = C1 + C2 = L1 * 0.3 + L2 + 0.7 * F

туман не повлиял на второй проход освещения. В результате дальние объекты начнут светиться через туман (для наглядности фактор тумана увеличен):


Можно посчитать фактор тумана таким образом, чтобы в каждом проходе накладывалась только часть тумана
Fi = F / N
, где N - число проходов освещения. Этот подход возможен, но достаточно сложный в реализации, потому как при отсечении источников света рисуется только та часть объектов, которая попала в зону влияния источника света.

Самым простым решением проблемы является обнуление цвета тумана (до черного). Результат вычисления:

C1 = L1 * 0.3 + F * 0.7
C2 = L2 * 0.3 + F * 0.7 = L2 * 0.3 + 0.0 * 0.7 = L2 * 0.3
C = L1 + L2 = L1 * 0.3 + 0.7 * F + L2 * 0.3 = (L1 + L2) * 0.3 + F * 0.7

Что и требовалось. Результат:



Код рендера выглядит примерно так:


// сохраняем настройки цвета тумана
D3DXCOLOR saveFogColor = _fogColor;
for(size_t lightIndex = 0; lightIndex < _lights.size(); ++lightIndex)
{
context.light = _lights[lightIndex];
context.renderPass = RenderPass_Lighting;

// если включены тени, рисуем карту теней
if (context.light->enableShadows)
RenderShadowMap(&context);

// рисуем все модели в сцене
for(size_t entityIndex = 0; entityIndex < _entities.size(); ++entityIndex)
{
context.entity = _entities[entityIndex];
context.entity->model->Render(context);
}

// обнуляем туман в последующих проходах
_fogColor = D3DXCOLOR(0, 0, 0, 0);

// включаем аддитивное наложение
device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
}

// восстанавливаем исходный цвет тумана
_fogColor = saveFogColor;

Комментариев нет: