Jelly Shader, Part 4: Integration With Unity

Part 4 – Integration With Unity

 

This is article 4 in our multi-part series on developing a custom shader for Unity. In this article we will be modifying our shader so it can receive input from scripts in our scene.

Let’s start by replacing the built-in _Time value with a value we provide ourselves. Allowing us to reset the wave animation at will. Let’s call this new variable _ControlTime and add it to variable declarations. Add to the property block:

_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
_ControlTime ("Time", float) = 0 //The new line.

And to the subshader:

half _Glossiness;
half _Metallic;
fixed4 _Color;
float _ControlTime; //The new line.

We also need to replace any references to _Time. There should be two. One at the origin declaration and another when we modify the vertex position. Those lines should look like:

float4 origin = float4(1.0 - _ControlTime * _ImpactSpeed, 0.0, 0.0, 0.0);
v.vertex.xyz += v.normal * sin(v.vertex.x * _Frequency + _ControlTime) * _Amplitude * (1 / dist);

Our shader is now setup to use this new time. Now we need to create a C# script to attach to our model that will update this new value. Inside of our Unity project, create a new C# script titled JellyClickReceiver.cs. Once the file has been created and named, attach it to your 3D model so that it’s on the same gameobject as the Mesh Renderer for your model. The scene setup for our example model looks like this:

Now to edit JellyClickReceiver.cs. First we need to declare two variables.

Renderer modelRenderer;
float controlTime;

The variable modelRenderer will just be used to cache our MeshRenderer component.

 

Component Caching

Lookup functions like GetComponent aren’t generally very efficient, so any time you plan to access a component in the Update function (or more than once anywhere in your app) you should greatly consider caching the component instead and only looking it up once. As usual, a more elaborate explanation is available on the official Unity docs under section 3 “Cache component lookups.”.

 

All we’re going to do in our Start function (for now) is cache our MeshRenderer.

modelRenderer = GetComponent();

And in our Update function we’re going to do two things:

controlTime += Time.deltaTime;

modelRenderer.material.SetFloat("_ControlTime", controlTime);

First we’re going to add to our controlTime with the current deltaTime to act as a running clock. UnityEngine.Time already has a property built in to track total time, but we’re going to be resetting controlTime later, something we can’t do with UnityEngine.Time.

Next is the fun part, we access the material associated with our MeshRenderer and call SetFloat. This function passes variables from your C# script to your shader. All you need to do is tell it the name of the variable you want to set inside the shader, and the value you want to set it to.

At this point, you should be able to fire up Unity and run the application, and if everything was done right, it should look…exactly the same! Your wave should slowly animate from one side of your sphere to the other. Your final script should look like this.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class JellyClickReceiver : MonoBehaviour {

Renderer modelRenderer;
float controlTime;

// Use this for initialization
void Start () {
modelRenderer = GetComponent();
}

// Update is called once per frame
void Update () {
controlTime += Time.deltaTime;

modelRenderer.material.SetFloat("_ControlTime", controlTime);
}
}