Brushes stay in place in transformed level instances

When using LoadLevelInstance to load a level instance at a different location/rotation than default anything that is built using CSG brushes will ignore then transform and stay in their default positions. This includes pretty much everything in the Volume category: post-processing volumes, character indirect lighting volumes, camera blocking volumes, etc. If you eject from the pawn, you can see that the brushes’ position changes, but their geometry stays at their original position.

For us, this severely limits the usage of transformed level instances since the loss of character indirect lighting volumes prevent us from fully leveraging baked lighting in dynamically-generated levels:


I’m attaching a project that demonstrates the problem:

Hi manoelneto,

It’s not that the lightmass volume isn’t being transformed, it’s that lightmass relies on precomputed lighting. This is explained in more detail in this post. During play in your level, I’m sure you noticed all of the warnings to build lighting even though lighting was built in the tile room.

I tested several other volumes (trigger, navmesh, camera blocking, etc) and all transformed and worked correctly in your project. Even the lightmass volumes are showing they are in the correct place if you look in the details panel and click through them while ejected.



I need to study the character indirect lighting source to see if its possible to displace the pre-computed light probes at all. But did you test geometric volumes? Solid brushes don’t get transformed with the instances. Place a brush box in the tile level and play the “dynamic level”, and this is what happens:


The coordinates of the objects in the details panel is transformed, but their actual geometry isn’t:


I was going through the source to see what could be done in regards to the lighting. My findings:

  • Each level has a FPrecomputedLightVolume object, which is used to sample pre-computed lighting. This class has a method called “ApplyWorldOffset”, which is used for world origin rebasing. The FPrecomputedLightVolume internal world offset is then subtracted to light sample query coordinates, so the data itself doesn’t need to be actually moved around. It doesn’t support rotation, so that would require modifications to the FPrecomputedLightVolume class.
  • Streaming levels are transformed using FLevelUtils::ApplyLevelTransform() in LevelUtils.cpp after they are loaded or made visible. All it does is loop through all Actors in the level and adjust their transforms accordingly.
  • Levels have a multicast delegate called OnApplyLevelTransform which is broadcast after FLevelUtils::ApplyLevelTransform(), which can be used so other parts of code can react to level transformations without the need to modify LevelUtils.cpp.

Since all that stuff is marked as ENGINE_API, I did a quick test which doesn’t involve modifying the engine (because I didn’t download the source for 4.16 yet). I created an actor class with a SceneComponent root and added this to its BeginPlay:


Then I placed one of those at the origin of the Tile level. The result:


I’ll download the 4.16 source code and make a proper fix this weekend.

I made a pull request with a fix for the precomputed light volumes:

I haven’t got started on the problem with brushes. I also found out lightmap directionality breaks when level instances are rotated, which is something for another fix.

Hey, we tried your fix (engine version 4.17.2) and it perfectly works in editor, but not in packaged builds. In packaged builds, some times some objects stay completely black.

I applied the changes from the commit to oculus 4.25.4, but I can see the volumetric preview is still all at the origin where I baked the lighting in the individual maps.

grabbed a copy of your example project and did a test with that as well and same deal. Both with engine changes and using the actor hack. Neither seems to move the light. Maybe it’s a timing issue, not sure.

Would you mind testing what you did on a 4.25+ branch and seeing if it also doesn’t update for you?