Hello,
I am trying to load glb/gtlf in ue5.6 with python scripting in order to render rgb, normals, depth.
Currently i am having issue with the materials and textures not loading correctly, in the rgb renders i see the object’s geometry / static mesh being loaded but with a generic base texture applied to it.
I am not gonna lie I am quite new to the python API so with the help of chatgpt and reading the documentation here : Unreal Python API Documentation — Unreal Python 5.6 (Experimental) documentation i was able to write the following code python script.
The import_gltf_asset
allows me to import the assets, i then return the imported_paths that i can use to later load the assets. The merge_imported_static_meshes
function basically reads all the static meshes and combines them using the merge merge_static_mesh_actors
function i found in the documentation. The issue is that it seems the materials / textures are not being used correctly during the rendering.
Can any experts on python scripting help me out here ? And fyi for the rendering part i simply used the merged actor and using cameraactor, render targets and SceneCaptureSource i am able to render the objects to render the rgb, depth and normals.
To debug the isssue I also added material_path=None
i am able to perfectly apply a custom material so the rendering seems to works just fine. It seems i am not able to render with the original materials present in the gltf/glb files.
I suspect i did something wrong while loading the assets or when i am merging the static meshes into a single actor.
def import_gltf_asset(gltf_file_path, destination_path="/Game/Imported"):
"""
Import assets into project.
"""
# list of files to import
fileNames = [gltf_file_path]
# create asset tools object
assetTools = unreal.AssetToolsHelpers.get_asset_tools()
# create asset import data object
assetImportData = unreal.AutomatedAssetImportData()
# set assetImportData attributes
assetImportData.destination_path = destination_path
assetImportData.filenames = fileNames
assetImportData.replace_existing = True
imported_assets = assetTools.import_assets_automated(assetImportData)
imported_paths = []
if imported_assets:
for asset in imported_assets:
if asset:
path = asset.get_path_name()
imported_paths.append(path)
return None if not imported_paths else imported_paths
def merge_imported_static_meshes(
imported_paths,
location=unreal.Vector(0,0,0),
rotation=unreal.Rotator(0,0,0),
base_package_name="/Game/Create/SM_Merged",
merged_actor_label="Merged Actor",
material_path=None
):
# First, find and compile all materials in imported assets
find_and_compile_materials_in_imported_assets(imported_paths)
# Step 0: Load and compile override material if specified
override_material = None
if material_path:
override_material = unreal.EditorAssetLibrary.load_asset(material_path)
if override_material:
try:
unreal.MaterialEditingLibrary.recompile_material(override_material)
unreal.log(f"Loaded and compiled override material: {material_path}")
except Exception as e:
unreal.log_warning(f"Could not recompile override material: {e}")
else:
unreal.log_warning(f"Could not load override material: {material_path}")
# Step 1: Find all StaticMesh assets and prepare them
meshes = []
for path in imported_paths:
asset = unreal.EditorAssetLibrary.load_asset(path)
if isinstance(asset, unreal.StaticMesh):
unreal.log(f"StaticMesh found: {path}")
# Force materials ready for each mesh
force_materials_ready(asset)
# Only apply override material if specified, otherwise preserve original materials
if override_material:
num_sections = asset.get_num_sections(0) # LOD 0
for idx in range(num_sections):
asset.set_material(idx, override_material)
unreal.log(f"Applied override material to mesh {path}")
else:
unreal.log(f"Preserving original materials for mesh {path}")
meshes.append(asset)
unreal.log(f"Found {len(meshes)} static meshes")
if not meshes:
unreal.log_warning("No StaticMesh assets found to merge.")
return None
# Step 2: Spawn StaticMeshActors in the level
actors_to_merge = []
for i, mesh in enumerate(meshes):
actor = unreal.EditorLevelLibrary.spawn_actor_from_object(mesh, location, rotation)
# Ensure the spawned actor's mesh component has materials properly set
mesh_comp = actor.get_component_by_class(unreal.StaticMeshComponent)
if mesh_comp:
# Force refresh materials on the component
mesh_comp.set_static_mesh(mesh)
unreal.log(f"Refreshed materials on spawned actor {i}")
actors_to_merge.append(actor)
if not actors_to_merge:
unreal.log_warning("No actors spawned to merge.")
return None
# Step 3: Set up merge options with material preservation
staticMeshSubsystem = unreal.get_editor_subsystem(unreal.StaticMeshEditorSubsystem)
merge_options = unreal.MergeStaticMeshActorsOptions()
merge_options.base_package_name = base_package_name
merge_options.destroy_source_actors = True
merge_options.new_actor_label = merged_actor_label
merge_options.spawn_merged_actor = True
# Enhanced mesh merging settings for better material preservation
merge_options.mesh_merging_settings.bake_vertex_data_to_mesh = False
merge_options.mesh_merging_settings.computed_light_map_resolution = False
merge_options.mesh_merging_settings.generate_light_map_uv = False
merge_options.mesh_merging_settings.lod_selection_type = unreal.MeshLODSelectionType.ALL_LO_DS
merge_options.mesh_merging_settings.merge_physics_data = True
merge_options.mesh_merging_settings.pivot_point_at_zero = True
# Important: These settings help preserve materials
merge_options.mesh_merging_settings.bake_vertex_data_to_mesh = False
merge_options.mesh_merging_settings.use_vertex_data_for_baking_material = False
merge_options.mesh_merging_settings.use_texture_binning = False
# Step 4: Merge actors into a single StaticMesh asset
merged_mesh = staticMeshSubsystem.merge_static_mesh_actors(actors_to_merge, merge_options)
if merged_mesh:
unreal.log(f"Merged {len(actors_to_merge)} actors into: {merged_mesh.get_name()}")
# Force compile materials on the merged mesh
force_materials_ready(merged_mesh)
return merged_mesh
else:
unreal.log_warning("Failed to merge actors.")
return None
imported_paths = import_gltf_asset(object_file_path, destination_path)
actor = merge_imported_static_meshes(imported_paths)