The reflective ocean is rendered in two steps. The image of the reflected terrain and sky is rendered (Color Plate 37U), reflected (Color Plate 37V), and then composited to create the final image (Color Plate 37W). The reflection image contains only the terrain and sky.
Because the ocean is a sphere, the reflection must be spherical. Figure 20.8 shows a screenshot of the AlienRockArt planet with a high water level: You can see that the terrain on different sides of the planet is reflected in different directions. This effect cannot be achieved with simple planar reflection. Rendering the reflection image means drawing the terrain reflected in the sphere. Figure 20.9 shows the requirements.
Figure 20.8. Reflections from a spherical surface reflected in different directions, as shown in the circled regions
Figure 20.9. The geometry of reflections on a spherical object
Given the eye and object position, the point R must be found such that the angle of incidence equals the angle of reflection. (These two angles are the arcs on the diagram.) Once R is found, the reflected point is be such that the line from it to the eye passes through R. (The location of the reflected point is not exactly defined, since for rendering a real-time reflection, the only constraint is that object order is preserved so that objects occlude each other properly. For instance, if a second object lies between R and the object, it would occlude the first object and so its reflected point must be closer to the eye than the first object's reflected point.)
Finding the point R exactly involves solving a fourth-order polynomial; see Reflections on Spheres and Cylinders of Revolution by Georg Glaeser. Once again, this is a computation that would be prohibitively costly. For RealWorldz, the reflection needs only to be good enough to fool the human eye, so mathematical precision is unnecessary. A viewer would expect reflections to have the following properties:
For the terrain, it is only necessary to consider points that are close to the planet surface. The sky is handled in a different way altogether, described in the next section.
One complication is that the terrain is rendered with triangles, so some triangles will have vertices in regions hidden from the viewer. For instance, a triangle that penetrates the reflector will have a vertex inside the sphere. For the reflected triangle to be rendered correctly, these hidden vertices must be "reflected" to an appropriate position.
Figure 20.10 shows the elements of a method that meets these criteria.
Figure 20.10. Approximating reflections on a spherical object
The view shown in Figure 20.10 is a cross-section of the situation for a given eye position. The reflector is centered at C, and the point H is on the horizon. That is, the point H is on the reflector sphere, and the line from H to the eye is at right angles to the line from H to C. The dark line is roughly the line in which points are reflected.
Two infinite cones are defined. The "divider" cone has its tip at the point C, with its axis lying on the line from the eye to the point C. The surface of the cone passes through H. It is the shaded area in Figure 20.10B.
The second cone, the "horizon" cone, has its tip at the point E, and its axis also lies on the line from the eye to the point C. Again, the surface of the cone passes through H. It is the shaded area in Figure 20.10C.
The divider cone determines the method for reflecting a given point. If the point is within the cone, then its reflection is its inversion in the reflector sphere (the curved section of the bold line); if the point is outside the cone, then its reflection is its inversion in the horizon cone (represented by the straight sections of the bold line).
By "inverting the point x in a surface S", we mean finding a point p on S with a surface normal n, such that p + kn = x, for some real k. Then the inverted location r is defined to be r = s kn. (Applying this definition to a plane surface gives the expected reflection transformation, that is, mirroring the points in the plane.)
This method for finding reflected points fulfills the criteria given above. The inversion in a sphere takes care of the first two requirements; the horizon cone inversion case was added for the procedure to fulfill the last requirement. Although not mathematically correct, in practice it produces convincing spherical reflections.
20.5.2. Reflected Sky
Rendering the reflection of the sky is much less complex. The sphere of the sky is considered to be at infinity, which greatly simplifies the mathematics. As described in the previous section, the sky is rendered as a sphere tessellated with constant-latitude rings. The constant-latitude ring and spherical reflector are invariant under rotation about the polar axis, so the reflection calculations can be so set up that they need only be done once per latitude.
20.5.3. Rendering the Ocean
The final step is to composite the reflection image onto the scene. The water effects simulated are reflection, warping of reflection due to waves, underwater caustics, and water transparency.
Underwater caustics are flickering light patterns on underwater surfacesthey are often seen at the bottom of swimming pools. They are due to the ripples and waves causing the light to refract in different directions. As a result, the light is not distributed evenly on the underwater surfaces; it is concentrated in some areas, which are the bright spots.
In RealWorldz, the caustic effects are simulated with an animated texture map. Another application generated the animated texture map by defining a water surface with a periodic wave pattern and simulating the paths of millions of photons refracted by the surface. This produced a sequence of tileable texture maps that make up the animation.
When the ocean is enabled, the caustic texture map is drawn on underwater terrain as the terrain is rendered; it fades out as the water depth decreases. This shader also sets the alpha component to indicate how much that pixel is occluded by the water. If the point is above water, the alpha is 0. The alpha value increases with depth and distance from the viewer, with 1.0 indicating that the pixel is completely obscured by the ocean. When the ocean is drawn, this alpha value controls the blend between the reflective ocean and the underlying terrain.
Another complication is that the ocean is drawn by re-rendering of the terrain and use of the vertex shader to project all the vertices onto the ocean sphere. Since the terrain patches overlap, some ocean pixels are drawn twice or more. Since the water is partially transparent, pixels that are drawn twice have the transparency effect applied twice, meaning that the ocean looks different in overlap regions.
The solution was to use the OpenGL blend mode GL_ONE_MINUS_DEST_ALPHA, GL_DST_ALPHA. The source alpha value is always 1.0, so the blend function simplifies to the following:
finalColor.rgb = source.rgb * (1-dest.a) + dest.rgb * dest.a; finalColor.a = 1.0;
where source is the RGBA value output by the fragment shader that renders the ocean; dest is the RGBA value presently in the framebuffer.
After a pixel is rendered, the alpha value in the framebuffer is set to 1.0. When the alpha component of a pixel in the framebuffer is 1.0, no further changes are made to that pixel. This solves the overdraw problems due to the overlap areas, since only one change will be made to each pixel.
The water ripples are produced by 2D warping of the reflection texture map. For each pixel, a "ripple" texture map is sampled; the R and G components of the sampled color perturb the read into the reflection texture map, giving the appearance of water ripples. At the edges of the screen, this could lead to the samples made off the edge of the reflection texture map. Clamping the perturbed texture coordinates to [0,1] fixes that problem but smears effects at the edge of the screen. A better solution is to render a reflection texture map corresponding to an area slightly larger than the visible screen area. This provides a border region, so the ripple offset is unlikely to result in a texture coordinate outside the [0,1] range, thereby fixing the smearing problem.