Trigger GPU Lightmass build via Python

Hi,

I’m trying to trigger the GPU Lightmass build via a Python script but am not having much luck with the Unreal Python API. I found the GPULightmassSubsystem and GPULightmassSettings APIs but can’t access the Editor instance to do a “Build Lighting” operation under the “Build->GPU Lightmass” menu. When I do “unreal.GPULightmassSettings().set_editor_property(XXX)” for example, I can see that it creates a new instance of the class but what I really want to do is to edit the properties that I can see/edit in the Editor.

Any help/hints appreciated. Thank you!

1 Like

Did you make any progress with this? looking into myself currently.

I’m trying to figure this out too, and so far I found that I can at least change the GPU Lightmass settings through Python script, but I can’t get the launching of the actual Build Lighting to work. I’m currently on UE 5.2.1

Here’s the limited info I worked with, I hope there would be more documentation with some examples. unreal.GPULightmassSubsystem

import unreal

gpu_lightmass_subsystem = unreal.GPULightmassSubsystem()
        
        if gpu_lightmass_subsystem:
            # Testing if I can change values. This works for me.
            gpu_lightmass_subsystem.set_realtime(False)
          
            # Trying to call Build Lighting doesn't work. What I'm missing?
            gpu_lightmass_subsystem.launch()

            # This returns False.
            print("GPULightmass is running: " + str(gpu_lightmass_subsystem.is_running()))

        else:
            print("GPU Lightmass not found.")

If anyone figures out how to launch GPU Lightmass baking from python script, please do share it here!

The other thing is that the editor is set to shut down after executing your python script, and that functionality needs to be disabled in order for GPU Lightmass to complete.

In EditorPythonExecuter.cpp, FExecuterTickable::Tick is where it shuts down the editor.

Instead, you’d need some other way to trigger the editor shutdown after GPU Lightmass has fully finished, and any packages have been saved.

I discovered that the problem with the approach above is that it is creating a new instance of the GPU Lightmass system, and GPU Lightmass on the C++ side expects that its UObject “outer” is the level. This has already been created on the C++ side, we just need a way to access it via python.

GPULightmassSubsystem is a World subsystem, and there isn’t out-of-the-box a way to get a reference to a World subsystem in python, so I had to add one in C++.

 */
static PyObject* GetWorldSubsystem(FPyScopedEditorTransaction* InSelf, PyObject* InArgs, PyObject* InKwds)
{
	PyObject* PyWorldObj = nullptr;
	PyObject* PySubsystemClassObj = nullptr;

	if (!PyArg_ParseTuple(InArgs, "OO:get_world_subsystem", &PyWorldObj, &PySubsystemClassObj))
	{
		return nullptr;
	}
	check(PyWorldObj);
	check(PySubsystemClassObj);

	UObject* WorldObj = nullptr;
	if (!PyConversion::NativizeObject(PyWorldObj, WorldObj, UWorld::StaticClass()))
	{
		PyUtil::SetPythonError(PyExc_TypeError, TEXT("get_world_subsystem"), *FString::Printf(TEXT("Parameter 0 must be a 'World' not '%s'"), *PyUtil::GetFriendlyTypename(PyWorldObj)));
		return nullptr;
	}
	UWorld* World = Cast<UWorld>(WorldObj);

	UClass* Class = nullptr;
	if (!PyConversion::NativizeClass(PySubsystemClassObj, Class, UWorldSubsystem::StaticClass()))
	{
		PyUtil::SetPythonError(PyExc_TypeError, TEXT("get_world_subsystem"), *FString::Printf(TEXT("Parameter 1 must be a 'Class' not '%s'"), *PyUtil::GetFriendlyTypename(PySubsystemClassObj)));
		return nullptr;
	}

	if (GEditor)
	{
		if (UWorldSubsystem* Subsystem = World->GetSubsystemBase(Class))
		{
			return PyConversion::Pythonize(Subsystem);
		}
	}

	Py_RETURN_NONE;
}

And the python code that uses that looks like:

world = unreal.UnrealEditorSubsystem().get_editor_world()
gpu_lightmass_subsystem = unreal.get_world_subsystem(world, unreal.GPULightmassSubsystem)

Where get_world_subsystem is the new function that I added in C++ (PyEditor.cpp), similar to get_editor_subsystem, but which takes the world as a parameter as well as the subsytem type.