class BuildShot:
    def __init__(self):
        self.project = Project()

    def build(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")
        self.item_gui.submitted.connect(self.results)

    def results(self, value):
        self.shot_name = value[0]
        self.shotBody = Project().get_body(self.shot_name)

        camElement = self.shotBody.get_element(Asset.CAMERA)
        asset_list = next(os.walk(camElement._filepath))[1]
        for name in asset_list:
            if name == "cache":
                asset_list.remove(name)
        asset_list.sort(key=unicode.lower)
        if len(asset_list) < 1:
            qd.error(
                "There is no camera for this shot, so it cannot be built. Quitting build for shot "
                + self.shot_name + "...")
        elif len(asset_list) == 1:
            self.camResults(asset_list)
        else:
            self.item_gui = sfl.SelectFromList(
                l=asset_list,
                parent=hou.ui.mainQtWindow(),
                title="Select a camera to clone")
            self.item_gui.submitted.connect(self.camera_results)

    def camResults(self, value):
        camName = value[0]
        self.camElement = self.shotBody.get_element(
            os.path.join(Asset.CAMERA, camName))
        options = ["Animation", "Layout", "Lights", "FX"]
        valueGui = qd.CheckboxSelect(
            text="Select what to import from this shot",
            options=options,
            parent=hou.ui.mainQtWindow(),
            title="Shot Build Settings")
        valueGui.submitted.connect(self.options_results)

    def options_results(self, options):
        '''for op in options:
            print(op)'''
        anim = options[0]
        layout = options[1]
        lights = options[2]
        fx = options[3]

        isCamera = self.get_camera()
        if not isCamera:
            return

        if anim:
            isAnim = self.get_all_anim()
            if not isAnim:
                qd.message(
                    "There is no animation published for this shot. Continuing to build shot..."
                )

        if layout:
            isLayout = self.get_layout()
            if not isLayout:
                qd.message(
                    "Couldn't clone the layout for this shot. Continuing to build shot..."
                )

        self.sequence_name = self.shot_name[:1]
        self.sequence = self.project.get_sequence(self.sequence_name)

        if lights:
            isLights = self.get_lights()
            if not isLights:
                qd.message(
                    "Couldn't clone sequence lighting. Continuing to build shot..."
                )

        if fx:
            self.get_fx()

        hou.node("/obj").layoutChildren()

        self.build_render()

    def get_camera(self):
        if self.camElement.get_last_version < 0:
            qd.error(
                "There is no camera for this shot, so it cannot be built. Quitting build for shot "
                + self.shot_name + "...")
            return False
        try:
            path = self.camElement.get_last_publish()[3]

            cameraNode = hou.node("/obj").createNode("cenoteCamera")
            cameraNode.setName(self.shot_name + "_camera", 1)
            cameraNode.parm("fileName").set(path)
            cameraNode.parm("scale").set(0.01)
            cameraNode.parm("buildHierarchy").pressButton()
            return True
        except Exception as e:
            print(e)
            return False

    def get_all_anim(self):
        animElement = self.shotBody.get_element(Asset.ANIMATION)
        asset_list = next(os.walk(animElement._filepath))[1]
        for name in asset_list:
            if name == "cache":
                asset_list.remove(name)
        asset_list.sort(key=unicode.lower)
        if len(asset_list) < 1:
            return False

        for asset in asset_list:
            self.get_anim(asset)
        return True

    def get_anim(self, asset):
        element = self.shotBody.get_element(
            os.path.join(Asset.ANIMATION, asset))
        if element.get_last_version() < 0:
            return False

        try:
            path = element.get_last_publish()[3]

            anim_cloner = AnimCloner()
            anim_cloner.asset_name = asset
            anim_cloner.build_network(path)
            return True

        except Exception as e:
            print(e)
            return False

    def get_layout(self):
        layout_element = self.shotBody.get_element(Asset.LAYOUT)
        path = os.path.join(layout_element._filepath, self.shot_name + ".usda")
        if not os.path.exists(path):
            print("Layout path doesn't exist")
            return False
        try:
            layoutUnpacker = LayoutUnpacker()
            layoutUnpacker.shot_name = self.shot_name
            layoutUnpacker.unpack(path)
            return True
        except Exception as e:
            print(e)
            return False

    def get_lights(self):
        lightElement = self.sequence.get_element(Asset.LIGHTS)
        if lightElement.get_last_version() < 0:
            return False

        path = lightElement.get_last_publish()[3]
        hou.hda.installFile(path)

        try:
            hda = hou.node("/obj").createNode("sequence_" +
                                              self.sequence_name + "_lights")
        except Exception as e:
            #qd.error("Couldn't create node of type " + name + ". You should still be able to tab in the node manually.")
            print(e)
            return False

        try:
            hda.setName(self.sequence_name + "_sequence_lights", 1)
        except:
            pass

        try:
            hda.allowEditOfContents()
        except:
            pass

        return True

    def get_fx(self):
        fxElement = self.sequence.get_element(Asset.HDA)
        fx_list = next(os.walk(fxElement._filepath))[1]
        for name in fx_list:
            if name == "cache":
                fx_list.remove(name)
        fx_list.sort(key=unicode.lower)

        for fx in fx_list:
            self.get_one_fx(fx)

    def get_one_fx(self, fx):
        element = self.sequence.get_element(os.path.join(Asset.HDA, fx))

        if element.get_last_version() < 0:
            return
        filepath = element.get_last_publish()[3]

        try:
            hou.hda.installFile(filepath)
        except Exception as e:
            print(e)
            return

        try:
            hda = hou.node("/obj").createNode(fx)
        except Exception as e:
            qd.error("Couldn't create node of type " + fx +
                     ". You should still be able to tab in the node manually.")

        try:
            hda.setName(fx, 1)
        except:
            pass

        try:
            hda.allowEditOfContents()
        except:
            pass

    def build_render(self):
        ris = hou.node("/out").createNode("cenote_layered_render")
        ris.parm("frame1").set(1)
        ris.parm("frame2").set(self.shotBody.get_frame_range())
        ris.parm("frame3").set(2)

        selected = None
        root = hou.node('/')
        camera_nodes = root.recursiveGlob('*', hou.nodeTypeFilter.ObjCamera)
        for cam in camera_nodes:
            if "shot" in cam.name():
                selected = cam
        if not selected:
            qd.error(
                "Error selecting camera for render. Will need to be done manually."
            )
        else:
            ris.parm("camera").set(selected.path())

        layers = self.build_layer_string()
        print(layers)
        ris.parm("render_layers").set(layers)

        ris.parm("build_rops").pressButton()

        for node in ris.children():
            if node.type().name() == "tractorsubmit_main":
                node.parm("job_title").set(self.shot_name + "_Test_Render")
            else:
                node.parm("override_camerares").set(True)
                old = node.parm("ri_display_0").unexpandedString()
                new = old.replace("render", "testRender")
                node.parm("ri_display_0").set(new)

    def build_layer_string(self):
        first = ""
        second = ""
        third = ""
        total = ""

        for node in hou.node("/obj").children():
            if node.type().name() == "cenoteAnimation":
                first = first + "[ " + node.name() + " ] "
            elif node.type().name() == "cenoteLayoutNet":
                third = third + node.name() + " "
            elif node.type().name(
            ) != "cenoteCamera" and not "sequence_lights" in node.name():
                second = second + node.name() + " "

        if len(first) > 0:
            total = total + first
        if len(second) > 0:
            total = total + "[ " + second + "] "
        if len(third) > 0:
            total = total + "[ " + third + "]"

        return total
Exemple #2
0
class AlembicExporter:
    def __init__(self, frame_range=1):
        self.frame_range = frame_range
        pm.loadPlugin("AbcExport")

    def asset_results(self, value):
        chosen_asset = value[0]
        print(chosen_asset)


    def exportSelected(self, asset_name, shot_name, camera=False):

        self.shot_name = shot_name
        self.shot = Project().get_shot(shot_name)

        if self.shot is None:
            return None

        start_frame = 0
        frame_range = str(self.shot.get_frame_range())
        #This means there's been no cameras even published for this shot but they're trying to save an animation. shouldn't ever happen
        if int(frame_range) == 0 and not camera:
            qd.error("How are you publishing without a camera yet? Get that done, bestie.")
            return
        #if this is previs we need to know where to move the keyframes to
        if camera:
            #ask the artist what frame the shot starts at and make sure that's a valid input
            start_frame = qd.input("Enter the starting frame for this shot")
            if start_frame is None or start_frame == u'':
                qd.error("Invalid frame range. Try publishing again.")
                return
            start_frame = str(start_frame)
            if not start_frame.isdigit():
                qd.error("Invalid frame range. Try publishing again.")
                return
            
            #ask the artist for the last frame and make sure that's valid input
            #we'll do this every time in case the length of the shot changes
            end_frame = qd.input("Enter the last frame for this shot")
            if end_frame is None or end_frame == u'':
                qd.error("Invalid frame range. Try publishing again.")
                return
            end_frame = str(end_frame)
            if not end_frame.isdigit():
                qd.error("Invalid frame range. Try publishing again.")
                return

            #calculate the frame-range and save it to the shot's .body file
            frame_range = int(end_frame) - int(start_frame) + 1
            self.shot.set_frame_range(frame_range)

            #now move the keyframes and build the command
            timeChange = int(start_frame) - 1
            anim_curves = mc.ls(type=['animCurveTA', 'animCurveTL', 'animCurveTT', 'animCurveTU'])  
            for each in anim_curves:  
                mc.keyframe(each, edit=True, relative=True, timeChange=-timeChange)

            path = self.getCameraPath(asset_name)
            command = self.buildAlembicCommand(path, uv=False)
                
        else:
            path = self.getFilePath(asset_name)
            command = self.buildAlembicCommand(path)
        

        cont = qd.yes_or_no("This asset is about to be saved with " + str(frame_range) + " frames. Is that correct?")
        if not cont:
            qd.error("Nothing was published.")
            return

        pm.Mel.eval(command)
        
        #now move the keyframes back for previs
        if camera:
            timeChange = int(start_frame) - 1
            anim_curves = mc.ls(type=['animCurveTA', 'animCurveTL', 'animCurveTT', 'animCurveTU'])  
            for each in anim_curves:  
                mc.keyframe(each, edit=True, relative=True, timeChange=timeChange)

        publish_info = [self.element, path]
        return publish_info

    def buildAlembicCommand(self, path, uv=True):
        #get selected nodes
        selected = mc.ls(sl=True,long=True)
        nodes = ""
        for node in selected:
            nodes += node
            nodes += " "

        frame_range = str(self.shot.get_frame_range())

        options = "-frameRange -48 " + frame_range
        if uv:
            options += " -uvWrite -writeUVSets"
        options += " -worldSpace -dataFormat ogawa -root " + nodes + "-file " + path

        command = "AbcExport -verbose -j \"" + options +"\""
        print(command)
        return command

    def getFilePath(self, asset_name):
        path = self.shot.get_filepath()
        dept = os.path.join(Asset.ANIMATION, asset_name) #this is to make it so we can keep track of the versions of animations for each asset
        path = os.path.join(path, dept)

        #try to create the element if it doesn't exist
        self.element = self.shot.create_element(dept, Element.DEFAULT_NAME)
        #retrieve it if it does already
        if self.element is None:
            self.element = self.shot.get_element(dept)
            
        self.element.update_app_ext(".abc")

        path = os.path.join(path, asset_name)
        last_version = self.element.get_last_version()
        current_version = last_version + 1
        path = path + "_v" + str(current_version).zfill(3) + ".abc"
        print(path)
        return path

    def getCameraPath(self, camera_name):
        path = self.shot.get_filepath()
        dept = os.path.join(Asset.CAMERA, camera_name) #this is to make it so we can keep track of the versions of animations for each camera
        path = os.path.join(path, dept)

        #try to create the element if it doesn't exist
        self.element = self.shot.create_element(dept, Element.DEFAULT_NAME)
        #retrieve it if it does already
        if self.element is None:
            self.element = self.shot.get_element(dept)

        self.element.update_app_ext(".abc")

        path = os.path.join(path, camera_name)
        last_version = self.element.get_last_version()
        current_version = last_version + 1
        path = path + "_v" + str(current_version).zfill(3) + ".abc"
        print(path)
        return path