
Hi all,
In this post I'll show you how to set up a portal effect using decals.
I’ve done a post on Decals before, which shows the shader code that constructs the local uv based on the depth texture and view position
Original Decals post: https://www.patreon.com/posts/49899065
The shader in this post uses that decal shader as a base
Example settings and textures are at the bottom
I have the same solution for URP and BIRP, I tried to use the URP Decal Projector, but due to Shader Graph and URP limitations I can’t use that component for this effect.
Instead I’m using the new? Graphics.RenderMesh: https://docs.unity3d.com/ScriptReference/Graphics.RenderMesh.html
to render Decals in a custom c# script.
The Decal Script
The script is very simple.

We set up some Render Parameters and then render a (cube) mesh using these parameters in Update()

To make them easier to see I added a Gizmo that draws a box and a line in the projection direction.
Stencils
I’ve talked about stencils before a few times here, most recently in the Wind Waker Style lights post: https://www.patreon.com/posts/wind-waker-style-78831006 , the stencil decals use a similar setup, but with an added fun part of clipping the stencil mask.
The Shader
The shader consists of 2 passes:
-Stencil Mask with clipping
-Swirly VFX effect on top of the masked hole
The last 2 passes are the same except for the side it will render on.
Stencil Mask Pass
As seen before, using the stencil buffer lets you write numbers in the screen, by default everything is set to Stencil 0. If you so if you take a cube and set it to write to stencil buffer ref 1, the result is like this, where red is the stencil output:

(This is with a child cube that has the special Hole shader that reads Stencil 1 assigned to it, otherwise you would see nothing as nothing is reading the 1 stencil value)
But the stencil buffer gets applied on a pixel basis, so we can actually discard pixels on the buffer using clip()

Here’s the same cube but clipping the alpha of a texture.
Creating a vortex
Using a Polar Coordinates function (I just used the one from the shader graph (https://docs.unity3d.com/Packages/[email protected]/manual/Polar-Coordinates-Node.html )

We can twist the uv result to get a spirally effect, it’s a bit easier to see in the shader graph preview

Multiply the spiral texture with the previous circle alpha and there’s a noisy effect

Now just add in time in the X and Y of the spiral uv and we get a moving vortex.
This might be enough if you don’t need any fancy glowing edges around the effect, in that case, remove the final 2 passes from the shader :)
VFX pass
Finally we add a vfx effect on the edges of the stencil, using the same setup as the stencil mask pass.

In these passes we don’t clip, so the cutoff doesn’t happen. The result is a grayscale swirling around the hole

Make it prettier by running a gradient map over the grayscale and increasing the intensity of the whole effect
And thats it! Try different textures and colors and have fun with it :)
Code Links
Decal.cs : https://pastebin.com/LsxchX6A
StencilDecal.shader : https://pastebin.com/5WX4WLBC
Hole.shader: https://pastebin.com/FK2iniRy
Setup:
- Import the Decal.cs script and the shaders
- Create an empty gameobject
- Add the Decal script
- Create materials from the shaders and add textures to it
- Add the decal material to the Decal Script
- Add a child object (like a sphere) with the Hole shader assigned to it
You should now see the stencil decal
- Put an object inside of the portal with a higher renderqueue than the hole shader
PS: The Tinting of the Decal.cs script is used, but the Texture isn’t, this is just there as an option for if you use the other decal system too.
FAQ
My decal is rendering over my character.
Make sure the material for your characters is set to a higher Queue than the decal material.
In URP the queue is hidden by default, you need to set the Queue Control to UserOverride to expose it
For example,
terrain is Geometry,
the decal stencil is Geometry +1,
the Hole shader is Geometry +2,
and the character is Geometry+3

I don’t see the decal projected on the floor properly
You might need to enable the Depth Texture in your URP settings
The Decal isn't changing
Turn the component off and on after switching Decal Materials
Material settings from example:

Settings

Noise Texture (Imported with Color texture unchecked)

Gradient Texture
Other Resources:
Unity has their own example on reconstructing world position using depth and view position:
https://docs.unity3d.com/Packages/[email protected]/manual/writing-shaders-urp-reconstruct-world-position.html
It’s not doing the final step of converting back to object space and it doesn’t clip outside of the cube mesh, but the idea is the same.
Thanks for reading!
