“Learn how I created a fun, customizable shader in Unity for my latest project! Discover tips on making creative, educational 3D visuals for games.”

Hello Everyone! I’m going to attempt to explain what I’ve got going on here. For starters, I’m working in Unity 2022.3.41f1 with URP (Universal Render Pipeline). I originally thought using an older version of Unity would be more stable, but this version is giving me a few challenges. I’ll explain more on that later For now, let’s dig into this shader. I’m attempting to make a gummy bear texture, for my hero, a gummy bear. I’ve had quite a lot of trouble making this shader, but I think I have something that I’m happy with for now. I’ll have to test it out in game play mode to see how it works during gameplay. I’ll have to update my code to test it out; stay tuned for that fun blog post!
Some of the trouble I’ve had is getting all of the shader elements to work together. This gummy shader is a lot like a thick glass that has a subsurface diffuse scattering on it, refraction, an appearance of a soft outer edge and a specular highlight that is the same hue as the base color, kind of like what you find in a metallic shader. You can see why I was having trouble. I tried all sorts of combinations to get all of those elements to work happily together… and I’ve decided the best approach is to fake it… which at the end of the day, is basically what a shader does anyways. However, this approach may backfire, so I’ll have to test it in actual game play. We’ll get to the testing soon.
Let me explain what I’ve got going on. For starters, I’ve created a URP Lit shader graph and since Unity 2022.3.41f1 doesn’t have a SSS node, I have to create one. To make the sub diffuse scattering I start with a custom node.

Imagine we have a translucent candle. If we have a directional light shining on the candle, some of the light will bounce off, but some of that light will enter the candle wax and then bounce around inside the wax before exiting on the opposite side. It also softens the light transition where the light hits the core shadow. The calculations to recreate this are pretty heavy, so we’re going to mimic it. In order to do that, we need three pieces of information. 1) The light direction (L), we will also need to know the opposite side light direction (-L), 2) We need to know the view direction (What we see, the camera, (V), 3) Lastly, we need the surface direction of the object, also known as the normal (N).
Now that we know what information we need, let’s get to work implementing it. Start out by creating a custom node in your shader graph. Under ‘Type’ select String. We’re not going to need a file just for a few lines of code. After you have selected type, go to the Name section. We’re going to add a name that describes this function. Personally, I prefer the Camel Case naming convention where I capitalize the first letter of each word, but feel free to use the Snake Case if that is your preference. I named my function GetMainLightDirection.
Next, head on up to your ‘outputs’ section. This is where we are going to enter our variables. For the first variable, we are going to name it MainLightDirection. Make this a vector 3. Name the next variable MainLightIntensity. Also, make this a vector 3. Now that we have the variables in place, let’s head over to the body to add our code.
#ifdef SHADERGRAPH_PREVIEW
MainLightDirection = float3(0.5,0.5,0);
MainLightIntensity = 1.0f;
#else MainLightDirection = GetMainLight().direction;
MainLightIntensity = length(GetMainLight().color);
Next, let’s add a Normal Vector node, make sure that the space is left to world. Let’s add these two vectors together. Create an Add node and connect the custom node to the ‘B’ input of the Add node. Before we connect the Normal node, let’s connect it to a Multiply node. This will allow us to control how much the normal effects the light direction. Once the Multiply node has been connected to the Normal node head over to the blackboard. Press the white plus button in the top right corner and add a float. Rename the float to ‘Normal Influence’. Now you’re free to drag it into the main editor window and connect it to the Multiply Node.

Now connect the Multiply node to the Add node. Since we have added 2 vectors together, we have to add a normalize node. This will turn it into what is called a Unit Vector. (You can find out more about normalizing vectors here: https://www.khanacademy.org/computing/computer-programming/programming-natural-simulations/programming-vectors/a/vector-magnitude-normalization#:~:text=To%20normalize%20a%20vector%2C%20therefore,the%20unit%20vector%20readily%20accessible. )
Remember the diagram of the candle at the beginning of this breakdown? We need more than just the light direction. We also need the information on where the light exits the candle. The negative light direction (-L). Add a Negate node and connect it to our Normalize node. Yeah! We’ve completed the first part of our SSS shader function! Let’s group the contents and name it Get Main Light Direction to keep things tidy. Just drag over and select all of your nodes and right click. Choose the group option and rename your group.
Ready? Let’s jump into the back scatter!
Let’s start by creating a View Direction node. Connect this node to a Dot Product node.
*(The name “dot product” is derived from the dot operator ” · ” that is often used to designate this operation; the alternative name “scalar product” emphasizes that the result is a scalar, rather than a vector (as in three-dimensional space).)
In the other input for the Dot Product node, connect the output of the Negate node (From the Get Main Light Direction group). After they have been hooked up, let’s add a Saturate node. This will make sure that the values remain between 0 and 1. Now we have a value that tells us how much scatter we have across the back of the surface. However, we’re going to want to have some control over that back scatter, so let’s add some nodes that will help us do that. For starters, add a Power node and next add a Multiply node. Make sure they are set up in this order, power then multiply.
Okay, now that the nodes have been hooked up, let’s head back to the blackboard. We need to create two new floats. The first float can be named SSS power and the second float can be named SSS intensity.

Now we want to connect the back scatter to the light intensity. In order to do that we need to add one more Multiply node, connect it to the previous Multiply node. Now connect the light intensity from our custom function to the input of the multiply node. Now the light intensity will affect our shader. Group the contents and name it ‘Back Scatter’.
When light leaves an object, it often has a different color. For example, your ears and fingertips will have a red color when light passes through them, because of our blood. A candle will also have a slightly different color, depending on the wax color. Let’s create an input to control that back scatter color.
To start, head over to the blackboard and select the color property, then name it something like ‘SSS Color’. Now create a new Multiply node. Connect this node to the last multiply node in the backscatter group. Drag your new SSS color property from the blackboard into the main editor and attach it to the other input on the Multiply node. Once it has been attached you can group this node and the color property and name it ‘SSS Color’.
Look at us, cruising along! Okay, let’s dive back in. I’m sure you’ve noticed that a really thick object wont have as much back scattering as a thin object. As far as I am aware, during run time, there is no easy way to calculate this… so let’s fake it with a texture map. There are some types of software, such as Substance Painter, that can actually bake thickness maps. However, if you don’t have access to Substance Painter, you can make a rough map by inverting a baked ambient occlusion texture. Head back over to the blackboard and create a new 2D texture property. Name this property something like “Thickness Texture.” Now drag this property on to the main editor. You will want to make a Sample Texture 2D node now. Connect your new Thickness property to the texture input on the Sample Texture node. Now add a Multiply node. Connect your R(1) output of your Sample Texture node and the output of your SSS Color group to your new Multiply node. We want more light to pass through the thinner parts of the object so we’re going to have to invert the texture map using a One Minus node. Place this One Minus node between the Sample Texture 2D node and your Multiply node.

You can now group this selections contents and name it ‘Thickness’. *Note: Substance painter uses white to represent the value of 1. You may not need the One Minus node if your values are already inverted.
Almost there. Let’s talk about the main color. We’re going to blend the Backscatter color to the color on the surface of our object.
To do this we need to create two new properties on the blackboard. One property will describe the Albedo texture (use a texture 2D property for this one) and a new color property. Name this new color property something like ‘Base Color.’ Now we are going to create a new node, it will be another Sample Texture 2d node. Now plug the Albedo texture into the texture T2 input. Next, add another multiply node and connect the Base Color property to input ‘A’. The Sample Texture 2D node can plug into input ‘B’. Now we’re going to add this information to the output of the Thickness group. To do this, let’s create an Add node. Connect the output of our current Multiply node to the ‘B’ input in the Add node. Then plug in the output of the Thickness group into the A input of the Add node. You can now group this selection and name it something like ‘Final Color’. Plug the output of your final color into the base color input of your master stack.

We actually have to add a few more parameters before this component of the shader is complete. Hang in there, we’re nearly there now. Next, let’s head back to the blackboard and create another Texture 2D property. Name this property something like AO (for ambient occlusion) texture. Drag the property into the main editor and then add a Sample Texture 2D node and connect them via the textureT2 input. Now connect the output of this node to the ambient occlusion in your master stack. Also, in the blackboard, create another new property. This new property will be a float; name it ‘Smoothness.” Drag this property into the main editor and connect it to the smoothness input of your master stack.
Let’s test out what we have so far. Save your asset and head over to your scene view. Now click create > material. This will create a new material based on our new shader. Start to change all of the default values from 0 and change the black colors to colors that are appropriate for your object. Your material should now start to react to the light position and intensity. Good work! We have a successful SSS Shader!
Let’s continue to build on this shader working towards our goal of making a gummy like texture. Personally, I’ve tried a bunch of different things and I’m still not getting the look I want. Perhaps I’m overpowering the shader a bit? Ahhh… oh well, I’ll tell you what else I’ve got going on in the little bear at the top of the screen. If anyone else has any ideas, feel free to let me know in the comments.
The next part that I’ve added in is an inner cube map with a Fresnel distortion. I’ll show you how I did that. Let’s get started!

Here is a copy of the gummy bear sky box I’ve made. It’s kind of a golden colored marble texture. I have two versions. A more crisp version where the marble veins are more pronounced and this softer version. I think this softer version will look better, but let’s test them both out. Once the skyboxes were created, I added them to the materials folder of my project. In the inspector, you can change some of the cube map’s parameters such as texture shape.
Now, just like before when we calculated the main light direction, we are going to start off with calculating the viewer direction.

Let’s start off with the Position node. This represents the pixel that we want drawn. Make sure it’s set to world space. Next, were going to need the position of the camera. We’re going to use a Subtract node to get the direction in which we are viewing the character. This is now our vector. Now we want to use a Normalize node so that we can get the vector to a length of 1.

Next we’re going to calculate the direction of the camera movement. Ha ha ha… okay, that sounds super confusing. I think of it like this, the camera is your head. The initial direction describes where your head is at and the direction influence describes where your head (face) is pointing, and with the Camera Direction Influence property, where your eyeballs are pointing. I hope that helps. Okay, let’s plug in the eyes. Start with a Camera node. This time, instead of position, select direction and plug it into a Multiply node. Next, create a Camera Direction property. This will be a float. Plug it into the Multiply node. Now we are going to want to add these two calculations together. Create an Add node and plug in your Camera Direction Influence and your Calculate Initial Direction. Great work! Now let’s have some fun with Fresnel lens effects.
Let’s start with what is a Fresnel effect? Well, the Fresnel equations were developed by a French physicist Augustin-Jean Fresnel. These equations describe how light reflects and transmits when interreacting with different materials and surfaces. In our case, the information for the equation is going to be coming from the direction the normal on the polygon is facing and a our camera angle. This is going to result in a dot product that will inform our Fresnel effect. The Fresnel effect it’s self is nice, because just like a lens, our picture area will be nice and clear, but were going to get some distortion around the edges of our object. This is a nice effect on 3D objects, because the light will bend around the object, highlighting it’s 3dimentional form, so it doesn’t look flat.

So let’s plug it all in. Head on over to the backboard and create a float property. Call this something like FresnelDistortionStrength. This float is going to plug into the Fresnel power.
*Note: If you ever need to create an easy outline, a Fresnel node is an option. It’s not perfect, but if you dial up the power you can create a rough outline.
Add the camera direction influence and the Fresnel together. Now we’re ready to plug in that cube map.
We’re going to need a few new parameters. Let’s head over to the blackboard and create a cube map property. I just named mine “main cube map.” Next, create a cube map node and a sampler state. The sampler state just describes the type of filter it’s using.

Now that we have the cube map plugged in, let’s have some fun with color! We’re going to going to use Fresnel again in order to create a colored edge.

For this group were going to start with a split node and a Fresnel Effect node. We’re going to use the alpha of the color to help regulate the intensity of the color. We will also need to properties. Create a color property and name it something like “Fresnel Color” and create another property, a float, named something like “Fresnel Strength”. Plug the Fresnel color property into the split node and the Fresnel strength into the the power input of the Fresnel effect. Plug both of the nodes into a multiply node to combine them. Lastly, I’m going to plug this group into a Lerp node to combine it with the cube map.

Now, I’m going to blend the Fresnel effect and the SSS aspect of the shader. Before I do that, I want to add a little control so I can either dial up the SSS aspect or the Fresnel or dial them back down if I need. In order to do that I’m going to create two more properties.

Both properties are floats. I named one Fresnel Blend Strength and the other SSS Blend Strength. Also, you may want to control the opacity of the blend. Create another property for this. This will also be a float. Plug it all together and an attach it to the base color of the Master stack. There are a couple of other properties you may want to control on the master stack. Create a property for Smoothness, Alpha strength and metallic strength. All floats. You can now control these aspects from the properties panel. Just be sure to save your shader first by clicking on the save asset button. Here’s a quick look at me playing with my Fresnel color so you can see what the effect of that is:

The first edge is yellow, the middle Fresnel is red the last is purple. The Fresnel strength is the same for all three gummy bears. Well, now that we know how the shader was made, let’s test it out! In order to test it out we will have to move over to the code. That’s exciting! Come check out my next post!
Leave a Reply