Tag Archives: maths

Dot Product

Dot product is a cheap and useful function in many situations. It calculate the cosAngle to two unit vectors which is 1 when acute, 0 to -1 for obtuse angle. These are some applications which I found very useful.

Check if two unit are facing each other by dot product their forwardVec, for 3D you can optionally ignore the height component for the vectors.

For airplane game, prevent a plane from over pitching by checking the planeDir dot worldUpVec and worldDownVec.

Test if an unit has passed a waypoint, assuming the unit is moving forward. Do a distance check to ensure the unit is near the waypoint. do a dot product between the unit forward vector and the direction to the waypoint, if the angle is obtuse, mean the unit has pass the waypoint.

For terrain dot product normals of two face to find out the steepness of a slope.

NdotL for lambert diffuse
NdotH for blinn specular
RdotV for phong specular

NdotV to detect edges of the model.


Not A Number

NaN is an insidious bug that often plague games and shader programs during development. If you are lucky, you would probably never encounter it before, but the first time would often be very painful.

It begin with a single unit disappearing from the map, then suddenly whole armies are teleported somewhere, and at last the player is teleported to limbo.

On a shader program, it is less obvious, as the color of NaN is BLACK!!! So for most of the time it would seem just like a few black speck on the screen. But turning on effect like HDR when there is a NaN would cause the whole screen to blacken out.

The worst thing about NaN is, it is more contagious than the plague. Any maths operator with a NaN would give you a NaN

Luckily there are not many ways to cause NaN. The most common ways and solution are

Division by zero
Have a check to ensure your divisor is not zero. In certain situations with a positive divisor, we can add a very small number to the divisor to ensure it is not zero.

Normalize a zero vector
Remember to normalize a vector is to divide every component of a vector with it magnitude. So to normalize a zero vector would cause a divison by zero. Do a check on the vector length or lengthSquare to ensure it is not zero before normalizing it.
Zero vector Normals are also very common in exported model, it could be the normal is not exported or some bug with teh exported, to export a zero normal. I often find a shader to display normals as color to be useful in such situation. If you have control over the content pipeline, Assert when there is a zero normal.

Calling ACos on a number outside -1 to 1
Dot product of two unit vectors would give the cosAngle. if any of the two vectors is not unit length, the result would probably be outside -1 to 1. Ensure both vectors are unit length, and try not to call ACos as cosAngle is very sufficent to solve most problems.


Linear Interpolation

It would commonly take in 3 scaler or 2 vector and a scaler, and return the result of the formula

x + s(y-x).


I often find this function useful for cheap generation of points along a relatively straight line. It is also very useful to calculate the display of health/power/magic bar, eg

healthBarLength = lerp(healthBarStart, healthBarMaxLength, %healthLeft)

In UI it is a very good helper function to convert relative screencoord to absolute screencoord


It is frequently used for alpha blending, blending of normal maps, terrain splatting. I like to use it for signal scaling,

eg getting value max(0, NdotL) / max(0, NdotV) to scale to some other values for various effects.

Playing with NormalMap

Combining tangent space normal map is different from combining normal images. Here are some ways to combine two normal map together. The general idea is the identity normal, float3(0, 0, 1), will use the vertex default normal.


Adding two normals and preserving both details can be done this way.
finalNormal = float3(normal1.xy + normal2.xy, normal1.z * normal2.z);
finalNormal = normalize(finalNormal);


Using lerp. we can easily blend two normal
lerp(normal1, normal2, factor)


To make the normal map look stronger we could do

normal.xy *= strength;

This will cause any slope to bent away from the surface normal making it look steeper.


To compress normal, it is common to copy the X value to the A channel of the image, and calculate the Z value from X and Y
In short it is to take advantage of the uncompressed A channel in DXT5 and to save an additional channel data by calculating Z during runtime.

float3 normal;
normal.xy = tex2D(normalMap, uv).ag;

normal.z = sqrt(1 – normal.x * normal.x – normal.y * normal.y);
which can be optimise to
normal.z = sqrt(1 – dot(normal.xy, normal.xy));


A Power function raised x to specific power.

It has an interesting property when x is between 0 – 1, the result will be always between 0 – 1. Do take note Power function will not preserve the sign of x, it may be necessary to calculate the sign beforehand.

What Power does is to change the curve of x to favor certain values.

This is the curve for using a joystick to aim at something. Typically when gamers want to have a fast movement on analog stick, They would push the analog stick to max. Using the Power function we can allocate 80% of the analog controls to slower movement, so gamers would have more control over aiming, yet allow the quick movement by pushing the analog stick to max.

Power is also very commonly used in graphics, We could use it to change color curves, contrast of images, fade off of lighting equation/fog/glows and many more.