in Tutorials, UE5

Python interpreter in UE5

In a previous tutorial we have embed a Python interpreter in a C++ application, now we can use it as a base to embed a Python interpreter in our Unreal Engine project. With this feature we will be able to use Python code inside our games.

We can start with an empty Unreal Engine C++ project. We are going define a class to manage the Python interpreter.

ue5_empty_project_cpp

Inside the project we can create a C++ class using Tools > New C++ Class

ue5_newcpp_class

And create a class to manage the Python interpreter

ue5_project_python_tree

For this example we are going to define a Unreal Engine node to calculate the cosine using a Python function.

PythonInterpreter.h

#pragma once

#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "UObject/NoExportTypes.h"

#include "PythonInterpreter.generated.h"

UCLASS(Blueprintable, BlueprintType)
class UE5_T_PYTHON_API UPythonInterpreter : public UObject
{
	GENERATED_BODY()
public:

	UFUNCTION(BlueprintCallable, Category = "PythonInterpreter|math|cos")
		void CalculateCosineNode(const float& input, float& output);
		
	UPythonInterpreter();
	~UPythonInterpreter();

private:
	float calculate_cosine(const float& input);

};

PythonInterpreter.cpp

#include "PythonInterpreter.h"

#pragma push_macro("check")
#undef check
#pragma warning (push)
#pragma warning (disable : 4191)
#pragma warning (disable : 4591)
#pragma warning (disable : 4686)
#include <pybind11/embed.h>
#pragma warning (pop)
#pragma pop_macro("check")

namespace py = pybind11;

UPythonInterpreter::UPythonInterpreter()
{
}

UPythonInterpreter::~UPythonInterpreter()
{
}

void UPythonInterpreter::CalculateCosineNode(const float& input, float& output)
{
	output = calculate_cosine(input);
}

float UPythonInterpreter::calculate_cosine(const float& input)
{
	py::scoped_interpreter guard{};
	auto math_module = py::module_::import("math");
	py::object result = math_module.attr("cos")(input);
	return py::cast<float>(result);
}

We are using pybind11 to wrap the Python with c++ calls, we need to add some wrap in their include to use it with UE5 and avoid some errors during the compilation

In the calculate_cosine function we instantiate the interpreter before import and call to the Python function math.cos. But each time that we call this function a Python interpreter is created and their math module is loaded.

To avoid this time overhead and increase the performance we can move and link the scope of the interpreter with the scope of the class. Then just instantiate only one object of this class, and use this object to call nodes that can use Python code.

We need to include our thirdparty libraries to the Build.cs file of the project using PrivateIncludePaths

Build.cs

using System.IO;
using UnrealBuildTool;

public class UE5_T_Python : ModuleRules
{
    public UE5_T_Python(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
        bUseRTTI = true;
        bEnableExceptions = true;

        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });

        PrivateDependencyModuleNames.AddRange(new string[] {  });

        PrivateIncludePaths.Add(Path.Combine(ModuleDirectory, "../UE5_T_Python/thirdparty/pybind11/include"));

        string python_path = @"D:\Programs\Python312";
        PrivateIncludePaths.Add(Path.Combine(python_path, "include"));
        PublicAdditionalLibraries.Add(Path.Combine(python_path, "libs", "python312.lib"));
    }
}

We are using a static linking of the Python library of the system. This library can be included in the release also and use a relative path to the .lib, note that we also need to add the include folder of the Python headers to the paths of the project

Other option is to use dynamic linking and then take their .dll with a call of PublicDelayLoadDLLs instead of PublicAdditionalLibraries

Now in the Unreal editor we can create the Blueprint wrapper of our class PythonInterpreter to use it as variable type in the level

ue5_editor_class

Then we can create a variable in the level blueprint

ue5_variables

Construct the variable and we can use the CalculateCosineNode to calculate the cosine using the python math module

ue5_level_blueprint

In the terminal we can see the result of the node execution

ue5_terminal

Conclusion

With this tutorial we have seen a simple way to embed a Python interpreter into an Unreal Engine project. This can be useful if we have Python modules that we do not want to port to c++ but we need to use it. Now we can execute Python code from our Unreal Engine games

Tutorial files

Support this blog!

For the past year I've been dedicating more of my time to the creation of tutorials, mainly about game development. If you think these posts have either helped or inspired you, please consider supporting this blog. Thank you so much for your contribution!

Write a Comment

Comment