diff --git a/intern/cycles/blender/addon/operators.py b/intern/cycles/blender/addon/operators.py index c39aa386203..a099970c58c 100644 --- a/intern/cycles/blender/addon/operators.py +++ b/intern/cycles/blender/addon/operators.py @@ -43,15 +43,15 @@ class CYCLES_OT_use_shading_nodes(Operator): class CYCLES_OT_denoise_animation(Operator): - """Denoise rendered animation sequence using current scene and view """ \ - """layer settings. Requires denoising data passes and output to """ \ - """OpenEXR multilayer files""" + "Denoise rendered animation sequence using current scene and view " \ + "layer settings. Requires denoising data passes and output to " \ + "OpenEXR multilayer files" bl_idname = "cycles.denoise_animation" bl_label = "Denoise Animation" input_filepath = StringProperty( name='Input Filepath', - description='File path for frames to denoise. If not specified, uses the render file path from the scene', + description='File path for image to denoise. If not specified, uses the render file path and frame range from the scene', default='', subtype='FILE_PATH') @@ -71,33 +71,41 @@ class CYCLES_OT_denoise_animation(Operator): in_filepath = self.input_filepath out_filepath = self.output_filepath - if in_filepath == '': - in_filepath = scene.render.filepath - if out_filepath == '': - out_filepath = in_filepath - - # Backup since we will overwrite the scene path temporarily - original_filepath = scene.render.filepath - - # Expand filepaths for each frame so we match Blender render output exactly. in_filepaths = [] out_filepaths = [] - for frame in range(scene.frame_start, scene.frame_end + 1): - scene.render.filepath = in_filepath - filepath = scene.render.frame_path(frame=frame) - in_filepaths.append(filepath) + if in_filepath != '': + # Denoise a single file + if out_filepath == '': + out_filepath = in_filepath - if not os.path.isfile(filepath): - scene.render.filepath = original_filepath - self.report({'ERROR'}, f"Frame '{filepath}' not found, animation must be complete.") - return {'CANCELLED'} + in_filepaths.append(in_filepath) + out_filepaths.append(out_filepath) + else: + # Denoise animation sequence with expanded frames matching + # Blender render output file naming. + in_filepath = scene.render.filepath + if out_filepath == '': + out_filepath = in_filepath - scene.render.filepath = out_filepath - filepath = scene.render.frame_path(frame=frame) - out_filepaths.append(filepath) + # Backup since we will overwrite the scene path temporarily + original_filepath = scene.render.filepath - scene.render.filepath = original_filepath + for frame in range(scene.frame_start, scene.frame_end + 1): + scene.render.filepath = in_filepath + filepath = scene.render.frame_path(frame=frame) + in_filepaths.append(filepath) + + if not os.path.isfile(filepath): + scene.render.filepath = original_filepath + self.report({'ERROR'}, f"Frame '{filepath}' not found, animation must be complete.") + return {'CANCELLED'} + + scene.render.filepath = out_filepath + filepath = scene.render.frame_path(frame=frame) + out_filepaths.append(filepath) + + scene.render.filepath = original_filepath # Run denoiser # TODO: support cancel and progress reports. diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index b5cc39ae37a..46e917226e4 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -549,6 +549,7 @@ if(WITH_CYCLES) add_cycles_render_test(bake) add_cycles_render_test(bsdf) add_cycles_render_test(denoise) + add_cycles_render_test(denoise_animation) add_cycles_render_test(displacement) add_cycles_render_test(hair) add_cycles_render_test(image_data_types) diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py index a01a6f74e15..1717210663a 100755 --- a/tests/python/cycles_render_tests.py +++ b/tests/python/cycles_render_tests.py @@ -14,61 +14,40 @@ def render_file(filepath, output_filepath): basedir = os.path.dirname(dirname) subject = os.path.basename(dirname) - custom_args = os.getenv('CYCLESTEST_ARGS') - custom_args = shlex.split(custom_args) if custom_args else [] + frame_filepath = output_filepath + '0001.png' + + common_args = [ + "-noaudio", + "--factory-startup", + "--enable-autoexec", + filepath, + "-E", "CYCLES", + "-o", output_filepath, + "-F", "PNG"] # OSL and GPU examples # custom_args += ["--python-expr", "import bpy; bpy.context.scene.cycles.shading_system = True"] # custom_args += ["--python-expr", "import bpy; bpy.context.scene.cycles.device = 'GPU'"] - - frame_filepath = output_filepath + '0001.png' + custom_args = os.getenv('CYCLESTEST_ARGS') + custom_args = shlex.split(custom_args) if custom_args else [] + common_args += custom_args if subject == 'opengl': - command = [ - BLENDER, - "--window-geometry", "0", "0", "1", "1", - "-noaudio", - "--factory-startup", - "--enable-autoexec", - filepath, - "-E", "CYCLES"] - command += custom_args - command += [ - "-o", output_filepath, - "-F", "PNG", - '--python', os.path.join(basedir, - "util", - "render_opengl.py")] + command = [BLENDER, "--window-geometry", "0", "0", "1", "1"] + command += common_args + command += ['--python', os.path.join(basedir, "util", "render_opengl.py")] elif subject == 'bake': - command = [ - BLENDER, - "-b", - "-noaudio", - "--factory-startup", - "--enable-autoexec", - filepath, - "-E", "CYCLES"] - command += custom_args - command += [ - "-o", output_filepath, - "-F", "PNG", - '--python', os.path.join(basedir, - "util", - "render_bake.py")] + command = [BLENDER, "--background"] + command += common_args + command += ['--python', os.path.join(basedir, "util", "render_bake.py")] + elif subject == 'denoise_animation': + command = [BLENDER, "--background"] + command += common_args + command += ['--python', os.path.join(basedir, "util", "render_denoise.py")] else: - command = [ - BLENDER, - "--background", - "-noaudio", - "--factory-startup", - "--enable-autoexec", - filepath, - "-E", "CYCLES"] - command += custom_args - command += [ - "-o", output_filepath, - "-F", "PNG", - "-f", "1"] + command = [BLENDER, "--background"] + command += common_args + command += ["-f", "1"] try: # Success