glsmap/smap_rvec2st.c

 
/* Copyright (c) Mark J. Kilgard, 1998.  */
 
/* This program is freely distributable without licensing fees
   and is provided without guarantee or warrantee expressed or
   implied. This program is -not- in the public domain. */
 
#include <math.h>
 
#include "glsmapint.h"
 
/* (x,y,z) reflection vector --> (s,t) sphere map coordinates */
int
smapRvecToSt(float rvec[3], float st[2])
{
    double m, recipm;
 
    /* In Section 2.10.4 ("Generating texture coordinates")
       of the OpenGL 1.1 specification, you will find the
       GL_SPHERE_MAP equations:
 
          n' = normal after transformation to eye coordinates
          u  = unit vector from origin to vertex in eye coordinates
 
          (rx, ry, rz) = u - 2 * n' * transpose(n') * u
 
          m  = 2 * sqrt(rx^2 + ry^2 + (rz + 1)^2))
 
          s = rx/m + 0.5
          t = ry/m + 0.5
 
        The equation for calculating (rx, ry, rz) is the
        equation for calculating the reflection vector for
        a surface and observer.  The explanation and
        derivation for this equation is found in Roger's
        "Procedural Elements for Computer Graphics" 2nd ed.
        in Section 5-5 ("Determining the Reflection Vector").
        Note that Roger's convention has the Z axis in
        the opposite direction from the OpenGL convention. */
 
    m = 2 * sqrt(rvec[0]*rvec[0] +
                 rvec[1]*rvec[1] +
                 (rvec[2]+1)*(rvec[2]+1));
    if (m == 0.0) {
        /* Some point on the sphere map perimeter. */
        st[0] = 0.0;
        st[1] = 0.5;
        return 0;
    }
 
    recipm = 1.0/m;
 
    st[0] = rvec[0]*recipm + 0.5;
    st[1] = rvec[1]*recipm + 0.5;
    return 1;
}
 
/* (s,t) sphere map coordinate --> reflection verctor (x,y,z) */
void
smapStToRvec(float *st, float *rvec)
{
    double tmp1, tmp2;
 
    /* Using algebra to invert the sphere mapping equations
       shown above in smapRvecToSt, you get:
 
         rx = 2*sqrt(-4*s^2 + 4*s - 4*t^2 + 4*t - 1)*(2*s-1)
         ry = 2*sqrt(-4*s^2 + 4*s - 4*t^2 + 4*t - 1)*(2*t-1)
         rz = -8*s^2 + 8*s - 8*t^2 + 8*t - 3
 
       The C code below eliminates common subexpressions. */
 
    tmp1 = st[0]*(1-st[0]) + st[1]*(1-st[1]);
    tmp2 = 2 * sqrt(4*tmp1 - 1);
 
    rvec[0] = tmp2 * (2*st[0]-1);
    rvec[1] = tmp2 * (2*st[1]-1);
    rvec[2] = 8 * tmp1 - 3;
}