Derivation of OpenGL Sphere-Mapping, Automatic, Texture-coordinate Generation for use in Environment Mapping
Kenneth E. Hoff
06/23/98
based on compiling information from the OpenGL redbook, the course notes, and from Mark Peercy at SGI
Sphere-mapping provides an interesting way of mapping a single-image texture onto the surface of an object that allows for view-dependent effects such as reflections, refractions, and even outlining and other non-photorealistic effects. More specifically, sphere-mapping maps all "reflected" vector directions into a single image (actually into the largest circle that will fit in the texture image). The problem then becomes determining the relationship between the (s,t) texture coordinates, the texture-map, the reflection vector, the eye, and a particular vertex for which we want to find tex-coords for.
We are given the following:
From this we wish to find the following:
Computing the reflection vector r:
r = u - 2(u.n)n
So, the reflection vector equals the viewing direction u minus 2 times the normal n scaled by the length of the projection of u onto n (or the cosine of the angle between u and n). This simply means that r is the reflection of u about the plane through the vertex with normal n (the standard reflection vector derived from the rule that the angle of incidence equals the angle of reflection, but it is hitting a plane that goes through the vertex and is perpendicular to the normal n).
Computing the (s,t) tex-coords based on the reflection vector r:
This is the tricky part. The goal is to map an arbitrary 3D direction r into a 2D circle. The (s,t) coords access the 2D bounding rectangle of the circle; the lower-left corner is (0,0), the top-right is (1,1), and the center of the circle is at (0.5,0.5) with a radius of 0.5. So naturally, the sphere-map should be a square to avoid any unnecessary waste (except for the corners).
Directly from the OpenGL redbook, we get the following:
m = 2 * sqrt(rx2 + ry2 + (rz+1)2) s = rx/m + 1/2 t = ry/m + 1/2
Where in the world did this come from?
The derivation of the sphere-map tex-coords:
In order to understand how we get s and t from the reflection vector, we must first understand how we get from the s and t values on the sphere-map to a normal, and then from a normal to a reflection vector. We can then invert this operation to derive the tex-coords.
Image that the sphere map is an orthographic projection of a unit sphere that is centered at the origin. The (s,t) values within the circular projection of the sphere are within [0,1], so for given (s,t) values we can obtain the (x,y) sphere coords in [-1,1] as follows through a simple scale and translate:
x = 2*s - 1 y = 2*t - 1
Since we know we are looking at the orthographic (or parallel) projection of the unit sphere and we have the (x,y) coords of a point on the sphere, we can compute the z coord from the implicit sphere equation:
x2 + y2 + z2 = 1 // implicit equation for a unit-sphere at the origin
z = sqrt(1-x2-y2)
Now we have a mapping from the (s,t) tex-coords to the points on the sphere in the sphere-map. This now directly relates the (s,t) values to the normals on the sphere by noticing that the normal of a sphere at a point p on the surface is simply p minus the sphere's origin. We are dealing with a unit sphere centered at the origin, so the normal is simply the (x,y,z) point we computed:
Normal n = (x,y,z) = ( 2s-1, 2t-1, sqrt(1-x2-y2) )
Now since are assuming the sphere-map is an orthographic projection of a sphere, the viewing direction u is simply down the negative z-axis. So we can easily compute the reflection vector in terms of the normal and then in terms of s and t:
u = (0,0,-1)
n = ( 2s-1, 2t-1, sqrt(1-x2-y2) )
r = u - 2(u.n)n
= (0,0,-1) - 2*-sqrt(1-x2-y2)*(2s-1,2t-1,sqrt(1-x2-y2))
= (0,0,-1) - 2*-nz*n
Now we have the reflection vector r in terms of the (s,t) tex-coords. Now if we work back towards a formulation of s and t in terms of the reflection vector, thus deriving the original sphere-mapping equations.
First we will invert the last equation and obtain n in terms of r:
n = (rx,ry,rz+1) / (2*nz)
So now, we see that the normal is proportional to (rx,ry,rz+1) (meaning that it is the same direction, but not the same length) by the value 1/(2*nz). We can ignore this value and simply normalize (rx,ry,rz+1) by dividing by the length of (rx,ry,rz+1):
n = (rx,ry,rz+1) / sqrt(rx2 + ry2 + (rz+1)2)
Now we obtain a definition of n in terms of the reflection vector components. We can continue to work backwards through our previous derivation to obtain s and t:
nx = rx / sqrt(rx2 + ry2 + (rz+1)2) ny = ry / sqrt(rx2 + ry2 + (rz+1)2)
Using definition of nx and ny from before, and then solving for s and t:
nx = 2*s - 1 ny = 2*t - 1
2*s - 1 = rx / sqrt(rx2 + ry2 + (rz+1)2) 2*t - 1 = ry / sqrt(rx2 + ry2 + (rz+1)2)
s = rx/(2*sqrt(rx2 + ry2 + (rz+1)2)) + 1/2 t = ry/(2*sqrt(rx2 + ry2 + (rz+1)2)) + 1/2
m = (2*sqrt(rx2 + ry2 + (rz+1)2))
s = rx/m + 1/2 t = ry/m + 1/2
Whew! Finally.