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?