I'm implementing normal mapping on my toy pathtracer. I need to compute the tangent (and bitangent) of any sphere point in order to create the matrix that will transform tangent space to world space.
More specifically, I want the tangent that runs along the u texture coordinate, and the bitangent that runs along the v coordinate.
Here's how I implemented it:
- At the intersection point P, compute the spherical coordinates (theta, phi) of P.
- Add a tiny delta to the angle that relates to the u texture coordinate (phi), finding another point Q on the sphere.
- Compute Q - P and normalize it to have the tangent.
- The bitangent is then computed by doing the cross product of the tangent and the normal at the point P.
Relevant code on the sphere collision function:
hitRecord.point = ray.pointAtParameter(t);
Vec3 localCoord = hitRecord.point - center;
float theta = asin(localCoord.y / radius); //[-pi/2,pi/2]
float phi = atan2(localCoord.z, localCoord.x); //[-pi,+pi]
float deltaPhi = phi + FLOAT_BIAS;
Vec3 deltaPoint(radius * cos(theta) * cos(deltaPhi),
radius * sin(theta),
radius * cos(theta) * sin(deltaPhi));
//Assume local space to be aligned with world space
//So this is also the tangent in world space
hitRecord.tangent = deltaPoint - localCoord;
hitRecord.tangent.normalize();
hitRecord.normal = localCoord / radius;
hitRecord.bitangent = hitRecord.tangent.cross(hitRecord.normal);
hitRecord.bitangent.normalize();
This seems to work, but all this trigonometry is not light and makes me wonder if there is a better way of doing it. Does anyone has any ideias/pointers?