Skip to content

load_placeholder

HoudiniPlaceholderLoadPlugin

Bases: HoudiniPlaceholderPlugin, PlaceholderLoadMixin

Workfile template plugin to create "load placeholders".

"load placeholders" will be replaced by AYON products.

Source code in client/ayon_houdini/plugins/workfile_build/load_placeholder.py
 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
137
138
139
140
141
142
class HoudiniPlaceholderLoadPlugin(
    HoudiniPlaceholderPlugin, PlaceholderLoadMixin
):
    """Workfile template plugin to create "load placeholders".

    "load placeholders" will be replaced by AYON products.

    """

    identifier = "ayon.load.placeholder"
    label = "Houdini Load"

    def create_placeholder(self, placeholder_data):
        node_name = self.get_placeholder_node_name(placeholder_data)
        # Create a placeholder node that can actually act as stub inside
        # a Houdini scene with the real deal, including input/output
        # connections
        loader_name: str = placeholder_data["loader"]
        loaders_by_name = self.builder.get_loaders_by_name()
        loader = loaders_by_name[loader_name]

        # Allow Loader plug-ins to define what kind of placeholder node to
        # create so they are relevant to the node context that eventually
        # gets created by the loader.
        if hasattr(loader, "create_load_placeholder_node"):
            placeholder_node = loader().create_load_placeholder_node(
                node_name,
                placeholder_data
            )
        else:
            placeholder_node = self.create_placeholder_node(node_name)

        HoudiniCreator.customize_node_look(placeholder_node)

        placeholder_data["plugin_identifier"] = self.identifier
        self._imprint(placeholder_node, placeholder_data)

    def populate_placeholder(self, placeholder):
        self.populate_load_placeholder(placeholder)

    def repopulate_placeholder(self, placeholder):
        self.populate_load_placeholder(placeholder)

    def get_placeholder_options(self, options=None):
        return self.get_load_plugin_options(options)

    def get_placeholder_node_name(self, placeholder_data):
        node_name = "{}_{}".format(
            self.identifier.replace(".", "_"),
            placeholder_data["product_name"]
        )
        return node_name

    def collect_placeholders(self):
        output = []
        load_placeholders = self.collect_scene_placeholders()

        for node in load_placeholders:
            placeholder_data = self._read(node)
            output.append(
                LoadPlaceholderItem(node.path(), placeholder_data, self)
            )

        return output

    # Take control of loaded repre data
    def load_succeed(self, placeholder, container):
        # Move the container to the placeholder and transfer connections
        placeholder_node = hou.node(placeholder.scene_identifier)
        target_context = placeholder_node.parent()

        # If placeholder node is an object merge then do not move the container
        # node, but instead set the object merge to point to the container node
        if placeholder_node.type().category().name() == "Sop":
            name = container.name().removesuffix("_CON")
            node = target_context.createNode(
                "object_merge",
                node_name=name,
                force_valid_node_name=True
            )
            node.setParms({
                "objpath1": container.path()
            })
        else:
            if container.parent() == target_context:
                node = container
            else:
                node = hou.moveNodesTo(
                    [container],
                    target_context,
                )[0]

        node.setPosition(placeholder_node.position())

        self.transfer_node_connections(placeholder_node, node)

    def transfer_node_connections(self, source_node, target_node):
        """Transfer input and output connections from source to target node.

        The source node is the placeholder node.
        The target node is the loaded container node.
        """
        # Transfer input connections
        for conn in source_node.inputConnections():
            target_node.setInput(
                conn.inputIndex(),
                conn.inputNode(),
                conn.outputIndex(),
            )

        # Transfer output connections
        for conn in source_node.outputConnections():
            # When going through `merge` target nodes insert new
            # connections so multiple loaded placeholders can all add into
            # a single merge.
            output_node = conn.outputNode()
            if output_node.type().name() == "merge":
                # Insert the connection after the placeholder connection
                output_node.insertInput(
                    conn.inputIndex() + 1,
                    target_node,
                    conn.outputIndex(),
                )
            else:
                output_node.setInput(
                    conn.inputIndex(),
                    target_node,
                    conn.outputIndex(),
                )

transfer_node_connections(source_node, target_node)

Transfer input and output connections from source to target node.

The source node is the placeholder node. The target node is the loaded container node.

Source code in client/ayon_houdini/plugins/workfile_build/load_placeholder.py
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
137
138
139
140
141
142
def transfer_node_connections(self, source_node, target_node):
    """Transfer input and output connections from source to target node.

    The source node is the placeholder node.
    The target node is the loaded container node.
    """
    # Transfer input connections
    for conn in source_node.inputConnections():
        target_node.setInput(
            conn.inputIndex(),
            conn.inputNode(),
            conn.outputIndex(),
        )

    # Transfer output connections
    for conn in source_node.outputConnections():
        # When going through `merge` target nodes insert new
        # connections so multiple loaded placeholders can all add into
        # a single merge.
        output_node = conn.outputNode()
        if output_node.type().name() == "merge":
            # Insert the connection after the placeholder connection
            output_node.insertInput(
                conn.inputIndex() + 1,
                target_node,
                conn.outputIndex(),
            )
        else:
            output_node.setInput(
                conn.inputIndex(),
                target_node,
                conn.outputIndex(),
            )