Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!uunet!seismo!uwvax!rutgers.rutgers.edu!sri-spam!ames!sdcsvax!ucbvax!ucsfcgl!pixar!ph
From: ph@pixar.UUCP (Paul Heckbert)
Newsgroups: comp.graphics
Subject: Re: Wanted: Clever Intersection Tests
Message-ID: <942@pixar.UUCP>
Date: Mon, 20-Jul-87 00:05:14 EDT
Article-I.D.: pixar.942
Posted: Mon Jul 20 00:05:14 1987
Date-Received: Tue, 21-Jul-87 03:47:39 EDT
References: <1222@byzantium.swatsun.UUCP>
Organization: Pixar -- Marin County, California
Lines: 67
Keywords: ray tracing
Summary: optimal ray-sphere intersection formulas

In article <1222@byzantium.swatsun.UUCP>, rice@swatsun (Dan Rice) writes:
>... one I saw recently calculated the intersection of a ray with a sphere
>by finding the closest approach of the ray to the center of the sphere with two
>dot products,and then found the actual intersection point by forming a triangle
>with the intersection point, the sphere center, and the point of closest
>approach.  Other ray-tracers that I've seen calculate this intersection by
>solving a quadratic equation for the intersection point directly...

This newsgroup already beat ray-polygon intersection testing into the ground,
so now let's move on to spheres...

The "best" computational formula I've seen for ray-sphere intersection
testing is what you called the "brute force" method, and goes something
like this:

------------------------------------------
	#define EPSILON 1e-7	/* tolerance to roundoff errors */

	/*
	 * SphereIntersect: find intersection of ray X=P+tD (where |D|=1)
	 * with sphere |C-X|^2 = r^2 by solving the quadratic equation:
	 *	|V-tD|^2 = t^2 - 2t(V.D) + (V.V-r^2) = 0
	 * where V=C-P.
	 * The roots are:
	 *	t = V.D +- sqrt((V.D)^2 - V.V + r^2)
	 */

	SphereIntersect(P, D, C, r2, tp)
	double P[3], D[3];	/* ray origin point and direction */
	double C[3], r2;	/* sphere center and radius_squared */
	double t[2];		/* t at intersection points (if any) */
	{
	    double V[3], b, disc;
s m a
0 0 3	    V = vsub(C, P);	/* vector subtract */
0 3 2	    b = vdot(V, D);	/* dot product */
0 4 4	    disc = b*b - vdot(V, V) + r2;
	    if (disc < 0.) return 0;		/* ray misses sphere */
1 0 0	    disc = sqrt(disc);
0 0 1	    t[0] = b-disc;			/* first root */
0 0 1	    t[1] = b+disc;			/* second root */
	    return 2;				/* return #roots */
	}
------------------------------------------

The numbers under "s m a" are the #sqrts, #multiplies, and #add/subtracts,
respectively.  With this scheme, it takes 7 multiplies and 9 adds to
determine if the ray hits the sphere, and 1 sqrt, 2 additions more to
find t at both intersection points.  I'd wager that this is "optimal"
given this set of inputs, outputs, and operators.

  [ General tip to fellow optimization freaks:
    I've found that I can often knock off a few superfluous multiplies
    and divides if I use the quadratic formula:
	    roots of x^2-2b*x+c=0 are x=b+-sqrt(b*b-c)
    instead of the tired old formula:
	    roots of a*x^2+b*x+c=0 are x=(-b+-sqrt(b*b-4*a*c))/(2*a) ]

These and other ray tracing issues will be discussed in the tutorial
"Introduction to Ray Tracing" at SIGGRAPH in Anaheim next week by speakers:
Andrew Glassner, Eric Haines, Rick Speer, Pat Hanrahan, Rob Cook, and myself.
See you there.

Paul Heckbert
Pixar				415-499-3600
P.O. Box 13719			UUCP: {sun,ucbvax}!pixar!ph
San Rafael, CA 94913		ARPA: ph%pixar.uucp@ucbvax.berkeley.edu