(Pardon the low fps)
Heya,
For a while now I wanted to emulate an effect found in The Witcher 3 - trees disappear as you move your camera close to them. I had a similar effect already done before, using the camera position and the pixel position and just doing a distance-based fade on those. The problem with that was - your camera would partially hide the tree. So if your fade distance was 100 units, you’d have a 100 unit big sphere mask hiding pixels. Any part of the tree that was outside of that radius would still be visible.
To rectify that I sat back down at the drawing board and came up with a solution. Mind you, it’s probably not optimal and I’m sure a lot of people here could whip up something more optimized, but it’s still a neat effect that I haven’t seen that often so I decided to share. I’ll go through it step-by-step.
First problem: Getting the position of foliage instances
Your usual ObjectPositionWS node, if used with foliage, returns the position of the containing InstancedStaticMeshActor, i.e. the geometric center of all your foliage instances. In order to get the per-foliage position, it has to be piped through the vertex shader, like so:
That solves that issue. Second comes a problem that took me a bit longer to crack.
Second problem: Getting the scale / height of the foliage
Turns out there is no easy way to get the height of the foliage, as stuff like ObjectScale and ObjectRadius don’t work properly with painted foliage. Luckily, Ryban Brucks solved the issue with the convenient FoliageScaleFactor material function. Less luckily - that function is broken in the current iteration of the engine.
The function works by taking the 0,0,0 local position and the 0,0,1 local position of the foliage instance, converting them to world space and taking their distance. Once you have that you can divide a nominal foliage height by it to get the height scale of your foliage. You’ll notice however that the transform nodes convert from Local to Local, which is a bug. Simply create your own FoliageScaleFactorFixed material function (or modify the engine one), copy all of that and change the transform nodes to Local -> World.
You’ll also notice that you have to pass in a height. This will have to be a parameter in your material, so you’ll have to enter this value for each foliage that you have. The static mesh editor shows the approximate size of a 3D model, I used the height given there .
Right-o, so now we got the foliage location and its height. With some math magic it is now possible to create our volume mask. In my case it’s going to be a rough cylinder mask.
I’ve split my logic into the vertical and horizontal mask. I then add them together to form the final result. I’ll start with the horizontal one since it’s simpler.
The two lines coming in from the left are the camera position and the foliage position calculated above. I mask out the Z since I only care about the XY plane at this point. I simply measure the XY distance of my camera from my tree and blend between FadeStartDistance and (FadeStartDistance + FadeLength) to get a 0-1 mask.
This now leaves the vertical portion of the masking. In essence it is simple:
- For a tree of height h, take its mid-point height Y and the camera vertical position X.
- Now subtract the two to get the vertical distance between the foliage’s mid-point and the camera. Take the absolute value of this to get X’.
- Now do the same blend as above but offset the FadeStartDistance by the half-height of the foliage, resulting in a blend between (FadeStartDistance + HalfHeight) and (FadeStartDistance + HalfHeight + FadeLength).
The image below has these steps outlined.
Once we have both our masks we combine them with a simple add and a clamp. This way, if we’re within the vertical “transparent zone”, if the horizontal one is still outside, the resulting opacity will still be 1.
As you can see I run it through a dither in the end for prettier results. I also have “Enable Opacity Mask Dither” turned on on my material.
That’s essentially it! Plug this in with the rest of your foliage material, punch in the correct values and you should have properly disappearing foliage. Hope someone finds this useful. If you have any questions let me know and I’ll try to help as best I can.