Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
84 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:


The main improvement of RacorX7 over RacorX6 is the usage of a specular reflection model instead of the diffuse reflection model used by the previous example.

Figure 3 - RacorX7 Specular Lighting

RacorX7 sets the same textures and texture stage states as RacorX6. It only sets one additional constant.

Define Constants (with SetPixelShaderConstant()/def)

Because this example uses a specular reflection model an eye vector must be set into c24 in FrameMove() as already shown in the RacorX4 example:

// eye vector
m_pd3dDevice->SetVertexShaderConstant(24, &vEyePt, 1);

This eye vector helps to build up the V vector, which describes the location of the viewer. This is shown in the next paragraph.

Pixel Shader Instructions

The pixel shader in this example calculates the specular reflection on the basis of a modified Blinn-Phong reflection model that was already used in RacorX4 in part 2 of this introduction.

Here is the diagram that visualizes the vectors involved in the common specular reflection models:

Figure 4 - Vectors for Specular Reflection

A model describing a specular reflection has to be aware of at least the location of the light source L, the location of the viewer V, and the orientation of the surface normal N. Additionally a vector R that describes the direction of the reflection might be useful. The half way vector H was introduced by Jim Blinn to bypass the expensive calculation of the R vector in the original Phong formula.

The original Blinn-Phong formula for the specular reflection looks like this:

kspecular (N dot H)n)


H = (L + V)/2

The simplified formula that was used in RacorX4 and will be used here is

kspecular (N dot (L + V))n)

Compared to the Blinn-Phong formula the specular reflection formula used by the examples in this introduction does not divide L + V through 2. This is compensated by a higher specular power value, which leads to good visual results. Although L + V is not equivalent to H, the term Half vector is used throughout the upcoming examples.

The calculation of the vector H works in a similar way as the calculation of the light vector L in the previous example in the vertex shader:

; position in world space
m4x4 r2, v0, c0

; get a vector toward the camera/eye
add r2, -r2, c24

; normalize eye vector
dp3 r11.x, r2.xyz, r2.xyz
rsq r11.xyz, r11.x
mul r2.xyz, r2.xyz, r11.xyz

add r2.xyz, r2.xyz, -c12 ; get half angle

; normalize half angle vector
dp3 r11.x, r2.xyz, r2.xyz
rsq r11.xyz, r11.x
mul r2.xyz, r2.xyz, r11.xyz

; transform the half angle vector into texture space
dp3 r8.x,r3,r2
dp3 r8.y,r4,r2
dp3 r8.z,r5,r2

; half vector -> oD1
mad oD1.xyz, r8.xyz, c33, c33 ; multiply by a half to bias, then add half

The first three code blocks caculate V. The next two code blocks generate the half vector H. H is transformed into texture space with the three dp3 instructions like the light vector in the previous example and it is stored biased in oD1 in the same way as the light vector was transfered in the previous example.

Like in the previous example, this pixel shader is driven by the vertex shader:

tex t0 ; color map
tex t1 ; normal map
dp3 r0,t1_bx2,v1_bx2; ; dot(normal,half)

mul r1,r0,r0; ; raise it to 32nd power
mul r0,r1,r1;
mul r1,r0,r0;
mul r0,r1,r1;

; assemble final color
mul r0,t0,r0

texld r0, t0 ; color map
texld r1, t1 ; normal map
dp3 r2, r1_bx2, v1_bx2 ; dot(normal, half)

mul r3,r2,r2 ; raise it to 32nd power
mul r2,r3,r3
mul r3,r2,r2
mul r2,r3,r3

mul r0, r0, r2

The pixel shader gets H via v1 and N, as in the previous example, via a normal map. The specular power is caculated via four mul instructions. This was done in RacorX4 in part 2 via a lit instruction in the vertex shader.

Using the mul instructions to perform the specular color leads to visible banding artifacts:

Figure 5 - RacorX7 Visual Artifacts

These artifacts are a result of the small precision of the pixel shader registers and the precision loss of the H vector by shifting this vector from the range [-1..1] to [0..1] in the vertex shader and back in the pixel shader, which is necessary because the vertex shader output registers deliver only values in the range [0..1]. The only way to provide higher precision is delivering a texture map with the specular values encoded, which is loaded in the pixel shader. This will be shown below in RacorX8.


This example showed one way to implement a specular reflection model. The weak point of this example is its low precision when it comes to the specular power values. The next example will show a way to get a higher precision specular reflection.



  Printable version
  Discuss this article

The Series
  Fundamentals of Vertex Shaders
  Programming Vertex Shaders
  Fundamentals of Pixel Shaders
  Programming Pixel Shaders
  Diffuse & Specular Lighting with Pixel Shaders