# FunTracer: specular lightning

This time we are going to add specular lightning – this will add “shiny”ness on objects.

The basic idea is simple: we reflect the currently traced ray, at the hit-point (using the normal of the object at this point) and look at the angle between the outgoing ray and the line from the hit-point to a light source (similar to our basic-shading model). If this is small we add the light-color (scaled by a specular-factor of the object) to our result-color.

Again we can use the cosine and it’s easy representation with the dot-product, but this time we are going raise this value to the 10th power – this will shrink the shiny-spot and intensify it around the point where a incoming ray would be reflected directly into the light source.

So the only hard part is to reflect the ray. To understand the math behind look at this picture:  $r$ is the direction of our ray and we can have (projection onto $n$): $r'=-(n \cdot r) n$ – please not the directions. The resulting reflected direction is then $r'+r+r' = r+2r' = r-2(n \cdot r)n$

Translated into F#:

        // reflected direction
let reflDir = hit.Ray.Direction - 2.0 * (hit.Normal <*> hit.Ray.Direction) * hit.Normal;


As mentioned above we calculate the specular factor by using the dot-product:

       let specF = (reflDir <*> lightDir) |> suppresNeg
let specColor = System.Math.Pow(specF, 10.0) * hit.Specular * light.Color


    let shade (getSigObjs : Ray -> SceneObj seq) (hit : HitResult) (light : Light) : Color =
// get the direction of the light for this point
let lightDir = hit.Pos |> light.GetDirection
// is the light visible?
let rayToLight = Ray.Create(hit.Pos, lightDir)
let lightVisible = findHitObj getSigObjs rayToLight |> Option.isNone

// reflected direction
let reflDir = hit.Ray.Direction - 2.0 * (hit.Normal <*> hit.Ray.Direction) * hit.Normal;

// lighting factors
let ambient = 0.4
let diffuse = 0.6
let diffF, specF =
if lightVisible then
// helper - we are only interessted in positive values
let suppresNeg x = if x <= 0.0 then 0.0 else x
// get the fraction of diffuse Light (cap at 0)
let diffF = (hit.Normal <*> lightDir) |> suppresNeg
// get the specular factor
let specF = (reflDir <*> lightDir) |> suppresNeg
diffF, specF
else
0.0, 0.0
// calculate the total color by ambient + diffuse + specular light
let diffuseColor = diffuse * diffF * hit.Color * light.Color
let specColor = System.Math.Pow(specF, 10.0) * hit.Specular * light.Color
let ambientColor = ambient * hit.Color * light.Color
ambientColor + diffuseColor + specColor


Here we changed the HitResult-type to include the Specular-“shiny”ness for a object:

type HitResult
= { Ray : Ray; Distance : float;
Pos : Point; Normal : Direction;
Color : Color; Specular : float }


This turns the scene from our last article into this: 