We created an example interactive vertex displacement effect with Shader Graph and the Lightweight Render Pipeline to help you use these features to design effects. This post will walk you through our process. Get the demo project with the Shader Graph shader, example scene, and some example game assets from the 3D Game Kit, and follow along!
The sphere in the video example below has a shader-based displacement effect that activates when we hit the space bar. In your game, you would assign this to some relevant gameplay event. In this article, we will look at how to create this shader using the Shader Graph package, and integrate the spacebar keypress trigger. The goal is to help you understand how to design effects in Shader Graph, and interact with them from your other C# scripts. The demo project contains the shader, the script that controls the shader, a preconfigured Lightweight Scriptable Render Pipeline (LWRP) Asset, and an example scene for you to get started with. If you prefer to view this tutorial as a video instead of text you can find it on the Unity YouTube channel.
First, let’s look at how to set up Shader Graph and the Lightweight Render Pipeline. Open the Package Manager and select install on the Lightweight RP package. This will automatically install the correct version of Shader Graph.
Once we’ve installed the Lightweight RP, we need to create a new Pipeline asset in the Project. Select Create->Rendering->Lightweight Render Pipeline Asset.
We can then activate this pipeline asset by going to Edit->Project Settings->Graphics, and dragging the LightweightRenderPipelineAsset into the Scriptable Render Pipeline Settings field. If you are following along with the downloaded assets, this step has already been completed for you.
Now that the Lightweight Render Pipeline is installed, we can look at creating a new Shader Graph. Let’s create a new graph in our project by selecting Create->Shader->PBR Graph. The PBR Graph allows us to create a new shader that takes inputs from Unity’s Physically Based Rendering system,so that our shader can use features such as shadows and reflections. Once we have created this shader, we add it to a new Material and attach the Material to a Sphere in our example scene by dragging and dropping the material onto the sphere.
To achieve the effect, we will displace the vertices in our mesh along its normals by changing the output Position in the PBR Master output node. We will displace by using an Add node on the base Object Position of each vertex. By adding the Normal Vector to the base Object Position, we can see all the vertices become extruded, making the sphere appear bigger. To vary this displacement, we will multiply this normal vector displacement semi-randomly by using a Simple Noise node.
When we click Save Asset, we can see in the Scene View that the sphere is now displaced based on Simple Noise.
Unfortunately, there are seams in the displacement because the Simple Noise is being sampled based on UV space. To fix the seams by using Object Space for the Simple Noise instead of UV Space, we can simply add a Position node set to Object.
To create the pulsation effect, we will scroll this Position output by adding it to a Time node, before sending it to the Simple Noise node. We can also use a Multiply with the Time node to vary the speed of the scroll.
To control our displacement, we expose a new Shader Property in our Shader Graph. Shader Properties allow us to provide inputs to our shader via values entered in the Inspector, or via our own C# scripts as in this case. We will create a new Vector1 property named Amount and changed the Reference to _Amount. The reference field is the string name by which we will access and change the displacement via script. If we do not change this, it will use an auto-generated value. If the string does not match exactly, we will not be able to address our property via script so double check that both match, including capitalization.
We use this Amount shader property in a Multiply node with the Simple Noise before it gets multiplied with the normal vector. This allows us to scale the noise before it’s applied to the vertex positions. Now, the Amount variable controls how much we displace each vertex in the mesh.
To control this Amount variable, we have created a C# script called DisplacementControl and attached it to the DisplacementSphere GameObject. This script controls the _Amount variable by interacting with the property we created in our material which is assigned to the MeshRenderer component. We store a reference to the MeshRenderer component in the variable meshRender, and declare a new float variable displacementAmount.
We use a simple lerp in the Update function to interpolate the displacementAmount variable to the value of 0. We then set the shader variable _Amount to the value stored in displacementAmount variable. This will update the Shader Graph’s _Amount variable, smoothing it over time to 0.
We are using Unity’s default “Jump” Input Axis (which is assigned to the space bar by default) to set the value of displacementAmount to 1 when pressed.
Now, when we enter Play Mode in the scene, we can see that by pressing the spacebar, displacementAmount gets set to the value of 1, and then slowly interpolates back to 0.
To create the adjustable glow effect, we will output to the Emission in the PBR Master node. We use a Voronoi Noise node and Multiply it to a Color node. This will create a little modulation in the glow effect with some dark spots. Then, we use a Lerp node with another Color node as the base color, and use the Amount variable in the T input. This will allow us to blend between a base Color node and the Voronoi Noise color node using the Amount variable.
Then, we will scroll the glow by using a similar setup as before. We use a Position node set to Object and add it to a Time node, and connect the output into the UV slot of our Voronoi Noise node.