|
Now you may be a little confused as to how an image which holds RGB data encodes normals which have floating point x, y, z data. This is quite simple. A normalized vector always has 3 components x, y, z. The values of x, y, z always will range from -1.0 to 1.0. A 24-bit texture holds RGB values that range between 0 and 255. The x component of the vector is stored in the red channel, the y component in the green channel and the z component in blue channel. The x, y, z values are scaled and biased to a range between 0 to 255 before they are stored in the RGB values.
Example: Let us imagine we have a vector that identifies the normal at a point
Vn = (Vn.x, Vn.y, Vn.z) = (0.0, 0.0, 1.0)
Before we store Vn.x, Vn.y, Vn.z in the normal map as r, g, b data, we scale and bias the values as follows
In = (In.R, In.G, In.B) = (Vn * 127.5) + 127.5 = (128, 128, 255)
The reverse of the above step is done in the pixel shader to get the surface normal from the normal map's RGB data. We then take the dot product of the surface normal at a point and the normalized light vector. Since the dot product of two unit/normalized vectors is equal to cos of the angle between them, no further calculations need to be done to get the brightness of a point at a texel.
Why does a normal map always look blueish?
The z component of a surface normal at point never points backwards
That is why you will always see a normal map having a blueish/purpleish tint. See Figure 10 for a sample height map and normal map. Note the difference between the two.
Another point to remember is that a normal map is always encoded in the tangent space coordinate system instead of the world space coordinate system. Go back to the section ‘Why use tangent space’ to understand why. You should get it now.
The vertex shader -calculating the light vector
The light vector is calculated at each vertex and then interpolated across the face. Although this is not an ideal method, there are some simple steps that we can follow at the game design level to prevent the disadvantages of using this method.
Step 1: Calculate the light vector.
In order to calculate the light vector, we assume that both the light position and the vertex position are in the world space coordinate system. The light vector is then calculated as follows
Li.Pos = Position of the light in world space
Vj.Pos = Position of the vertex in world space
Step 2: Convert the light vector from the world space coordinate system to a vector in the tangent space coordinate system.
Assuming that you have already calculated the tangent space matrix for each vertex and passed it into the vertex shader via the texture channels, this is just a simple matrix multiplication.
Step 3: Normalize the light vector
The light vector is then normalized.
This light vector is passed to the pixel shader in a previously decided texture stage. One very big advantage of doing this is that the light vector gets interpolated across the face for free.
Note: The interpolated light vector is no longer normalized when it reaches the pixel shader, but in our case this minor inaccuracy does not make any difference.
The pixel shader
Calculating the diffuse brightness at the pixel
Step 1: Get the light vector
Unlike getting a normal texture, you need to load the texture coordinate from the texture stage. This texture stage will generally not have any texture assigned to it. The light vector is cleverly stored as texture coordinates as a means of transporting data from the vertex shader to the pixel shader. This can be done using the texcrd instruction available in pixel shader 1.4.
There is no need to re-normalize the light vector at this stage. We can live with the inaccuracies and we will continue to assume that it is normalized.
Step 2: Get the normal at the texel
Assuming the normal map is assigned to a pre defined texture stage, load the normal / surface orientation at the texel and then scale and bias the values to fit back to a range from -1.0 to 1.0. If you remember, the values in RGB data range from 0 to 255 and when these are sent to the pixel shader they are converted to a range 0 to 1. The color data can be loaded using the texld instruction available in pixel shaders version 1.4
The first line loads the normal that is encoded as color data. The second line converts the color data back to a normal.
Step 3: Calculating the surface brightness
Now that we have the light vector and the surface normal at the texel, we can calculate the brightness of the surface at the using a simple dot3 product
As both the light vector and surface normal have already been normalized, the dot product will always range from a value from 0.0 to 1.0
Step 4: Modulate with the diffuse color
To get the color of the output pixel, just modulate [multiply] the color of the diffuse texture with the brightness at the current texel [pixel].
That is all that we need to do in order to get a bump mapped surface.
|
T = E2-1.xyz / E2-1.u
This formula does not seem correct. Wouldn't this just scale the edge?
I think the formula is supposed to be more like this(could be wrong though):
NE2-1 = Normalize(E2-1)
NE3-1 = Normalize(E3-1)
T = (NE2-1.xyz / E2-1.u) + (NE3-1.xyz / E3-1.u)
http://www.blacksmith-studios.dk/projects/downloads/tangent_matrix_derivation.ph
p
These 2 website have good explanations about tangent space.
Does any body know, if 2 vertex of a triangle have the same UV, then should I ignore that triangle, or ask art to change the UV? The determinant will become 0 in this case...