В этом примере будут рассмотрены несколько техник амбиентного освещения и будет показано, как они влияют на результат финальной картинки.
Вышеописанный случай константного амбиента, формула L = Ld + La, где L - результат вычисления, Ld - диффузная составляющая, La - амбиентная составляющая.
При детальном рассмотрении картинки заметно, что карта нормалей совсем потерялась на неосвещенных участках - они выглядят плоскими.
Чтобы сделать рельеф нормалей заметным, подсветим его дополнительным источником света, направленным сверху. В шейдере это выглядит так:
// vertex shader
OUT.SkyVector = mul(float3(0, 1, 0), TBN);
// pixel shader
float ambientPart = 0.5 + 0.5 * dot(IN.SkyVector, BumpNormals);
т.е. мы передаем из вершинного шейдера в пиксельный направление на вектор {0,1,0} - SkyVector в пространстве TBN. В пиксельном шейдере вычисляем результат амбиента как обычный источник света и смещаем результат в диапазон [0, 1]. Дальше делаем с результатом все то же самое, что и с обычной константой амбиента. Результат:
Этот результат можно еще улучшить. Представим себе дневное освещение в реальном мире. В солнечную погоду часть солнечных лучей преломляется в атмосфере и дает голубоватый оттенок. В пасмурную погоду оттенок ближе к серому. При закатном солнце - розово-оранжевый.
Более того, снизу объекты подсвечиваются светом, отраженным от поверхности, на которой они находятся. Если это асфальт или земля - оттенок темно-серый. Если это трава - зеленый. Вода - синий.
Используем это в шейдере. Передадим туда значения "верхнего" и "нижнего" освещения. Используем уже имеющийся результат для интерполяции между ними:
float3 ComputeAmbientColor(float3 skyVector, float3 normalVector)
{
float factor = 0.5 + 0.5 * dot(skyVector, normalVector);
return lerp(g_AmbientBottom.xyz, g_AmbientTop.xyz, factor);
}
Результат (только ambient):
Результат (diffuse + ambient):
Результат (с текстурой):
Комментариев нет:
Отправить комментарий