Parts

Requisites

At the moment of writing the Ozonex editor renders the water quite differently. In turn the rendering of the water that you see in the Ozonex editor is not representative to what you'd see in-game. The GPG editor uses the exact same procedures and is therefore completely representative.

Settings

Elevation height

The primary usage of these elevation parameters is to both define the water surface and the range of the water ramp.

Surface
Defines at which height the surface is. There can only be one surface of water - multiple surfaces to support maps with varying water height is not supported. Is also used as a marking point as to where the water ramp starts.

Any value above the surface will share the same value as the one on the surface. Uses the pixel in the most top left corner of the water ramp.

Deep
Has no meaning of any kind. It is an aesthetic parameter as it is mentioned in the shader that renders the water, but never referenced anywhere in a computation. Has no game play effect of any kind.

Abyss
Defines at which height the water ramp is at its lowest. Has no game play effect of any kind - solely used for coloring the terrain underneath.

Any value below the abyss will share the same value as the one on the abyss. Uses the pixel in the most top right corner of the water ramp.

surface-ramp.png
Water with a surface in the left top slice, water without a surface but with the water ramp applied in the right bottom slice

Sun color

The sun color parameters influence the color of the reflection of the sun. This reflection is a form of specular lighting and the options for the specular lighting are below the header 'Sun and Fresnel', discussed below. The sun color is a typical RGB color component as one would expect.

The values range between 0.0 and 2.0, which allows you to overload the color significantly. This is useful in the case that color is reduced due to shadows of some kind. Typically the range is between 0.0 and 1.0, representing values between 0 and 255 in integral-based colors.

Red
The red component of the sun color.

Green
The green component of the sun color.

Blue
The blue component of the sun color.

sun-color.png
A slice with red and a green sun color

The reflection of the sun is unrelated to the angle of the sun defined in the lighting settings. It is always most visible when looking perpendicular at the water, where as the reflections are invisible when looking parallel with the water.

Surface color and interpolation
The surface color parameters influence the color of the surface itself. It colors the entire surface based on an interpolation of depth of the water. Lets look at the code to find out how this plays out in practice:

float4 HighFidelityPS(...)
{
   // (...)

    // as found in water2.fx

    // we want to lerp in some of the water color based on depth, but
    // not totally on depth as it gets clamped
    float waterLerp = clamp(waterDepth, waterLerp.x, waterLerp.y);

    // lerp in the color
    refractedPixels.xyz = lerp( refractedPixels.xyz, waterColor, waterLerp);

   // computations such as reflections and wave crests
}

The waterDepth is a value in the range between 0.0 and 1.0. At 0.0 we are at the surface height, at 1.0 we are at the abyss height. We defined these values earlier. The water depth is clamped between the two interpolation values. This has a set of consequences:

  • Any depth value smaller than the minimal value will have a fixed surface color.
  • Any depth value larger than the maximal value will have a fixed surface color.
  • Any depth value between the minimal and maximal value will have some form of interpolation applied to them.

That means that if we have a minimal value that is larger than 0 all the water will always have some surface color and isn't transparent. This causes a visual annoyance when zooming out described in another article:

Now that we're aware of this we can also understand why the water becomes opaque when we up the values: we are interpolating between the refracted image of what is behind the water over a single color that we defined ourselves. When we up the values, all that remains is the surface color we defined.

An inconvenient error is that the depth of the water is inaccurately defined. This isn't as obvious when you view the water from up top, but it becomes clear when you view the water from an angle.

surface-error.png

The reason for this is that the surface is changed in color, but not the color of the terrain behind the surface. That color is changed according to a water ramp, which we'll touch upon in this article and discuss in another.

Reflections of the sky and water crests will always appear on the surface - these are computed and combined after the surface color computations are complete.

Essentially what the surface color and its interpolation values describe is how clear the water is. Take the water from that cup standing next to you in comparison to water that you mixed with lemonade: the former is clear (hopefully) and the latter is almost opaque.

Reflection and refraction

Reflection is the idea that water reflects light of its environment back to its environment. This is effect becomes more apparent the more parallel our viewing angle is with the water.

Refraction is the idea that water changes the angle of light that passes through it. This effect becomes more apparent the more perpendicular our viewing angle is with the water.

Sun
A linear interpolation as to how reflective the sun should be. Not sure where this is being used directly.

Sky
Determines how much the sky (cubemap) should be reflected.

Unit
Determines how much a unit should be reflected.

Refraction
Determines how strongly the water distorts anything that is under water.

The sky reflection parameter has precedence over the unit reflection parameter. If there is no sky reflection, then there won't be a unit reflection either. This correlation exists because the sky reflection parameter is used, on its own, to determine whether we reflect anything at all.

float4 HighFidelityPS(...)
{
    // (...)

    // as found in water2.fx

    // lerp the reflection into the refraction     
    refractedPixels = lerp( refractedPixels, reflectedPixels, saturate(skyreflectionAmount * fresnel));

    // (...)
}

As a result, if you decrease the amount the sky is reflected you'll also decrease the amount a unit is reflected by the water. If there is no sky reflection then only the refracted pixels and the surface color remain.

reflections.png

Sun and Fresnel

Texture maps

About you

If you have interesting sources, approaches, opinions or ideas that aren't listed yet but may be valuable to the article: feel free to leave a message down below or contact me on Discord. The idea is to create a bunch of resources to share our knowledge surrounding development in Supreme Commander.

If you've used this resource for one of your maps feel free to make a post below: I'd love to know about it!