diff options
Diffstat (limited to 'intern/cycles/blender/addon')
-rw-r--r-- | intern/cycles/blender/addon/__init__.py | 6 | ||||
-rw-r--r-- | intern/cycles/blender/addon/operators.py | 133 | ||||
-rw-r--r-- | intern/cycles/blender/addon/properties.py | 6 | ||||
-rw-r--r-- | intern/cycles/blender/addon/ui.py | 23 |
4 files changed, 145 insertions, 23 deletions
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py index 038126278aa..1f148538328 100644 --- a/intern/cycles/blender/addon/__init__.py +++ b/intern/cycles/blender/addon/__init__.py @@ -37,6 +37,8 @@ if "bpy" in locals(): importlib.reload(version_update) if "ui" in locals(): importlib.reload(ui) + if "operators" in locals(): + importlib.reload(operators) if "properties" in locals(): importlib.reload(properties) if "presets" in locals(): @@ -118,6 +120,7 @@ classes = ( def register(): from bpy.utils import register_class from . import ui + from . import operators from . import properties from . import presets import atexit @@ -130,6 +133,7 @@ def register(): properties.register() ui.register() + operators.register() presets.register() for cls in classes: @@ -141,6 +145,7 @@ def register(): def unregister(): from bpy.utils import unregister_class from . import ui + from . import operators from . import properties from . import presets import atexit @@ -148,6 +153,7 @@ def unregister(): bpy.app.handlers.version_update.remove(version_update.do_versions) ui.unregister() + operators.unregister() properties.unregister() presets.unregister() diff --git a/intern/cycles/blender/addon/operators.py b/intern/cycles/blender/addon/operators.py new file mode 100644 index 00000000000..c39aa386203 --- /dev/null +++ b/intern/cycles/blender/addon/operators.py @@ -0,0 +1,133 @@ +# +# Copyright 2011-2019 Blender Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# <pep8 compliant> + +import bpy +from bpy.types import Operator +from bpy.props import StringProperty + + +class CYCLES_OT_use_shading_nodes(Operator): + """Enable nodes on a material, world or light""" + bl_idname = "cycles.use_shading_nodes" + bl_label = "Use Nodes" + + @classmethod + def poll(cls, context): + return (getattr(context, "material", False) or getattr(context, "world", False) or + getattr(context, "light", False)) + + def execute(self, context): + if context.material: + context.material.use_nodes = True + elif context.world: + context.world.use_nodes = True + elif context.light: + context.light.use_nodes = True + + return {'FINISHED'} + + +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""" + 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', + default='', + subtype='FILE_PATH') + + output_filepath = StringProperty( + name='Output Filepath', + description='If not specified, renders will be denoised in-place', + default='', + subtype='FILE_PATH') + + def execute(self, context): + import os + + preferences = context.user_preferences + scene = context.scene + render_layer = scene.render.layers.active + + 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 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. + import _cycles + try: + _cycles.denoise(preferences.as_pointer(), + scene.as_pointer(), + render_layer.as_pointer(), + input=in_filepaths, + output=out_filepaths) + except Exception as e: + self.report({'ERROR'}, str(e)) + return {'FINISHED'} + + self.report({'INFO'}, "Denoising completed.") + return {'FINISHED'} + + +classes = ( + CYCLES_OT_use_shading_nodes, + CYCLES_OT_denoise_animation +) + +def register(): + from bpy.utils import register_class + for cls in classes: + register_class(cls) + + +def unregister(): + from bpy.utils import unregister_class + for cls in classes: + unregister_class(cls) diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 23ab1cf6a30..1106923f529 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -1344,6 +1344,12 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup): default=False, update=update_render_passes, ) + denoising_neighbor_frames: IntProperty( + name="Neighbor Frames", + description="Number of neighboring frames to use for denoising animations (more frames produce smoother results at the cost of performance)", + min=0, max=7, + default=0, + ) cls.use_pass_crypto_object = BoolProperty( name="Cryptomatte Object", description="Render cryptomatte object pass, for isolating objects in compositing", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 2f1adfe4178..e372843d763 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -22,7 +22,6 @@ import _cycles from bpy.types import ( Panel, Menu, - Operator, ) @@ -912,27 +911,6 @@ class CYCLES_OBJECT_PT_cycles_settings(CyclesButtonsPanel, Panel): sub.prop(cob, "use_distance_cull") -class CYCLES_OT_use_shading_nodes(Operator): - """Enable nodes on a material, world or lamp""" - bl_idname = "cycles.use_shading_nodes" - bl_label = "Use Nodes" - - @classmethod - def poll(cls, context): - return (getattr(context, "material", False) or getattr(context, "world", False) or - getattr(context, "lamp", False)) - - def execute(self, context): - if context.material: - context.material.use_nodes = True - elif context.world: - context.world.use_nodes = True - elif context.lamp: - context.lamp.use_nodes = True - - return {'FINISHED'} - - def find_node(material, nodetype): if material and material.node_tree: ntree = material.node_tree @@ -1870,7 +1848,6 @@ classes = ( CYCLES_PT_context_material, CYCLES_OBJECT_PT_motion_blur, CYCLES_OBJECT_PT_cycles_settings, - CYCLES_OT_use_shading_nodes, CYCLES_LAMP_PT_preview, CYCLES_LAMP_PT_lamp, CYCLES_LAMP_PT_nodes, |