diff --git a/source/blender/compositor/COM_render_context.hh b/source/blender/compositor/COM_render_context.hh index 62fe09acc19..281ef858eb7 100644 --- a/source/blender/compositor/COM_render_context.hh +++ b/source/blender/compositor/COM_render_context.hh @@ -90,6 +90,10 @@ class FileOutput { * data from each of the evaluations of each view, for instance, to save all views in a single file * for the File Output node, see the file_outputs_ member for more information. */ class RenderContext { + public: + /* True if the render context represents an animation render. */ + bool is_animation_render = false; + private: /* A mapping between file outputs and their image file paths. Those are constructed in the * get_file_output method and saved in the save_file_outputs method. See those methods for more diff --git a/source/blender/nodes/composite/nodes/node_composite_file_output.cc b/source/blender/nodes/composite/nodes/node_composite_file_output.cc index c05246cfad7..7b66251a4ca 100644 --- a/source/blender/nodes/composite/nodes/node_composite_file_output.cc +++ b/source/blender/nodes/composite/nodes/node_composite_file_output.cc @@ -169,6 +169,7 @@ static Vector compute_image_path(const StringRefNull dire const ImageFormatData &format, const Scene &scene, const bNode &node, + const bool is_animation_render, char *r_image_path) { char base_path[FILE_MAX] = ""; @@ -188,7 +189,7 @@ static Vector compute_image_path(const StringRefNull dire frame_number, &format, scene.r.scemode & R_EXTENSION, - true, + is_animation_render, BKE_scene_multiview_view_suffix_get(&scene.r, view)); } @@ -238,8 +239,16 @@ static void output_path_layout(uiLayout *layout, { char image_path[FILE_MAX]; - const Vector path_errors = compute_image_path( - directory, file_name, file_name_suffix, view, scene.r.cfra, format, scene, node, image_path); + const Vector path_errors = compute_image_path(directory, + file_name, + file_name_suffix, + view, + scene.r.cfra, + format, + scene, + node, + false, + image_path); if (path_errors.is_empty()) { layout->label(image_path, ICON_FILE_IMAGE); @@ -729,6 +738,7 @@ class FileOutputOperation : public NodeOperation { format, this->context().get_scene(), this->bnode(), + this->is_animation_render(), r_image_path); if (!path_errors.is_empty()) { @@ -782,6 +792,14 @@ class FileOutputOperation : public NodeOperation { domain.transformation.location() = float2(0.0f); return domain; } + + bool is_animation_render() + { + if (!this->context().render_context()) { + return false; + } + return this->context().render_context()->is_animation_render; + } }; static NodeOperation *get_compositor_operation(Context &context, DNode node) diff --git a/source/blender/render/intern/pipeline.cc b/source/blender/render/intern/pipeline.cc index 31e22f3a5fb..30c7c9e654e 100644 --- a/source/blender/render/intern/pipeline.cc +++ b/source/blender/render/intern/pipeline.cc @@ -1366,6 +1366,7 @@ static void do_render_compositor(Render *re) CLOG_STR_INFO(&LOG, "Executing compositor"); blender::compositor::RenderContext compositor_render_context; + compositor_render_context.is_animation_render = re->flag & R_ANIMATION; LISTBASE_FOREACH (RenderView *, rv, &re->result->views) { COM_execute(re, &re->r, diff --git a/tests/python/compositor_file_output_tests.py b/tests/python/compositor_file_output_tests.py index c676883c7c4..d2017ea39df 100644 --- a/tests/python/compositor_file_output_tests.py +++ b/tests/python/compositor_file_output_tests.py @@ -209,7 +209,7 @@ class FileOutputTest(unittest.TestCase): # Set output directory for all existing file output nodes. set_directory(bpy.data.scenes[0].compositing_node_group, f'{curr_out_dir}/') bpy.data.scenes[0].render.compositor_device = f'{self.execution_device}' - bpy.ops.render.render() + bpy.ops.render.render(animation=True, start_frame=1, end_frame=1) if __name__ == "__main__":