def deserialize_from_dict( nodes_data: List[Dict[str, Any]], parent: hou.Node ) -> List[hou.Node]: nodes = [] for node_data in nodes_data: node_instance = node.deserialize_from_dict(node_data, parent) nodes.append(node_instance) # create connections for node_data in nodes_data: node_instance: hou.Node = parent.node(node_data["name"]) if node_instance: for connection_data in node_data["inputConnections"]: input_node = parent.node(connection_data["inputNode"]) if input_node: node_instance.setInput( input_index=connection_data["inputIndex"], item_to_become_input=input_node, output_index=connection_data["outputIndex"], ) return nodes
def get_parms_commandline(node: hou.Node) -> list[str]: parms_multiparm: hou.Parm = node.parm("params") start_index = parms_multiparm.multiParmStartOffset() num_parms = parms_multiparm.evalAsInt() value_command = [] for i in range(start_index, start_index + num_parms): parm_type = node.parm(f"graph_parm_type{i}").evalAsString() parm_name = node.parm(f"graph_parm_name{i}").evalAsString() parm_value_name = value_map[parm_type].format(i) use_color = node.parm(f"use_color_editor{i}").evalAsInt() if parm_type == "FLOAT3" and use_color: parm_value_name = f"rgb_value{i}" if parm_type == "FLOAT4" and use_color: parm_value_name = f"rgba_value{i}" value_parm: hou.ParmTuple = node.parmTuple(parm_value_name) value = value_parm.eval() value_command += [ "--set-value", f"{parm_name}@{','.join((str(v) for v in value))}" ] return value_command
def get_time_commandline(node: hou.Node): time_type = node.parm("time_type").evalAsString() time = 0.0 (frame_start, frame_end, _) = node.parmTuple("f").eval() frame = hou.frame() if time_type == "range": time = (frame - frame_start) / (frame_end - frame_start) elif time_type == "range_loop": time = (frame - frame_start) / (frame_end - frame_start + 1.0) elif time_type == "custom": time = node.evalParm("time") return ["--set-value", f"$time@{time}"]
def get_matched_graphs(node: hou.Node, sbsar_json: dict) -> list[str]: graphs = sbsar_json["graphs"] pattern = node.parm("output_graphs").evalAsString() pattern = pattern.strip() if not pattern or pattern == "*": return sbsar_json["graphs"].keys() return [graph for graph in graphs if hou.text.patternMatch(pattern, graph)]
def fill_outputs_from_json(node: hou.Node): sbsar_json = load_sbsar_json(node) sbs_graphs = sbsar_json["graphs"] graphs = get_matched_graphs(node, sbsar_json) outputs_multiparm: hou.Parm = node.parm("graph_outputs") output_names = get_multiparm_tuples(outputs_multiparm, ("output_name{}", "output_type{}")) outputs = list( set( it.chain.from_iterable(sbs_graphs[graph]["outputs"] for graph in graphs))) for outp in outputs: if (outp, 0) not in output_names: last_index = outputs_multiparm.eval() outputs_multiparm.insertMultiParmInstance(last_index) node.parm(f"output_name{last_index + 1}").set(outp)
def fill_inputs_from_json(node: hou.Node): sbsar_json = load_sbsar_json(node) sbs_graphs = sbsar_json["graphs"] graphs = get_matched_graphs(node, sbsar_json) inputs_multiparm: hou.Parm = node.parm("inputs") input_names = get_multiparm_tuples(inputs_multiparm, ("input_name{}", "input_type{}")) inputs = list( set( it.chain.from_iterable(sbs_graphs[graph]["inputs"] for graph in graphs))) for entry in inputs: if (entry, 0) not in input_names: last_index = inputs_multiparm.eval() inputs_multiparm.insertMultiParmInstance(last_index) node.parm(f"input_name{last_index + 1}").set(entry)
def deserialize_from_dict( node_data: Dict[str, Any], parent: hou.Node ) -> hou.Node: node_instance: hou.Node = parent.node(node_data["name"]) if not node_instance: node_instance = parent.createNode( node_type_name=node_data["type"]["name"], node_name=node_data["name"], ) node_instance.setPosition( vector2.deserialize_from_dict(node_data["position"]) ) # apply parameter changes exceptions: List[str] = [] for parm_name, parm_data in node_data["parms"].items(): parm: hou.Parm = node_instance.parm(parm_name) try: if parm: node_instance.parm(parm_name).set(parm_data["rawValue"]) except TypeError: exceptions.append(parm_data) if exceptions: print( "Unable to set the following parameters on '{}': {}".format( node_instance.name(), ", ".join(exceptions) ) ) # deserialize children children = nodes.deserialize_from_dict( node_data["children"].values(), node_instance ) return node_instance
def get_inputs_commandline(node: hou.Node) -> list[str]: inputs_multiparm: hou.Parm = node.parm("inputs") inputs: list[SBSARInput] = get_multiparm_namedtuples( inputs_multiparm, SBSARInput) result = [] for i in inputs: if i.input_type == 0: result += ["--set-entry", f"{i.name}@{i.path}"] else: result += ["--set-entry-usage", f"{i.usage}@{i.path}"] return result
def fill_parms_from_json(node: hou.Node): sbsar_json = load_sbsar_json(node) sbs_graphs = sbsar_json["graphs"] graphs = get_matched_graphs(node, sbsar_json) parms = list( set( it.chain.from_iterable(sbs_graphs[graph]["parms"].items() for graph in graphs))) parms_multiparm: hou.Parm = node.parm("params") names = get_multiparm_instances(parms_multiparm, "graph_parm_name{}") for parm in parms: if parm[0] not in names and parm[0] not in ("$outputsize", "$randomseed"): last_index = parms_multiparm.eval() parms_multiparm.insertMultiParmInstance(last_index) parm_name: str = parm[0] if parm_name.startswith("$"): parm_name = "\\" + parm_name node.parm(f"graph_parm_name{last_index + 1}").set(parm_name) node.parm(f"graph_parm_type{last_index + 1}").set(parm[1])
def serialize_as_dict(node_instance: hou.Node) -> Dict[str, Any]: return { "class_name": node_instance.__class__.__name__, "name": node_instance.name(), "type": nodetype.serialize_as_dict(node_instance.type()), "color": color.serialize_as_dict(node_instance.color()), "position": vector2.serialize_as_dict(node_instance.position()), "parms": { x.name(): parm.serialize_as_dict(x) for x in list(node_instance.parms()) if not x.isAtDefault( compare_temporary_defaults=True, compare_expressions=False ) }, "inputConnections": [ nodeconnection.serialize_as_dict(x) for x in list(node_instance.inputConnections()) ], "isNetwork": node_instance.isNetwork(), "children": nodes.serialize_as_dict(list(node_instance.children())) if node_instance.isNetwork() else {}, }
def get_outputs_commandline(node: hou.Node) -> list[str]: inputs_multiparm: hou.Parm = node.parm("graph_outputs") outputs: list[SBSAROutput] = get_multiparm_namedtuples( inputs_multiparm, SBSAROutput) result = [] for o in outputs: if o.output_type == 0: result += ["--input-graph-output", o.name] if o.out_format != "default": result += ["--set-output-format", f"{o.name}@{o.out_format}"] if o.bitdepth != "default": result += ["--set-output-bit-depth", f"{o.name}@{o.bitdepth}"] if o.colorspace.strip(): result += ["--set-output-colorspace", o.colorspace] else: result += ["--input-graph-output-usage", o.usage] return result
def run_sbsrender(node: hou.Node): sbsar_json = load_sbsar_json(node) cl = [node.evalParm("sbsrender_path")] cl += ["render"] cl += [node.parm("sbsar").evalAsString()] output_path: str = node.evalParm("output_path") if output_path.strip(): cl += ["--output-path", output_path] output_name: str = node.evalParm("output_name") if output_name.strip(): cl += ["--output-name", output_name] if node.evalParm("engine_override"): cl += ["--engine", node.parm("engine").evalAsString()] cl += get_settings_commandline(node) pattern = node.parm("output_graphs").evalAsString() pattern = pattern.strip() if pattern and pattern != "*": cl += get_output_graphs_commandline(node, sbsar_json) cl += get_time_commandline(node) cl += get_inputs_commandline(node) if node.evalParm("use_graph_outputs"): cl += get_outputs_commandline(node) size_type = node.evalParm("size_type") size_x = node.parm("size_x").evalAsString() size_y = node.parm("size_y").evalAsString() if size_type == 0: cl += ["--set-value", f"$outputsize@{size_x},{size_x}"] else: cl += ["--set-value", f"$outputsize@{size_x},{size_y}"] if node.evalParm("use_randomseed"): cl += ["--set-value", f"$randomseed@{node.evalParm('random_seed')}"] cl += get_parms_commandline(node) if node.parm("use_preset").eval(): cl += ["--use-preset", node.parm("preset").evalAsString()] #print(cl) # with hou.InterruptableOperation(f"Rendering SBSAR: {node.parm('sbsar').evalAsString()}", open_interrupt_dialog=True): startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW result = subprocess.run(cl, stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo) if (result.returncode != 0): message = result.stderr.decode("utf-8") _error(message, hou.NodeError) elif node.evalParm("pdg_logoutput"): result_json = result.stdout.decode("utf-8") result = json.loads(result_json) for graph in result: if "outputs" not in graph: continue for output in graph["outputs"]: if "value" not in output: continue print(f"OUTPUT_FILE:{output['value']};")
def get_settings_commandline(node: hou.Node): result = [] if node.evalParm("settings_format"): result += [ "--output-format", node.parm("output_format").evalAsString() ] if node.evalParm("settings_compression"): result += [ "--png-format-compression", node.parm("png_compression").evalAsString() ] if node.evalParm("settings_colorspace"): result += [ "--output-colorspace", node.parm("color_space").evalAsString() ] if node.evalParm("settings_cachedir"): result += ["--cache-dir", node.parm("cache_dir").evalAsString()] if node.evalParm("settings_cpucount"): result += ["--cpu-count", str(node.parm("cpu_count").eval())] if node.evalParm("settings_memorybudget"): result += ["--memory-budget", str(node.parm("memory_budget").eval())] if node.evalParm("settings_ocioconfig"): result += ["--ocio", node.parm("ocio_config").evalAsString()] if node.evalParm("use_ace"): result += ["--ace"] result += [ "--ace-render-intent", node.parm("ace_render_intent").evalAsString() ] result += [ "--ace-working-space", node.parm("ace_working_space").evalAsString() ] icc_path = node.evalParm("icc_profiles_path") if icc_path.strip(): result += ["--icc-profiles-dir", icc_path] return result
def refresh_sbsar_cache(node: hou.Node): sbsar_path = node.parm("sbsar").evalAsString() sbsar_info = get_sbsar_info(node.evalParm("sbsrender_path"), sbsar_path) sbsar_json = get_sbsar_json(sbsar_info) cache_sbsar_json(node, sbsar_json)
def cache_sbsar_json(node: hou.Node, sbsar_json: str): node.setUserData(SBSAR_USERDATA_KEY, sbsar_json)
def load_sbsar_json(node: hou.Node) -> dict: sbsar_json = node.userData(SBSAR_USERDATA_KEY) if sbsar_json is not None: return json.loads(sbsar_json) return {"graphs": {}, "metadata": {}}