As we discussed in class, you have a lot of freedom in what you choose to work on in class. You can expand on your ray tracer with bump mapping or other features, do dynamics or particle simulation, try some inverse kinematics, key-frame animation using splines, or anything else that might be cool and interesting. Follow your bliss. Here are some notes on various topics to help you along.
As we said in class, implementing dynamics can be quite simple. Given an object at location P, where P = [px,py,pz], you can implement velocity V = [vx,vy,vz], the derivative over time of position, by adding, at each animation frame:
P += ε Vwhere you set ε to the elapsed time in seconds per frame, as computed by taking successive differences in the value of ( System.currentTimeMillis() / 1000.0 ).
Similarly, you can accelarate an object, by adding accelaration A = [ax,ay,az], the derivative over time of its velocity, by adding, at each animation frame:
V += ε AIf you set A = [0,-G,0], where G is just a numerical gravity constant, then you have implemented gravity!
This will tend to make your objects fall down at an ever accelarated rate. So of course you also need to implement collisions, bouncing, friction, and so forth.
If your object is a sphere at center C = [cx,cy,cz] and radius r, then the falling sphere will hit a tabletop surface at y when the bottom of your sphere reaches y. In other words, when y = cy+r. When this happens, you probably want the sphere to bounce. You do this simply by flipping the sign of the velocity at that animation frame: [vx,vy,vz] → [vx,-vy,vz].
You can make things more realistic by reducing the velocity by some fraction at the moment the sphere hits the table. This simulates the process of some energy being transferred from the sphere to the table.
It's also easy to simulate springy things, as in the bobbing bird example on my home page. Springs are characterized by a linear relationship between how stretched or compressed the string is, and how much the spring wants to go back to its uncompressed/unstretched state. In otherwords, A = -KP, where A is accelaration, P is position relative to the resting position, and K is just a numerical constant. So at every animation frame, you just need to add -εKP to your spring object's accelaration, and then do the same P += εV and V += εA that you would do for any other dynamic simulation.
One way to simulate fluids is by approximation as discrete particles - like a collection of small balls that have local influence on each other. If you make them try to maintain a constant distance between each perticle and its nearest neighbors, then you will be implementing the volume preserving property of liquids. If you make them try to maintain the relative angle between each particle and and its various neighbors, then you will be implementing viscosity (slow moving liquids like molasses have high viscosity - a lot of friction occurs when the molecules to slide over each other).
If you use a relatively small number of particles, then you can just loop through each particle, look through all the other particles to see which ones are nearby, and then adjust the positions of each particle to move them toward an "optimal" pairwise neighboring distance. To avoid popping (as a particle switches over time from being near enough to be considered a neighbor and too far away to be a neighbor), you should have a fall-off weight for how much you apply this restorative force. Neighbors that are far away should only weakly influence a particle's position, up to, say, a distance of twice the nearest allowable distance between particles.
You can apply all the usual dynamics forces to each particle in a simulated fluid - gravity, collision with objects, spring forces between particles, and so forth. Treating the interaction between neighboring particles of a fluid as springs is an excellent way to simulate thermal energy. "Hotter" fluids will have a lot of springing back and forth between neighboring particles, and this springing will propogate gradually through the "fluid", just as it does in a real fluid.
Bump mapping surface normals for ray tracing
If you want the directions of your reflected rays to vary with "bumps" on a surface, then you need to do bump mapping. If your texture was created by Noise function, then the key is to realize that the Normal vector is the derivative of your surface equation. This means that as a surface location is varied by some function, such as noise(x,y,z), its Normal vector will vary as the derivative of that function. You can compute the derivative of the Noise function as follows:
F0 = noise(x,y,z)for some small ε such as 0.001. The derivative of Noise at (x,y,z) is then given by [Fx - F0, Fy - F0, Fz - F0].
Fx = noise(x+ε,y,z)
Fy = noise(x,y+ε,z)
Fz = noise(x,y,z+ε)
To implement bump mapping, just add this derivative to your surface normal, and then normalize the result (ie: adjust the resulting vector back to unit length). Do your ray tracing using this adjusted normal, and you will have cool bumpy reflections and refractions!