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

- Part 1. A Journey Into Journey’s Sand Shader
- Part 2. Journey Sand Shader: Diffuse Colour
- Part 3. Journey Sand Shader: Sand Normal
**Part 4. Journey Sand Shader: Specular Reflection**- Part 5. Journey Sand Shader: Glitter Reflection
- Part 6. Journey Sand Shader: Sand Ripples

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

Both the diffuse component and the rim lighting are RGB colours ranging from to . The final colour is given by their sum. This means that, potentially, it might be greater than .

If you are new to shader coding, you might know that colours should be clamped between and . However, there are cases in which we want colours to be greater than . If your camera is set to support High Dynamic Range, pixels with an intensity greater than will “leak” light onto nearby pixels. This technique is used to simulate bloom effects, halos and specular highlights. However, it requires a **post-processing effect** to perform this operation.

### 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?

It’s */frəˈnɛl/*, which sounds a bit like *fruh-nel*.

If you have learnt shaders from written tutorials, you might have never heard the correct pronunciation of *Fresnel*. As a form of respect towards those researchers which works we are using every day, I believe we should all make an effort to pronounce their names correctly.

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 (, in red) is orthogonal to the **view direction** (, in blue).

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

Using 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 and 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 is given by:

(1)

where and are two parameters that can be used to control the contrast and the strength of the effect. and 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?

It is likely there will be an overlap between **rim lighting** and **ocean specular**. Certain parts of the dune, especially at glazing angles, might exhibit both Fresnel and Blinn-Phong reflectance. Summing both contributions would make dune too shiny.

Taking the maximum is an efficient, yet effective way to avoid this problem.

### ⭐ Recommended Unity Assets

Unity is free, but you can upgrade to **Unity Pro** or **Unity Plus** subscription plans to get more functionalities and training resources for your games.

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 of a surface is given by the following equation:

(2)

where

(3)

The denominator of (3) divides the vector by its length. This ensures that has length . The equivalent shader function to perform this operation is `normalize`

. Geometrically speaking, represents the vector “in between” and , which is why is called the **half vector**.

❓ Why is *H* in between *V* and *L*?

It might not be intuitive to understand why is the vector in between and .

To understand why, lets, we should recall the Parallelogram law, which gives a geometrical interpretation to the sum between two vectors. The sum of and can be found by translating at the end of , and drawing a new vector from the base of to the tip of .

The second step involved is to understand that the two quantities and are the same. This means that the following two geometrical constructions are the same:

We can join them to form a parallelogram, which sides share the same length. Because of this, we have the guarantee that the diagonal (which is ) bisects the angle. This means that the blue and yellow angles are equal (below, left).

Now we know that is a vector in between and , but its length is not guaranteed to be . Normalising means stretching it until it reaches length , making it into a unit vector (above, right).

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.

- Part 1. A Journey Into Journey’s Sand Shader
- Part 2. Journey Sand Shader: Diffuse Colour
- Part 3. Journey Sand Shader: Sand Normal
**Part 4. Journey Sand Shader: Specular Reflection**- Part 5. Journey Sand Shader: Glitter Reflection
- Part 6. Journey Sand Shader: Sand Ripples

### 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.

## Leave a Reply