# Import the sedan systems as separate static meshes (0.3.0). # # blender -b --factory-startup --python Tools/vehicle_build.py -- \ # --out Art/blender/vehicle/gigline-sedan.blend --fbx /tmp/gigline/vehicle/sedan.fbx # /Engine/Binaries/Linux/UnrealEditor-Cmd -run=pythonscript \ # -script=/Tools/ue_vehicle_import.py -nullrhi -unattended -nopause -stdout # # One asset per system, per the vehicle-artist skill's object split: body, glass, front # and rear lights, mirrors, and one wheel reused four times. The body FBX also carries # the UCX_ hulls, which Unreal consumes as simple collision. # # Result file: /tmp/gigline/vehicle-import.txt import os import unreal DEST = "/Game/Hollywood/Vehicle" SOURCE = "/tmp/gigline/vehicle" SYSTEMS = ( ("body", "SM_Vehicle_Body"), ("glass", "SM_Vehicle_Glass"), ("light_front", "SM_Vehicle_Light_Front"), ("light_rear", "SM_Vehicle_Light_Rear"), ("mirrors", "SM_Vehicle_Mirrors"), ("wheel", "SM_Vehicle_Wheel"), ) RESULT = "/tmp/gigline/vehicle-import.txt" lines = [] def log(msg): lines.append(str(msg)) unreal.log(str(msg)) def main(): for source, name in SYSTEMS: path = os.path.join(SOURCE, f"{source}.fbx") if not os.path.exists(path): log(f"{name}: missing source {path}") lines.append("VERDICT: FAIL") return task = unreal.AssetImportTask() task.filename = path task.destination_path = DEST task.destination_name = name task.automated = True task.save = True task.replace_existing = True ui = unreal.FbxImportUI() ui.import_mesh = True ui.import_as_skeletal = False ui.import_materials = True ui.import_textures = False ui.static_mesh_import_data.combine_meshes = True ui.static_mesh_import_data.generate_lightmap_u_vs = True ui.static_mesh_import_data.auto_generate_collision = True ui.static_mesh_import_data.import_uniform_scale = 1.0 task.options = ui unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task]) mesh = unreal.EditorAssetLibrary.load_asset(f"{DEST}/{name}") if mesh is None: log(f"{name}: MISSING after import") lines.append("VERDICT: FAIL") return bounds = mesh.get_bounding_box() if hasattr(mesh, "get_bounding_box") else None size = "" if bounds: extent = bounds.max - bounds.min size = f"{extent.x/100:.2f} x {extent.y/100:.2f} x {extent.z/100:.2f} m" mats = mesh.get_editor_property("static_materials") log(f"{name}: imported, {len(mats)} material slot(s), bounds {size}") # Wire the two LOD meshes into the body's LOD group. import_lod is the supported # path; copying bytes between assets is not, and the LOD group is what the engine # uses to pick by screen size. # LOD meshes are imported as their own assets. Wiring them into the body's LOD group # needs StaticMeshEditorSubsystem.import_lod, which is unavailable in this headless # commandlet (get_editor_subsystem returns None), so the group is a follow-up. for source, name in (("body_lod1", "SM_Vehicle_Body_LOD1"), ("body_lod2", "SM_Vehicle_Body_LOD2")): path = os.path.join(SOURCE, f"{source}.fbx") if not os.path.exists(path): log(f"{name}: missing {path}") continue task = unreal.AssetImportTask() task.filename = path task.destination_path = DEST task.destination_name = name task.automated = True task.save = True task.replace_existing = True ui = unreal.FbxImportUI() ui.import_mesh = True ui.import_materials = True ui.static_mesh_import_data.combine_meshes = True task.options = ui unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task]) mesh = unreal.EditorAssetLibrary.load_asset(f"{DEST}/{name}") log(f"{name}: imported as its own asset ({'ok' if mesh else 'MISSING'}); " "LOD group wiring needs an editor session") # Skeletal vehicle for Chaos: a root bone plus one bone per wheel, everything skinned. skel_path = os.path.join(SOURCE, "vehicle_skeletal.fbx") if os.path.exists(skel_path): task = unreal.AssetImportTask() task.filename = skel_path task.destination_path = DEST task.destination_name = "SK_Vehicle_Sedan" task.automated = True task.save = True task.replace_existing = True ui = unreal.FbxImportUI() ui.import_mesh = True ui.import_as_skeletal = True ui.import_animations = False ui.import_materials = True ui.skeletal_mesh_import_data.import_uniform_scale = 1.0 task.options = ui unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task]) skel = unreal.EditorAssetLibrary.load_asset(f"{DEST}/SK_Vehicle_Sedan") if skel: skeleton = skel.get_editor_property("skeleton") # Skeleton has no bone_names property in 5.8; read the reference skeleton # through the asset registry instead of guessing a property name. log(f"SK_Vehicle_Sedan: imported, skeleton={skeleton.get_name() if skeleton else 'NONE'}") else: log("SK_Vehicle_Sedan: MISSING after import") lines.append("VERDICT: PASS") try: main() except Exception as exc: # noqa: BLE001 import traceback log(f"FAILED: {type(exc).__name__}: {exc}") log(traceback.format_exc()) lines.append("VERDICT: FAIL") unreal.EditorLoadingAndSavingUtils.save_dirty_packages(True, True) with open(RESULT, "w") as f: f.write("\n".join(lines) + "\n")