7
$\begingroup$

is there a way to automate render file names and avoid accidental overwrites?

E.G. add timestamp to filename?

I find my workflow involves many fast test renders, and it drives me nuts that for each time I launch F12 if I have not renamed previous render and overwrite is enabled I lose it, if overwrite is not enabled it does not save the file automatically.

I am using the compositor file output node to at least automate file saving for images

I do not understand why there is no simple way to press F12 and have a file with a unique name (eg. timestamp added at end) be saved automatically as soon as the render is complete, it seems ridiculous that you can wait maybe hours for a render to be done and risk losing it entirely because it is accidentally overwritten or you forget that you have not saved it.

After a day passed fruitlessly googling and reading forums I humbly ask for help here!

$\endgroup$
2
  • 2
    $\begingroup$ Related: blender.stackexchange.com/questions/127573/… $\endgroup$
    – p2or
    Commented Mar 23, 2020 at 11:34
  • $\begingroup$ All I want is a stopper: "Are you sure about overwriting the previous file? CANCEL OK" pop up. Obviously since I see the red filename box all the time I don't even pay attention as I just written over my texture image with a render of the object I was texturing image. $\endgroup$ Commented Jan 9, 2022 at 17:08

3 Answers 3

11
$\begingroup$

The following add-on generates a unique file path from a given directory and the current timestamp. It modifies both the output path (Output Properties > Output) and every base path of File Output nodes.

UI screenshot

For instance, if the directory (Output Properties > Auto-Filename > Directory) is set to C:\tmp\ and the current timestamp is 2020-03-22_01_10_43_857754 then the output path is C:\tmp\2020-03-22_01_10_43_857754\#### and the base path of the File Output nodes are C:\tmp\2020-03-22_01_10_43_857754\[name of the file output node].

bl_info = {
    "name": "Auto-Filepath",
    "author": "Robert Guetzkow",
    "version": (1, 0, 2),
    "blender": (2, 80, 0),
    "location": "Output Properties > Auto-filepath",
    "description": "Automatically sets a unique filepath for each frame based on the current timestamp.",
    "warning": "",
    "wiki_url": "",
    "category": "Render"}

import bpy
import datetime
from pathlib import Path
from bpy.app.handlers import persistent


@persistent
def update_filepath(self):
    if not bpy.context.scene.auto_filepath_settings.use_auto_filepath:
        return
    now = datetime.datetime.now()
    path = Path(bpy.context.scene.auto_filepath_settings.directory)
    base_path = path / now.strftime('%Y-%m-%d_%H_%M_%S_%f')
    bpy.context.scene.render.filepath = str(base_path / "####")
    bpy.context.scene.render.use_file_extension = True
    bpy.context.scene.render.use_overwrite = False
    if bpy.context.scene.use_nodes:
        for node in bpy.context.scene.node_tree.nodes:
            if node.type == "OUTPUT_FILE":
                node.base_path = str(base_path / node.name)


def set_directory(self, value):
    path = Path(value)
    if path.is_dir():
        self["directory"] = value


def get_directory(self):
    return self.get("directory", bpy.context.scene.auto_filepath_settings.bl_rna.properties["directory"].default)


class AutoFilepathSettings(bpy.types.PropertyGroup):
    use_auto_filepath: bpy.props.BoolProperty(name="Automatic filepath generation.",
                                              description="Enable/disable automatic filepath generation. When enabled, "
                                                          "this will overwrite the output path and the base path of "
                                                          "all File Output nodes.",
                                              default=False)

    directory: bpy.props.StringProperty(name="Directory",
                                        description="Directory where files shall be stored.",
                                        default="/",
                                        maxlen=4096,
                                        subtype="DIR_PATH",
                                        set=set_directory,
                                        get=get_directory)


class AUTOFILEPATH_PT_panel(bpy.types.Panel):
    bl_label = "Auto-Filepath"
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_context = "output"
    bl_options = {"DEFAULT_CLOSED"}

    def draw_header(self, context):
        self.layout.prop(context.scene.auto_filepath_settings, "use_auto_filepath", text="")

    def draw(self, context):
        layout = self.layout
        layout.prop(context.scene.auto_filepath_settings, "directory")


classes = (AutoFilepathSettings, AUTOFILEPATH_PT_panel)


def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    bpy.types.Scene.auto_filepath_settings = bpy.props.PointerProperty(type=AutoFilepathSettings)
    if update_filepath not in bpy.app.handlers.render_pre:
        bpy.app.handlers.render_pre.append(update_filepath)


def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)
    del bpy.types.Scene.auto_filepath_settings
    if update_filepath in bpy.app.handlers.render_pre:
        bpy.app.handlers.render_pre.remove(update_filepath)


if __name__ == "__main__":
    register()

The add-on can also be downloaded from GitHub Gist.

$\endgroup$
10
  • $\begingroup$ Wow this is almost exactly what I need, thank you so much! If I may ask, is there a way to adapt the code so the renaming occurs just to the file name itself rather than creating a sub-folder for each render? In any case thank you so much for your help, this is already a big problem solved! $\endgroup$ Commented Mar 22, 2020 at 21:39
  • $\begingroup$ Yes, that's possible. How should the names be formatted? It would still be necessary to have unique names among multiple file output nodes. Should the node name be included in the filename? $\endgroup$ Commented Mar 22, 2020 at 21:55
  • $\begingroup$ Ideally I would like the file naming to work in this way: render image: filename is timestamp, file is in output folder. render animation: filename is timestamp + #### framenumber, in output folder or subfolder, it makes little difference. I currently only ever use one output node, and name does not need to be included, as compositing or separate render layers are not a big part of my workflow. Thanks! $\endgroup$ Commented Mar 23, 2020 at 7:53
  • 1
    $\begingroup$ @ddd That look like an error to me, but it's currently 3am. Let me take another look tomorrow. $\endgroup$ Commented Oct 8, 2020 at 0:42
  • 1
    $\begingroup$ @ddd Yes, that was an error. It's fixed now. $\endgroup$ Commented Oct 8, 2020 at 9:27
1
$\begingroup$

Press F2 and click "+" next to the file name input field. This indexes .blend files. The same goes for rendered images (F3). To my knowledge your problem involves scripting or code alteration as this is not yet automatic by default.

$\endgroup$
1
  • $\begingroup$ FYI, you can also use Numpad+, Shift Numpad+ and Ctrl Numpad+. $\endgroup$
    – lemon
    Commented Mar 22, 2020 at 6:53
0
$\begingroup$

Here is my take Robert's plugin. Rather than creating new folder for each rendered image or animation frame the plugin will preppend timestamps to file names. The timestamp is created when the render job is started and not when the frame is rendered thus for animation renders the timestamp will be the same for all frames and thus images can be used as image sequence. There is also additional setting that lets you put animation jobs into a separate timestamped folder.

Save the code below as .py file and install as addon in Blender. Also for the near future code will be maintained on gist: https://gist.github.com/QuietNoise/c56c5f4bf1e42238928bf2cef481cde0

bl_info = {
    "name": "Auto-Filename",
    "author": "J. Wrong",
    "version": (1, 0, 1),
    "blender": (4, 00, 0),
    "location": "Output Properties > Auto-filename",
    "description": "Automatically sets a unique filename for each frame based on the current timestamp. Inspired by original code by Robert Guetzkow",
    "warning": "",
    "wiki_url": "",
    "category": "Render"}

import bpy
import datetime
from pathlib import Path
from bpy.app.handlers import persistent


@persistent
def update_filename(self):
    # If auto filename generation is disabled, do nothing.
    if not bpy.context.scene.auto_filename_settings.use_auto_filename:
        return

    # Get the current timestamp and Path object for the base directory.
    now = datetime.datetime.now()
    base_path = Path(bpy.context.scene.auto_filename_settings.directory)
    foldername = now.strftime('%Y-%m-%d_%H_%M_%S_%f')
    filename = foldername + " - ####"

    # Should animation renders be put in a subfolder?
    if bpy.context.scene.auto_filename_settings.animations_in_subfolder:
        bpy.context.scene.render.filepath = str(base_path / foldername / filename)
    else:
        bpy.context.scene.render.filepath = str(base_path / filename )

    if bpy.context.scene.use_nodes:
        for node in bpy.context.scene.node_tree.nodes:
            if node.type == "OUTPUT_FILE":
                node.file_slots[0].path = node.name + " - " + filename


def set_directory(self, value):
    path = Path(value)
    if path.is_dir():
        self["directory"] = value


def get_directory(self):
    return self.get("directory", bpy.context.scene.auto_filename_settings.bl_rna.properties["directory"].default)


class AutoFilenameSettings(bpy.types.PropertyGroup):
    use_auto_filename: bpy.props.BoolProperty(name="Automatic filename generation.",
                                              description="Enable/disable automatic filename generation for renders",
                                              default=False)

    directory: bpy.props.StringProperty(name="Directory",
                                        description="Directory where files shall be stored",
                                        default="/",
                                        maxlen=4096,
                                        subtype="DIR_PATH",
                                        set=set_directory,
                                        get=get_directory)

    animations_in_subfolder: bpy.props.BoolProperty(name="Put animation jobs in subfolder.",
                                              description="Whether animation render jobs should be put in a timestamped subfolder",
                                              default=False)


class AUTOFILENAME_PT_panel(bpy.types.Panel):
    bl_label = "Auto-Filename"
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_context = "output"
    bl_options = {"DEFAULT_CLOSED"}

    def draw_header(self, context):
        self.layout.prop(context.scene.auto_filename_settings, "use_auto_filename", text="")

    def draw(self, context):
        layout = self.layout
        layout.prop(context.scene.auto_filename_settings, "directory")
        layout.prop(context.scene.auto_filename_settings, "animations_in_subfolder", text="Put animation jobs in subfolder")


classes = (AutoFilenameSettings, AUTOFILENAME_PT_panel)


def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    bpy.types.Scene.auto_filename_settings = bpy.props.PointerProperty(type=AutoFilenameSettings)
    if update_filename not in bpy.app.handlers.render_init:
        bpy.app.handlers.render_init.append(update_filename)



def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)
    del bpy.types.Scene.auto_filename_settings
    if update_filename in bpy.app.handlers.render_init:
        bpy.app.handlers.render_init.remove(update_filename)


if __name__ == "__main__":
    register()
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .