Triton 3D Oceans for UnityIntegrating reflections of your scene on the water is the biggest thing you can do to create realistic water with the Triton Ocean SDK. But, producing the texture map Triton needs for planar reflections can be a little tricky. Here are some tips for getting started.

The heart of Triton’s reflection support is the Environment::SetPlanarReflectionMap() method. At a minimum, this requires you to pass in a reflection texture and a matrix to transform a view vector from the water to texture coordinates in the texture you provided. This means you must introduce a reflection pass into your engine, which renders the scene into a texture each frame that is then passed into SetPlanarReflectionMap().

This reflection pass must flip the scene upside-down. In a flat coordinate system, this is fairly straightforward; just introduce a scaling transform that for example scales Y by -1 if Y is “up” in your scene. But in the geocentric, ECEF systems so many of our customers use, the math gets tricky for this. To make it easier, we provide the Ocean::ComputeReflectionMatrices() method. It will use the current camera position, and give you back the proper matrix you need to transform your scene into an upside-down reflection map. As an added bonus, it also gives you the texture matrix you need to pass into SetPlanarReflectionMap() for the resulting reflection texture.

Rendering the scene upside-down isn’t all that’s required, however. You also need to clip out objects that are below water, since only objects above water will be reflected by the water surface. A user clipping plane that matches the water surface will do the job, or you might consider using an oblique projection matrix instead.

To maximize performance, make sure you’re not rendering more stuff than you need into the reflection pass. The sky, ships, and coastlines should be all you really need – and even those can be at a lower level of detail if necessary.

To make it easier for OpenSceneGraph users, we provide an OpenSceneGraphReflection sample application with the Triton SDK that’s a working example of using planar reflections in OSG. The same techniques could be used in osgEarth as well, although you will need to read the comments for guidance on adapting it to a round-Earth, ECEF coordinate system.

What if you just can’t afford the time required for an extra reflection pass, even after paring that pass down to the bare minimum? Triton offers an alternate reflection scheme using an environment map. The idea is that you can provide Triton a cube map that just captures the sky, which can be updated much less frequently than every frame, and still get much more realistic water than you would without any reflections at all. You can even use SilverLining’s Atmosphere::GetEnvironmentMap() method to get the required cube map automatically. This cube map should aligned against the primary X, Y, and Z axes, regardless of your local coordinate system or which way is “up”. Once you have a cube map, you can pass it into Triton with the Environment::SetEnvironmentMap() method.

It’s all a bit of work, but the visual results are well worth it!