'''
quick utility function to check which assets have published materials
'''
import os

from pipe.pipeHandlers.project import Project
from pipe.pipeHandlers.body import Body
from pipe.pipeHandlers.body import Asset
from pipe.pipeHandlers.body import AssetType
from pipe.pipeHandlers.element import Element
from pipe.pipeHandlers.environment import Environment
from pipe.pipeHandlers import pipeline_io

project = Project()
assets = project.list_assets()
output = "\n\n"
for name in assets:
    asset = project.get_asset(name)
    element = asset.get_element(Asset.MATERIALS)
    if element and element.get_last_version() >= 0:
        path = element.get_last_publish()[3]
        out = name + "\n"#+ " material at " + path + "\n"
        output += out

print(output)
class LayoutUpdater:
    def __init__(self):
        self.project = Project()
        self.assetList = self.project.list_assets()
        for asset in self.assetList:
            asset = re.sub(r'\W+', '', asset)

    def updateAll(self):
        obj = hou.node("/obj")
        for node in obj.children():
            if node.type().name() == "cenoteLayoutNet":
                self.updateLayout(node)

    def updateLayout(self, layout):
        print("updating " + layout.name())
        #reload its usd reference node
        self.reloadUsd(layout)
        #update all materials in the layout's library
        lib = None
        for node in layout.children():
            if node.type().name() == "matnet":
                lib = node

        matList = []
        for mat in lib.children():
            self.reloadMaterial(mat)
            matList.append(mat.name())

        #undo all material assignments (set to 0)
        layout.parm("num_materials").set(0)
        #parse through the material bindings again
        matDict = self.getMatDict(layout)
        self.assignMats(layout, matDict, matList, lib)

        qd.message("Successfully updated " + layout.name())

    def reloadUsd(self, layout):
        refNodePath = layout.parm("loppath").eval()
        refNode = hou.node(refNodePath)
        refNode.parm("reload").pressButton()

    def reloadMaterial(self, matNode):
        typeName = matNode.type().name()
        if typeName not in self.assetList:
            return  #not a material from the pipe, move on

        if matNode.isLockedHDA():
            matNode.allowEditingOfContents()
        matNode.matchCurrentDefinition()
        matNode.allowEditingOfContents()

    def getMatDict(self, layout):
        refNodePath = layout.parm("loppath").eval()
        refNode = hou.node(refNodePath)
        stage = refNode.stage()
        matDict = {}

        for prim in stage.Traverse():
            #print(prim.GetName() + " " + prim.GetTypeName())

            mat_path = prim.GetRelationship("material:binding")
            #we decide what to copy into it's own geometry node by what has its own material
            if mat_path:
                #print(prim.GetName() + " has a material at path " + str(mat_path.GetForwardedTargets()[0]))

                primPaths = ""
                if prim.GetTypeName() == "Mesh":
                    primPaths = primPaths + "@path=" + str(
                        prim.GetPath()) + " "
                else:
                    children = self.getDescendants(prim)
                    for child in children:
                        if child.GetTypeName() == "Mesh":
                            primPaths = primPaths + "@path=" + str(
                                child.GetPath()) + " "

                mat_path = mat_path.GetForwardedTargets()
                if mat_path[0].IsPrimPath():
                    #print(mat_path[0])
                    mat_name = os.path.basename(str(mat_path[0]))
                    #print("\t" + mat_name)

                    if mat_name in matDict.keys():
                        matDict[mat_name] += primPaths
                    else:
                        matDict[mat_name] = primPaths

        return matDict

    def assignMats(self, layout, matDict, matList, library):

        layout.parm("num_materials").set(len(matDict.keys()))
        index = 1

        for mat in matDict.keys():
            if re.sub(r'\W+', '', mat) in matList:
                #this material is already up to date
                matNode = hou.node(library.path() + "/" + mat)

            else:
                #clone in that material's hda to the network
                asset = self.project.get_asset(mat)
                if not asset:
                    print("Well there's your problem :/")
                    continue

                element = asset.get_element(Asset.MATERIALS)
                matNode = None
                if element.get_last_version() >= 0:
                    path = element.get_last_publish()[3]
                    hdaPath = path.split(".")[0] + ".hda"
                    try:
                        hou.hda.installFile(hdaPath)

                        matNode = library.createNode(re.sub(r'\W+', '', mat))
                        matNode.setName(mat, 1)
                        matNode.setMaterialFlag(True)
                    except Exception as e:
                        qd.error(
                            "The material for " + mat +
                            " needs to be republished. Sorry for the inconvenience."
                        )
                        #print(e)

            #assign the material to all the paths
            layout.parm("group" + str(index)).set(matDict[mat])
            if matNode:
                layout.parm("shop_materialpath" + str(index)).set(
                    matNode.path())

            index += 1

    def getDescendants(self, prim):
        all = []
        children = prim.GetChildren()
        all.extend(children)
        for child in children:
            all.extend(self.getDescendants(child))

        return all


#the only part that should need to be redone is the material stuff
#so first, make sure to reload the usda file
#from there, the lop import should be fine, so don't mess with that
#parse through the usda to get the material assignments
#and apply the materials like before

#updating the materials might also be a problem, they won't update automatically but
#there might be a way to force it to update from the hda file, which should take
#care of it.

#for each material node
#check if it's an hda
#check if it's unlocked, if not then unlock it
#call hou.Node.matchCurrentDefinition()
#unlock it again
class UpdateAssets:
    def __init__(self):
        self.project = Project()

    def update_assets(self):
        lists = ShotgunReader().getAssetLists()
        asset_list = lists[0]
        assets = lists[1]

        #update .asset_list
        list_file = open(
            os.path.join(self.project.get_assets_dir(), ".asset_list.txt"),
            "w")
        list_file.truncate(0)
        for name in asset_list:
            list_file.write(name + "\n")
        list_file.close()

        #update .short_asset_list
        list_file = open(
            os.path.join(self.project.get_assets_dir(), ".short_asset_list"),
            "w")
        list_file.truncate(0)

        for asset in assets:
            name = asset["name"]
            variants = asset["children"][:]
            print("name: " + name)
            print("variants: ", variants)

            self.build_asset(name, variants)

            list_file.write(name + "\n")

        list_file.close()

        qd.message("Assets updated successfully.")

    def build_asset(self, main_name, variants):
        stage = hou.node("/stage")
        self.primpath = "/" + main_name

        prim = stage.createNode("primitive")
        prim.setName("base_prim", 1)
        prim.parm("primpath").set(self.primpath)

        config = stage.createNode("configurelayer")
        config.setName("set_default_prim", 1)
        config.setInput(0, prim)
        config.parm("defaultprim").set(self.primpath)
        config.parm("setdefaultprim").set(1)

        add_var = stage.createNode("addvariant")
        add_var.parm("primpath").set(self.primpath)

        in_count = 1

        for var in variants:
            self.add_variant(var, config, add_var, in_count)
            in_count += 1

        out_label = stage.createNode("null")
        out_label.setName(main_name + "_OUT", 1)
        out_label.setInput(0, add_var)

        #our asset is now assembled, and just needs to be published
        body = self.project.get_asset(main_name)
        if not body:
            qd.error("Error publishing asset " + main_name +
                     ". Continuing to next asset.")
            return

        element = body.get_element(Asset.USD)
        element.update_app_ext(".usda")

        path = os.path.join(element._filepath, "temp.usda")

        rop = hou.node("/stage").createNode("usd_rop")
        rop.setInput(0, out_label)
        rop.parm("lopoutput").set(path)
        rop.parm("enableoutputprocessor_simplerelativepaths").set(0)
        rop.parm("execute").pressButton()

        stage.layoutChildren()

        comment = "Automatic publish"
        username = "******"
        name = main_name

        element.publish(username, path, comment, name)

        for child in stage.children():
            child.destroy()

    def add_variant(self, var, config, add_var, in_count):
        stage = hou.node("/stage")

        ref1 = stage.createNode("reference")
        ref1.setName(var + "_geo", 1)
        ref1.parm("primpath").set(self.primpath)
        geo_path = self.getGeoPath(var)
        ref1.parm("filepath1").set(geo_path)

        disp = stage.createNode("rendergeometrysettings")
        disp.parm("xn__primvarsdisplacementboundsphere_control_n4br").set(
            "set")
        disp.parm("xn__primvarsdisplacementboundsphere_mrbr").set(1)
        disp.setInput(0, ref1)

        lib1 = stage.createNode("reference")
        lib1.setInput(0, disp)
        lib1.parm("primpath").set("/materials/")
        mat_path = self.getMatPath(var)
        lib1.parm("filepath1").set(mat_path)

        mat_asgn = stage.createNode("assignmaterial")
        mat_asgn.setInput(0, lib1)
        mat_asgn.parm("primpattern1").set(self.primpath)
        usd_stage = mat_asgn.stage()
        mat_prim = usd_stage.GetPrimAtPath("/materials")
        shader_path = mat_prim.GetChildren()[0].GetPath()
        #print("SHADER PATH: " + str(shader_path))
        mat_asgn.parm("matspecpath1").set(str(shader_path))

        label = stage.createNode("null")
        label.setName(var + "_OUT", 1)
        label.setInput(0, mat_asgn)

        graft = stage.createNode("graftstages")
        graft.setName(var, 1)
        graft.parm("primpath").set(self.primpath)
        graft.parm("destpath").set("/")
        graft.setInput(0, config)
        graft.setInput(1, label)

        add_var.setInput(in_count, graft)

    def getGeoPath(self, var):
        body = self.project.get_asset(var)
        if not body:
            body = self.project.create_asset(var)

        element = body.get_element(Asset.GEO)
        if element.get_last_version() >= 0:
            return element.get_last_publish()[3]

        else:
            #copy over the blank usda file
            src = self.project.get_project_dir()
            src = os.path.join(src, "blank.usda")
            dst = os.path.join(element._filepath, var + "_main.usda")

            shutil.copyfile(src, dst)
            pio.set_permissions(dst)

            return dst

    def getMatPath(self, var):
        body = self.project.get_asset(var)
        if not body:
            body = self.project.create_asset(var)

        element = body.get_element(Asset.MATERIALS)
        myPath = os.path.join(element._filepath, var + "_main.usda")
        if os.path.exists(myPath):
            return myPath

        else:
            #create and publish a basic material, return the path
            dst = os.path.join(element._filepath, var + "_main.usda")

            mat_lib = hou.node("/stage").createNode("materiallibrary")
            pink = mat_lib.createNode("usdpreviewsurface")
            pink.setName(var)
            pink.parm("diffuseColorr").set(.6)
            pink.parm("diffuseColorg").set(.6)
            pink.parm("diffuseColorb").set(.6)

            rop = hou.node("/stage").createNode("usd_rop")
            rop.setInput(0, mat_lib)
            rop.parm("lopoutput").set(dst)
            rop.parm("enableoutputprocessor_simplerelativepaths").set(0)
            rop.parm("execute").pressButton()

            mat_lib.destroy()
            rop.destroy()

            pio.set_permissions(dst)

            return dst
Exemple #4
0
class AnimCloner:
    def __init__(self):
        self.project = Project()

    def clone(self):
        shot_list = self.project.list_existing_shots()

        self.item_gui = sfl.SelectFromList(l=shot_list,
                                           parent=hou.ui.mainQtWindow(),
                                           title="Select a shot to clone from")
        self.item_gui.submitted.connect(self.shot_results)

    def shot_results(self, value):
        self.shot_name = value[0]
        self.shot = self.project.get_shot(self.shot_name)
        element = self.shot.get_element(Asset.ANIMATION)

        asset_list = next(os.walk(element._filepath))[1]
        for name in asset_list:
            if name == "cache":
                asset_list.remove(name)
        asset_list.sort(key=unicode.lower)

        self.item_gui = sfl.SelectFromList(l=asset_list,
                                           parent=hou.ui.mainQtWindow(),
                                           title="Select an asset to clone")
        self.item_gui.submitted.connect(self.asset_results)

    def asset_results(self, value):
        self.asset_name = value[0]
        element = self.shot.get_element(
            os.path.join(Asset.ANIMATION, self.asset_name))

        if element.get_last_version < 0:
            qd.error("There are no publishes for this asset in this shot.")
            return
        path = element.get_last_publish()[3]
        self.build_network(path)

    def build_network(self, path):
        animNode = hou.node("/obj").createNode("cenoteAnimation")
        animNode.setName(self.asset_name + "_anim", 1)
        animNode.parm("fileName").set(path)
        animNode.parm("scale").set(0.01)
        animNode.parm("buildHierarchy").pressButton()
        #animNode.parm("rendersubd").set(True)

        matPath = self.getMatPath()
        hdaPath = matPath.split(".")[0] + ".hda"
        if os.path.exists(hdaPath):
            hou.hda.installFile(hdaPath)
            for child in hou.node("/mat").children():
                if child.type().name() == re.sub(r'\W+', '', self.asset_name):
                    child.destroy()
            newMat = hou.node("/mat").createNode(
                re.sub(r'\W+', '', self.asset_name))
            newMat.setName(self.asset_name, 1)
            newMat.setMaterialFlag(True)

            animNode.parm("materialPath").set("/mat/" + newMat.name())
        else:
            qd.error(
                "The material for " + self.asset_name +
                " needs to be republished before it can be cloned in. Republish the material and try again."
            )

    def getMatPath(self):
        asset = self.project.get_asset(self.asset_name)
        element = asset.get_element(Asset.MATERIALS)
        if element.get_last_version() < 0:
            return os.path.join(element._filepath,
                                self.asset_name + "_main.usda")
        path = element.get_last_publish()[3]
        return path