Journey Sand Shader: Specular Reflection

This is the fourth part of the online series dedicated to Journey Sand Shader.

In this fourth post, we will focus on the specular reflections that make the dunes look like an ocean of sand.

One of the most intriguing effects of Journey‘s sand rendering, is the way dunes shine in the light. Such reflection is called specular, from the Latin speculum, which means mirror. Specular reflection is an umbrella term that includes all those types of interactions in which light is strongly reflected in one direction, instead of being scattered and diffuse. It is because of specular reflections that both water and polished surfaces appear to shine at certain angles.

Journey features three different types of specular reflections: rim lighting, ocean specular and glitter reflections, as seen in the diagram below. In this lecture, we will address the first two.

Rim Lighting

You might have noticed that each level of Journey features a limited set of colours. While this adds to its strong and clean aesthetic, it is rather problematic for the sand rendering. Dunes are only rendered using a handful of shades, so it might be impossible to distinguish where one ends and another starts in the far distance.

To compensate for this, the edge of each dune presents a subtle shimmering effect, which highlights its contours. This prevents dunes from disappearing into the horizon, and gives the illusion of a much larger and complex environment.

Before exploring how such an effect can be achieved, let’s extend the lighting function presented in the first lecture to include both the diffuse colour (previously discussed in Journey Sand Shader: Diffuse Colour) and a new generic specular component.

float4 LightingJourney (SurfaceOutput s, fixed3 viewDir, UnityGI gi)
{
    // Lighting properties
    float3 L = gi.light.dir;
    float3 N = s.Normal;

    // Lighting calculation
    float3 diffuseColor	= DiffuseColor (N, L);
    float3 rimColor     = RimLighting  (N, V);

    // Combining
    float3 color = diffuseColor + rimColor;

    // Final color
    return float4(color * s.Albedo, 1);
}

In the snippet above we can see that the specular component of the rim lighting, called rimColor, is simply added to the original diffuse colour.

❗ High Dynamic Range and Bloom Effects

Fresnel Reflectance

There are many ways in which a rim lighting can be achieved. The most common in shader coding relies on the well-known Fresnel reflectance model.

❓ How to pronounce Fresnel?

To understand the equation behind the Fresnel reflectance, it is helpful to visualise where it occurs. The diagram below shows a dune seen by a camera (in blue). The red arrow indicates the surface normal to the top of the dune, which is where we want the specular reflection to be. It is easy to see that all edges of the dune share a similar property: their normal (N, in red) is orthogonal to the view direction (V, in blue).

Similarly to what we have done in  Journey Sand Shader: Diffuse Colour, we can use the dot product between N and V to get a measure of their alignment. In this case, the N \cdot V is 0 when the two unit vectors are orthogonal; we can use 1- N \cdot V instead, to measure how misaligned they are instead.

Using 1- N \cdot V directly would not yield good results, as it reflects way too much. If we want to make the reflection sharper, we can simply take its power. The power of a value between 0 and 1 remains bounded within the same range, but the transition between light and dark becomes sharper.

The Fresnel reflectance model states that the intensity of light I is given by:

(1)   \begin{equation*} I = \left(1 -N \cdot V\right)^\mathit{power} * \mathit{strength}\end{equation*}

where \mathit{power} and \mathit{strength} are two parameters that can be used to control the contrast and the strength of the effect. \mathit{power} and \mathit{strength} are sometimes called specular and gloss, although naming conventions may vary.

Equation (1) translates very easily to code:

float _TerrainRimPower;
float _TerrainRimStrength;
float3 _TerrainRimColor;

float3 RimLighting(float3 N, float3 V)
{
    float rim = 1.0 - saturate(dot(N, V));
    rim = saturate(pow(rim, _TerrainRimPower) * _TerrainRimStrength);
    rim = max(rim, 0); // Never negative
    return rim * _TerrainRimColor;
}

Its result can be seen in the animation below.

 

Ocean Specular

One of the most peculiar aspects of Journey‘s gameplays is that, at times, the player is literally surfing on the dunes. Lead Engineer John Edwards explained how thatgamecompany indeed wanted the sand to feel more like a fluid, than a solid.

This is not entirely incorrect, since sand can be thought of as a rough approximation of a fluid. And under certain circumstances, for instance in an hourglass, it does behave like one.

To reinforce the idea that sand could have a fluid component, Journey adds a second specular effect, which is often seen on liquid bodies. John Edwards referred to this as ocean specular, and the idea is to get the same type of reflection that you would see on an ocean or lake at sunset (below).

As before, let’s change the lighting function LightingJourney to include a new type of specular reflection.

float4 LightingJourney (SurfaceOutput s, fixed3 viewDir, UnityGI gi)
{
    // Lighting properties
    float3 L = gi.light.dir;
    float3 N = s.Normal;
    float3 V = viewDir;

    // Lighting calculation
    float3 diffuseColor	= DiffuseColor  (N, L);
    float3 rimColor     = RimLighting   (N, V);
    float3 oceanColor   = OceanSpecular (N, L, V);

    // Combining
    float3 specularColor = saturate(max(rimColor, oceanColor));
    float3 color = diffuseColor + specularColor;

    // Final color
    return float4(color * s.Albedo, 1);
}

❓ Why do we take the maximum of the two specular components?

Specular reflections on water are often implemented using the Blinn-Phong reflectance, which is an inexpensive solution for shiny materials. It was first described by James F. Blinn in 1977 (paper: “Models of Light Reflection for Computer Synthesized Pictures“), as an approximation of an earlier shading technique developed by Bùi Tường Phong in 1973 (paper: “Illumination for Computer Generated Pictures“).

Using Blinn-Phong shading, the luminosiry I of a surface is given by the following equation:

(2)   \begin{equation*} I = \left(N \cdot H\right)^\mathit{power} * \mathit{strength}\end{equation*}

where

(3)   \begin{equation*} H = \frac{V + L}{\left \| V+L \right \|}\end{equation*}

The denominator of (3) divides the vector V+L by its length. This ensures that H has length 1. The equivalent shader function to perform this operation is normalize. Geometrically speaking, H represents the vector “in between” V and L, which is why is called the half vector.

❓ Why is H in between V and L?

For a more detailed description of the Blinn-Phong reflectance, you can read Physically Based Rendering and Lighting Models. Below, you can see a simple implementation in shader code.

float _OceanSpecularPower;
float _OceanSpecularStrength;
float3 _OceanSpecularColor;

float3 OceanSpecular (float3 N, float3 L, float3 V)
{
    // Blinn-Phong
    float3 H = normalize(V + L); // Half direction
    float NdotH = max(0, dot(N, H));
    float specular = pow(NdotH, _OceanSpecularPower) * _OceanSpecularStrength;
    return specular * _OceanSpecularColor;
}

The following animation provides a comparison between a traditional diffuse Lambertian shading and a specular Blinn-Phong one:

 

📰 Ad Break

What’s Next…

In this fourth part of the online series about the sand rendering in Journey, we focused on the shimmering reflections that make Journey’s dunes appear almost like an ocean.

In the next part, Journey Sand Shader: Glitter Reflection, we will continue working on the specular reflections, adding tiny glitters to the dunes to make it even more realistic.

Credits

The videogame Journey is developed by Thatgamecompany and published by Sony Computer Entertainment. It is available for PC (Epic Store) and PS4 (PS Store).

The 3D models of the dunes, backgrounds and lighting settings were made by Jiadi Deng.

The 3D model of the Journey’s player was found on the (now closed) FacePunch forum.

Download Unity Package

Become a Patron!
If you want to recreate this effect, the full Unity package is available for download on Patreon. It includes everything needed, from the shaders to the 3D models.

Comments

4 responses to “Journey Sand Shader: Specular Reflection”

  1. […] Part 4. Journey Sand Shader: Specular Reflection […]

  2. […] Part 4. Journey Sand Shader: Specular Reflection […]

  3. […] Part 4. Journey Sand Shader: Specular Reflection […]

  4. […] Part 4. Journey Sand Shader: Specular Reflection […]

Leave a Reply

Your email address will not be published. Required fields are marked *