1
$\begingroup$

So close yet so far (I think)

A function within an addon am creating is suppose to rename the file ouput using tokens. This is based on the Oscurart tools.

The projects consists of markers on every frame with different binded cameras. The rendered image name needs to consist of a Marker and Camera.

def replaceMarker (dummy):
    global renderpath
#Set Tokens variables
    cameraCURRENT = bpy.context.scene.camera.name
    markerTIMELINE = []
    for marker in bpy.context.scene.timeline_markers:
        name = marker.name
        markerTIMELINE.extend([name])
    markerCURRENT = markerTIMELINE[bpy.context.scene.frame_current-1]

    tokens = {
        "$Marker":markerCURRENT,
    "$Camera":cameraCURRENT
        }
#Replace filename output
    renderpath = bpy.context.scene.render.filepath

    bpy.context.scene.render.filepath = renderpath.replace("$Marker",tokens["$Marker"]).replace("$Camera",tokens["$Camera"])
    print(bpy.context.scene.render.filepath)
#Clear list to repeat sequence
    markerTIMELINE.clear()

The function does not replace the marker and only uses one camera name.

Am I suppose to more this to the init.py? How can I call the function between every frame?

Thanks

EDIT Question to circumvent the issue, it is possible to access the Metadata in fileoutput and use it to rename the file?

$\endgroup$
5
  • $\begingroup$ Have you checked that the file path actually contains the markers? If it doesn't, then it can't replace them. $\endgroup$ – Robert Gützkow Dec 3 '19 at 11:59
  • $\begingroup$ Yes, I can using a dummy file to test the addon. The output is set to /tmp\AAA - $Marker - $Camera $\endgroup$ – Sharl Dec 3 '19 at 12:11
  • $\begingroup$ I think we are missing some context information in how this function is used that would explain the problem. $\endgroup$ – Robert Gützkow Dec 3 '19 at 12:43
  • $\begingroup$ Basically, I am creating a proof of concept to develop an addon which will integrate Blender in the Company's future 3D pipeline. All functions are outside the init.py file, called upon with the import function. As I progress, I can keep adding functions and tools to assist none 3D personal. The file output rename function is in its own file. $\endgroup$ – Sharl Dec 3 '19 at 13:18
  • $\begingroup$ I would very much like to see a solution for this. My current project has several cameras bound to the timeline, and I want my output frames named according to the cameras they were rendered from. $\endgroup$ – Coby Randal Apr 29 '20 at 3:53
0
$\begingroup$

So sorry for the very late reply. I found the answer in another thread and with some help.

But below is the Render Function I am currently using.

    bl_idname = "render.colorways"
    bl_label = "Render list"
    bl_description = "Render colorways with marker in filename"

    # Define some variables to register
    _timer = None
    shots = None
    stop = None
    rendering = None
    path = "/tmp/"

    # Set up the handler methods
    def pre(self, scene, depsgraph):
        self.rendering = True

    def post(self, scene, depsgraph):
        self.rendering = False

    def cancelled(self, scene, depsgraph):
        self.stop = True

    def execute(self, context):
        # Define the variables during execution. This allows
        # to define when called from a button
        self.stop = False
        self.rendering = False

        # Get all markers in a list and assign them to shots variable
        itemmarkers = bpy.context.scene.timeline_markers.items()
        self.shots = []
        self.shots.clear
        for m in itemmarkers:
            self.shots.append(m[0])
            
        #don't know why but I need to begin 1 frame before the start
        bpy.context.scene.frame_set(bpy.context.scene.frame_start - 1)
        
        self.path = context.scene.render.filepath

        bpy.app.handlers.render_pre.append(self.pre)
        bpy.app.handlers.render_post.append(self.post)
        bpy.app.handlers.render_cancel.append(self.cancelled)

        # The timer gets created and the modal handler
        # is added to the window manager
        self._timer = context.window_manager.event_timer_add(0.5, window=context.window)
        context.window_manager.modal_handler_add(self)

        return {"RUNNING_MODAL"}

    def modal(self, context, event):
        if event.type == 'TIMER':
            scn = context.scene
            
            # filename prefix ans suffix
            firstpart = bpy.context.scene.TextInputProps.nameprefix
            lastpart = bpy.context.scene.TextInputProps.namesuffix
            
            # No frames in the list or user hits ESC
            if True in (scn.frame_current >= scn.frame_end, self.stop is True):

                # We remove the handlers and the modal timer to clean everything
                bpy.app.handlers.render_pre.remove(self.pre)
                bpy.app.handlers.render_post.remove(self.post)
                bpy.app.handlers.render_cancel.remove(self.cancelled)
                context.window_manager.event_timer_remove(self._timer)

                # Reset the output path
                scn.render.filepath = self.path
                return {"FINISHED"}

            elif self.rendering is False: # Nothing is currently rendering.
                                          # Proceed to render.
                # Get the marker from the list
                marker_name  = self.shots[scn.frame_current]

                #Create filename variable
                if firstpart == "" and lastpart == "":
                    finalfilename = marker_name
                elif firstpart == "" and lastpart != "":
                    finalfilename = marker_name +"_"+ lastpart
                elif firstpart != "" and lastpart == "":
                    finalfilename = firstpart +"_"+ marker_name
                else:
                    finalfilename = firstpart +"_"+ marker_name +"_"+ lastpart
    
                # Assemble the file path and filename
                scn.render.filepath = os.path.join(self.path, finalfilename + "." + scn.render.image_settings.file_format)

                # Call the render operator
                bpy.ops.render.render("INVOKE_DEFAULT", write_still=True)
                
                # Set the next frame
                scn.frame_set(scn.frame_current + 1)

        return {"PASS_THROUGH"}

There is one issue, in the render process certain frames don't save. Perhaps optimizing the loop the statement in the def modal would help.

I hope this helps.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.