Post process. Туман (fog)

В SkyXEngine пост процессорный эффект тумана претерпевал очень много изменений. Сам по себе туман очень простой эффект, но в то же время очень эффектный. Туман может скрыть некоторые ошибки, помешать их обнаружению, и в самом простом случае прибавить сцене атмосферы, объема, конечно же при грамотном подходе дизайнера))

Теория

Вся суть тумана заключается в интерполяции от цвета сцены до цвета тумана (либо простым языком: смешивание сцены с туманом) в зависимости от значения глубины, как правило эта зависимость линейная, то есть чем больше глубина пикселя, тем больше в данном пикселе будет цвета тумана.

Параметры тумана:

  • плотность — коэффициент влияния тумана на конечный цвет пикселя, 0 — значит нет тумана (но просчеты все-равно будут), 1 значит пиксель будет на столько в тумане на сколько он удален от камеры (0 — возле камеры, 1 — максимальная дальность видимости), но это значение может быть больше 1
  • цвет — float3, значения [0,1]

Дополнительными параметрами могут выступать ограничители, к примеру минимальное значение тумана и максимальное.

Реализация

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

return lerp(vSceneColor, vFogColor, fDepth * fDensity);

где:

  • vSceneColor — цвет пикселя сцены
  • vFogColor — цвет тумана
  • fDensity — плотность тумана

Однако в данном случае есть один существенный недостаток, для необходимо получать цвет пикселя сцены, а это значит самостоятельно делать смешивание в шейдере.

В SkyXEngine начиная с версии 0.9.0 мы рисуем туман при помощи аппаратного смешивания, то есть устанавливаем alpha blend (альфа смешивание), а именно:

PPSet::DXDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
PPSet::DXDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

PPSet::DXDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
PPSet::DXDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

то есть, тот цвет который мы запишем шейдером, будет смешан с цветом render target и тем самым мы избежим необходимости в шейдере смешивать вручную, ведь это можно сделать аппаратно))

А код шейдера выглядит следующим образом:

return half4(FogColor,FogDenisty * Depth);

по длине может быть несущественно, но по производительности по-лучше))

Небо и туман

В вышеприведенной реализации небо при прямом распределении (0 — минимум, 1 — максимум) глубины может быть полностью в тумане, если глубина неба имеет максимальную глубину (как в нашем случае). Это не совсем хорошо, поэтому необходимо добавить проверку и отсечь факт затуманивания неба (если надо)

half Depth = tex2D(DepthMap, IN.TexUV).r;

[branch]if(Depth >= 1.f)
clip(-1);

Меня беспокоил вопрос … надо ли небо (sky box) «затуманивать»? Сейчас когда мы уже сделали погодный цикл в движке, могу смело сказать этого делать не надо было, потому что конкретный цикл погоды устанавливает «затуманенность» неба и уж лучше конкретно в погодном цикле регулировать этот момент, нежели выносить это на пост процесс.

Однако, если уж очень надо, то необходимо определить где находится небо. При заполнении карты глубины необходимо заполнить его максимальным дальним значением:

  • если прямое распределение (0 — минимум, 1 — максимум) то единицей (D3DCOLOR_ARGB(255, 255, 255, 255)),
  • если обратное распределение (1 — минимум, 0 — максимум) то 0 (D3DCOLOR_ARGB(0, 0, 0, 0)).

А после смешать цвет неба с цветом тумана на основании указанной плотности тумана специально для неба.

Поделиться:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*

*

code