I lately have used lot of time for making Planar reflection actors to perform better. At first pass I tuned screen percentage, LODDistance Factor and Max View Distance Override.
Then I started to disable features, basically all of them. I needed to hack some shaders to disable static shadow distance fading to allow disabling dynamic shadows.
List of all things that I disable with c++ code.
[SPOILER] const bool t = false;
p->ShowFlags.SetPrecomputedVisibility(t);
I am also working with some other optimizations. Like using tighter frustum for planar reflection that don’t cover whole screen.
So do others have some optimizations tips to share?
I dont have anything to add besides horizontal blur options XD But nevertheless…THIS IS AWESOME! Thank you so much man! I think these are great and important optimizations
Just updated. https://github.com/EpicGames/UnrealEngine/pull/4827
Figured way to calculate accurate planar reflection world space corners. These can be used to calculate 4 additional frustum planes that then enclose planar reflection actor. This way only objects that actually are reflected from planar reflection actor are rendered. For small reflection actors this will save huge amount of rendering time.
awesome work!
haven’t used planar reflections myself (I’ve had no need so far and they seem expensive anyway) but I hope your changes make it to the engine
Made some performance testing.
Flying Template Scene with planar reflection added: 763 draw calls. With added frustum planes: 524 draw calls. Without planar reflections 474 draw calls.
So in this scene Planar reflections add 269 draw calls. With this single PR this drops to 50 draw calls. This is 81% saving. The saving amount is dependant how big portion planar reflection actor is covering. Savings from adding clip plane as frustum plane help always. Even when planar reflection actor cover whole screen.
Edit: PR -> https://github.com/EpicGames/UnrealEngine/pull/4827
Without optimizations, with optimizations, planar reflection disabled.
Found that occlusion culling still has some issues. Only worked every other frame. This was caused by wrong number of buffered frames. So I made new PR to fix this. https://github.com/EpicGames/UnrealEngine/pull/4833
basically when both views are showing the same reflection, changing camera position on one view was affecting the second view. I have not digged this issue, since it was reported for me and I have only tested how to reproduce and make the submission report.
@Kalle_H if I recall correctly you work alot with mobile (not sure if with vulkan) and I have found issues with Vulkan and planar reflections, so just for you to be aware these exists. I will link the issue number as soon as I find it:
This is output of RenderDoc texture viewer of Planar reflection texture. Like you can see most of the stuff is out of bounds of actual planar reflection and never can be seen but these pixels are not free. All big objects like skyboxes etc are drawed to them. So my idea was to use Scissoring to cull those pixels early. Red rectangle is what I would use as scissor rect. But I am not sure can I set it globally from PlanarReflection rendering. Messing up with ViewRects didn’t work.
Something I’ve noticed is that planar reflections (and scene captures) seem to do global distance field updates regardless of showflags, and translucency volume lighting is calculated even if translucency is disabled, if deferred lighting is enabled. Is this something that could be optimized? I assume this also applies to the main view.
The fix with with adding planar reflection plane as clipping one wont work with 4.20, since in 4.20 there is a check that ViewFrustum.Planes.Num() == 5 in BuildLightViewFrustumConvexHull function - have you by chance managed to modify that function to take into account that Frustum.Planes.Num() == 10 for reflection captures ? (or I must frap my head around that fishy Edges table to fix this) ? (adding those additional clipping planes greatly improves performance, so I do not want to lose this change)
Good catch. You can change the assert to be like this.
check(Frustum.Planes.Num() >= PlaneCount);
But this will not be optimal for planar reflection dynamic shadows. But proper fix to get this optimization for dynamic shadows will be bit more complex and you would need to add more edges to that list. In our project we use static shadows only for planar reflections so I haven’t seen this assert my self.