Fix #134920: File Output writes frame for single render
The File Output node always appends the frame number even if the render is not an animation. This patch makes it such that the frame number is only written if the render is an animation. The user can use a frame variable to manually append the frame number if needed. The command line rendering interface already uses animation rendering in all cases, so it should not be affected. However, rendering using the render.render() operator with animation=False will see the behavior change, however, setting animation=False and start_frame and end_frame to the same frame number should be sufficient to restore the old behavior. Pull Request: https://projects.blender.org/blender/blender/pulls/141209
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -169,6 +169,7 @@ static Vector<path_templates::Error> 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<path_templates::Error> 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_templates::Error> path_errors = compute_image_path(
|
||||
directory, file_name, file_name_suffix, view, scene.r.cfra, format, scene, node, image_path);
|
||||
const Vector<path_templates::Error> 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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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__":
|
||||
|
||||
Reference in New Issue
Block a user