Tuesday, March 29, 2011

Why to use tangent space

You might've been wondering why you see lots of people doing their vector calculations in what they call texture or tangent space. Why can't they just do it in World space for example?

Well, because they want their special texture maps to be portable.

Let's take normals for example: 3D vectors which can be stored in textures to provide detail normals for every pixel on a texture (texel). Textures which store normals are called normal or bump maps. Here's an example of a normal map of a brick wall:

This image has three channels: R, G and B. They're used to store the X, Y and Z amount of a normal that's supposed to be at that given texel. This normal can be used to change surface lighting without having to add geometry. The only downside is that the object will still look flat from a side: it's just a trick to change lighting response, not to add actual depth. Lighting effects are changed because these normals are used in the color calculations, not the linear ones passed by the Vertex Shader.

Now about the colors: red equals to normals pointing along (tangent to) the surface, green equals to normals pointing left (bitangent to) and blue equals to normals pointing up away from the surface.

A pure blue (0,0,255) pixel (the perfect surface normal) will be our test subject.

Let's say we were using this vector as a world space normal. That would work perfectly fine for a surface lying flat on its back. The texture reader would read (0,0,255) and determine the current normal pointing 100% up in World space. Then imagine an object on its belly with this texture. The GPU reading the texture will still read (0,0,255) believing the normal is still pointing up in World space. This is not the case, since the object itself has rotated. Oops.

Looks like we can't just pluck world normals out of a texture, because world normals are object orientation dependant. The normals are relative to the surface the texture is applied on. So, we need to know surface orientation to be able to use these normals. There's no way to store portable world normals in a texture.

But there's always hope: just convert your data which is in stored in World Space to Tangent space.