Talk:Ray-sphere intersection

From DmWiki

It took me awhile to convince myself the optimized code was correct, here are the derivation steps to save others my confusion:

// Un-optimized
float intersectRaySphere(const Ray &ray, const Sphere &sphere) {
	// Assumes ray.d is normalized
	// Uses quadratic formula, A = 1 because ray.d is normalized.
	// For derivation, see:
	// http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter1.htm
	Vec dst = ray.o - sphere.o;
	float B = 2.0f * dot(dst, ray.d);
	float C = dot(dst, dst) - sphere.r2;
	float D = B*B - 4.0f * C; // Discriminant.
	if (D < 0)
		return std::numeric_limits<float>::infinity();
	float sqrtD = sqrt(D);
	float t0 = (-B - sqrtD) * 0.5f; // Will always be the smaller, but may be negative
//	float t1 = (-B + sqrtD) * 0.5f; // The second intersection, if you care
	return t0;
}

We pull out the factor of 2 in B, which makes D = 2*B*2*B - 4.0f * C, which we then pull out the factor of 4, since that won't change whether it is negative or not for the test. After the test, we factor that 4 out of the sqrt (the factor becomes 2), which gives t0 = (-2.0f * B - 2.0f * sqrtD) * 0.5f, and the factors cancel out. Very clever optimization, but a derivation would have been nice.

// Optimized
float intersectRaySphere(const Ray &ray, const Sphere &sphere) {
	// Assumes ray.d is normalized
	// Uses quadratic formula, A = 1 because ray.d is normalized.
	// For derivation, see:
	// http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter1.htm
	Vec dst = ray.o - sphere.o;
	float B = dot(dst, ray.d); // B really equals 2.0f this value
	float C = dot(dst, dst) - sphere.r2;
	float D = B*B - C;  // Discriminant.  D really equals 4.0f times this value
	if (D < 0)
		return std::numeric_limits<float>::infinity();
	float sqrtD = sqrt(D); // sqrtD really equals 2.0f times this value
//	float t0 = (-2.0f * B - 2.0f * sqrtD) * 0.5f;  // The factors cancel out
	float t0 = (-B - sqrtD); // Will always be the smaller, but may be negative
//	float t1 = (-B + sqrtD); // The second intersection, if you care
	return t0;
}
DevMaster navigation