Продвинутое освещение и текстурирование в XNA Часть 3

Продвинутое освещение и текстурирование в XNA Часть 3

Немного изменяем пиксельный шейдер:

float4 ParallaxMapping_PixelShader(VS_OUTPUT IN) : COLOR0

{

float3 HalfVector = normalize(IN.LightDirection + IN.ViewDirection);

float2 TextureCoordinate =

GetParallaxCorrectSamplingPosition (IN.TextureCoordinate,

HalfVector);

float3 Normal = normalize(tex2D(NormalMap,

TextureCoordinate).rgb * 2.0f — 1.0f);

float3 NormalizedLightDirection = normalize(IN.LightDirection);

float NormalDotLight = saturate(dot(Normal, LightDirection));

float NormalDotHalf = saturate(dot(Normal, HalfVector));

float SpecularPower = (NormalDotLight == 0.0f) ?

0.0f :

pow(NormalDotHalf, MaterialShininess);

float4 FinalColor = (MaterialAmbient * LightAmbient) +

(IN.Diffuse * NormalDotLight) +

(IN.Specular * SpecularPower);

FinalColor *= tex2D(DiffuseSampler, TextureCoordinate);

if(LightType == LIGHT_POINT)

{

float Attenuation = saturate(1.0f — dot(IN.LightDirection,

IN.LightDirection));

FinalColor *= Attenuation;

}

else if(LightType == LIGHT_SPOT)

{

float Attenuation = saturate(1.0f — dot(IN.LightDirection,

IN.LightDirection));

FinalColor *= Attenuation * GetSpotLightEffect(NormalizedLightDirection,

IN.SpotDirection);

}

return FinalColor;

}

Relief Mapping

Relief Mapping — как и parallax mapping, моделирует глубину на поверхности. Но, в отличие от parallax mapping, мы не должны читать значения высоты от HeightTexture. Relief mapping извлекает значения высоты из текстуры нормали, которую здесь называют ReliefTexture. Используя это значение высоты, как при parallax mapping, мы вычисляем смещение для позиции образца текстуры. Код ниже показывает, как извлечь нормаль поверхности и новую позицию выборки текстуры из ReliefTexture:

float3 GetNormalFromReliefTexture(float2 TextureCoordinate)

{

float3 Normal = tex2D(ReliefSampler, TextureCoordinate).rgb;

Normal.xy = 2 * Normal.xy — 1;

Normal.y = -Normal.y;

Normal.z = sqrt(1.0 — Normal.x * Normal.x — Normal.y * Normal.y);

return Normal;

}

float2 GetReliefCorrectSamplingPosition(float2 texCoord, float3 viewDirection)

{

float3 TextureCoordinate = float3(texCoord, 0);

float3 v = viewDirection;

v.z = abs(v.z);

float DepthBias = 1.0 — v.z;

DepthBias *= DepthBias;

DepthBias *= DepthBias;

DepthBias = 1.0 — DepthBias * DepthBias;

v.xy *= DepthBias;

v.xy *= HeightScale;

const int LinearSteps = 15;

const int BinarySteps = 6;

v /= v.z * LinearSteps;

int i;

for(i = 0; i *lt; LinearSteps; i++)

{

float4 tex = tex2D(ReliefSampler, TextureCoordinate.xy);

if (TextureCoordinate.z < tex.w)

{

TextureCoordinate += v;

}

}

for(i = 0; i < BinarySteps; i++)

{

v *= 0.5;

float4 tex = tex2D(ReliefSampler, TextureCoordinate.xy);

if (TextureCoordinate.z < tex.w)

{

TextureCoordinate += v;

}

else

{

TextureCoordinate -= v;

}

}

return TextureCoordinate;

}

Вертексный шейдер для Relief Mapping такой же, как и для parallax mapping:

VS_OUTPUT ReliefMapping_VertexShader(float3 Position : POSITION,

float2 TextureCoordinate : TEXCOORD0,

float3 Normal : NORMAL,

float4 Tangent : TANGENT)

{

VS_OUTPUT OUT;

float3 n = mul(Normal, (float3x3)WorldIT);

float3 t = mul(Tangent.xyz, (float3x3)WorldIT);

float3 b = cross(n, t) * Tangent.w;

float3x3 TangentBinormalNormal = float3x3(t.x, b.x, n.x,

t.y, b.y, n.y,

t.z, b.z, n.z);

float3 PositionInWorld = mul(float4(Position, 1.0f), World).xyz;

OUT.Position = mul(float4(Position, 1.0f), WorldViewProjection);

OUT.ViewDirection = normalize(mul(CameraPosition — PositionInWorld,

TangentBinormalNormal));

OUT.TextureCoordinate = TextureCoordinate;

OUT.Diffuse = MaterialDiffuse * LightDiffuse;

OUT.Specular = MaterialSpecular * LightSpecular;

if(LightType == LIGHT_DIRECTIONAL)

{

OUT.SpotDirection = 0;

OUT.LightDirection = mul(-LightDirection, TangentBinormalNormal);

}

else if(LightType == LIGHT_POINT)

{

OUT.SpotDirection = 0;

OUT.LightDirection = mul((LightPosition — PositionInWorld) / LightRange,

TangentBinormalNormal);

}

else if(LightType == LIGHT_SPOT)

{

OUT.LightDirection = mul((LightPosition — PositionInWorld) / LightRange,

TangentBinormalNormal);

OUT.SpotDirection = mul(LightDirection,

TangentBinormalNormal);

}

return OUT;

}

Пиксельный шейдер для Relief Mapping нуждается в небольшом изменении:

float4 ReliefMapping_PixelShader(VS_OUTPUT IN) : COLOR0

{

float2 TextureCoordinate =

GetReliefCorrectSamplingPosition (IN.TextureCoordinate,

IN.ViewDirection);

float3 Normal = GetNormalFromReliefTexture(TextureCoordinate);

float3 NormalizedLightDirection = normalize(IN.LightDirection);

float4 FinalColor = GetFinalColor(Normal,

NormalizedLightDirection,

IN.ViewDirection,

IN.Diffuse,

IN.Specular);

FinalColor *= tex2D(DiffuseSampler, TextureCoordinate);

if(LightType == LIGHT_POINT)

{

float Attenuation = saturate(1.0f — dot(IN.LightDirection,

IN.LightDirection));

FinalColor *= Attenuation;

}

else if(LightType == LIGHT_SPOT)

{

float Attenuation = saturate(1.0f — dot(IN.LightDirection,

IN.LightDirection));

FinalColor *= Attenuation * GetSpotLightEffect(NormalizedLightDirection,

IN.SpotDirection);

}

return FinalColor;

}

Заключение

В этой статье я рассмотрел четыре различных типа освещения и показал, как использовать их в Ваших играх. Также мы говорили о четырех популярных методиках наложения текстур. Для будущей работы мы можем добавить окружающее отражение и тени в нашей сцене; но из-за некоторых причин они не были рассмотрены в этой статье.

Я обеспечил исходный код и демонстрационную версию для всего, о чем мы говорили; вы можете скачать их здесь.

Библиография

  1. Arnold, G. (2001). 3D Lighting: History, Concepts, and Techniques. Jenifer L. Niles.
  2. Carter, C. Microsoft® XNA™ Unleashed. Sams.
  3. Mathematics for 3D Game Programming and Computer Graphics.
  4. Tatarchuk, N. Practical Parallax Occlusion Mapping For Highly Detailed Surface Rendering.

Реклама
Запись опубликована в рубрике Uncategorized. Добавьте в закладки постоянную ссылку.

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

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s