In this last project you are asked to make two changes to the ray tracer given in class.
- There is a problem with the sphere intersection method given in class:
- Consider what happens when the ray starts inside of a sphere (as it will in this project).
- How can you tell if the ray starts inside of the sphere?
- Should you subtract off the little piece of v in this case?
- You'll have to modify the sphere Intersect method to fix this.
I've decided just to give you my code that fixes this problem. The key difference is that when the ray originates inside of a sphere the the segment labeled t is added to the length v rather than subtracted from it. This code fragment may also help demystify the issues of the inside flag. In the future, I will use this version in lecture.// An example "Renderable" object class Sphere implements Renderable { Surface surface; Vector3D center; float radius; float radSqr; private static final float TINY = 0.001f; public Sphere(Surface s, Vector3D c, float r) { surface = s; center = c; radius = r; radSqr = r*r; } public boolean intersect(Ray ray) { float dx = center.x - ray.origin.x; float dy = center.y - ray.origin.y; float dz = center.z - ray.origin.z; float v = ray.direction.dot(dx, dy, dz); // Make sure the ray is heading towards the sphere if (v < 0) return false; // Do the following quick check to see if there is even a chance // that an intersection here might be closer than a previous one float t = v - radius; if (t > ray.t) return false; float d = dx*dx + dy*dy + dz*dz; // Test if the ray actually intersects the sphere t = radSqr + v*v - d; if (t < 0) return false; t = (float) Math.sqrt(t); // Consider if ray starts inside or outside of sphere if (d + TINY < radSqr) { // inside t = v + t; // Test if the intersection is in the positive // ray direction and it is the closest so far if ((t > ray.t) || (t < 0)) return false; ray.inside = true; } else { // outside t = v - t; // Test if the intersection is in the positive // ray direction and it is the closest so far if ((t > ray.t) || (t < 0)) return false; ray.inside = false; } ray.t = t; ray.object = this; return true; } . . .Unfortunately, you will either have to make these changes by hand, or cut and paste them. Otherwise, I would have to back out too many of my additions (primitives and other features), and I'd rather get this to you sooner than latter.
You'll also need to make a few changes to the Ray class in order to use this code. Below are the changes that I made. You might find other useful hints here.class Ray { public static final float MAX_T = Float.MAX_VALUE; Vector3D origin; Vector3D direction; float t; Renderable object; boolean inside; public int level; public Ray(Vector3D eye, Vector3D dir) { origin = new Vector3D(eye); direction = Vector3D.normalize(dir); level = 0; } public Ray(Vector3D eye, Vector3D dir, int plevel) { origin = new Vector3D(eye); direction = Vector3D.normalize(dir); level = plevel + 1; } . . .