Creating the Shaders
The
HLSL code for the effects is stored in LambertBlinnPhong.fx. In the
vertex shader, the code starts off by transforming the vertex position
as usual, and then it moves on to compute the transformed normal vector
to account for the object rotating. It computes the light vector, which
is computed by normalizing the light position from the vertex position,
and the view vector, which is the normalized difference of the camera
position and the vertex position. The vectors are interpolated across
the surface as they are passed to the pixel shader from the vertex
shader, which is the same as if we calculated the vectors in the pixel
shader using the computed pixel position. We hold off on normalizing
until we reach the pixel shader stage since the interpolation could
possibly de-normalize the vectors, and we’d have to re-normalize anyway
just to keep this from happening.
In the
pixel shader all vectors are normalized, and the half vector is
computed for the Blinn-Phong algorithm. Once the vectors are
normalized, the diffuse contribution is computed by calculating N dot
L, and the specular contribution is computed from N dot H raised to a
power that represents the shininess factor, which in this demo is 25.
Since this demo is just a simple example of lighting, the diffuse and
specular values are multiplied by the color white and stored as the
output color. We could have multiplied them by a specific object color,
light color, texture color, and so forth.
The LambertBlinnPhong.fx shader is shown in Listing 1.
Listing 1. The LambertBlinnPhong.fx Shader
float4 lightPos; float4 eyePos;
DepthStencilState DepthStencilInfo { DepthEnable = true; DepthWriteMask = ALL; DepthFunc = Less; };
cbuffer cbChangesEveryFrame { matrix World; matrix View; };
cbuffer cbChangeOnResize { matrix Projection; };
struct VS_INPUT { float4 Pos : POSITION; float3 Norm : NORMAL; float2 Tex : TEXCOORD; };
struct PS_INPUT { float4 Pos : SV_POSITION; float3 Norm : NORMAL; float3 LightVec : TEXCOORD0; float3 ViewVec : TEXCOORD1; };
PS_INPUT VS(VS_INPUT input) { PS_INPUT output = (PS_INPUT)0;
float4 Pos = mul(input.Pos, World); Pos = mul(Pos, View); output.Pos = mul(Pos, Projection);
output.Norm = mul(input.Norm, World); output.Norm = mul(output.Norm, View);
output.LightVec = lightPos.xyz - Pos.xyz; output.ViewVec = eyePos.xyz - Pos.xyz;
return output; }
float4 PS(PS_INPUT input) : SV_Target { float3 normal = normalize(input.Norm); float3 lightVec = normalize(input.LightVec); float3 viewVec = normalize(input.ViewVec); float3 halfVec = normalize(lightVec + viewVec); float diffuse = saturate(dot(normal, lightVec)); float specular = pow(saturate(dot(normal, halfVec)), 25);
float4 white = float4(1, 1, 1, 1);
return white * diffuse + white * specular; }
technique10 BlinnPhongSpecular { pass P0 { SetDepthStencilState(DepthStencilInfo, 0);
SetVertexShader(CompileShader(vs_4_0, VS())); SetGeometryShader(NULL); SetPixelShader(CompileShader(ps_4_0, PS())); } }
|