def tab_in(self, parent, asset_name, already_tabbed_in_node=None, excluded_departments=[]): print "Creating node for {0}".format(asset_name) body = Project().get_body(asset_name) if body is None or not body.is_asset(): qd.error( "Pipeline error: This asset either doesn't exist or isn't an asset." ) return if body.get_type() == AssetType.CHARACTER: return self.dcc_character(parent, asset_name, already_tabbed_in_node, excluded_departments) elif body.get_type() == AssetType.PROP: return self.dcc_geo(parent, asset_name, already_tabbed_in_node, excluded_departments) elif body.get_type() == AssetType.SET: return self.dcc_set(parent, asset_name, already_tabbed_in_node) else: qd.error( "Pipeline error: this asset isn't a character, prop or set.") return
def post_publish(element, user, published=True, comment="No comment."): scene_file, created_new_file = get_scene_file() if published: if not mc.file(q=True, sceneName=True) == '': mc.file(save=True, force=True) #save file scene_prep() username = user.get_username() dst = element.publish(username, scene_file, comment) #Ensure file has correct permissions try: os.chmod(dst, 0660) except: print("Setting file permissions failed badly.") # Export JSON print('Publish Complete. Begin Exporting JSON if set.') body = Project().get_body(element.get_parent()) if body and body.is_asset(): if body.get_type() == AssetType.SET or body.get_type( ) == AssetType.SHOT: json_export = JSONExporter() json_export.go(body, body.get_type()) convert_to_education()
def dcc_character(self, parent, asset_name, already_tabbed_in_node=None, excluded_departments=[], mode=UpdateModes.CLEAN, shot=None): # Set up the body/elements and make sure it's a character body = Project().get_body(asset_name) if not body.is_asset() or not body.get_type() == AssetType.CHARACTER: qd.error("Must be a character.") return None # If there's an already tabbed in node, set it to that node node = already_tabbed_in_node if already_tabbed_in_node else parent.createNode( "dcc_character") try: node.setName(asset_name.title()) except: node.setName(asset_name.title() + "_1", unique_name=True) node.parm("asset_name").set(asset_name) # Set the asset_name data tag data = node.parm("data").evalAsJSONMap() data["asset_name"] = asset_name node.parm("data").set(data) # Set the contents to the character's nodes self.update_contents_character(node, asset_name, excluded_departments, mode, shot) return node
def subnet_type(self, asset_name): body = Project().get_body(asset_name) if body is None or not body.is_asset(): qd.error( "Pipeline error: This asset either doesn't exist or isn't an asset." ) return if body.get_type() == AssetType.ACTOR: return "dcc_character" elif body.get_type() == AssetType.PROP: return "dcc_geo" elif body.get_type() == AssetType.SET: return "dcc_set" else: qd.error("Pipeline error: this asset isn't an actor, prop or set.") return
def update_contents_geo(self, node, asset_name, excluded_departments=[], mode=UpdateModes.SMART, shot=None): # Set up the body/elements and make sure it's not an actor. Just do some simple error checking. body = Project().get_body(asset_name) if body is None: qd.error("Asset doesn't exist.") return None if not body.is_asset() or body.get_type( ) == AssetType.SET or "dcc_geo" not in node.type().name(): qd.error("Must be a prop or actor.") return None # Get interior nodes importnode = node.node("import") inside = node.node("inside") # Set the asset_name and reload if node.parm("asset_name").evalAsString() != asset_name: node.parm("asset_name").set(asset_name) importnode.parm("reload").pressButton() # Tab in each content HDA based on department for department in self.dcc_geo_departments: # If the department is not excluded, tab-in/update the content node like normal if department not in excluded_departments: self.update_content_node( node, inside, asset_name, department, mode, inherit_parameters=department == Department.MODIFY) # If the department is excluded, we should delete it. elif mode == UpdateModes.CLEAN: self.destroy_if_there(inside, department) inside.layoutChildren() # If this prop is being animated, set parms accordingly if shot is not None: node.parm("space").set("anim") node.parm("asset_department").set("rig") node.parm("shot").set(shot) return node
def exportPropJSON(self, filePath, rootNode, isReference=True, name="", version_number=None): # TODO: look here for why the set json isn't created properly if isReference: body = get_body_from_reference(rootNode) else: body = Project().get_body(name) name = body.get_name() print("Body: ", str(body)) print("filepath: ", filePath) print("rootNode: ", rootNode) if not body or not body.is_asset() or body.get_type() != AssetType.PROP: print "The asset %s does not exist as a prop, skipping.".format(name) return None # Check if verNum is nothing - if so, we need to make it be an int 0 if not version_number: version_number = 0 firstMesh, path = find_first_mesh(rootNode) vertpos1, vertpos2, vertpos3 = get_anchor_points(firstMesh) # Put all relevant data into dictionary object json_data = {"asset_name": name, "version_number": version_number, "path" : path, "a" : [vertpos1.x, vertpos1.y, vertpos1.z], "b" : [vertpos2.x, vertpos2.y, vertpos2.z], "c" : [vertpos3.x, vertpos3.y, vertpos3.z] } print("json data: ", json_data) # Write JSON to fill jsonRef = json.dumps(json_data) wholePath = os.path.join(filePath, os.path.join(filePath, name + "_" + str(version_number) + ".json")) outfile = open(wholePath, "w") # *** THIS IS THE NAME OF THE OUTPUT FILE *** outfile.write(jsonRef) outfile.close() if not isReference: qd.info("JSON references written successfully.") return {"asset_name" : json_data["asset_name"], "version_number" : json_data["version_number"]}
def dcc_set(self, parent, set_name, already_tabbed_in_node=False, mode=UpdateModes.CLEAN): # Check if it's a set and that it exists body = Project().get_body(set_name) if not body.is_asset() or not body.get_type() == AssetType.SET: qd.error("Must be a set.") node = already_tabbed_in_node if already_tabbed_in_node else parent.createNode( "dcc_set") try: node.setName(set_name) except: node.setName(set_name + "_1", unique_name=True) # Update contents in the set self.update_contents_set(node, set_name, mode) return node
def update_contents_character(self, node, asset_name, excluded_departments=[], mode=UpdateModes.SMART, shot=None): # Set up the body/elements and make sure it's a character. Just do some simple error checking. body = Project().get_body(asset_name) if not body.is_asset() or body.get_type( ) != AssetType.CHARACTER or "dcc_character" not in node.type().name(): qd.error("Must be a character.") return None # Reset the data parm data = node.parm("data").evalAsJSONMap() data["asset_name"] = asset_name node.parm("data").set(data) inside = node.node("inside") # Make sure the geo is set correctly geo = inside.node("geo") if geo is not None: if mode == UpdateModes.SMART: self.update_contents_geo(geo, asset_name, excluded_departments, mode) elif mode == UpdateModes.CLEAN: geo.destroy() geo = self.dcc_geo(inside, asset_name, excluded_departments=excluded_departments, character=True) else: geo = self.dcc_geo(inside, asset_name, excluded_departments=excluded_departments, character=True) # Tab in each content HDA based on department for department in self.dcc_character_departments: # If the department is not excluded, tab-in/update the content node like normal if department not in excluded_departments: self.update_content_node(node, inside, asset_name, department, mode) # If the department is excluded, we should delete it. elif mode == UpdateModes.CLEAN: self.destroy_if_there(inside, department) inside.layoutChildren() geo.parm("version_number").setExpression( "ch(\"../../version_number\")", language=hou.exprLanguage.Hscript) # If this character is being animated, set parms accordingly if shot is not None: geo.parm("space").set("anim") geo.parm("asset_department").set("rig") geo.parm("shot").set(shot) return node
def update_contents_set(self, node, set_name, mode=UpdateModes.SMART): # Check if reference file exists set_file = os.path.join(Project().get_assets_dir(), set_name, "model", "main", "cache", "whole_set.json") # Error checking try: with open(set_file) as f: set_data = json.load(f) except Exception as error: qd.error("No valid JSON file for " + set_name) return node.parm("asset_name").set(set_name) data = node.parm("data").evalAsJSONMap() data["asset_name"] = set_name node.parm("data").set(data) inside = node.node("inside") # Grab current DCC Dynamic Content Subnets that have been tabbed in current_children = [ child for child in inside.children() if child.type().name() in ["dcc_set", "dcc_character", "dcc_geo"] ] # Smart updating will only destroy assets that no longer exist in the Set's JSON list if mode == UpdateModes.SMART: non_matching = [ child for child in current_children if len([ reference for reference in set_data if matches_reference(child, reference) ]) == 0 ] for non_match in non_matching: non_match.destroy() # Clean updating will destroy all children. elif mode == UpdateModes.CLEAN: inside.deleteItems(inside.children()) # Grab current children again current_children = [ child for child in inside.children() if child.type().name() in ["dcc_set", "dcc_character", "dcc_geo"] ] # Tab-in/update all assets in list for reference in set_data: body = Project().get_body(reference["asset_name"]) if body is None: print 'Error on: ', reference["asset_name"] continue if not body.is_asset() or body.get_type() == AssetType.SET: continue # get the most recent data for this reference cloned_subnet, instances = Cloner().asset_results( [reference["asset_name"]]) # move the cloned asset inside the set node and delete the one on the top level subnet = cloned_subnet.copyTo(inside) cloned_subnet.destroy() # Try to not override parameters in the set if mode == UpdateModes.SMART: for key in reference: # Pull parm from node parm = subnet.parm(key) # If a non-default value is there, it most likely came from a user. Don't overwrite it. if parm and parm.isAtDefault(): parm.set(reference[key]) # Override parameters in the set elif mode == UpdateModes.CLEAN: newparms = { "asset_name": reference["asset_name"], "version_number": reference["version_number"] } subnet.setParms(newparms) # Build the set accordingly subnet.parm("space").set("set") subnet.parm("set").set(set_name) subnet.parm("update_mode").set( UpdateModes.list_modes().index(mode)) # Set the data subnet.parm("data").set({ "asset_name": str(reference["asset_name"]), "version_number": str(reference["version_number"]) }) inside.layoutChildren()
def exportPropJSON(self, filepath, rootNode, isReference=True, name="", version_number=None): if isReference: try: body = get_body_from_reference(rootNode) except: qd.warning("Could not find " + str(filepath) + " in scene. Skipping.") return None else: body = Project().get_body(name) if not body or not body.is_asset(): if body: if body.get_type() == AssetType.SHOT: qd.warning( "Shots in sets are not supported. Can't export " + str(rootNode)) return None else: qd.warning("Asset not found in pipe: " + str(rootNode)) return None qd.warning(str(rootNode) + " does not exist in pipe.") return None name = body.get_name() # Increment the version number version_number, version_string = body.version_prop_json(name, filepath) firstMesh, path = find_first_mesh(rootNode) try: vertpos1, vertpos2, vertpos3 = get_anchor_points(firstMesh) except Exception as e: print(str(e)) qd.warning( "Couldn't export JSON for " + str(rootNode) + ". Is there a camera or a rig associated with this reference? Skipping this object." ) return None # Put all relevant data into dictionary object json_data = { "asset_name": name, "version_number": version_number, "path": path, "a": [vertpos1.x, vertpos1.y, vertpos1.z], "b": [vertpos2.x, vertpos2.y, vertpos2.z], "c": [vertpos3.x, vertpos3.y, vertpos3.z] } print("json data: ", json_data) # Write JSON to fill jsonRef = json.dumps(json_data) wholePath = os.path.join( filepath, os.path.join(filepath, name + "_" + version_string + ".json")) outfile = open(wholePath, "w") # *** THIS IS THE NAME OF THE OUTPUT FILE *** outfile.write(jsonRef) outfile.close() if not isReference: print("JSON references written successfully.") return { "asset_name": json_data["asset_name"], "version_number": json_data["version_number"] }
def import_shot(self, shot_name): shot_name = shot_name[0] # Bring in the body so we can get info body = Project().get_body(shot_name) print("shot name: ", shot_name) print("body: ", str(body)) if not body: qd.error("Error with asset.") return elif not body.is_shot(): qd.error("Body is not shot?") return # Bring in element so we can get cache directory element = body.get_element(Department.ANIM) if not element: qd.error( "Anim department does not exist for {0} ".format(shot_name)) return cache_dir = element.get_cache_dir() sets_json = [] actors_json = [] animated_props_json = [] # open the json files for sets actors and animated props try: with open(os.path.join(cache_dir, "sets.json")) as f: sets_json = json.load(f) except Exception as error: print "{0}/sets.json not found.".format(cache_dir) try: with open(os.path.join(cache_dir, "actors.json")) as f: actors_json = json.load(f) except Exception as error: print "{0}/actors.json not found.".format(cache_dir) try: with open(os.path.join(cache_dir, "animated_props.json")) as f: animated_props_json = json.load(f) except Exception as error: print "{0}/animated_props.json not found.".format(cache_dir) set_nodes = [] actor_nodes = [] animated_prop_nodes = [] print("Loading sets:") for set in sets_json: print("Set: ", set) try: set_node = Assembler().tab_in(hou.node("/obj"), set["asset_name"]) except Exception as e: print "Error with {0}: ".format(set) + str(e) continue set_nodes.append(set_node) print("Loading props in set ", set) for prop in set_node.children(): print("Prop: ", prop) data_parm = prop.parm("data") if data_parm is None: continue data = data_parm.evalAsJSONMap() for animated_prop in animated_props_json: if data["asset_name"] == animated_prop[ "asset_name"] and data[ "version_number"] == animated_prop[ "version_number"]: prop.parm("space").set("anim") prop.parm("shot").set(shot_name) animated_prop_nodes.append(prop) print("Loading actors: ") for actor in actors_json: print("Actor: ", actor) if actor["asset_name"] == "dcc_camera": camera_node = self.tab_in_camera(shot_name) actor_nodes.append(camera_node) continue try: # get the most recent data for this reference asset_name = actor["asset_name"] actor_body = Project().get_body(asset_name) asset_type = actor_body.get_type() try: from pipe.tools.houtools.cloner.cloner import Cloner except: pass actor_node, instances = Cloner().asset_results([asset_name]) # Assembler().update_contents_actor(actor_node, asset_name, shot=shot_name) # actor_node = cloned_subnet.copyTo(inside) # cloned_subnet.destroy() # actor_node = Assembler().dcc_actor(hou.node("/obj"), actor["asset_name"],shot=shot_name) # TODO: add the shot name in the dcc_geo inside dcc_actor if asset_type == AssetType.ACTOR: inside = actor_node.node("inside") geo = inside.node("geo") geo.parm("version_number").setExpression( "ch(\"../../version_number\")", language=hou.exprLanguage.Hscript) geo.parm("space").set("anim") geo.parm("asset_department").set("rig") geo.parm("shot").set(shot_name) elif asset_type == AssetType.PROP: actor_node.parm("version_number").setExpression( "ch(\"../../version_number\")", language=hou.exprLanguage.Hscript) actor_node.parm("space").set("anim") actor_node.parm("asset_department").set("model") actor_node.parm("shot").set(shot_name) actor_nodes.append(actor_node) except Exception as e: print "Error with {0}: ".format(actor) + str(e) continue #shot_parm = actor_node.parm("shot") #shot_parm.set(shot_name) data_parm = actor_node.parm("data") data = data_parm.evalAsJSONMap() data["version_number"] = str(actor["version_number"]) data_parm.set(data) version_number_parm = actor_node.parm("version_number") version_number_parm.set(actor["version_number"]) cam_dir = body.get_element(Department.CAMERA).get_cache_dir() camera_files = os.listdir(cam_dir) cameras = [] for camera_file in camera_files: cameras.append(self.tab_in_camera(str(shot_name), str(camera_file))) # create network box in houdini and fill it with all objects in the shot box = hou.node("/obj").createNetworkBox() box.setComment(shot_name) for set_node in set_nodes: box.addItem(set_node) for actor_node in actor_nodes: box.addItem(actor_node) for animated_prop_node in animated_prop_nodes: box.addItem(animated_prop_node) for camera in cameras: box.addItem(camera) # move all the imported objects to a non-overlaid position in the node editor for set_node in set_nodes: set_node.moveToGoodPosition() for actor_node in actor_nodes: actor_node.moveToGoodPosition() for animated_prop_node in animated_prop_nodes: animated_prop_node.moveToGoodPosition() for camera in cameras: camera.moveToGoodPosition() layout_object_level_nodes()
class Exporter: def __init__(self): self.body = None self.item_gui = None self.list = ["alembic", "fbx", "json", "usd"] self.cameras = True def auto_export_all(self): self.export() def export_one(self, alembic=False, fbx=False, json=False, usd=False, methods=None): self.export(alembic=alembic, fbx=fbx, json=json, usd=usd, methods=methods) def export(self, alembic=True, fbx=True, json=True, usd=True, methods=None): if methods is None: methods = self.list asset_name = os.environ.get("DCC_ASSET_NAME") if not asset_name: qd.error("You must first create or clone an asset.") return self.body = Project().get_body(asset_name) if alembic: AlembicExporter().auto_export(asset_name, self.cameras) if self.body and self.body.is_asset(): if json: if self.body.get_type() == AssetType.SET or self.body.get_type( ) == AssetType.SHOT: json_export = JSONExporter() json_export.go(self.body, self.body.get_type()) else: methods.remove("json") if fbx: if self.body.get_type( ) == AssetType.PROP or self.body.get_type() == AssetType.ACTOR: FbxExporter().auto_export(asset_name) else: methods.remove("fbx") if usd: print("USD isn't supported... yet :|") methods.remove("usd") if methods: qd.info("Successfully exported " + str(asset_name) + " as " + str(methods)) else: qd.info("Nothing was exported.") def export_without_cameras(self): self.cameras = False self.export() def export_with_options(self): self.item_gui = co.CheckBoxOptions(parent=maya_main_window(), title="Select export methods:", options=self.list) self.item_gui.submitted.connect(self.export_results) def export_results(self, export_results): fbx = True alembic = True json = True usd = True methods = [] for item in export_results.items(): if item[0] == "fbx": if item[1] is False: fbx = False else: methods.append("fbx") elif item[0] == "alembic": if item[1] is False: alembic = False else: methods.append("alembic") elif item[0] == "json": if item[1] is False: json = False else: methods.append("json") elif item[0] == "usd": if item[1] is False: usd = False else: methods.append("usd") self.export(alembic=alembic, fbx=fbx, json=json, usd=usd, methods=methods)