Wednesday, May 28, 2025

learning python scripting in Unreal Engine for Artists

i'm still very much a beginner in python scripting in Unreal Engine but thought these personal work python snippets i made may be helpful for learning.  there may be bugs and better ways to code them so please modify/use at your own risk.


import unreal

import logging

logger = logging.getLogger(__name__)

logging.basicConfig(level=logging.DEBUG)


print("yaaay running a script")


def doIt():

#addCamera()

#addBoneActor()

#translateActor("TestCylinder", translateY=0.0)


#getCameras()

#getCameraPosition()


#translateExistingCamera()

#debug()

#setMaterialAllStaticMeshes(materialName="/Engine/VREditor/UI/FrameMaterial.FrameMaterial")

#setMaterialAllStaticMeshes()


#debug()

#printKeyFramesControl()


#???translateControlRig()

#createFkControl()

#applyMaterial()


#createMaterial()

#addCubeToLevelSequence()


#printStaticActorsInOutliner()


#printStaticActorsInFocusedLevelSequence()


def debug():

#print("material" in dir(unreal.StaticMeshActor))

print(dir(unreal.MovieSceneScriptingFloatChannel))



def printStaticActorsInOutliner():

print("yaaay printing stuff")

pass


actorSystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)

actors = actorSystem.get_all_level_actors()

meshActors = [act.get_actor_label() for act in actors if isinstance(act, unreal.StaticMeshActor)]


print(meshActors)




def printStaticActorsInFocusedLevelSequence():

print("yaay static actors in focused level sequence")

levelSequence = unreal.LevelSequenceEditorBlueprintLibrary.get_current_level_sequence()


print(levelSequence, type(levelSequence))

#LogPython: <Object '/Game/TestA_LS.TestA_LS' (0x000008A280176680) Class 'LevelSequence'> <class 'LevelSequence'>


#get static mesh actors in this level sequence

#help(levelSequence)


staticMeshActors = []


#need to use binding

rootBindings = levelSequence.get_bindings()

for binding in rootBindings:

print(type(binding)) #LogPython: <class 'MovieSceneBindingProxy'>

actorName = binding.get_name()

print(actorName)


bindingClass = binding.get_possessed_object_class()

print(bindingClass)

print(type(bindingClass))

print(bindingClass.get_name())

#only store static meshes

if not bindingClass.get_name() == "StaticMeshActor":

continue

staticMeshActors.append(actorName)

print(staticMeshActors)

return staticMeshActors


def addCubeToLevelSequence():

#add a cube static mesh to an existing level sequence


#change these to where to find level sequence

folderName = '/Game/testSequences'

levelSequenceName = 'testShot_a'

#change this to what name of cube static mesh is in outliner

meshName = "Cube" 

levelSequence = unreal.load_asset("{0}/{1}".format(folderName, levelSequenceName))


print(type(levelSequence)) #LevelSequence


#find static mesh actor

actorSystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)

actors = actorSystem.get_all_level_actors()

meshActors = [act for act in actors if isinstance(act, unreal.StaticMeshActor) and act.get_actor_label() == meshName]


if not meshActors:

return


meshActor = meshActors[0]

unreal.log(type(meshActor)) #StaticMeshActor


#add static mesh actor to level sequence

levelSequenceSystem = unreal.get_editor_subsystem(unreal.LevelSequenceEditorSubsystem)

bindings = levelSequenceSystem.add_actors([meshActor])


#inspired by dev dot epicgames dot com : Python Scripting in Sequencer






def createMaterial():

#create a green material

#create base material

matName = "testGreenMat" #name of material

location = "/Game/testMaterials" #assumes this already exists. it is where to save material


assetTools = unreal.AssetToolsHelpers.get_asset_tools()

material = assetTools.create_asset(matName, 

location,

unreal.Material,

unreal.MaterialFactoryNew()) #returns material object


#material = unreal.load_asset("/Game/testMaterials/testGreenMat")


#create constant 3 vector

constantNode = unreal.MaterialEditingLibrary.create_material_expression(material,

unreal.MaterialExpressionConstant3Vector,

-400, 

200)


#change to green constant and plug it into base color

constantNode.constant = unreal.LinearColor(0,1,0)


unreal.MaterialEditingLibrary.connect_material_property(constantNode,

"",

unreal.MaterialProperty.MP_BASE_COLOR)

#save

unreal.MaterialEditingLibrary.recompile_material(material)


#inspired by TomCic on Unreal Engine developer forum: forums dot unrealengine dot com




def applyMaterial(materialName = "/Game/testMaterials/testMatYellow"):

#apply an existing material to selected static mesh

material = unreal.load_asset(materialName)

print(type(material))


actorSystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)

actors = actorSystem.get_selected_level_actors()


if not actors:

return


mesh = actors[0]

if not isinstance(mesh, unreal.StaticMeshActor):

unreal.log("requires a selected static mesh actor")

return


meshComponent = mesh.get_component_by_class(unreal.StaticMeshComponent)

unreal.log("meshComponent:{}".format(meshComponent))

meshAsset = meshComponent.get_editor_property("static_mesh")

unreal.log("meshAsset:{}".format(meshAsset))

unreal.log("type meshAsset")

unreal.log(type(meshAsset)) #StaticMesh

meshAsset.set_material(0, material) #using 0 material index




def createFkControl():

#creating fk control on existing control rig

rigs = unreal.ControlRigBlueprint.get_currently_open_rig_blueprints()


print("open rigs:",rigs)

#LogPython: open rigs: ["/Script/ControlRigDeveloper.ControlRigBlueprint'/Game/simple_leg_scene_CtrlRig.simple_leg_scene_CtrlRig'"]


#print(type(rigs[0]))  # <class 'ControlRigBlueprint'>


#controller = rigs[0].get_controller()

#print(controller)

#print(type(controller)) #<class 'RigVMController'>


controller = rigs[0].get_hierarchy_controller()

#print(controller)

#print(type(controller)) #<class 'RigHierarchyController'>



controlSetting = unreal.RigControlSettings()

controller.add_control('yaay_ctrl', 

unreal.RigElementKey(type=unreal.RigElementType.BONE, name='upLeg'), 

controlSetting, 

unreal.RigHierarchy.make_control_value_from_euler_transform(unreal.EulerTransform(location=[0.000000,0.000000,0.000000],rotation=[0.000000,-0.000000,0.000000],scale=[1.000000,1.000000,1.000000]))

)





#levelSequence = unreal.LevelSequenceEditorBlueprintLibrary.get_current_level_sequence()#get_focused_level_sequence()#"animMap"

#rigs = unreal.ControlRigSequencerLibrary.get_control_rigs(levelSequence)

#print("rigs:",rigs)

#print(type(rigs[0]))

#rigs[0] #ControlRigSequencerBindingProxy

#print(type(rigs[0].control_rig)) #ControlRig

#controlRig = rigs[0].control_rig


#print("controlRig")

#print(controlRig)

#print("levelSequence", levelSequence)


def translateControlRig():

#???

levelSequence = unreal.LevelSequenceEditorBlueprintLibrary.get_current_level_sequence()#get_focused_level_sequence()#"animMap"

rigs = unreal.ControlRigSequencerLibrary.get_control_rigs(levelSequence)

#print(type(rigs[0]))

#rigs[0] #ControlRigSequencerBindingProxy

#print(type(rigs[0].control_rig)) #ControlRig

controlRig = rigs[0].control_rig


print("controlRig")

print(controlRig)

print("levelSequence", levelSequence)

print(controlRig.current_control_selection())

worldTransform = unreal.ControlRigSequencerLibrary.get_control_rig_world_transform(levelSequence, controlRig, "Bone_ctrl", unreal.FrameNumber(1))

#print("world transform")

#print(worldTransform)

curTransform = unreal.ControlRigSequencerLibrary.get_local_control_rig_euler_transform(levelSequence, controlRig, "Bone_ctrl", unreal.FrameNumber(0)) #depends on value of control rig set to euler transform

print(curTransform)

unreal.ControlRigSequencerLibrary.set_local_control_rig_euler_transform(levelSequence, controlRig, "Bone_ctrl", unreal.FrameNumber(1), unreal.EulerTransform(location=[0, 0, 21]), set_key=False)

#curTransform = unreal.ControlRigSequencerLibrary.get_local_control_rig_euler_transform(levelSequence, controlRig, "Bone_ctrl", unreal.FrameNumber(0)) #depends on value of control rig set to euler transform

#print(curTransform)




def printKeyFramesControl():

#print all keyframes on a control of a control rig

logger.info("yaay - printing keyframes")


controlRigName = "cube_skinned_b_CtrlRig"

controlName = "Bone_ctrl"

attr = "Location.Y"

levelSequence = unreal.LevelSequenceEditorBlueprintLibrary.get_current_level_sequence()#get_focused_level_sequence()#"animMap"

rigs = unreal.ControlRigSequencerLibrary.get_control_rigs(levelSequence)


#print(rigs)

rig = rigs[0].control_rig

print(rig)

#<Object '/Game/cube_skinned_b_CtrlRig_Take1.cube_skinned_b_CtrlRig_Take1:MovieScene_0.MovieSceneControlRigParameterTrack_0.cube_skinned_b_CtrlRig' (0x000005BC19285400) Class 'cube_skinned_b_CtrlRig_C'>


rigTrack = rigs[0].track

print("rigTrack")

print(rigTrack)


keyedSection = rigTrack.get_section_to_key()

print("keyedSection")

print(keyedSection)


channelObjs = keyedSection.get_all_channels()#get_channel(channelName)

for channelObj in channelObjs:

print(channelObj)

print(type(channelObj))

logger.info(channelObj.get_path_name())

keys = channelObj.get_keys()

print("keys >>>")

print(keys)


for key in keys:

keyTime = key.get_time().frame_number.value


keyValue = key.get_value()


print(keyTime, keyValue)




def setMaterialAllStaticMeshes(materialName="/Engine/MaterialTemplates/Gradients/Gradient_Linear.Gradient_Linear"):

meshes = getStaticMeshes()

print(meshes)

material = unreal.load_asset(materialName)

print(material)

print(type(material))


for mesh in meshes:

meshComponent = mesh.get_component_by_class(unreal.StaticMeshComponent)

logger.info("meshComponent:{}".format(meshComponent))

meshAsset = meshComponent.get_editor_property("static_mesh")

logger.info("meshAsset:{}".format(meshAsset))

meshAsset.set_material(0, material)

def getStaticMeshes():

actorSystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)

actors = actorSystem.get_all_level_actors()


#print(actors)

result = [x for x in actors if isinstance(x, unreal.StaticMeshActor)]


return(result)



def translateExistingCamera():

logger.info("translate a camera...")


cameras = getCameras() or []

if not cameras:

return


camera = cameras[0]


location = camera.get_actor_location()

logger.info("before cam position {}".format(location))


newLocation = unreal.Vector(location.x, location.y+100, location.z)

camera.set_actor_location(newLocation, False, False) #position, sweep, teleport


location = camera.get_actor_location()

logger.info("after cam position {}".format(location))



def getCameraPosition():

cameras = getCameras() or []

if not cameras:

return


camera = cameras[0]


location = camera.get_actor_location()

logger.info("cam position {}".format(location))


def getCameras():

actorSystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)

actors = actorSystem.get_all_level_actors()


#print(actors)

result = [x for x in actors if isinstance(x, unreal.CineCameraActor)]

print(result)

#for a in actors:

# print(type(a))

return result


def addCamera():

logging.info("adding camera")


#add camera actor

#CineCameraActor #can get this by manually creating

actorClass = unreal.CineCameraActor

cylinderActor = unreal.EditorLevelLibrary.spawn_actor_from_class(actorClass, unreal.Vector(0,0,20), unreal.Rotator(0,0,0)) #class, translation, rotation


#add actor to level sequence

levelSystem = unreal.get_editor_subsystem(unreal.LevelSequenceEditorSubsystem) #?one per level sequence

levelSystem.add_actors([cylinderActor])



def addBoneActor():

print("add bone actor")

#loading a skeletal mesh

mesh = unreal.load_object(name="/Game/cube_skinned_b", outer=None)

factory = unreal.ControlRigBlueprintFactory

rig = factory.create_control_rig_from_skeletal_mesh_or_skeleton(selected_object=mesh)


hierarchy = rig.hierarchy

elements = hierarchy.get_all_keys()

for e in elements:

print(e)


    #LogPython: <Struct 'RigElementKey' (0x0000052EDB1D92E0) {type: Bone, name: "Bone"}>

#LogPython: <Struct 'RigElementKey' (0x0000052EDB1D63F0) {type: Bone, name: "Bone_end"}>

"""

    hierarchyCtrl = rig.get_hiearchy_controller()

    #add bone

    newBone = hierarchyCtrl.add_bone(name="testBone", parent=unreal.RigElementKey(), transform=unreal.Transform())


    #add an end bone to bone at a given offset

    newLoc = unreal.Transform(location=[0, 0, 5]) #xyz  offset

    endBone = hierarchyCtrl.add_bone(name="testEndBone", parent=newBone, transform=newLoc)

    """


def translateActor(actorName, translateY=5.0):

#shows info on finding an actor by name. and setting an actor location attribute

#unreal.Actor python docs

actorSystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)

actors = actorSystem.get_all_level_actors()


actor = [x for x in actors if x.get_actor_label() == actorName]

if not actor:

return

actor = actor[0]


print(actor)


curLoc = actor.get_actor_location()

newLoc = unreal.Vector(curLoc.x, translateY, curLoc.z)

actor.set_actor_location(newLoc, False, False) #position, sweep, teleport



"""

def addCylinderActor():

#add an actor to scene

print("addCylinderActor")


cylinderMesh = unreal.load_asset('/Engine/BasicShapes/Cylinder') #to get path - can create a sphere and in ui gui can browse to its folder location

#actorClass = unreal.StaticMeshActor

cylinderActor = unreal.EditorLevelLibrary.spawn_actor_from_object(cylinderMesh, unreal.Vector(0,0,10), unreal.Rotator(0,0,0)) #object, translation, rotation

"""


"""

def addCylinderActor_v0():

#add an actor to scene

print("addCylinderActor")


cylinderMesh = unreal.load_asset('/Engine/BasicShapes/Cylinder') #to get path - can create a sphere and in ui gui can browse to its folder location

actorClass = unreal.StaticMeshActor

cylinderActor = unreal.EditorLevelLibrary.spawn_actor_from_class(actorClass, unreal.Vector(0,0,70), unreal.Rotator(0,0,0)) #class, translation, rotation

"""


"""

def printActors():

#print actors in scene


actorSystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)

actors = actorSystem.get_all_level_actors()

print(actors)


def printSelectedActors():

actorSystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)

actors = actorSystem.get_selected_level_actors()

print(actors)

print(len(actors))

unreal.log("printSelectedActors")

#print(type(actors[0]))

#LogPython: <class 'StaticMeshActor'>


#staticMeshComponent = actors[0].get_editor_property("static_mesh_component")

#print(type(staticMeshComponent))

#LogPython: <class 'StaticMeshComponent'>


def translateUpSelectedActors(amount=5):

actorSystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)

actors = actorSystem.get_selected_level_actors()

for actor in actors:

#from unreal.Actor

actor.add_actor_world_offset((0,0,amount), False, False)


"""


#printActors()

#printSelectedActors()

#translateUpSelectedActors(amount=20)

#addCylinderActor()


doIt()


#py "C:\Users\Nathaniel\Documents\unreal_learning\dev_area\topics.py"


#inspired by

#https://forums.unrealengine.com/t/how-to-create-static-mesh-actors-in-level-using-python-script/473670/2



Thanks for looking


inspired by,

Matt Lake MattLakeTA

matthewlake dot net