I’m unable to get to get baked lightmaps working after loading a lighting scenario dynamically. By working I mean seeing the baked shadows. This works fine in editor, but doesn’t work on Android device.
To try and debug this I setup a vanilla UE project to reproduce the problem as minimally as possible. This involved baking two lighting scenarios, one with a red directional light, the other with a green directional light, a shadow casting object and a floor plane.
The steps were
First time in - :
UGameplayStatics::LoadStreamLevel( lighting scenario with red light )
And then this loop, on a UI button, alternating between red and green light.
UGameplayStatics::UnloadStreamLevel ( lighting scenario with red light )
UGameplayStatics::LoadStreamLevel( lighting scenario with green light )
What I see is a ‘red’ scene follow by a ‘green’ scene etc as I’d expect, but without the shadows on the floor. The attached videos show it working in editor, but not on Android device ( OnePlus 10t, but reproable with other android devices ). I understand this to mean the lighting scenarios are loading in, but whatever is contained in the “_BuildData” asset ( lightmaps ? ) of the lighting scenario levels is either not loading or is not refreshing.
Both lighting scenarios are set to “blueprint” instead of “always loaded”. Both are marked as lighting scenarios as opposed to normal levels.
It looks like the objects in the World are not refreshing the references to the new light maps when changing lighting scenarios, but that’s just guessing.
Is this a known issue on mobile devices ? Is there a specific way you have to load lighting scenarios or something you have to call to refresh something after the levels have loaded ?
Thanks.
[Attachment Removed]
Steps to Reproduce
For the test project
Disable lumen in project settings
Create two empty levels, put one directional red light and one directional green light in the corresponding levels, along with a box to cast shadows on the floor.
Build lighting for both scenarios
Observe the _builtData assets exist for both
Make sure the _builtData assets are included in the packaging for the build.
Create a UI button on the HUD to load lighting scenario 1 and 2.
On red button press,
- if nothing loaded, call UGameplayStatics::LoadStreamLevel( red scenario )
- if green loaded, call UGameplayStatics::UnloadStreamLevel( green scenario ), followed by UGameplayStatics::LoadStreamLevel( red scenario )
On green button press,
- if nothing loaded, call UGameplayStatics::LoadStreamLevel( green scenario )
- if red loaded, call UGameplayStatics::UnloadStreamLevel( red scenario ), followed by UGameplayStatics::LoadStreamLevel( green scenario )
In all cases, the code makes sure the currently loaded scenario is fully unloaded ( confirmed by checking ULevelStreamingDynamic::GetLevelStreamingState == Unloaded ) before trying to load the new scenario.
[Attachment Removed]
One of our engineers found a solution to this.
It seems that in AActor::PostRegisterAllComponents(), the line which releases the actor instance GUIDs is responsible. Commenting out that line fixes the problem we have.
It’s apparently because the calculation of the light’s GUID is a combination of its own GUID and the owner actor’s GUID. When the GUID is invalid, the lookup to the shadow map in the map’s built data then fails and the shadows disappear.
It seems this is only an issue when you switch lighting scenarios within a level dynamically. If you load another level and then come back, presumably all actors are destroyed and recreated and so the GUIDs are all valid. In this case, there are no missing shadows / light bakes.
It’s probably not a permanent solution as not releasing the instance guids probably has other knock ons.
void AActor::PostRegisterAllComponents()
{
ensureMsgf(bHasRegisteredAllComponents == true, TEXT("bHasRegisteredAllComponents must be set to true prior to calling PostRegisterAllComponents()"));
FNavigationSystem::OnActorRegistered(*this);
FActorInstanceGuid::ReleaseActorInstanceGuid(*this);
}
[Attachment Removed]
Hi Mark,
Thank you for the report and for the workaround.
Dev team concurs that this is not a permanent solution but do believe you should be able to roll with it since when level destruction occurs, annotations will also be cleaned up in the same process. However, we cannot integrate this as it as a more complete solution would involve detecting that a level is lighting scenario driven and to keep GUIDs alive only for actors that have static lighting.
Best regards.
[Attachment Removed]