Lighting and Shadows in a 3D Scene


For a point light source the amount of light hitting a surface is based on the cosine of the angle between the normal vector to the surface and the vector to the light source. For diffusion surfaces the brighness is almsot exacly linear interpolation between ambient and fully illuminated using the cosine of the angle.

the cosine of the angle can be calculated by the dot product definition

cos(θ)=nlnlcos(\theta) = {\vec{n}\cdotp\vec{l} \over |\vec{n}||\vec{l}|}
then if
aa = ambient multiplier (no light)
ff = full illumination multiplier (full light)

then the diffuse color would be about
diffuse color = colordiffusecolor_{diffuse} = (r', g', b') = (r, g, b)*lerp(aa, bb, cos(θ)cos(\theta))
where the "lerp" is equivelent to
a+(ba)cos(θ)a + (b - a)cos(\theta)

when implemented a problem where when cos(θ)cos(\theta) is negative makes it so past 180 degrees away from the light can make negative brightness which doesn't make sense, so cos(θ)cos(\theta) must be clamped between 0 and 1, or basically if it is below 0 set it to 0.

l\vec{l} is easy to calculate, it would just be the light position minus the point at which is being colored in (final minus initial)

n\vec{n}, the normal vector, depends on the shape of the object, but for spheres it is really easy as it is just the difference between the point and the center of the sphere since a spheres surface is always tangent to the center so the normal vector is just straight out

For specular light it is based on the angle between the reflected vector from the camera and the light source, assuming the light source is a point.

the reflected vector would be the reflection of l\vec{l} and n\vec{n}, where the equation for reflection is lref=l2lnn2nl_{ref} = l-{2l\cdotp n \over |n|^2}n, then to find cos(θref)cos(\theta_{ref}) just use the same dot product proof, then also clamp it between 0 and 1 again so that it avoid negative values

the actual color value is based on a power of cos(θref)cos(\theta_{ref}), the power being the shinyness
specular factor = f=cos(θref)sf = cos(\theta_{ref})^s, where ss is shinyness, and then the actual color is lerp(colordiffusecolor_{diffuse}, colorlightcolor_{light}, ff), which is the equivelent of
final color = fcolorlight+(1f)colordiffusef*color_{light} + (1-f)*color_{diffuse}
this means that when ff is big or when cos(θref)cos(\theta_{ref}) is near, meaning the angle is small the color is close to the light since it is reflecting into the camrea, and when cos(θref)cos(\theta_{ref}) is small or the angle is big the sphere returns to its regular diffuse color