I have a script all setup to let me render out my various Level Sequences using MRQ. It gets the MoviePipelineQueueSubsystem queue, deletes all the existing jobs, allocates a new job, configures it, then uses a MoviePipelinePIEExecutor to render_queue_with_executor_instance. This works well, with one exception.
My renders always end up around the world origin. Each of my Level Sequences are hooked up in the game using a Level Sequence Actor that enables Instance Data and then sets the Transform Origin Actor to an actor in the world that positions the sequence in the proper location. I have not seen a way to have this take affect when rendering though. Since the job only accepts a path to the Level Sequence ASSET and not the Level Sequence ACTOR, I’m not sure how it is supposed to find it.
Adding to the difficulty, the Level Sequence Actor is located within a Level Instance that is a few levels deep. As a simple example, there is a world partition gameworld, it holds a Level Instance that holds the game geometry and lights in the area of a mission, and that also holds the Level Instance for the cinematic. That LI will hold any geometry/lights specific to the cinematic, and also hold the Level Sequence Actor.
In this case, you can see the LS_Cinematic is the Level Sequence Actor. This points at a LS_MissionSequence Level Sequencer Asset. It also points at the SM_Location geometry that positions the cinematic via the Transform Origin Actor.
How do I make the MRQ respect the Transform Origin actor so my sequence stops rendering at the origin?
Are you using world partition? You may need to do some other scripting work to make sure that all the parts you need are loaded as well.
You might try setting a breakpoint in UMoviePipeline::InitializeLevelSequenceActor. This is the code that trolls through the level to find a sequence to play on. See if it finds your sequence or not, and then make sure that the actor that it’s attached to is loaded as well.
Yeah, we are using World Partition. It feels like the problem is backward. I mean, MRQ (or MRG) takes a level sequence asset, not an actor. Does it search for level sequence actors and then see if their sequence parameter is pointing to the given level sequence asset?
That is correct, in UMoviePipeline::InitializeLevelSequenceActor, we iterate through all of the level sequence actors in the world, stops any that might be playing, and then it will use the last found one to do the render.
If that doesn’t serve your need, that is where you could make an adjustment to do what you would like.
Cool. So, one quick question, does this mean I need to somehow get my graph Execute Script node to “open for edit” the specific level instance that holds the level sequence actor, or, do I just need to make sure that the area of the world that holds the level sequence actor is “loaded”? I know in the editor I need to do both, otherwise the level sequence actor isn’t visible. But I am not so familiar with PIE to now what I need to get setup to make it work. Want to make sure I know what the end goal is so I can implement the right stuff.
In general, if you have the level instance loaded, the contents of that level instance should be able to be found. Double-check that your level sequence is spawned as well. If, for some reason, when you load that level instance, your level sequence is not there, then double-check with the setup to make sure there isn’t additional work to do that is specific to your project.
So it appears when you use MovieRenderGraph that the method you pointed to, InitializeLevelSequenceActor is not called.
I have noticed that if I set my Data Layers to “Activated” before I render then I get the proper results. My cinematic shows up in the right place with the right geometry around it. If I level then set as “Unloaded” then everything shows up at the origin. I try to set the RunTime state to “Activated” in the pre-job callback (I had to add a SetInitialRuntimeState method to the DataLayerInstace class). This didn’t affect the result as the geometry is still not visible and the cinematic plays at the origin.
I’m still trolling through the code, but I thought I’d ask. Do you know when/where the MovieRenderGraph process looks for the level sequence actor? Maybe the job callback is getting called after that happens. Also, do you know of a way to get these data layers to activate within the render process without having to edit them in the editor, and save them, before rendering?
You have two options, you could set the level sequence to not be spatially loaded (every actor in the world has this under the world partition section of their details panel) for the time in which you need to render. This will have it load when the level starts, but then you’ll want to add significant warmup frames for the rest of the world to load. Another option is to setup a data layer that could load that section of the world that you can call before you launch the MRQ render. This would require some bp script or python to setup.
All of my Level Sequence Actors already are non spatially loaded. That isn’t enough for them to be visible since they also have a data layer assigned. I need to activate the run time data layer for it to be loaded, and then it is visible. I have that working, but that gets me to the world geometry. I also nee to hand activate all the relevant data layers for that as well. But I’m running into issues finding that. I can ask the world for all the actors that overlap a certain area. Done. I get a list of actors. I can ask each actor what data layer assets it has assigned. Actor->GetDataLayerAssets() but this return null for all actors not at the root of my world. Any actor in any level instance even the one I am currently editing, reports an empty list of data layers assets.
I suppose now I will try to find a different way to get a list of data layers that are used by a list of actors.
Looks like MovieGraphSequenceDataSource::CacheLevelSequenceData(ULevelSequence* InSequence) is where it looks for and overrides the level sequence actor when using Movie Render Graph. Debugging that shows that my level sequence actor is not found in the world. In my pre-job callback a activate the data layer that holds my level sequence actor.
UUnrealEditorSubsystem* UnrealEditorSubsystem = GEditor->GetEditorSubsystem<UUnrealEditorSubsystem>(); UWorld* World = UnrealEditorSubsystem->GetGameWorld(); UDataLayerManager* DataLayerManager = UDataLayerManager::GetDataLayerManager(World); UDataLayerInstance* DataLayerInstance = const_cast<UDataLayerInstance*>(DataLayerManager->GetDataLayerInstanceFromAssetName(DataLayerAssetFName)); DataLayerManager->SetDataLayerInstanceRuntimeState(DataLayerInstance, EDataLayerRuntimeState::Activated, true);This seems correct, but happy to have you verify this.
The question then is, how do I force this to finish up, load the geometry into the world, before proceeding with the render so that the level sequence actor - and all my actual world geometry - is available for the render?