in Shaders, Tutorial, Unity

Journey Sand Shader: Glitter Reflection

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

In this fifth post, we will recreate the shimmering reflections that are typically seen on sand dunes.

Shortly after the publication of this series, Julian Oberbeck and Paul Nadalack made their own attempt at recreating a Journey-inspired scene in Unity. You can see in the thread below how they have improved the glitter reflection to have more temporal coherence. You can read more about their implementation on IndieBurg’s article Mip Map Folding.

The previous lecture in this online course covered the two basic specular reflections features in Journey‘s sand rendering: rim lighting and ocean specular. This post will explain how to implement the last variant of specular reflection: glitter.

If you have visited an actual desert, it is hard not to notice how shimmering the sand really is. As discussed in the third lecture, Journey Sand Shader: Sand Normal, each grain of sand can potentially reflect light in a random direction. By virtue of sheer numbers, some of these reflected rays will hit the camera. This causes random points of the sand to appear as very bright. These glitters are also very sensitive to movement, as even the slightest misalignment will prevent the reflected rays from hitting the camera.

Other games, including Astroneer and Slime Rancher, have used glitter reflections for sand and caves.

It is easier to appreciate these shimmering specs in the zoomed images below:

It is undeniably true that the glitter effect that can be seen on real dunes is solely determined by the fact that some grains of sand randomly reflect light back into our eyes. Technically speaking, that is something that we have already modelled in the second part of this online course, Journey Sand Shader: Sand Normal, when we have modelled the random distribution of the normals. So why do we need yet another effect for this?

The answer might not be so obvious. Let’s imagine that we try replicating the glitter effect using the normals only. Even if all normals would point towards the camera, the sand still would not shimmer. This is because the normals can only reflect as much light as available in the scene. So, at best, that approach could only reflect 100% of the light back (if we had completely white sand).

What we want here, however, is different. To make a pixel appear so bright that light leaks on its nearby pixels, the colour must be greater than 1. This is because in Unity, when a bloom filter is applied to the camera using a post-processing effect, colours brighter than 1 will be propagated to nearby pixels, resulting in a halo that gives the impression certain pixels are glowing. This is the base of HDR rendering, where HDR stands for High Dynamic Range.

So no, normal mapping cannot be easily used to create glitter surfaces. This is why such an effect is more conveniently implemented as a separate process.

Microfacet Theory

To approach this scenario more formally, we need to treat the dunes as if they were made out of microscopic mirrors, each one with a random orientation. This approach is called microfacet theory, where a microfacet is the technical name of one of these tiny mirrors. The Mathematical foundation of most modern shading models is based on microfacet theory, including Unity’s Standard shader.

The first step is to divide the dune surface in microfacets, and to find the orientation of each one. As already discussed, we have done something similar already in Journey Sand Shader: Sand Normal, where the UV position of the dune’s 3D model was used to sample a random texture. The same approach can be reused here, to associate a random orientation to each microfacet. The size of each microfacet will depend on the scale of the texture, and on its mipmap level. Our task is to reproduce a particular aesthetics, not to embark on a quest for photorealism; this approach will be good enough.

Once we have sampled a random texture, we can associate a random direction with each grain of sand/microfacet that makes up the done. Let’s call it G. This represents the glitter orientation, which is the normal direction of the grain of sand we are looking at. An incoming ray of light that hits the glitter will be reflected assuming the microfacet as a perfect mirror which is facing the direction G. The resulting reflected ray of light, R, is what needs to hit the camera (below).

Once again, we can use the dot product between R and V to measure their degree of alignment.

One approach is to take the power of R \cdot V, as explained in Journey Sand Shader: Specular Reflection. If you try, you will see that the result looks very different from what seen in Journey. Glitter reflections should be rare, and very bright. The simplest solution is to only consider the glitter reflections for which R \cdot V is below a certain threshold.

⭐ Suggested Unity Assets ⭐
Unity is free, but you can upgrade to Unity Pro or Unity Plus subscriptions plans to get more functionality and training resources to power up your projects.

Implementation

We can easily implement the glitter effect described in the paragraph above thanks to the reflect function in Cg, which allows calculating R very easily.

sampler2D_float _GlitterTex;
float _GlitterThreshold;
float3 _GlitterColor;

float3 GlitterSpecular (float2 uv, float3 N, float3 L, float3 V)
{
    // Random glitter direction
    float3 G = normalize(tex2D(_GlitterTex, uv).rgb * 2 - 1); // [0,1]->[-1,+1]

    // Light that reflects on the glitter and hits the eye
    float3 R = reflect(L, G);
    float RdotV = max(0, dot(R, V));
	
    // Only the strong ones (= small RdotV)
    if (RdotV > _GlitterThreshold)
        return 0;
	
    return (1 - RdotV) * _GlitterColor;
}

Technically speaking, if G is completely random, then R as well will be completely random. It might seem unnecessary to use reflect. While this is true for a static frame, what happens if the lighting source is moving? This could either be because the sun itself is moving, or because there is a point light attached to the player. In both cases, the sand would lose temporal consistency between a frame and the next one, causing the glittering effect to appear at random locations. Using the reflect function, instead, allows for a much more stable rendering.

You can see the result below:

If you remember the first post in this series, the glitter component is added to the final colour.

#pragma surface surf Journey fullforwardshadows

float4 LightingJourney (SurfaceOutput s, fixed3 viewDir, UnityGI gi)
{
    float3 diffuseColor = DiffuseColor    ();
    float3 rimColor     = RimLighting     ();
    float3 oceanColor   = OceanSpecular   ();
    float3 glitterColor = GlitterSpecular ();

    float3 specularColor = saturate(max(rimColor, oceanColor));
    float3 color = diffuseColor + specularColor + glitterColor;
	
    return float4(color * s.Albedo, 1);
}

That is likely to cause certain pixels to end up with a colour greater than 1, which will result in a bloom effect. This is exactly what we want. The effect is also added on top of the already existing specular reflection (discussed in Journey Sand Shader: Specular Reflection), so that shimmering grains of sand can also be seen where the dunes are well lit.

There are many ways in which this technique can be improved. It all depends on the final look that you want to achieve. Both Astroneer and Slime Rancher, for example, rely on this effect only at night. This can be achieved by modulating the strength of the glitter effect based on the direction of the sunlight.

The quantity max(dot(L, fixed3(0,1,0),0)), for instance, is 1 when the sun comes from above, and zero when is behind the horizon. But you can create your own to fit the aesthetic that you have in mind.

❓ Why the Blinn-Phong reflectance does not use reflect?
The ocean specular that we have seen in the previous post, Journey Sand Shader: Specular Reflection, was implemented using the Blinn-Phong reflectance.

That is a very popular model used in early 3D graphics to shader highly reflective surfaces, such as metal and plastic. It’s equation is:

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

where

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

The Blinn-Phong reflectange is a variant of the more expensive Phong Reflectange, which equation is:

(3)   \begin{equation*}  I = \left(R \cdot V\right)^\mathit{power} * \mathit{strength} \end{equation*}

which indeed calculates the amount of reflected light that goes back into the camera.

The problem is that reflect can be expensive. For front facing surfaces, the Blinn-Phong reflectance replaces R \cdot V with N \cdot H, which is a very close approximation.

What’s Next…

In this fifth part of the online series about the sand rendering in Journey, we continued working on the specular reflections, adding tiny glitters to the dunes to make it even more realistic.

The next part, Journey Sand Shader: Sand Ripples, will conclude this online series by adding ripples based on the dunes inclination.

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.

💖 Support this blog

This website exists thanks to the contribution of patrons on Patreon. If you think these posts have either helped or inspired you, please consider supporting this blog.

Patreon Patreon_button
Twitter_logo

YouTube_logo
📧 Stay updated

You will be notified when a new tutorial is released!

📝 Licensing

You are free to use, adapt and build upon this tutorial for your own projects (even commercially) as long as you credit me.

You are not allowed to redistribute the content of this tutorial on other platforms, especially the parts that are only available on Patreon.

If the knowledge you have gained had a significant impact on your project, a mention in the credit would be very appreciated. ❤️🧔🏻

Write a Comment

Comment

  1. Thanks for this tutorial. How do you pass in the uv to the GlitterSpecular function? In your code you have not passed in the parameters in line 8.

Webmentions

  • Journey Sand Shader: Specular Reflection - Alan Zucconi May 19, 2020

    […] Part 5. Journey Sand Shader: Glitter Reflection […]

  • Journey Sand Shader: Diffuse Colour - Alan Zucconi May 19, 2020

    […] Part 5. Journey Sand Shader: Glitter Reflection […]

  • A Journey Into Journey's Sand Shader - Alan Zucconi May 19, 2020

    […] Part 5. Journey Sand Shader: Glitter Reflection […]