Community
FBX Forum
Welcome to Autodesk’s FBX Forums. Share your knowledge, ask questions, and explore popular FBX topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Exporting multiple fbx per-object from a source scene (Issue preserving connections)

1 REPLY 1
Reply
Message 1 of 2
RobertLutz-WPM
276 Views, 1 Reply

Exporting multiple fbx per-object from a source scene (Issue preserving connections)

 

Hi,

 

I'm developing a system where I need to load an FBX file that was generated from 3dsmax, then iterate through the objects, and export each individual object to an FBX file.

 

I think I'm close. This script is opening my source FBX file, iterating through the nodes and then writing out each one to a new file. The problem I'm struggling with is how to preserve the material connections in the individual FBX output files.

 

I followed along with the merge scene example as a base for this, and from what I can tell the issue is that as I'm iterating through the child nodes and disconnecting from the source scene/reconnecting to the destination scene it is making it so that nodes that are processed later in the iteration don't have access to the objects that they are connected to since the materials are shared amongst multiple nodes. 

 

I can see this if I view an object like this for example, the first of it's type to be exported:

Connections are intact, materials show up in model when imported in DCCConnections are intact, materials show up in model when imported in DCCMaterial connections are not in ASCII, no material assignments when viewing in DCCMaterial connections are not in ASCII, no material assignments when viewing in DCC

The first object of this type is correct, it has it's materials and they show up as connections listed in the ASCII. The second object of this type has no materials assigned when imported into Maya. I confirmed that the ASCII has no material connections listed. Most of the exported objects are this way, missing some or all of their material connections.

 

I'm beginning to think that my approach is wrong. The next thing I tried was maintaining dicts of cloned objects and connecting them, but I'm getting the same result. I feel that there's a simple solution to this that I'm not seeing.

 

Here's the code:

from fbx import *
from FbxCommon import *

'''
FBX Copy scene
'''

SRC_FILEPATH = r"D:\_dev\fbxSdk\fbx\input\test_scene.fbx"
OUT_ROOTPATH = r"D:\_dev\fbxSdk\fbx\output"

def get_childNodes(scene):
    numChildren = scene.GetRootNode().GetChildCount()
    childNodes = []
    for i in range(0, numChildren):
        # Obtain a child node from the source scene
        childNode = scene.GetRootNode().GetChild(i)
        # Save it
        childNodes.append(childNode)
    return childNodes

'''
FBX Setup
'''
sdk_manager = FbxManager.Create()

src_scene = FbxScene.Create(sdk_manager, "src")

importer = FbxImporter.Create(sdk_manager, "importer")
importstat = importer.Initialize(SRC_FILEPATH, -1)

# Import the fbx into the source scene
importer.Import(src_scene)

# File is imported, it is safe to destroy
importer.Destroy()
importer = None

'''
FBX Move contents into new scene

This is exporting the mesh correctly, and all of the materials
are showing up when viewing the FBX ASCII, but seems the connections
are not intact because of disconnecting the fbx objects in the loop.

Only the first node that is processed in the loop with given 
fbx object connections has the correct material connections.
'''

# Get child nodes of source scene
childNodes = get_childNodes(src_scene)
for childNode in childNodes:

    clean_name = childNode.GetName().replace('"', '').replace('/', '')
    export_path = os.path.join(OUT_ROOTPATH,"{}.fbx".format(clean_name))

    # Create destination scene to copy into
    dst_scene = FbxScene.Create(sdk_manager, clean_name)

    # Move the node tree of the source scene into the destination scene
    dst_scene.GetRootNode().AddChild(childNode)

    # Remove the children from the root node of the source scene
    src_scene.GetRootNode().DisconnectSrcObject(childNode)

    # Move other objects to the destination scene
    numSceneObjects = src_scene.GetSrcObjectCount()

    for i in range(0, numSceneObjects):
        fbxObj = src_scene.GetSrcObject(i)
        
        if not fbxObj or fbxObj == src_scene.GetRootNode() or fbxObj == src_scene.GetGlobalSettings() or type(fbxObj) == FbxAnimEvaluator:
            continue

        # Check if the current fbx object is connected as a destination from the source child node
        if fbxObj.IsConnectedDstObject(childNode):

            if isinstance(fbxObj, FbxSurfaceMaterial) or isinstance(fbxObj, FbxMesh):
                print("connect {} to dst_scene".format(fbxObj.GetName()))
                
                # Connect it to scene
                fbxObj.ConnectDstObject(dst_scene)

        # Disconnect from source scene
        src_scene.DisconnectSrcObject(fbxObj)

    exporter = FbxExporter.Create(sdk_manager, "{}_exp".format(dst_scene.GetName()))
    exportstat = exporter.Initialize(export_path, -1)
    exporter.Export(dst_scene)

 

Thank you!!

 

 

1 REPLY 1
Message 2 of 2

I found a solution to this today in case this helps anyone.

 

Since I only wanted to load a main source scene once and copy each object in the tree into it's own scene for export, I found it simpler to just create new materials for each node:

 

'''
FBX Move contents into new scene per-object

'''

# Get child nodes of source scene
childNodes = get_childNodes(src_scene)

for childNode in childNodes:

    clean_name = childNode.GetName().replace('"', '').replace('/', '')
    DST_FILEPATH = os.path.join(ROOTPATH,"{}.fbx".format(clean_name))

    # Create destination scene to copy into
    dst_scene = FbxScene.Create(sdk_manager, clean_name)

    # Move the node tree of the source scene into the destination scene
    dst_scene.GetRootNode().AddChild(childNode)
    
    # Remove objects from src scene
    src_scene.GetRootNode().DisconnectSrcObject(childNode)
    src_scene.DisconnectAllSrcObject()

    attrType = childNode.GetNodeAttribute().GetAttributeType()
    if attrType == FbxNodeAttribute.eMesh:
        for i in range(childNode.GetMaterialCount()):
            lMaterial = childNode.GetMaterial(i)

            mat = get_new_material(lMaterial, dst_scene)
            childNode.AddMaterial(mat)

    exporter = FbxExporter.Create(sdk_manager, "{}_exp".format(dst_scene.GetName()))
    exportstat = exporter.Initialize(DST_FILEPATH, get_ascii_format_id(sdk_manager))
    exporter.Export(dst_scene)

    exporter.Destroy()


def get_new_material(lMaterial, scene):
    '''
    Create a new material based on the FbxSurface Class Id
    Get/Set properties from the source material.
    '''
    if (lMaterial.GetClassId().Is(FbxSurfacePhong.ClassId)):
        
        mat = FbxSurfacePhong.Create(scene, lMaterial.GetName())

        mat.ShadingModel.Set(lMaterial.ShadingModel.Get())
        mat.Ambient.Set(lMaterial.Ambient.Get())
        mat.Diffuse.Set(lMaterial.Diffuse.Get())
        mat.Specular.Set(lMaterial.Specular.Get())
        mat.Emissive.Set(lMaterial.Emissive.Get())
        mat.EmissiveFactor.Set(lMaterial.EmissiveFactor.Get())
        mat.TransparencyFactor.Set(lMaterial.TransparencyFactor.Get())
        mat.TransparentColor.Set(lMaterial.TransparentColor.Get())
        mat.Shininess.Set(lMaterial.Shininess.Get())
        mat.Reflection.Set(lMaterial.Reflection.Get())

    elif lMaterial.GetClassId().Is(FbxSurfaceLambert.ClassId):
        
        mat = FbxSurfaceLambert.Create(scene, lMaterial.GetName())

        mat.ShadingModel.Set(lMaterial.ShadingModel.Get())
        mat.Ambient.Set(lMaterial.Ambient.Get())
        mat.Diffuse.Set(lMaterial.Diffuse.Get())
        mat.Emissive.Set(lMaterial.Emissive.Get())
        mat.TransparencyFactor.Set(lMaterial.TransparencyFactor.Get())
        mat.TransparentColor.Set(lMaterial.TransparentColor.Get())
    else:
        print("Error: Unknown type of Material")

    return mat

 

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report