Для того, что бы игры выглядели более реалистичными, необходимо по максимуму имитировать в них физические процессы происходящие в реальной жизни. Одним из таких процессов является - освещение. Далее мы разберем несколько наиболее известных моделей освещения применяемых в современной игровой индустрии.
I = max(0, dot(N, L));
Реализацию этой техники можно найти здесь SpecularBump.zip
Lambert Lighthing Model
Наиболее простой, на мой взгляд, является модель освещения Ламберта. Она основывается на исключительно диффузном распределении света на поверхности. Это значит что поверхность считается матовой и гладкой, не имеет крупных шероховатостей и глянца. Не плохим примером такой поверхности может служить бумага.
Принцип расчета такого освещения сводится к следующей формуле.
I = max(0, dot(N, L));
где:
I - итоговый коэффициент затенения,
N - нормаль полигона в мировом пространстве,
L - направление света.
L - направление света.
Таким образом, идея заключается в следующем:
мы получаем угол между нормалью и световым вектором,
и чем этот угол больше, тем меньше освещен полигон.
Ниже представлен код пиксельного шейдера, в котором и происходит расчет
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
const float3 lightDir = float3(1, 0, 1);
float LdotN = max(0.0, dot(lightDir, input.Normal));
return float4(0.5, 0.5, 0.5, 1) * LdotN;
}
Исходный код к статье lambert.zip
Phong Lightning Model
Следующая модель освещения - это бликовая модель освещения Фонга.
В отличии от модели Ламберта, она не только учитывает нормали, но так-же учитывает отражение света по отношению к наблюдателю.
Код пиксельного шейдера приведен ниже:
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
const float3 lightDir = float3(1, 0, 1);
const float3 viewDir = normalize(float3(0, -75, 0));
float LdotN = dot(lightDir, input.Normal);
float3 Reflection = normalize(2.0f * input.Normal * LdotN - lightDir);
float RdotV = max(0.0, dot(Reflection, viewDir));
float SpecExp = 50;
float4 SpecColor = float4(1, 1, 1, 1);
float4 TotalSpecular = SpecColor * pow(RdotV, SpecExp);
return float4(0.5, 0.5, 0.5, 1) * saturate(max(0.0, LdotN)) + TotalSpecular;
}
Код пиксельного шейдера приведен ниже:
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
const float3 lightDir = float3(1, 0, 1);
const float3 viewDir = normalize(float3(0, -75, 0));
float LdotN = dot(lightDir, input.Normal);
float3 Reflection = normalize(2.0f * input.Normal * LdotN - lightDir);
float RdotV = max(0.0, dot(Reflection, viewDir));
float SpecExp = 50;
float4 SpecColor = float4(1, 1, 1, 1);
float4 TotalSpecular = SpecColor * pow(RdotV, SpecExp);
return float4(0.5, 0.5, 0.5, 1) * saturate(max(0.0, LdotN)) + TotalSpecular;
}
Исходный код к статье PhongModel.zip
Normal + Specular Mapping
Совмещая бликовую и диффузную модели освещения, можно получать более сложные эффекты. Одним из таких эффектов является Normal Mapping. Мы уже знаем что для расчета диффузного освещения нужно использовать дот продукт векторов нормали и направления света. Нормали обычно хранятся в самой модели. Можно сказать, что для одного полигона
(треугольника) нормаль расчитывается как среднее арифметическое из трех нормалей вершин полигона. Соответственно, детализация объекта ограничивается сложностью модели. Для того что-бы придать модели более детализированный вид, был придуман следующий способ. Художники сохраняли нормали в текстуру, и после текстурирования такой текстурой модели, нужно считать нормаль из нее и использовать для расчета освещения. В результате, можно добиться высокой визуальной сложности моделей, не затрагивая ее сетки.
Комментариев нет:
Отправить комментарий