Getting started with Unity's new Shader Graph Node-based Shader Creator/Editor (tutorial 6 - Getting Glow/Bloom Effect wihout Post-Processing by Inverting Fresnel...Sort Of...)
Introduction (to the Tutorial Series):
I will be writing about my own experiences using Unity's new beta Shader Graph, part of its upcoming 2018 release (also in beta). The Shader Graph lets you create a variety of Unity shaders using nodes - not requiring you to write code.I will be writing about this journey over multiple posts, usually spaced about a week apart. Each post will be a short tutorial on how to use various node types to create different shader effects. And will include brief discussions on types of shaders and their uses, and later, how the Shader Graph compares with code-based shaders. I will try not to get overly technical, but will try to give you an idea of the complexity involved in shaders, from lighting to vertex and fragment manipulation.
Given the nature of beta software, expect the Shader Graph (and later tutorials) to vary from earlier ones that you can now find online. Even within my tutorials there will be changes if/when the beta evolves - including, if necessary, going over the basics again if something in the editor changes significantly.
I hope you find this tutorial useful. If you do, please be kind and click an interesting ad to help support this site. It really does help, believe me. And thank you, I'm grateful to you!
Other Tutorials in this Series:
Tutorial 1 - Setup and First 'Basic' Shader Graph (shader)Tutorial 2 - Tiling, Offsets, Blending, Subgraphs and Custom Channel Blending
Tutorial 3 - Normal maps, Faux-Water Effect, Animation with Time and Noise
Tutorial 4 - Updating to Next Beta and the Dissolve Shader via Turning Cg/HLSL Code into Node-Based Graph
Tutorial 5 - Exploring Fresnel/Color Rim and Update on Vertex Displacement Attempts
Downloads:
The following zip file contains the shader graph Asset and its Material Asset, plus other items as needed.
InvertedFresnel (Glow/Bloom-like Effect) (Final) DOWNLOAD (Note: includes a GIF showing the shader in use...Gif is large, over 10 meg in size.)
Requirements:
You need Unity's 2018.1 beta. I am using 2018.1.0b12 in this tutorial. You also need the latest Shader Graph Editor (1.1.2-preview) and Lightweight Render Pipeline (1.1.2-preview). And we will start with the same Lightweight-Preview project from tutorial 1 but will be creating a new shader graph called InvertedFresnelShader. You should have a sphere object using InvertedFresnelMat.For more information on setting up the beta and updating to the latest Shader Graph Editor, please see tutorial 1.
The later the tutorial in the series, the less hand-holding. That means I assume you know how to open the Shader Graph editor, what the Blackboard is, how to create Properties, how to bring up the Create Node window and so forth. If you need a refresher, please see Tutorial 1.
Note: Update - Since these tutorials began an important procedural change that has happened since earlier Shader Graph betas is that you now create shader graphs by Assets->Create -> Shader->PBR Graph (or Sub Graph or Unlit Shader) instead of Assets->Create->Shader Graph. At the end, I added an update about my experiences with 0b10.
Note: Remember, now you use Assets->Create->Shader->PBR Shader to create a shader graph for PBR.
Creating a Glow Effect...a Bit of Background (Step 1):
While I'm waiting for Unity to include vertex displacement into the shader graph - the real fun starts when you can do displacement, and then tessellation! - I tried to think of other things to do. So I tried to think of cool visual effects that would be nice to do with a shader. Often these effects involve either particle systems or post-processing.
I looked into doing a really common effect, and a very useful one. That effect is known as Glow or Bloom. But I'm not going to do it with HDR (as is normal) or by doing it as a post effect that only works on the camera. In making it into a shader effect, I found some interesting things. The most interesting was that it's still a surface shader since I'll be doing the Glow from the Emission input. That means it still is affected by light sources as you'll see in the following images and gifs.
That may or may not be what you might want, but I find that it make for a more interesting effect. Besides, you can always turn off the lights. (Or rewrite the shader, too!)
Normally, a glowing effect means post-processing after all the geometry has been drawn. Imagine a light bulb, the glow from the light extends past the light bulb itself and into the general scene. When using shaders, you can't go past the border of the mesh. So you can't affect the pixels that aren't directly (or at least partially) affected by your mesh geometry.
Now, you can do Bloom as a post effect and Unity does has post-processing abilities. For more information, see this documentation page.
You can even write scripts to do the post work directly - see this super cool tutorial by Jasper Flick on Catlike Coding.
But, if you only care about some simple glowing effects and you don't mind creating a bit of an illusion with your mesh (i.e. it's going to LOOK smaller than it actually is), then you can use a shader.
And in a way, yes, we are trying to reverse the Fresnel effect. Instead of a hard colored edge that blends inward - as with the Unity Fresnel node, we want a soft edge that gets brighter and stronger as you go inward. In other words, we want a glowing object effect. So, I just decided to call it Inverted Fresnel, even if that isn't 100% accurate.
Note: If you really want to get precise, the Fresnel that Unity is using isn't really a true Fresnel effect (since that requires post-processing). The Fresnel effect (pronounced "freh - 'nell") is the phenomena where when light reaches the interface between two materials, some of that light will reflect off the surface of the interface and some will refract through the surface.
I looked into doing a really common effect, and a very useful one. That effect is known as Glow or Bloom. But I'm not going to do it with HDR (as is normal) or by doing it as a post effect that only works on the camera. In making it into a shader effect, I found some interesting things. The most interesting was that it's still a surface shader since I'll be doing the Glow from the Emission input. That means it still is affected by light sources as you'll see in the following images and gifs.
That may or may not be what you might want, but I find that it make for a more interesting effect. Besides, you can always turn off the lights. (Or rewrite the shader, too!)
Normally, a glowing effect means post-processing after all the geometry has been drawn. Imagine a light bulb, the glow from the light extends past the light bulb itself and into the general scene. When using shaders, you can't go past the border of the mesh. So you can't affect the pixels that aren't directly (or at least partially) affected by your mesh geometry.
Now, you can do Bloom as a post effect and Unity does has post-processing abilities. For more information, see this documentation page.
You can even write scripts to do the post work directly - see this super cool tutorial by Jasper Flick on Catlike Coding.
But, if you only care about some simple glowing effects and you don't mind creating a bit of an illusion with your mesh (i.e. it's going to LOOK smaller than it actually is), then you can use a shader.
And in a way, yes, we are trying to reverse the Fresnel effect. Instead of a hard colored edge that blends inward - as with the Unity Fresnel node, we want a soft edge that gets brighter and stronger as you go inward. In other words, we want a glowing object effect. So, I just decided to call it Inverted Fresnel, even if that isn't 100% accurate.
Note: If you really want to get precise, the Fresnel that Unity is using isn't really a true Fresnel effect (since that requires post-processing). The Fresnel effect (pronounced "freh - 'nell") is the phenomena where when light reaches the interface between two materials, some of that light will reflect off the surface of the interface and some will refract through the surface.
A couple of notes on this tutorial. For some reason, I can no longer open my shader subgraphs in the shader editor. I know we are dealing with beta software, but it's annoying nonetheless. So in this tutorial and until the ability magically reappears, I won't be using subgraphs!
Now, let's get started.
If you haven't done so already, create a new Shader Graph called InvertedFresnelShader and a new Material called InvertedFresnelMat and set InvertedFresnelShader as that material's shader. Open up the InvertedFresnelShader in the Shader Graph Editor (double click or single click select the shader and then click Open Shader Editor in the Inspector.)
Now, let's get started.
Creating a Fresnel-like Node Graph (Step 2):
If you haven't done so already, create a new Shader Graph called InvertedFresnelShader and a new Material called InvertedFresnelMat and set InvertedFresnelShader as that material's shader. Open up the InvertedFresnelShader in the Shader Graph Editor (double click or single click select the shader and then click Open Shader Editor in the Inspector.)
We will be creating the equation for Fresnel this time, then modifying it slightly.
The Fresnel equation we are using as our guide is the following:
This is a simplified version of the Fresnel equation.
Except we will be modifying the '1' in the equation to be our InversionAmt. (Inversion Amount) In other words,
Create four properties in the Blackboard.
First, RimPower (a Vector1, Slider, with a Default of 4, a Min of 0 and a Max of 100). This is different than the Fresnel tutorial. I decided I wanted to be able to play with a greater range.
Second, add RimColor (a Color, with the color of your choice. I used a Lime Green.)
Third, add Albedo (a Color, pick a default of solid mid-gray) The gray is to compare it to the previous Colored Fresnel created in Tutorial 5.
Fourth, create InversionAmt (a Vector1, Slider, with Default at 0.2, a Min of 0 and a Max of 1). This will the the Inversion Amount, or rather a fraction of that '1' from the original equation.
The Fresnel equation we are using as our guide is the following:
Effect = pow( (1 + dot(V, N)) , RimPower)
This is a simplified version of the Fresnel equation.
Except we will be modifying the '1' in the equation to be our InversionAmt. (Inversion Amount) In other words,
Effect = pow( (InversionAmt + dot(V,N)) , RimPower)
Create four properties in the Blackboard.
First, RimPower (a Vector1, Slider, with a Default of 4, a Min of 0 and a Max of 100). This is different than the Fresnel tutorial. I decided I wanted to be able to play with a greater range.
Second, add RimColor (a Color, with the color of your choice. I used a Lime Green.)
Third, add Albedo (a Color, pick a default of solid mid-gray) The gray is to compare it to the previous Colored Fresnel created in Tutorial 5.
Fourth, create InversionAmt (a Vector1, Slider, with Default at 0.2, a Min of 0 and a Max of 1). This will the the Inversion Amount, or rather a fraction of that '1' from the original equation.
Drag the properties into the workspace. They are now nodes.
Right-Click and select Create Node. Create the following nodes. (Quickest way is to type their name into the Search window of Create Node.)
A View Direction node. Then set it to Object space.
A Normal Vector node. Then set it to Object space.
A Dot Product node.
An Add node.
A Power node.
Connect the Output of the View Direction to the Dot Product A Input.
Connect the Output of the Normal Vector to the Dot Product B Input.
Note: Order is important here. We are doing the calculation - dot product of View Direction by Normal Vector.
Connect the InversionAmt property node to the A Input of the Add node.
Connect the Output of the Dot Product node to the B Input of the Add node.
Now, again, be sure to do this in the right order.
Connect the Output of the Add node to the A Input of the Power node.
Connect the RimPower property node to the B Input of the Power node.
A View Direction node. Then set it to Object space.
A Normal Vector node. Then set it to Object space.
A Dot Product node.
An Add node.
A Power node.
Connect the Output of the View Direction to the Dot Product A Input.
Connect the Output of the Normal Vector to the Dot Product B Input.
Note: Order is important here. We are doing the calculation - dot product of View Direction by Normal Vector.
Connect the InversionAmt property node to the A Input of the Add node.
Connect the Output of the Dot Product node to the B Input of the Add node.
Now, again, be sure to do this in the right order.
Connect the Output of the Add node to the A Input of the Power node.
Connect the RimPower property node to the B Input of the Power node.
Right-Click and Create Node again. This time type Multiply into the search window. Create a Multiply node. We are going to multiply our RimColor and the output of our Power node to get a colored inversion effect.
Connect RimColor to the Multiply A Input.
Connect the Power node Output to the Multiply B Input.
Also Connect the Power node Output to the Alpha Input of the PBR Master. (This will control Alpha as well.)
Also Connect the Power node Output to the Alpha Input of the PBR Master. (This will control Alpha as well.)
Connect the Output of the Multiply node to the Emission Input of the PBR Master.
Set the PBR Master node to Transparent. We need the ability to have transparency in this shader.
And finally, connect the Albedo property node to the Albedo Input of the PBR Master.
Don't forget to SAVE ASSET before leaving the Shader Graph Editor!
You just created your own version of Fresnel, but with an inverted twist since we modified the equation. You should have something like this! Congratulations!
Set the PBR Master node to Transparent. We need the ability to have transparency in this shader.
And finally, connect the Albedo property node to the Albedo Input of the PBR Master.
Don't forget to SAVE ASSET before leaving the Shader Graph Editor!
You just created your own version of Fresnel, but with an inverted twist since we modified the equation. You should have something like this! Congratulations!
Note: Remember, you can double-click an image here and it should enlarge -- if your browser supports it.
If you haven't already, make sure your shader graph has a material and assign your InvertedFresnelMat material to an object in your scene.
Now let's have a bit more fun.
If you haven't already, make sure your shader graph has a material and assign your InvertedFresnelMat material to an object in your scene.
Now let's have a bit more fun.
Modifying RimPower and Albedo in the Inspector (Step 3):
Make sure your shader is being used by your material, and that your material is assigned to an object in your scene. I have placed my material on a Sphere and put it next to the Sphere with the Colored Fresnel (Color Rim) shader created in Tutorial 5.
Select your Sphere and make sure you can see the shader properties (dropdown arrow). Set RimPower to 2. You should see something like this. The sphere on the left is using the regular Fresnel shader. The one on the right is using the InvertedFresnel shader.
Notice that the sphere is transparent at the edges. The Albedo color (gray) is the halo effect.
Also notice that the Sphere is still reflecting the default lighting in the scene.
Now set RimPower to 6.
Select your Sphere and make sure you can see the shader properties (dropdown arrow). Set RimPower to 2. You should see something like this. The sphere on the left is using the regular Fresnel shader. The one on the right is using the InvertedFresnel shader.
Notice that the sphere is transparent at the edges. The Albedo color (gray) is the halo effect.
Also notice that the Sphere is still reflecting the default lighting in the scene.
Now set RimPower to 6.
Go ahead and change the Albedo setting now. You'll see that the halo changes to the color you choose. In fact, you'll see that the whole object may change color. That is because it is still reacting to external lighting.
You'll also note that changing the transparency of the Albedo has NO effect. You'll remember that we connected the Power node to both the Multiply node (for color) and also to the PBR Master's Alpha input. So the Power setting controls the Alpha.
Pretty cool effect, isn't it?
Now, we could modify the shader settings via a C# script if we want to cycle through the Albedo colors to get another cool effect. Or we might want to change the RimPower or Inversion amount to get other effects.
Let's go ahead and do one of those effects in the shader itself.
Let's add a Pulsing action to the effect.
Adding a Pulsing Effect (Step 4):
Reopen the InvertedFresnelShader in the Shader Graph Editor.
Create three new properties on the Blackboard.
First, add Pulse (a Boolean, unchecked...in other words, false)
Second, add RimRangeMinXMaxY (a Vector2, set the first parameter, X, to 4 and the second, Y, to 10).
Note: Unfortunately, when viewed in the Inspector, you will see four parameters instead of two. That is why I added the X and Y to RimRangeMinXMaxY. If you decide this is annoying, just go ahead and create two Vector1 properties, one for Min and one for Max. However, you will need to Combine them into a Vector2 in order to connect them to the Remap node.
Third, create PulseFrequency (a Vector1, Slider, Default to 4, Min at 0, Max at 10)
Now right-click in the work area of the editor and select Create Node to bring up the Create Node window. Use the Search box to make the process faster. Create the following nodes.
Time
Multiply
Sine
Remap
Branch
Connect the PulseFrequency property node to the A Input of the Multiply node.
Connect the Time Output on the Time node to the B Input of the Multiply node.
Connect the Multiply Output to the Sine node Input.
Now, connect the Output from the Sine node to the In input of the Remap node. We are going to map the Sine output, which ranges from -1 to 1, to the Rim Range we want (the values in RimRangeMinXMayY). This will cycle back and forth across the Rim Range, and will make our Rim Power fluctuate.
Note: I used Sine rather than SineTime (from the Time node). This is because I wanted to be able to multiply the value I'm taking the Sine of, i.e. Sine(Freq * Time).
For the In Min Max for the Remap node, set the values to -1 and 1. This is the same range that the Sine node will output.
For the Out Min Max for the Remap node, connect the RimRangeMinXMaxY property node. This is the range we want -1 to 1 mapped to.
Now we hook up our logic. We only want the pulsing effect if the Pulse boolean is set to True. Otherwise, we want our RimPower property to be our setting.
Connect the Pulse property node to the Predicate input of the Branch node.
Connect the Output of the Remap node to the True input of the Branch node.
Connect the RimPower property node to the False input of the Branch node.
Connect the output of the Branch node to the B input of the Power node. This used to be where RimPower was connected, but now it's the result of the branching logic.
If you check the Pulse property (in the Blackboard), so it is set to TRUE, you should now see a pulsing effect in the Preview window.
Be sure to SAVE ASSET before you return to the main Unity editor to check the effect.
If you play around with your settings in the shader, you can see the pulsing effect and how the various range settings affect it, not to mention how the PulseFrequency setting lets you speed up or slow down the pulsing.
As you can see in the gif below (assuming you browser can play large gifs), the effect will vary depending on the mesh. Just as the lighting (and object reflections) will change as you rotate/scale/move the mesh, the emission based glow effect will also vary depending on the vertices, the color chosen, the Rim Power chosen and so forth.
A smaller GIF (below) in case you can't see the large one I included (above).
From left to right: A capsule, a cylinder, and a sphere.
Conclusion:
You've finished with the Glow effect, though I wouldn't recommend making any of it a subgraph just yet. I don't know why I can't edit subgraphs anymore. So if you do decide to make part of this a subgraph for easy reuse, just keep that in mind. The beta software may not cooperate if you want to re-edit your subgraph.
Now, have fun and play around with this new shader. Try writing a script that cycles the Albedo colors. Or a script that makes the glowing object explode in then out in some interesting way - similar to when a transparent shield is hit by a projectile in a game?
I suggest a script for better reuse of the shader (and simplicity). Too many parameters on a shader tend to make artists overwhelmed. But yes, if you wanted, you could certainly alter the shader to add more cycling/changing/random effects. If you go that direction, you may want to make multiple shaders, each with a different variation - just to keep the shader more manageable.
Note: You can't duplicate a shader in the Unity editor. But you can duplicate the Asset using your machine's normal file system. Just copy and paste the shader and then rename it. When you return to Unity, it should update the Assets folder and your copied shader should now be present.
Remember, any collisions happen via the collider you attach to your game object. This shader (on this mesh) doesn't have a collider. So if you wanted an effect like a glowing shield for your character, the collider needs to be scaled appropriately to fit within the glow. Otherwise, seeing objects bounce off outside the 'glowing object' may seem a little odd to others.
Note: If you want to have Albedo control transparency in addition the Glow effect, you'll have to blend the two transparency (Alpha) channels before feeding the Alpha of the PBR Master node.
Now, have fun and play around with this new shader. Try writing a script that cycles the Albedo colors. Or a script that makes the glowing object explode in then out in some interesting way - similar to when a transparent shield is hit by a projectile in a game?
I suggest a script for better reuse of the shader (and simplicity). Too many parameters on a shader tend to make artists overwhelmed. But yes, if you wanted, you could certainly alter the shader to add more cycling/changing/random effects. If you go that direction, you may want to make multiple shaders, each with a different variation - just to keep the shader more manageable.
Note: You can't duplicate a shader in the Unity editor. But you can duplicate the Asset using your machine's normal file system. Just copy and paste the shader and then rename it. When you return to Unity, it should update the Assets folder and your copied shader should now be present.
Remember, any collisions happen via the collider you attach to your game object. This shader (on this mesh) doesn't have a collider. So if you wanted an effect like a glowing shield for your character, the collider needs to be scaled appropriately to fit within the glow. Otherwise, seeing objects bounce off outside the 'glowing object' may seem a little odd to others.
Note: If you want to have Albedo control transparency in addition the Glow effect, you'll have to blend the two transparency (Alpha) channels before feeding the Alpha of the PBR Master node.
It's up to you. Enjoy! And I hope you find this tutorial useful!
copyright 2018 cg anderson - all rights reserved
Very cool effect, thank you! Would you happen to know how access camera depth in the shader graph? I'm trying to make an intersection shader.
ReplyDeleteI don't know if Unity has offered up a camera node per se for the shader graph. You can access Camera depth from script, and you can also create a custom node. So it might be possible to create a custom node that accesses the camera.
Deletesee the following links:
https://blogs.unity3d.com/2018/03/27/shader-graph-custom-node-api-using-the-code-function-node/
and
https://docs.unity3d.com/ScriptReference/Camera-depthTextureMode.html
and (for regular code shaders) see:
https://docs.unity3d.com/Manual/SL-CameraDepthTexture.html
For those who's trying this in 2019 and it is not working - add two Normalize nodes (one for View Direction and one for Normal Vector) and process output of View Direction and Normal Vector nodes through these before connecting them to Dot Product - this will fix the issue.
ReplyDelete