Nanite Assembly/ USD Stage Import Python Script

Hello I am working on Blender -> Unreal Nanite Assembly pipeline. I have produced Blender Exporter that is able to export Nanite Assembly compatible USD files, which can be manually imported into Unreal and work as expected.

Since we are trying to achieve some data separation and order in our assets we have source data and content split, but they have mirrored folder structure (for example SourceContent/Objects/Vegetation/Tree.fbx -> will get imported as -> Content/Objects/Vegetation/Tree.uasset).

Because we want to adhere to our rules as much as possible I am also automating the import after the export (if the editor is running). We have already a few specific import scripts but for fbx and they are using InterchangePipeline Assets which afaik are not usable for Usd Stage import.

For now I have an import function that works:

def import_usd_asset(source_path: str, destination_path: str) -> None:
    if not os.path.isfile(source_path):
        wh_warnings.warn(f"File doesn't exist: \'{source_path}\'")
        return

    if not unreal.EditorAssetLibrary.does_directory_exist(destination_path):
        unreal.EditorAssetLibrary.make_directory(destination_path)

    task = unreal.AssetImportTask() 
    task.filename = source_path
    task.destination_path = destination_path
    task.automated = True
    task.replace_existing = True
    task.save = True
    
    asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
    asset_tools.import_asset_tasks([task])

But it may not work the same on every PC especially if someone tinkered with the manual Usd Import settings. Therefore I have been trying to somehow set up the import so it will be always the same as needed.

I tried linking UsdStageImportOptions and UsdStageImportFactory with the import task but it resulted in Unreal being unable to import the asset alltogether. Also I was trying to create the options as follows:

Later on I stumbled upon UsdStageEditorLibrary which allows importing of the opened stage and not only that but allows setting up ImportOptions and the import directory! Sounds great.

Sadly, even though I set up the import destination for example to: /Game/Objects/Vegetation/ it would import everything to the /Game/UsdAssets folder and create new UsdAssetCache (which we might use later, but for now we decided to go with the simplest route that works and refine it later). And also I set in the UsdStageImportOptions the parameter of use_existing_asset_cache to False. So seems like it ignores everything.

unreal.UsdStageEditorLibrary.file_open(source_path)
unreal.UsdStageEditorLibrary.actions_import(destination_path, import_options)
unreal.UsdStageEditorLibrary.file_close()

At this point I am really confused. Because I can see like 2-3 different solutions which none seems to meet our needs.

Do you have any recommendations for the Usd Import unification? If there is better epic way of the Nanite Assembly storage and import I would like to hear it. The documentation as of now is sparse and I can not see what is the designated Unreal way for this pipeline.

Thanks for any and all help.

PS: Here is how I was trying to create the import options, as I said we would prefer to have one InterchangePipeline Asset that we would just reuse during the import script but that is not an option. I saw some InterchangeTranslator forum post but I am not sure if that would be something we need.

def get_usd_stage_import_options() -> unreal.UsdStageImportOptions:
    import_options = unreal.UsdStageImportOptions()
    
    import_options.import_actors = False
    import_options.import_at_specific_time_code = False
    import_options.import_geometry = True
    # ... More import options here
    import_options.share_assets_for_identical_prims = True
    import_options.use_existing_asset_cache = False
    
    # There is also Stage Options as an attribute, but we do not override it.
    
    return import_options

Steps to Reproduce
You can reproduce the UsdStageEditorLibrary issues by trying to call actions_import with destination folder and UsdStageImportSettings and it should not work properly. It imports assets into /Game/UsdAssets and also sometimes did not even import all of the assets needed for the assembly (when I tried closing the stage window after actions_import).

One thing that is good to mention in my opinion is that we are using Unreal 5.8.0

Maybe I was too quick to ask since this:

def get_usd_stage_import_options() -> unreal.UsdStageImportOptions:
    import_options = unreal.UsdStageImportOptions()
 
    import_options.import_actors = False
    import_options.import_geometry = True
    import_options.import_materials = False
    import_options.import_skeletal_animations = False
    import_options.existing_asset_policy = unreal.ReplaceAssetPolicy.REPLACE
    import_options.existing_actor_policy = unreal.ReplaceActorPolicy.REPLACE 
 
    return import_options

works when assigned to the task.options without issues. Maybe the problem is with some specific option/s.

Hello,

There were a couple of recent articles posted on EDC about Nanite Assemblies here that may be helpful if you haven’t already had the opportunity to read them:

Nanite Assemblies in USD: Part 2 - Houdini Tutorials | Tutorial (Houdini example, not Blender)

As for the USD importer modifications I’m passing this issue to a colleague who is more familiar with that area.

Hi Ondrej,

Can you clarify, is your problem fixed now with your updated get_usd_stage_import_options()? Because using unreal.AssetImportTask() with unreal.UsdStageImportOptions is indeed the correct way to specify the import options and do an import with the USDImporter.

Also, since you’re using 5.8, it is now possible to import Nanite assemblies through the Interchange OpenUSD plugin. Why are you saying it’s not an option for you?

Yes we had it disabled, I will ask our devops team to enable it. Thank you for this nugget of information.

For your information, Nanite Assembly support was added to Interchange in 5.7, along with the new Nanite Assembly USD schemas, so the setup is a bit different from before 5.7. This new setup is the recommended approach and that’s what we support going forward (the pages that Alex posted earlier).

For using Interchange with Python, you can check this page with an example showing how to support different pipelines: https://dev.epicgames.com/documentation/en\-us/unreal\-engine/importing\-assets\-using\-interchange\-in\-unreal\-engine\#import\-an\-asset\-using\-python

Well, my bad, I did not know that was an option, maybe the OpenUSD plugin is not installed or enabled in our version (yet) since I tried looking for USDInterchange assets, then I would just use them.

And yes I fixed it by getting rid of some nonessential options and it started working. I’ll look into the OpenUSD inerchange plugin.

Thank you very much!

We know about those. I was going through them a few weeks ago.