Thanks for demonstrating it so clearly. I think the root cause here is that planar reflections don’t handle roughness correctly. The floor of the ship should have specular, it’s just so rough that it looks like diffuse. I’ll probably fade out planar reflections based on roughness.
It’s probably possible to do something like that, which converts the receiver point’s distance from the reflection plane into an offset into the planar reflection texture. The whole determination of how normals distort the planar reflection lookup is just a heuristic based on where the reflection ray intersects a virtual sphere centered at the receiver point. I’ll investigate this further next time I’m working on ocean reflections.
Thanks for the detailed report. It’s actually not a planar reflection bug as memory climbs even without a planar reflection, although the planar reflection makes it much worse. Hopefully something we can fix for 4.13.
On having explicit control over what receives the planar reflection - In a deferred renderer like UE4 you have to fit data like this into the GBuffer, which is pretty much full. Reflections are done in a deferred pass long after materials and components are rendered. The nice thing about this approach is that you can layer different reflection methods easily, each one is just a different pass that blends into the reflection buffer mapped onto the screen. For example if the planar reflection is faded out, SSR kicks in, and if SSR is faded out, reflection captures cover the reflection, and they are blended between.
So I don’t intend to add direct control for what receives planar reflections at this point. In theory, planar reflections are accurate for a slab of positions near the plane, there’s no reason you should have to mask them to certain objects. Same reason we don’t have flags for each reflection method (SSR, reflection captures) on receiving components / materials. Instead I want to improve the heuristics for when the planar reflection is valid or not, so that it ‘just works’.
On giving direct access to the render target like scene captures do - it’s possible but a decent amount of work. It can’t just be a UTextureRenderTarget2D because the size of the planar reflection texture comes from the screen size.
I have to disagree with that, you don’t necessarily need to have flags for what is effected by SSR or reflection captures (well there is SSR flag for translucent materials) but that’s very different from planar reflections if you ask me!
SSR is fairly accurate regardless of position and reflection captures are never accurate anyway (they are there to pretty much fill the empty space with something, ideally you would never want to use those :p) but planar reflections on the other hand are only relevant and accurate for a surface aligned and as close to the planar capture actor… every object that is too far above or below the plane has no good reason to receive planar reflections, it just looks too inaccurate and out of place and pretty much ruins it in my opinion, better accounting for roughness is not going to always help.
What if you have a fairly reflective box above a reflective floor but you only want the floor to receive the reflections from the planar capture actor? the box is simply going to look wrong reflecting things it should never be able to :p.
Anyways if render target access cannot be done very easily then what about implementing the clip plane in the regular scene capture 2d component? is that possible?
Have you considered pre blurring planar reflection texture with varying roughness values to mipmaps? This work well for cubemap and should work for planar reflections too. Memory increase is only minimal(under +33%). Just couple mips should be fine with trilinear filtering.
In fact, that’s all you need to make planar reflections:
adding a “clipping plane” option with a few parameters (center of the plane, right vector of the plane) to the scenecapture 2D actor. Then you could display these reflections in any mesh you want by plugging the render target (with screenposition in uv’s) to the emissive channel of it’s material.
adding a optionnal “mirroring location” flag so that the scenecapture position mirrors the camera position, so you don’t need blueprint stuff to get this result (optionnal only so that you could also use the clipping plane option to make portals much easier).
About the rendertarget size: it could however been defined manually according to the choosen game resolution.
This way, it wouldn’t “just work”, you would have to edit emissive channels manually to make it work (which is trivial) but you would have all possible controls over the reflections (those given by the scenecapture showflags and postprocess tweakings).
That’s what I thought planar reflections would be (as an extended version of scenecapture2D actor - because that’s how Ryan Bruck’s described this in an other pot) and that’s why I was surprised when I saw how it was implemented.
There are many reasons to mask out certain objects; if you have special meshes in first person (common in first person shooters) they’ll show up when you look at the surface which is reflecting, which ruins the effect.
You can’t “pre-blur” the textures, planar reflections are done in realtime. Best that can be hoped for is multiple importance sampling, which needs enough resolution.
Even simple cheap gaussian blur would fix most of the issues. Better approximation could calculate blend weights using reflection pass depth buffer. There are lot that can be done in realtime. This is nice prensetation for same problem but with SSR context. Stochastic Screen-Space Reflections - Frostbite
From what I understand you have to have the Planar Reflection actor in the scene as it has attributes to control various parameters of the planar reflection. I just placed both the “mirror mesh” and the “planar reflection” actor in the same place in the scene. The one that I found was that I scaled the planar reflection actor to be very thin, to match the “mirror mesh” and I didn’t get any results. I changed the scale of the “planar reflection” actor to be 1.0 in the depth plane (thickness of mirror mesh) and that fixed it. I’m guessing that the “planar reflection” actor has to overlap scene in “depth” to determine the extent of what is reflected into the “mirror mesh”. Hope that makes sense.
Okay so it looks like it’s simple to enable the clipping plane in the scene capture 2d component.
All you need to do is add something like this:
FPlane MirrorPlane = FPlane(FVector(0, 0, 0), FVector(0, 0, 1)); //Plane base, plane normal
SceneRenderer->Views[0].GlobalClippingPlane = MirrorPlane;
// Jitter can't be removed completely due to the clipping plane
// Also, this prevents the prefilter pass, which reads from jittered depth, from having to do special handling of it's depth-dependent input
SceneRenderer->Views[0].bAllowTemporalJitter = false;
In SceneCaptureRendering.cpp after about line 305.
Obviously a little bit more code would be needed to expose the plane parameters and add an optional boolean but my point is that this could have been added in like 5 minutes by someone who knows what is doing (I’m not lol) so can we please pleasee add this in the next 4.12 update?
You’re talking about controlling what objects appear in the reflection, not what receives the reflection. You can already mask out objects from appearing in the reflection using the blueprint function HideComponent. In 4.13 there will be an array in the details panel that you can assign actors to, which is easier to setup.
You can use the fade distance and normal fade settings on the planar reflection to limit where it’s applied to just the floor.
Some improvements to planar reflections that will be in 4.13:
Height fog now works properly in planar reflections
The ray used for computing fog is first clipped by the reflection plane
Fading out planar reflections based on roughness since they don’t have support for variable roughness (fade starts at .2 roughness, ends at .3)
Added bRenderSceneTwoSided to planar reflections, which can be useful to limit leaking
Added ShowOnlyActors and HiddenActors to SceneCaptureComponent for easy use without having to call BP functions
Added bShowPreviewPlane to planar reflection actors
The view state is recreated on planar reflection edit, which resets the Temporal AA history, allowing instant previewing of changes
I guess I will try submitting a pull request.
Is there any this is added in 4.12.x if I submit the pr? or 4.13 at best? Q_Q
Btw, is it a good idea to change the render target size at runtime? (that would only need to happen when changing resolution, not each tick) or is that not recommended?
Is this the reason why planar reflections use FPlanarReflectionRenderTarget?