This tutorial will be an introduction to using specular lighting in DirectX 10 with HLSL.
The code in this tutorial builds on the code from the previous tutorial.

Specular lighting is the use of bright spot highlights to give visual clues for light source locations.
For example a red sphere with just ambient and diffuse lighting looks like the following:

Now if we add a white specular highlight we get the following result:

Specular lighting is most commonly used to give light reflection off of metallic surfaces such as mirrors and highly polished/reflective metal surfaces.
It is also used on other materials such as reflecting sunlight off of water.
Used well it can add a degree of photo realism to most 3D scenes.

The reflection vector in this equation has to be produced by multiplying double the light intensity by the vertex normal.
The direction of the light is subtracted which then gives the reflection vector between the light source and the viewing angle:

ReflectionVector = 2 * LightIntensity * VertexNormal - LightDirection

The viewing direction in the equation is produced by subtracting the location of the camera by the position of the vertex:

ViewingDirection = CameraPosition - VertexPosition

Lets take a look at the modified light shader to see how this is implemented:

The viewing direction is calculated here in the vertex shader.
We calculate the world position of the vertex and subtract that from the camera position to determine where we are viewing the scene from.
The final value is normalized and sent into the pixel shader.

The reflection vector for specular lighting is calculated here in the pixel shader provided the light intensity is greater than zero.
This is the same equation as listed at the beginning of the tutorial.

The amount of specular light is then calculated using the reflection vector and the viewing direction.
The smaller the angle between the viewer and the light source the greater the specular light reflection will be.
The result is taken to the power of the specularPower value.
The lower the specularPower value the greater the final effect is.

The Render function now takes in a cameraPosition, specularColor, and specularPower value and sends them into
the SetShaderParameters function to make them active in the light shader before rendering occurs.

SetShaderParameters now takes in the cameraPosition, specularColor, and specularPower.
It then sets each of these values in the light shader using the new pointers to each global shader variable.

void LightShaderClass::SetShaderParameters(D3DXMATRIX worldMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix,
ID3D10ShaderResourceView* texture, D3DXVECTOR3 lightDirection, D3DXVECTOR4 ambientColor,
D3DXVECTOR4 diffuseColor, D3DXVECTOR3 cameraPosition, D3DXVECTOR4 specularColor, float specularPower)
{
// Set the world matrix variable inside the shader.
m_worldMatrixPtr->SetMatrix((float*)&worldMatrix);
// Set the view matrix variable inside the shader.
m_viewMatrixPtr->SetMatrix((float*)&viewMatrix);
// Set the projection matrix variable inside the shader.
m_projectionMatrixPtr->SetMatrix((float*)&projectionMatrix);
// Bind the texture.
m_texturePtr->SetResource(texture);
// Set the direction of the light inside the shader.
m_lightDirectionPtr->SetFloatVector((float*)&lightDirection);
// Set the ambient color of the light.
m_ambientColorPtr->SetFloatVector((float*)&ambientColor);
// Set the diffuse color of the light inside the shader.
m_diffuseColorPtr->SetFloatVector((float*)&diffuseColor);
// Set the position of the camera.
m_cameraPositionPtr->SetFloatVector((float*)&cameraPosition);
// Set the specular color of the light.
m_specularColorPtr->SetFloatVector((float*)&specularColor);
// Set the specular power of the light.
m_specularPowerPtr->SetFloat(specularPower);
return;
}
void LightShaderClass::RenderShader(ID3D10Device* device, int indexCount)
{
D3D10_TECHNIQUE_DESC techniqueDesc;
unsigned int i;
// Set the input layout.
device->IASetInputLayout(m_layout);
// Get the description structure of the technique from inside the shader so it can be used for rendering.
m_technique->GetDesc(&techniqueDesc);
// Go through each pass in the technique (should be just one currently) and render the triangles.
for(i=0; i<techniqueDesc.Passes; ++i)
{
m_technique->GetPassByIndex(i)->Apply(0);
device->DrawIndexed(indexCount, 0, 0);
}
return;
}

Lightclass.h

The LightClass has been modified for this tutorial to include specular components and specular related helper functions.

In the light class object we now set the specular color and the specular power.
For this tutorial we set the specular color to white and set the specular power to 32.
Remember that the lower the specular power value the greater the specular effect will be.