The Dissolving Shader creates a visual effect of a Character or Object breaking apart and floating away in a million little pieces. It is driven 100% by a Function Material made in Unreal 4’s Material Editor. Originally, I created the Material for VR Sports Challenge, but Sanzaru Games also brought the effect over to Marvel VR: Powers United.
When assigned to this task, our Core Tech Lead shared a wonderful Unreal Engine video about the development and techniques used in their “Bullet Train” demo. Among other things, they discussed their “Derez” effect for despawning the entire world and enemy soldiers in a very Tron-like way. The video discussion on the enemy Derez materials starts at the 50 minute mark.
https://youtu.be/PG2fHLdzRIs?t=3024 ( all those Unreal video podcasts are great by the way! )
The Art Director definitely wanted an effect similar to that, but with a less digitized look. He described it to me like “Alkazetzer dissolving in water.” The idea of many little filaments dissolving away stuck with me. For reference, two film effects came to mind; the T-3000 being magnetized to the MRI in Terminator Genesys and Wolverine in X-Men III when his skin was peeling off when confronting the Phoenix. Gruesome.
Oculus VR is a very demanding platform. There are two separate HD displays to render to, each with a 90Hz refresh rate. That’s at least SIX times more to render compared to Uncharted 4’s 30 Hz, single screen! In addition, VR Sports Challenge has a very taxing amount of sport players to render at once. So, I needed to make sure the Dissolving Effect could be done as cheaply as possible, and without interfering with the already established pipeline. I decided to create the effect as a standalone Material, without the assistance of VFX or post processing.
MANY MATERIALS ALREADY
I was assigned the Dissolving Shader after VR Sports Challenge’s character art pipeline was firmly established. Dozens of Instance Materials ( for varying sport uniforms ) derived from several “Master” Materials. To seamlessly integrate my shader effect into those materials, I decided to compartmentalize the effect into a Function Material, and pass the Master Materials through it via Material Attributes Input. That way, only one node needed to be added to already established materials, and if the effect is not needed, its very easy to remove.
For the sake of performance and avoiding Transparent Materials ( which behave very differently from opaque ), I needed to set the materials to Masked so that the meshes would be able to “dissolve” away. I incorporate a one or two tricks to help the fade away feel less binary.
So, here is the entire Function Material. The main driving force is the “Phase” scalar parameter. From 0 to 1, it drives the Gradient Mask which, in turn, drives the transition from regular to dissolve visuals and the vertex displacement. The effect works both forward and backwards. For debug, I use a Time node passed through a sine node to ping pong the effect.
The Gradient Mask is generated inside the function material. I used the local vertex positions, mesh size, and a vector parameter to create a normalized gradient on a single axis. Phase simply subtracts from the Gradient Mask value, offsetting it. Changing the vector parameter ( labeled Dissolve Axis ) shifts the direction of the Dissolve Effect on the mesh.
The Dissolving Shader has three vertex offset effects applied to it; a major offset, crunching, and oscillation. I added a simple sine wave pattern down a single axis ( with a vector parameter controlling it just like the DissolveAxis ). In VR Sports Challenge, The team player poly count is at about the 6th console generation level. ( around 8,000 tris at LOD 1 ). That’s enough edge loops though for a sine wave pattern to work if the pattern is not repeated too much. Actually, the smooth movement of the sinewave is probably more important than the number of edge loops anyway. ( heck, the GameBoy had amazing sine wave scene transitions, despite it’s 144 pixel screen )
INFLATING AND CRUNCHING
As the Dissolve Effect moves through the character or object, I slightly inflate the mesh by offsetting the verts by their Normals. After the main visual passes through, the shader switches gears and collapses the vertices along a given axis. Since Masked Materials don’t allow for a smooth fade out, collapsing the vertices helps the binary alpha gradually fade the mesh out.
The largest vertex offset is displacing the fully masked vertices in one direction ( also controlled by a vector parameter ). To make this displacement feel more flowing, I added another directional influence, with an exponential falloff, so that the “particles” curve as they fly away. Unfortunately, the low density of the sport player mesh prevents a truly smooth looking curve path, but it does help.
The Dissolve Shader transitions between the mesh’s regular material and the dissolving “particle” visuals. A Vfx Artist on the team kindly created two mask textures that, when applied to Opacity Mask, looks like the regular material is broken up into a bunch of little particles. The material samples both textures twice, using the Custom Rotator node at varying speeds and angle. When scrolling fast, it looks like a bunch filaments swirling around in chaos. The Phase controls both the scale and alpha of the textures. As the Phase value gets closer to 1, the particles shrink to nothing ( since only the brightest pixels survive the Phase subtraction ).
For that last extra oomph, I apply an emissive glow to the edge of the “particles”. I create a second mask from the first one by subtracting, multiplying, clamping, and using 1-Minus. This leaves me with an inverse mask that is black at center of the “particles”. Multiplying the two masks together and with the emissive color leaves me with rings around all the particles. The emissive effect is actually strongest when the Phase is about to pass through a section of the mesh. The intended look is supposed to be that the mesh is cracking apart or adhering itself together when played in reverse.
IMPLEMENTING INTO GAME
Like I mentioned before, the Dissolving Shader was compartmentalized into a function material. For VR Sports Challenge, we only needed a handful of Instance Materials to feature the effect. So, I added a Static Switch to the Master Material as well, and we toggled it for all the relevant materials. In C++, the programmer was already making Dynamic Instances of other sport player materials. When spawning in the characters, all he needed to do was lerp the scalar Phase parameter from 1 to 0 to reverse dissolve ( or I guess materialize ) the sport players into the game!
ISSUES WITH ANIMATION
The Art Director was happy with the effect when I demonstrated it in my test map, but the Dissolve Effect did not reproduce 100% the same when applied during gameplay. There were two reasons for this; the animation and distance from camera. Since the Dissolve was controlled by a gradient moving along a single axis, body parts could disappear and reappear when moving in and out of the gradient space. So, a frantic run animation was basically breaking the Dissolve Illusion. The solution is to have a more subdued animation when spawning or despawning a Character ( one that doesn’t constantly alter the mesh’s silhouette )
ISSUES WITH TEMPORAL AA
The second major issue was that Unreal’s Temporal anti-aliasing was smearing away the dissolving effect at a distance. When the player is attempting to make a rushing touchdown in VR Sports Challenge, the opposing team players were spawning in with frantic animation and moving very quickly. At their distance ( especially with the lower resolution scale ) much of the swirling particle effect was getting lost. Without disabling any features, the solution was to slow down the visuals or decrease the texture repeating so each “particle” was larger than merely a handful of pixels.
I think the biggest accomplishment with this project was that I created a convincing dissolving trail strictly within a masked material. I’m always very mindful about stepping on other people’s work, ( or creating more work for them ). So, I’m also very glad that the entire effect is standalone ( just run any material through it ) and only takes one scalar parameter ( and a few vector parameters for direction ) to control it. I wonder how much better we could make the dissolving effect with a larger memory budget and using every part of the buffalo as they say.