|
|
Объемный свет.
Что еще можно добавить в нашу сцену? Ну конечно же объемный свет. Этот эффект является аналогом шафтов, но имеет другое название – God Rays
Для реализации потребуется внедрение пост-процесса, т.к. этот эффект реализован в 2Д. Что нам понадобится для этого? Во первых текстура сцены натянутой на квад. Этого я объяснять не буду – примеров море. Далее когда мы отрисовываем облака, делаем второй проход – рисуя облака в отдельную текстуру. Только шейдер сильно изменяется – нам нужна только альфа облака. На черном фоне. Сам смысл – получить изображение кадра из камеры наблюдателя, который изначально черный, отрисовываем облака белым цветом.
В результате получим примерно вот такую текстуру :
Чтобы повысить быстродействие программы – данная текстура должна быть меньше основного разрешения. Если разрешение равно 1024*768 – то текстура может быть 512*384 – без потери качества.
Что делать с этой текстурой? Выводим ее на финальную сцену таким шейдером :
PS_INPUT VS( VS_INPUT input )
{
PS_INPUT output = (PS_INPUT)0;
output.Pos=input.Pos;
output.Tex=input.Tex;
return output;
}
half Density = 2.0f;
half Weight = 0.95f;
half Decay = 0.95f;
half Exposition = 0.1f;
//GLightPos - вектор света !
int numSamples = 64;
float4 PS( PS_INPUT input) : SV_Target
{
float4 shaft = ShaftMap.Sample( samLinear, input.Tex );
half4 screenPos = mul(GLightPos*2000, WorldViewProjection);
half2 ssPos = screenPos.xy / screenPos.w * float2(0.5,-0.5) + 0.5;
half2 oriTexCoord = input.Tex;
half2 texCoord = input.Tex;
half2 deltaTexCoord = (texCoord - ssPos);
deltaTexCoord *= 1.0f / numSamples * Density;
half3 color = ShaftMap.Sample( samLinear, texCoord).xyz;
half illuminationDecay = 1.0f;
for (int i=0; i < numSamples; i++)
{
texCoord -= deltaTexCoord;
half3 sample = ShaftMap.Sample( samLinear, texCoord).xyz;
sample *= illuminationDecay * Weight;
color += sample;
illuminationDecay *= Decay;
}
half amount = dot(mul(-GLightPos,View), half3(0.0f,0.0f,-1.f));
float3 V1 = normalize(CamDir.xyz);
float A = saturate(max(dot(GLightPos,V1),0));
half4 sampleFrame = ColorMap.Sample( samLinear, oriTexCoord);
//Шафты только днем, закат они порят...
if (GLightPos.y<0.1) {A=lerp(A/2,A,GLightPos.y*(1/0.1));}
float4 colframe = saturate(A-0.2) * (half4((1-color) * Exposition, 1))/2.5 + sampleFrame;
return float4(colframe.xyz,1);
} |
Что делает шейдер? По вершинному – можно сказать одно – мы рисуем в экранных координатах – т.е. пост-процесс. В пиксельном шейдере, ShaftMap – это тексель нашей текстуры шафтов. ColorMap – тексель тексуры сцены. Сначала мы переводим источник света в экранные координаты. Матрица WorldViewProjection – считается так:
D3DXMatrixIdentity(&PWVP);
D3DXMatrixTranslation(&PWVP,LightDirection.x*1000,LightDirection.y*1000, LightDirection.z*1000);
D3DXMatrixMultiply(&PWVP,&PWVP,&mView);
D3DXMatrixMultiply(&PWVP,&PWVP,&mProj);
ShaftR_WorldViewProjection->SetMatrix( ( float* )&PWVP ); |
Далее шейдер получает значение точки и её затемнения – трассируя по вектору солнце-тексель. Вообще-то шейдер практически совпадает с шейдером облаков.
После, цвета инвертируются – ведь шафты – это затенение, а у нас текстура белая.
Вот результат :
|
Copyright CSS PSV 2009 Kherson
|
|