CPE 471, Spring 2016, Professor Sueda
This project was inspired by the following scene from the movie Life of Pi:
- Fish at randomized depths and rotations
- Texture rendering to make the reflection and refraction
- Distortion in the water
- Blending to create fog effects
- Ray casting for the boat
Reflection and Refraction
To create the reflection, I used a mirrored version of the scene and only drew points above the y=0 plane (which is the surface of the water).
I used a separate framebuffer so that I could render this new scene as a texture. I used the same technique for the refraction, though I did
not mirror the scene and only drew points below the y=0 plane. After incorporating an offset to the textures (discussed in Water Distortion), I blended
the two textures together to create a single texture that had both reflection and refraction. I used the fresnel effect to make the ratio between
the two textures depend on the dot product of the eye vector and the normal of the surface of the water (see
here for a video describing the fresnel effect). This way, looking straight into the water will show more of the refraction, while looking across the surface of the
water will make the water reflection more apparent.
To create the distortion of the water, I used a sample du/dv map to offset the texture coordinates of the water. I interpreted the rgb value of each point
on the du/dv map as a vector, which I then added to the actual texture coordinate. To make the surface of the water have the wavy motion, I used the current
time as an offset when getting the vector from the du/dv map.
To simulate depth and distance, I used blending to make the fish blend with the color of the water when deeper or farther away. I also used blending to
make the horizon easier on the eyes. Without it, the boundary between the ocean and the sky was a sharp line, which I disliked.
When I first inserted the boat into the scene, I realized that the water plane cut through the boat, making it look like it was taking on water:
To remedy this, I needed to discard the fragments of the water plane that were inside the boat. First, I used an axis-aligned bounding box for the boat
to check if the fragment was in the general vicinity of the boat. If so, then I used ray casting to check if the fragment was actually in the boat. The
method I used involved checking how many times a ray intersected the sides of a polygon. If it intersected the polygon an odd number of times, then the
ray originated from inside the polygon. In my case, I had to check if a ray originating at the fragment intersected the sides of the boat an odd number
of times. To do this, I made a line from the fragment to a point that I knew was outside of the boat. Using this line, I compared it to every side of the
polygon representing the boat, checking if the lines were intersecting. If there were an odd number of intersections, then the fragment was inside the
boat, and was discarded. For more information about this technique, look here.
Obj files sources
Life of Pi picture source