Using a cubemap lookup into a tangent-space normal map is a bit tricky, since two neighbouring pixels rendered from the same primitive might be looking up from different cube map faces, with different tangent directions.
A simple way to solve this is to ensure your sphere geometry is split exactly on the lines corresponding to the edges of the cubemap (say, by taking a subdivided cube and normalizing all the vertex positions to bend it into a ball - something like this).
Once you've done that, you can lay out your cube map faces as a flat 2D texture, and map into it with regular UV mapping instead of cube map lookups, if you prefer. Your exporter should be able to generate usable tangents for this version automatically.
This is probably the most reliable way to get a consistent mapping between your normal map generation and rendering.
If that's not an option, then you may need to compute your tangent vector in the fragment shader, so it can handle cubemap face discontinuities (and thus, potential tangent discontinuities) within a single primitive. The math here gets a bit tricky if you want to remove all visible pucker where cubemap faces meet, so I don't recommend it.
Here's a first stab at the problem...
(For the following, I'm assuming a left-handed coordinate system with y+ pointing up/north. I assume that the non-polar cubemap faces expect the tangent to point "east," with the texture's "up" pointing to z+ for the north pole face and z- for the south pole. You may need to flip some signs if this doesn't match your setup.)
First, determine which cube map face the current fragment belongs to by finding which component (x, y, z) of its normal is furthest from zero.
- If x: your tangent is sign(normal.x) * normalize(cross(normal,
cross((0, 0, +1), normal))
- If y: your tangent is
normalize(cross(normal, cross((+1, 0, 0), normal))
- If z: your tangent
is sign(normal.z) * normalize(cross(normal, cross((-1, 0, 0),
(In each case, the tangent points along the perimeter of a great circle running through the current pixel and the center of one of the neighbouring cubemap faces)
Note that the v direction of a cubemap face isn't perpendicular to the u direction at the corners of the cubemap when projected onto a sphere (they meet at a 120 degree angle), so if that causes visible artifacts you'll need to compute a non-perpendicular bitangent too, using equations similar to the above.
I hope that's of some use!