I thought about this whole ordeal with blurred cubemaps and there was a
few things I really didn’t like:
- Outside tools are required.
- The generated images might need to be rotated in the way Unreal expects
them.
- The input cubemap, which gets blurred, usually has no relation to the
actual Unreal map where it will be used on. “One reflection fits all” is a rather
old-school approach.
Yes, learning and using CubeMapGen is not that difficult, the images can be
rotated by an ImageMagick script, you can capture cubemaps of actual
maps, export and convert them to a format CubeMapGen can load, blur them
then bring everything back again, every time the map changes significantly.
All that could be done but I prefer having the computer do the tedious work,
not me, so I tried to come up with a better workflow.
As it turns out, it is possible to produce a decent blur right in Unreal. Like
this one:
The trick is to use a recursive shader and let it run for a second.
Since actual loops are not allowed in Unreal shaders (not even in the custom
code node) I had to put on my “Hacky” hat and make a special
SceneCaptureCubemapActor.
The capture point is located inside an extra StaticMesh component, which is
an inside-out sphere (so the normals are facing toward the center).
There is a blur shader applied to this sphere: it blurs a bit the referenced
cubemap which is generated by the same SceneCapture actor.
So in one frame it captures the surrounding sphere, the next frame the
sphere’s shader gets updated and blurs stuff a bit. The change is captured in
the next frame, then the updated cubemap is processed again and so on.
With the proper blur shader it’s also easy to simulate multilayer reflections
like this:
(It’s one cubemap and not two mixed together.)
There is a time limit set in the actor after which everything is deactivated
and removed from the scene. The generated cubemap stays there so you
can save it as an “offline” asset if you want.
The base cubemap might be some imported HDRI image, but can also be
captured: place a normal SceneCaptureCubeMapActor above the map and
set it’s near plane to skip the actual map and only see the really distant
environment.
So the blurring workflow becomes like this:
- Set blur parameters.
- Start a PIE session and wait for a few seconds.
- Close PIE and save the generated cubemap.
It’s also possible to have a more flexible and generalized way of dealing with
reflections, if you are willing to sacrifice the first second of each map.
Have cubemaps like “Environment” and “EnvironmentBlurred” in a package and
generate them once every time a map starts. By using only these CMs in
reflective shaders you can stop the proliferation of cubemaps and related
material instances and you can also be sure that reflections have at least a
remote resemblance to the visuals of the actual map.
So I set up this material:
and now I can forget about it, it will look right whatever I do to the skybox.
The next logical step would be having separate cubemaps for separate areas
on a map and have the (Static)Meshes use the closest ones automatically. I
don’t have time for that now but I’d like to dig into it in the future.