Bases: HoudiniInstancePlugin
Validate the instance Output Node.
This will ensure
- The Output Node Path is set.
- The Output Node Path refers to an existing object.
- The Output Node is a Sop or Obj node.
- The Output Node has geometry data.
- The Output Node doesn't include invalid primitive types.
Source code in client/ayon_houdini/plugins/publish/validate_fbx_output_node.py
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
137
138
139
140 | class ValidateFBXOutputNode(plugin.HoudiniInstancePlugin):
"""Validate the instance Output Node.
This will ensure:
- The Output Node Path is set.
- The Output Node Path refers to an existing object.
- The Output Node is a Sop or Obj node.
- The Output Node has geometry data.
- The Output Node doesn't include invalid primitive types.
"""
order = pyblish.api.ValidatorOrder
families = ["fbx"]
label = "Validate FBX Output Node"
actions = [SelectROPAction, SelectInvalidAction]
def process(self, instance):
invalid = self.get_invalid(instance)
if invalid:
nodes = [n.path() for n in invalid]
raise PublishValidationError(
"See log for details. "
"Invalid nodes: {0}".format(nodes),
title="Invalid output node(s)"
)
@classmethod
def get_invalid(cls, instance):
output_node = instance.data.get("output_node")
# Check if The Output Node Path is set and
# refers to an existing object.
if output_node is None:
rop_node = hou.node(instance.data["instance_node"])
cls.log.error(
"Output node in '%s' does not exist. "
"Ensure a valid output path is set.", rop_node.path()
)
return [rop_node]
# Check if the Output Node is a Sop or an Obj node
# also, list all sop output nodes inside as well as
# invalid empty nodes.
all_out_sops = []
invalid = []
# if output_node is an ObjSubnet or an ObjNetwork
if output_node.childTypeCategory() == hou.objNodeTypeCategory():
for node in output_node.allSubChildren():
if node.type().name() == "geo":
out = get_obj_node_output(node)
if out:
all_out_sops.append(out)
else:
invalid.append(node) # empty_objs
cls.log.error(
"Geo Obj Node '%s' is empty!",
node.path()
)
if not all_out_sops:
invalid.append(output_node) # empty_objs
cls.log.error(
"Output Node '%s' is empty!",
node.path()
)
# elif output_node is an ObjNode
elif output_node.type().name() == "geo":
out = get_obj_node_output(output_node)
if out:
all_out_sops.append(out)
else:
invalid.append(node) # empty_objs
cls.log.error(
"Output Node '%s' is empty!",
node.path()
)
# elif output_node is a SopNode
elif output_node.type().category().name() == "Sop":
all_out_sops.append(output_node)
# Then it's a wrong node type
else:
cls.log.error(
"Output node %s is not a SOP or OBJ Geo or OBJ SubNet node. "
"Instead found category type: %s %s",
output_node.path(), output_node.type().category().name(),
output_node.type().name()
)
return [output_node]
# Check if all output sop nodes have geometry
# and don't contain invalid prims
invalid_prim_types = ["VDB", "Volume"]
for sop_node in all_out_sops:
# Empty Geometry test
if not hasattr(sop_node, "geometry"):
invalid.append(sop_node) # empty_geometry
cls.log.error(
"Sop node '%s' doesn't include any prims.",
sop_node.path()
)
continue
frame = instance.data.get("frameStart", 0)
geo = sop_node.geometryAtFrame(frame)
if len(geo.iterPrims()) == 0:
invalid.append(sop_node) # empty_geometry
cls.log.error(
"Sop node '%s' doesn't include any prims.",
sop_node.path()
)
continue
# Invalid Prims test
for prim_type in invalid_prim_types:
if geo.countPrimType(prim_type) > 0:
invalid.append(sop_node) # invalid_prims
cls.log.error(
"Sop node '%s' includes invalid prims of type '%s'.",
sop_node.path(), prim_type
)
if invalid:
return invalid
|