1
\$\begingroup\$

I have difficulties understanding the tangent/bitangent concept for normal mapping, or rather the calculations of them.

I draw a sphere which is generated with the code in the OpenGL redbook http://www.glprogramming.com/red/chapter05.html. I use cube mapping to texture the sphere.

Now, pretty much everything in the web links to http://www.terathon.com/code/tangent.html. But in that algorithm, they use the texture coords u and v, which I don't have like this because my texture mapping is 3D...

Any pointers to how I can compute the tangents and bitangents with this setup?

Also, aren't the tangents just vectors orthogonal to the normal of a point on the sphere? To me it seems there could be an easier way..

Edit: As far as I understand I need those values to be able to "apply" the normal from the normal map to the point on the sphere. (I'm not sure what the correct mathematical terminologies are here). In other words, to deviate the normals of any point on the sphere based on the normal map. I calculated the normals as point_on_surface - center_of_sphere (which, in modelspace, when the center is (0,0,0), is just point_on_surface)

\$\endgroup\$
  • \$\begingroup\$ There are infinitely many tangent vectors in 3D, because actually the "tangent" at a 3-space point is a tangent-plane \$\endgroup\$ – bobobobo Dec 1 '13 at 18:41
  • \$\begingroup\$ @Schtibe Why don't you have texcoords if you want to do normal mapping? \$\endgroup\$ – TravisG Dec 1 '13 at 18:48
  • \$\begingroup\$ @TravisG Well I do have them, but they have three components, whereas the algorithms require two... \$\endgroup\$ – arsenbonbon Dec 1 '13 at 18:55
  • \$\begingroup\$ So you're using cube normal maps? Any particular reason for it? \$\endgroup\$ – TravisG Dec 1 '13 at 19:00
  • \$\begingroup\$ Yes. Actually I was just exploring ways to map a texture on a sphere and ended up with cube maps because the result was very satisfying \$\endgroup\$ – arsenbonbon Dec 1 '13 at 19:15
0
\$\begingroup\$

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), normal))

(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!

\$\endgroup\$
1
\$\begingroup\$

In principle, you can use any method of generating tangents and bitangents that you like, as long as the method is consistent between the process generating the normal map, and the process applying it.

Usually, we use tangents and bitangents that match up with the texture UV axes because that gives the colors of normal maps a simple interpretation - red controls the left-right deflection (relative to the texture) and green controls the up-down deflection. It also allows the same normal map to be reused on many surfaces with different orientations in 3D, or different UV mappings.

Your normal map plugin presumably assumes this is the case. When generating a normal map from a 2D map of the earth, it creates a red channel that represents left-right deflection relative to the texture, and a green channel that represents up-down deflection.

So, to apply this normal map correctly you would need to create tangents and bitangents that correctly represent what "left", "right", "up", "down" in texture space correspond to in 3D space. The simplest way to do this is to create a UV mapping that correctly applies the original 2D map to the sphere (e.g. using a Mercator projection, or whatever the original projection of the map was), then generate the tangents and bitangents from the UV mapping in the usual way.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.