Skip to content

load_fbx

Fbx Loader for houdini.

FbxLoader

Bases: HoudiniLoader

Load fbx files.

Source code in client/ayon_houdini/plugins/load/load_fbx.py
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
class FbxLoader(plugin.HoudiniLoader):
    """Load fbx files. """

    label = "Load FBX"
    icon = "code-fork"
    color = "orange"

    order = -10

    product_types = {"*"}
    representations = {"*"}
    extensions = {"fbx"}

    def load(self, context, name=None, namespace=None, data=None):
        # get file path from context
        file_path = self.filepath_from_context(context)
        file_path = file_path.replace("\\", "/")

        # get necessary data
        namespace, node_name = self.get_node_name(context, name, namespace)

        # create load tree
        nodes = self.create_load_node_tree(file_path, node_name, name)

        self[:] = nodes

        # Call containerise function which does some automations for you
        #  like moving created nodes to the AVALON_CONTAINERS subnetwork
        containerised_nodes = pipeline.containerise(
            node_name,
            namespace,
            nodes,
            context,
            self.__class__.__name__,
            suffix="",
        )

        return containerised_nodes

    def update(self, container, context):
        node = container["node"]
        try:
            file_node = next(
                n for n in node.children() if n.type().name() == "file"
            )
        except StopIteration:
            self.log.error("Could not find node of type `file`")
            return

        # Update the file path from representation
        file_path = self.filepath_from_context(context)
        file_path = file_path.replace("\\", "/")

        file_node.setParms({"file": file_path})

        # Update attribute
        node.setParms({"representation": context["representation"]["id"]})

    def remove(self, container):
        node = container["node"]
        node.destroy()

    def switch(self, container, context):
        self.update(container, context)

    def get_node_name(self, context, name=None, namespace=None):
        """Define node name."""

        if not namespace:
            namespace = context["folder"]["name"]

        if namespace:
            node_name = "{}_{}".format(namespace, name)
        else:
            node_name = name

        return namespace, node_name

    def create_load_node_tree(self, file_path, node_name, product_name):
        """Create Load network.

        you can start building your tree at any obj level.
        it'll be much easier to build it in the root obj level.

        Afterwards, your tree will be automatically moved to
        '/obj/AVALON_CONTAINERS' subnetwork.
        """
        # Get the root obj level
        obj = hou.node("/obj")

        # Create a new obj geo node
        parent_node = obj.createNode("geo", node_name=node_name)

        # In older houdini,
        # when reating a new obj geo node, a default file node will be
        # automatically created.
        # so, we will delete it if exists.
        file_node = parent_node.node("file1")
        if file_node:
            file_node.destroy()

        # Create a new file node
        file_node = parent_node.createNode("file", node_name=node_name)
        file_node.setParms({"file": file_path})

        # Create attribute delete
        attribdelete_name = "attribdelete_{}".format(product_name)
        attribdelete = parent_node.createNode("attribdelete",
                                              node_name=attribdelete_name)
        attribdelete.setParms({"ptdel": "fbx_*"})
        attribdelete.setInput(0, file_node)

        # Create a Null node
        null_name = "OUT_{}".format(product_name)
        null = parent_node.createNode("null", node_name=null_name)
        null.setInput(0, attribdelete)

        # Ensure display flag is on the file_node input node and not on the OUT
        # node to optimize "debug" displaying in the viewport.
        file_node.setDisplayFlag(True)

        # Set new position for children nodes
        parent_node.layoutChildren()

        # Return all the nodes
        return [parent_node, file_node, attribdelete, null]

create_load_node_tree(file_path, node_name, product_name)

Create Load network.

you can start building your tree at any obj level. it'll be much easier to build it in the root obj level.

Afterwards, your tree will be automatically moved to '/obj/AVALON_CONTAINERS' subnetwork.

Source code in client/ayon_houdini/plugins/load/load_fbx.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
def create_load_node_tree(self, file_path, node_name, product_name):
    """Create Load network.

    you can start building your tree at any obj level.
    it'll be much easier to build it in the root obj level.

    Afterwards, your tree will be automatically moved to
    '/obj/AVALON_CONTAINERS' subnetwork.
    """
    # Get the root obj level
    obj = hou.node("/obj")

    # Create a new obj geo node
    parent_node = obj.createNode("geo", node_name=node_name)

    # In older houdini,
    # when reating a new obj geo node, a default file node will be
    # automatically created.
    # so, we will delete it if exists.
    file_node = parent_node.node("file1")
    if file_node:
        file_node.destroy()

    # Create a new file node
    file_node = parent_node.createNode("file", node_name=node_name)
    file_node.setParms({"file": file_path})

    # Create attribute delete
    attribdelete_name = "attribdelete_{}".format(product_name)
    attribdelete = parent_node.createNode("attribdelete",
                                          node_name=attribdelete_name)
    attribdelete.setParms({"ptdel": "fbx_*"})
    attribdelete.setInput(0, file_node)

    # Create a Null node
    null_name = "OUT_{}".format(product_name)
    null = parent_node.createNode("null", node_name=null_name)
    null.setInput(0, attribdelete)

    # Ensure display flag is on the file_node input node and not on the OUT
    # node to optimize "debug" displaying in the viewport.
    file_node.setDisplayFlag(True)

    # Set new position for children nodes
    parent_node.layoutChildren()

    # Return all the nodes
    return [parent_node, file_node, attribdelete, null]

get_node_name(context, name=None, namespace=None)

Define node name.

Source code in client/ayon_houdini/plugins/load/load_fbx.py
76
77
78
79
80
81
82
83
84
85
86
87
def get_node_name(self, context, name=None, namespace=None):
    """Define node name."""

    if not namespace:
        namespace = context["folder"]["name"]

    if namespace:
        node_name = "{}_{}".format(namespace, name)
    else:
        node_name = name

    return namespace, node_name