[comp.graphics] How do YOU compute refraction vectors?

hollasch@ENUXHA.EAS.ASU.EDU (Steve Hollasch) (05/21/91)

    About a month ago I posted a request for a reference on the particular
refraction equation I used, but no one responded.  Could have been
disinterest, but perhaps there are people who haven't heard of it,
either.                                     _          _
                                        P1 |            |
    The equation I use is  R = (D.N)N + -- | D - (D.N)N |, where P1 is the
                                        P2 |_          _|

index of refraction of the material containing the ray origin, P2 is
the index of refraction of the intersected object, N is the surface
normal, and D is the ray direction vector TOWARDS the surface.  Note that
the resulting vector is NOT a unit vector.

    Does anybody know of a more efficient equation?  How do YOU compute
the refraction vector?

    For those of you who are interested, the derivation of the above
equation follows.

//////////////////  WARNING -- DERIVATION AHEAD  /////////////////////

N: Normal vector                    N
                                  /|\
b: "horizontal" component          |
   of vector D.                    |  b
                                   |/........o
a: Negative "vertical"          a /:\      _/
   component of vector D.          :     _/
                                   :   _/
                       P1          :A_/ D
                       ____________:/___________
                                  /:
                       P2        / :
                                /A':
                               /   :
                              /    :
                             /     :
R: Refraction vector     R |/.....\:/ -a
                             \ kb  |
                                   |
                                  \|/ -N


               || b ||     || D - (D.N)N ||
    sin(A)  =  -------  =  ----------------
               || a ||      || - (D.N)N ||

               || kb ||     k || D - (D.N)N ||
    sin(A') =  --------  =  ------------------
               || -a ||        || (D.N)N ||

    By Snell's law,  P1 sin(A) = P2 sin(A'),  so  (P1/P2) sin(A) = sin(A').
Using this equality and combining the above two equations, we get

             k || D - (D.N)N ||      P1 || D - (D.N)N ||
             ------------------  =   -- ----------------  
                || (D.N)N ||         P2  || - (D.N)N ||

Since  || (D.N)N || = || - (D.N)N ||,  this equation simplifies to
k = (P1/P2).  So, solving for the refraction vector R, we arrive at the
following equation:
                                   _          _
                               P1 |            |
    R  =  -a + kb  =  (D.N)N + -- | D - (D.N)N |
                               P2 |_          _|

______________________________________________________________________________
Steve Hollasch                /      Arizona State University (Tempe, Arizona)
hollasch@enuxha.eas.asu.edu  /  uunet!mimsy!oddjob!noao!asuvax!enuxha!hollasch

erich@eye.com (Eric Haines) (05/22/91)

In article <9105210459.AA01904@enuxha.eas.asu.edu> hollasch@enuxha.eas.asu.edu (Steve Hollasch) writes:
>
>    About a month ago I posted a request for a reference on the particular
>refraction equation I used, but no one responded.  Could have been
>disinterest, but perhaps there are people who haven't heard of it,
>either.                                     _          _
>                                        P1 |            |
>    The equation I use is  R = (D.N)N + -- | D - (D.N)N |, where P1 is the
>                                        P2 |_          _|
>
>index of refraction of the material containing the ray origin, P2 is
>the index of refraction of the intersected object, N is the surface
>normal, and D is the ray direction vector TOWARDS the surface.  Note that
>the resulting vector is NOT a unit vector.
>
>    Does anybody know of a more efficient equation?  How do YOU compute
>the refraction vector?

Sorry, I missed your original posting.  Offhand, I don't see how your equation
detects total internal reflection, so I am loathe to analyze it further.  For
example, in Heckbert's method he detects if there is total internal reflection
by seeing if the value "C2" is negative - taking the square root of a negative
number is interpreted as TIR.

However, assume I've missed something and your equation works.  Have you
compared your method with Heckbert's, in "An Introduction to Ray Tracing"
edited by Andrew Glassner?  I've found his methods (pages 290-292) to be
pretty minimal.  He talks about Whitted's original method and gives his own
and a variation on it.  Whitted's has 2 square roots, 8 divides, 17 mults, and
15 adds.  Heckbert's has 1 square root, 1 divide, 13 mults, and 8 adds.  His
variant formulation has 1 square root, 4 divides, 8 mults, and 8 adds (nice if
your machine does divides almost as fast as mults).  Note that he's starting
with normalized vectors and computing a normalized vector.

Eric

markv@pixar.com (Mark VandeWettering) (05/23/91)

In article <9105210459.AA01904@enuxha.eas.asu.edu> hollasch@enuxha.eas.asu.edu (Steve Hollasch) writes:
>
>    About a month ago I posted a request for a reference on the particular
>refraction equation I used, but no one responded.  Could have been
>disinterest, but perhaps there are people who haven't heard of it,
>either.                                     _          _
>                                        P1 |            |
>    The equation I use is  R = (D.N)N + -- | D - (D.N)N |, where P1 is the
>                                        P2 |_          _|
>
>index of refraction of the material containing the ray origin, P2 is
>the index of refraction of the intersected object, N is the surface
>normal, and D is the ray direction vector TOWARDS the surface.  Note that
>the resulting vector is NOT a unit vector.

Whenever I need a refraction formula, I refer back to Heckbert's way of 
calculating it.  He did a study of how to compute this and wrote up
a small paper that was reproduced in some Siggraph course notes which 
I could not find immediately.  The code for it is reproduced in the 
simple framework that he has in "Intro to Ray Tracing" by Glassner.

For those of you who just want the answer....

/* this slightly differs from his code in the book, but is (in principle)
 * the same */

TransmissionDirection(m1, m2, I, N, T)
 double m1, m2 ;			/* the index of refraction */
 Vector3 I, N, T ;			/* incoming, normal and Transmitted */
{
	double eta, c1, cs2 ;

	eta = n1 / n2 ;			
	c1 = -VecDot(I, N) ;
	cs2 = 1 - eta * eta * (1 - c1 * c1) ;

	if (cs2 < 0)
		return 0 ;		/* total internal reflection */
	
	/* 
	 * VecComb(a, v1, b, v2, v3)
	 * computes v3 = a * v1 + b * v2, 
	 * where a & b are scalars, and v1, v2, v3 are vectors */
	VecComb(eta, I, eta * c1 - sqrt(cs2), N, T) ;

	return 1 ;
}

Hope this helps 

mark

hollasch@ENUXHA.EAS.ASU.EDU (Steve Hollasch) (05/27/91)

    Well, it's time for my netwide self-abasement.  As some people have
pointed out (thanks Juhana and Colm), the nifty wonderful and
oh-so-efficient method I posted last week is also oh-so-incorrect.  (sigh)

    It turns out that I was using the lesser-know Snell's Dog's Law:

                                   n1
                         tan(A1) = -- tan(A2)
                                   n2

    In my defense, I got the formula from class notes that were themselves
incorrect, but I have to confess that I duplicated the error while driving
through the derivation.

    So, please ignore (I think most people already have, thankfully) my
last post about refraction vector calculation.

______________________________________________________________________________
Steve Hollasch                /      Arizona State University (Tempe, Arizona)
hollasch@enuxha.eas.asu.edu  /  uunet!mimsy!oddjob!noao!asuvax!enuxha!hollasch