Hi, I’m trying to figure out a way to create cheap fake shadows on unlit surfaces with forward shading.
After browsing online for weeks now, I believe this is one of the least talked about areas in the engine with no solutions that I could find and i’m not simply speaking of blob shadows (even this seems to be a problem to achieve).
I heard there may be a way with scene capture 2d and depth? But i’m not sure how to go about it or if it would work on an unlit surface shader.
I heard many say that this is not possible without custom code and accessing the source.
When learning basics of Dx7 (in Blitz3D), a lifetime ago, I used to make cheap shadows by tracing from light point and creating a flat poly mesh on contact meshes occluded by character.
Was pretty fast even for the ancient gpu I had, but I guess you’re talking about rendering to an actual pixel buffer so I don’t know if doing what the engine already does could be of any use; btw they have those custom HLSL nodes for materials, never used them tho.
Notice how well it works on any unlit object because it’s a projection.
In UE4 I can’t seem to get any projection that is modulated or (multiplied) to work on unlit or lit for that matter that is a projection. Decals don’t seem to work either.
First problem I want to overcome it seems is how to get modulated projected shadow texture map (any map) to “project in multiplied form” onto a surface. I wouldn’t care if shadows don’t blend together nicely, that’s something I can cheat with colors later.
Not really, I couldn’t find an elegant solution via camera projection, and even if I did, Forward seems to have a problem with anti aliasing Scene depth. So any object casting modulated shades on surfaces will result any geometry moving above it to be aliased or ignored by AA.
Well, the question is “does it need to be dynamic?” If not, you can fake the shadows by manually placing Decals that you render out from a DCC.
If you need dynamic, then not really. Even a scene capture adds complexity to the render thread so you may as well pay the cost of deferred rendering and go back to regular shadows (assuming ofc the device you need to publish on supports this).
If you want to mess around, maybe you can use the distance to nearest surface node creatively to instantiate a color change that looks/feels like a fake shadow.
You can perhaps offset it with something like world position dot Direction.
Also, the distance field gradients if available may be perfect for this as they natively isolate the side by channel.
it’s not as cheap as a decal, and it won’t ever look as good as the actual rendered/baked shadows, but it is a possibly cheaper alternative…
You can transform the system into a material function, and manually apply it to everything that needs to receive shadows…
The latter part of your suggestion needs a sample showcase, I haven’t investigated it personally.
As for why not to use differed even with projection fake shadows, it’s because of a few reasons (the idea is to have it dynamic of course, otherwise static fake shadows are easy to bake in):
1 - You want to use MSAA and the extra performance factors that come with forward.
2 - You don’t have too many dynamic lights in the scene (maybe up to 3 at worst and none cast actual shadows).
3 - You want only specific units on screen to cast shadows.
Personally sometimes and in certain cases I would prefer the look of the fake shadows over dynamic ones from deffered which are always sharp and have the same look everywhere unless you go low res and then it becomes pixelated. with fake shadowing I can render area light shadows offline with a few tricks and use that to have a dynamic shadow look currently impossible to achieve using any real time engine for games + get very good performance that can even run on a mobile.
It’s something to consider for specific cases.
Edit: Also remember Casting dynamic shadows in UE or in any engine is often number one killing factor of performance, people would argue its everything and it depends on the game, true but don’t forget that dynamic lighting isn’t just lighting and affecting shaders, it is casting self shadows.
These shadows are calculating the complexity of the geometry on screen. in other words you could have the simplest shader networks but you if you have a dozen dynamic units with high poly counts and multiple elements each, then one light could cause that performance dip VS having a hundred super complex units not self shadowing but with fake shadow projections on the ground. In my experience I often found having more draw calls and less dynamic shadow enabled lights to be more performance savy than the opposite.