Housewarming (GGJ 2019)

Two weeks ago, I participated in the Global Game Jam at the NYU Game Center jam site for the first time. I was very fortunate to have the opportunity to work with some amazing artists and engineers, including two of our lovely FRL Lab members, Pasan and Marcus. It was a stressful but exhilarating experience for me, and it also didn’t hurt that our final submission Housewarming won the Best Visuals and got nominated for the Best Audios.

Housewarming is a walking simulator and the player can click around to decorate the empty apartment that you have recently moved into. One of the proudest moment for me as a technical artist on this project was coming up with this shader effect that fades the color of an object as if the color is being painted on. I would like to share how I was able to achieve this effect with y’all.

The basic idea behind this effect is rather simple. The shader has an uniform color value the user can freely set to in the Unity material inspector. In the fragment shader, a reference value is used to lerp between a white color value and the user assigned color value, and this reference value is sampled from a noise map (and yes it is Perlin noise!).

How To

As mentioned above, our shader needs a user assigned color value and a reference noise texture, so we need to add them to the property of our material and declare them in the shader. Since the auto-generated template has already declared a color property we can simply repurpose it and then declare the property for our noise mask. Furthermore, we need two more reference values for the control of the effect — a range value to control the color fading progress and a cutoff value to determine the boundary between the white color region and the assigned color region. Overall, the declaration part of our shader code should look somewhat like below.

Shader "Custom/ColorSwipeShader" {
     Properties 
     {
          _Color ("Color", Color) = (1,1,1,1)
          _SwipeMask ("Swipe Mask", 2D) = "white" {}
          _SwipRange ("Swipe Range", Range(0,1)) = 0.0
          _Cuttoff ("Cutoff", Range(-5,5)) = 0.5
          _Glossiness ("Smoothness", Range(0,1)) = 0.5
          _Metallic ("Metallic", Range(0,1)) = 0.0
     }

...

     sampler2D _SwipeMask;

     struct Input 
     {
          float2 uv_SwipeMask;
     };

     half _Glossiness;
     half _Metallic;
     half _SwipeRange;
     half _Cutoff;
     fixed4 _Color;

...

After we declare all the necessary properties, all it’s left to do is to implement the logic in the fragment shader. However, the surface shader does not provide us with the traditional vertex shader and fragment shader implementation. Instead, it gives us a surf function. Within the surf function, we will implement our effect logic. Internally, Unity compiles the surface shader into the traditional fragment/vertex shader, the standard surface shader is just a more convenient way for us to write a PBR shader.

...

     void surf (Input IN, inout SurfaceOutputStandard o) 
     {
          // sample the mask value
          fixed mask = tex2D(_SwipeMask,IN.uv_SwipeMask).r;
          // test the swipe boundry
          half test = smoothstep(0.1,0.9,mask)-_SwipeRange > _Cutoff ? 0:1;
          // lerp the value
          fixed4 c = lerp(fixed4(1.0,1.0,1.0,1.0),_Color,test);
          o.Albedo = c.rgb;
	  // Metallic and smoothness come from slider variables
	  o.Metallic = _Metallic;
	  o.Smoothness = _Glossiness;
	  o.Alpha = c.a;
     }

...

Now we can test out our material by creating an instance of the material using our shader. For the game jam, I used the noise map shown below for the final effect but feel free to change up the mask texture to suit your artistic needs.

Finally, you should see this if everything is going smoothly.

Overall, I was pretty happy with the effect I achieved within a short time budget. However, right as I am writing this post, I can already see different ways I can improve on this shader. One way is using an HDR color value to indicate the edge and write that color value to the emission channel to make the edge appear glowing. Another improvement can be done is to use a tri-planar projection coordinate to sample the noise map so this effect is independent of how the mesh’s uv is unwrapped. I will provide the full source code below for the shader and feel free to play around with it!

(P.S. click here to try out the game if you are interested)

Leave a Comment

Your email address will not be published.