diff options
Diffstat (limited to 'intern/cycles/blender')
20 files changed, 3171 insertions, 3116 deletions
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py index 038126278aa..d222b4c8038 100644 --- a/intern/cycles/blender/addon/__init__.py +++ b/intern/cycles/blender/addon/__init__.py @@ -19,7 +19,7 @@ bl_info = { "name": "Cycles Render Engine", "author": "", - "blender": (2, 76, 0), + "blender": (2, 80, 0), "location": "Info header, render engine menu", "description": "Cycles Render Engine integration", "warning": "", @@ -52,7 +52,7 @@ from . import ( class CyclesRender(bpy.types.RenderEngine): bl_idname = 'CYCLES' - bl_label = "Cycles Render" + bl_label = "Cycles" bl_use_shading_nodes = True bl_use_preview = True bl_use_exclude_layers = True @@ -66,34 +66,35 @@ class CyclesRender(bpy.types.RenderEngine): engine.free(self) # final render - def update(self, data, scene): + def update(self, data, depsgraph): if not self.session: if self.is_preview: cscene = bpy.context.scene.cycles use_osl = cscene.shading_system and cscene.device == 'CPU' - engine.create(self, data, scene, - None, None, None, use_osl) + engine.create(self, data, preview_osl=use_osl) else: - engine.create(self, data, scene) - else: - engine.reset(self, data, scene) + engine.create(self, data) + + engine.reset(self, data, depsgraph) - def render(self, scene): - engine.render(self) + def render(self, depsgraph): + engine.render(self, depsgraph) - def bake(self, scene, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result): - engine.bake(self, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result) + def bake(self, depsgraph, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result): + engine.bake(self, depsgraph, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result) # viewport render def view_update(self, context): if not self.session: - engine.create(self, context.blend_data, context.scene, + engine.create(self, context.blend_data, context.region, context.space_data, context.region_data) - engine.update(self, context.blend_data, context.scene) + + engine.reset(self, context.blend_data, context.depsgraph) + engine.sync(self, context.depsgraph, context.blend_data) def view_draw(self, context): - engine.draw(self, context.region, context.space_data, context.region_data) + engine.draw(self, context.depsgraph, context.region, context.space_data, context.region_data) def update_script_node(self, node): if engine.with_osl(): diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py index 83b9a8eee0c..b8bc74f9e35 100644 --- a/intern/cycles/blender/addon/engine.py +++ b/intern/cycles/blender/addon/engine.py @@ -81,7 +81,7 @@ def _parse_command_line(): return parser = _configure_argument_parser() - args, unknown = parser.parse_known_args(argv[argv.index("--") + 1:]) + args, _ = parser.parse_known_args(argv[argv.index("--") + 1:]) if args.cycles_resumable_num_chunks is not None: if args.cycles_resumable_current_chunk is not None: @@ -133,13 +133,12 @@ def exit(): _cycles.exit() -def create(engine, data, scene, region=None, v3d=None, rv3d=None, preview_osl=False): - import bpy +def create(engine, data, region=None, v3d=None, rv3d=None, preview_osl=False): import _cycles + import bpy data = data.as_pointer() - userpref = bpy.context.user_preferences.as_pointer() - scene = scene.as_pointer() + prefs = bpy.context.preferences.as_pointer() if region: region = region.as_pointer() if v3d: @@ -147,12 +146,8 @@ def create(engine, data, scene, region=None, v3d=None, rv3d=None, preview_osl=Fa if rv3d: rv3d = rv3d.as_pointer() - if bpy.app.debug_value == 256: - _cycles.debug_flags_update(scene) - else: - _cycles.debug_flags_reset() - - engine.session = _cycles.create(engine.as_pointer(), userpref, data, scene, region, v3d, rv3d, preview_osl) + engine.session = _cycles.create( + engine.as_pointer(), prefs, data, region, v3d, rv3d, preview_osl) def free(engine): @@ -163,38 +158,46 @@ def free(engine): del engine.session -def render(engine): +def render(engine, depsgraph): import _cycles if hasattr(engine, "session"): - _cycles.render(engine.session) + _cycles.render(engine.session, depsgraph.as_pointer()) -def bake(engine, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result): +def bake(engine, depsgraph, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result): import _cycles session = getattr(engine, "session", None) if session is not None: - _cycles.bake(engine.session, obj.as_pointer(), pass_type, pass_filter, object_id, pixel_array.as_pointer(), num_pixels, depth, result.as_pointer()) + _cycles.bake(engine.session, depsgraph.as_pointer(), obj.as_pointer(), pass_type, pass_filter, object_id, pixel_array.as_pointer(), num_pixels, depth, result.as_pointer()) -def reset(engine, data, scene): +def reset(engine, data, depsgraph): import _cycles + import bpy + + if bpy.app.debug_value == 256: + _cycles.debug_flags_update(depsgraph.scene.as_pointer()) + else: + _cycles.debug_flags_reset() + data = data.as_pointer() - scene = scene.as_pointer() - _cycles.reset(engine.session, data, scene) + depsgraph = depsgraph.as_pointer() + _cycles.reset(engine.session, data, depsgraph) -def update(engine, data, scene): +def sync(engine, depsgraph, data): import _cycles - _cycles.sync(engine.session) + _cycles.sync(engine.session, depsgraph.as_pointer()) -def draw(engine, region, v3d, rv3d): +def draw(engine, depsgraph, region, v3d, rv3d): import _cycles + depsgraph = depsgraph.as_pointer() v3d = v3d.as_pointer() rv3d = rv3d.as_pointer() # draw render image - _cycles.draw(engine.session, v3d, rv3d) + _cycles.draw(engine.session, depsgraph, v3d, rv3d) def available_devices(): @@ -253,8 +256,6 @@ def register_passes(engine, scene, srl): if crl.use_pass_volume_direct: engine.register_pass(scene, srl, "VolumeDir", 3, "RGB", 'COLOR') if crl.use_pass_volume_indirect: engine.register_pass(scene, srl, "VolumeInd", 3, "RGB", 'COLOR') - cscene = scene.cycles - if crl.use_pass_crypto_object: for i in range(0, crl.pass_crypto_depth, 2): engine.register_pass(scene, srl, "CryptoObject" + '{:02d}'.format(i), 4, "RGBA", 'COLOR') diff --git a/intern/cycles/blender/addon/presets.py b/intern/cycles/blender/addon/presets.py index 17efb00abdb..78a8605e93f 100644 --- a/intern/cycles/blender/addon/presets.py +++ b/intern/cycles/blender/addon/presets.py @@ -24,7 +24,7 @@ class AddPresetIntegrator(AddPresetBase, Operator): '''Add an Integrator Preset''' bl_idname = "render.cycles_integrator_preset_add" bl_label = "Add Integrator Preset" - preset_menu = "CYCLES_MT_integrator_presets" + preset_menu = "CYCLES_PT_integrator_presets" preset_defines = [ "cycles = bpy.context.scene.cycles" @@ -49,7 +49,7 @@ class AddPresetSampling(AddPresetBase, Operator): '''Add a Sampling Preset''' bl_idname = "render.cycles_sampling_preset_add" bl_label = "Add Sampling Preset" - preset_menu = "CYCLES_MT_sampling_presets" + preset_menu = "CYCLES_PT_sampling_presets" preset_defines = [ "cycles = bpy.context.scene.cycles" diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 23ab1cf6a30..c60db9ffc2b 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -17,12 +17,16 @@ # <pep8 compliant> import bpy -from bpy.props import (BoolProperty, - EnumProperty, - FloatProperty, - IntProperty, - PointerProperty, - StringProperty) +from bpy.props import ( + BoolProperty, + EnumProperty, + FloatProperty, + IntProperty, + PointerProperty, + StringProperty, +) + +from math import pi # enums @@ -154,586 +158,591 @@ enum_texture_limit = ( class CyclesRenderSettings(bpy.types.PropertyGroup): - @classmethod - def register(cls): - bpy.types.Scene.cycles = PointerProperty( - name="Cycles Render Settings", - description="Cycles render settings", - type=cls, - ) - cls.device = EnumProperty( - name="Device", - description="Device to use for rendering", - items=enum_devices, - default='CPU', - ) - cls.feature_set = EnumProperty( - name="Feature Set", - description="Feature set to use for rendering", - items=enum_feature_set, - default='SUPPORTED', - ) - cls.shading_system = BoolProperty( - name="Open Shading Language", - description="Use Open Shading Language (CPU rendering only)", - ) - cls.progressive = EnumProperty( - name="Integrator", - description="Method to sample lights and materials", - items=enum_integrator, - default='PATH', - ) + device: EnumProperty( + name="Device", + description="Device to use for rendering", + items=enum_devices, + default='CPU', + ) + feature_set: EnumProperty( + name="Feature Set", + description="Feature set to use for rendering", + items=enum_feature_set, + default='SUPPORTED', + ) + shading_system: BoolProperty( + name="Open Shading Language", + description="Use Open Shading Language (CPU rendering only)", + ) - cls.use_square_samples = BoolProperty( - name="Square Samples", - description="Square sampling values for easier artist control", - default=False, - ) + progressive: EnumProperty( + name="Integrator", + description="Method to sample lights and materials", + items=enum_integrator, + default='PATH', + ) - cls.samples = IntProperty( - name="Samples", - description="Number of samples to render for each pixel", - min=1, max=2147483647, - default=128, - ) - cls.preview_samples = IntProperty( - name="Preview Samples", - description="Number of samples to render in the viewport, unlimited if 0", - min=0, max=2147483647, - default=32, - ) - cls.preview_pause = BoolProperty( - name="Pause Preview", - description="Pause all viewport preview renders", - default=False, - ) - cls.preview_active_layer = BoolProperty( - name="Preview Active Layer", - description="Preview active render layer in viewport", - default=False, - ) + use_square_samples: BoolProperty( + name="Square Samples", + description="Square sampling values for easier artist control", + default=False, + ) - cls.aa_samples = IntProperty( - name="AA Samples", - description="Number of antialiasing samples to render for each pixel", - min=1, max=2097151, - default=128, - ) - cls.preview_aa_samples = IntProperty( - name="AA Samples", - description="Number of antialiasing samples to render in the viewport, unlimited if 0", - min=0, max=2097151, - default=32, - ) - cls.diffuse_samples = IntProperty( - name="Diffuse Samples", - description="Number of diffuse bounce samples to render for each AA sample", - min=1, max=1024, - default=1, - ) - cls.glossy_samples = IntProperty( - name="Glossy Samples", - description="Number of glossy bounce samples to render for each AA sample", - min=1, max=1024, - default=1, - ) - cls.transmission_samples = IntProperty( - name="Transmission Samples", - description="Number of transmission bounce samples to render for each AA sample", - min=1, max=1024, - default=1, - ) - cls.ao_samples = IntProperty( - name="Ambient Occlusion Samples", - description="Number of ambient occlusion samples to render for each AA sample", - min=1, max=1024, - default=1, - ) - cls.mesh_light_samples = IntProperty( - name="Mesh Light Samples", - description="Number of mesh emission light samples to render for each AA sample", - min=1, max=1024, - default=1, - ) + samples: IntProperty( + name="Samples", + description="Number of samples to render for each pixel", + min=1, max=2147483647, + default=128, + ) + preview_samples: IntProperty( + name="Preview Samples", + description="Number of samples to render in the viewport, unlimited if 0", + min=0, max=2147483647, + default=32, + ) + preview_pause: BoolProperty( + name="Pause Preview", + description="Pause all viewport preview renders", + default=False, + ) + aa_samples: IntProperty( + name="AA Samples", + description="Number of antialiasing samples to render for each pixel", + min=1, max=2097151, + default=128, + ) + preview_aa_samples: IntProperty( + name="AA Samples", + description="Number of antialiasing samples to render in the viewport, unlimited if 0", + min=0, max=2097151, + default=32, + ) + diffuse_samples: IntProperty( + name="Diffuse Samples", + description="Number of diffuse bounce samples to render for each AA sample", + min=1, max=1024, + default=1, + ) + glossy_samples: IntProperty( + name="Glossy Samples", + description="Number of glossy bounce samples to render for each AA sample", + min=1, max=1024, + default=1, + ) + transmission_samples: IntProperty( + name="Transmission Samples", + description="Number of transmission bounce samples to render for each AA sample", + min=1, max=1024, + default=1, + ) + ao_samples: IntProperty( + name="Ambient Occlusion Samples", + description="Number of ambient occlusion samples to render for each AA sample", + min=1, max=1024, + default=1, + ) + mesh_light_samples: IntProperty( + name="Mesh Light Samples", + description="Number of mesh emission light samples to render for each AA sample", + min=1, max=1024, + default=1, + ) - cls.subsurface_samples = IntProperty( - name="Subsurface Samples", - description="Number of subsurface scattering samples to render for each AA sample", - min=1, max=1024, - default=1, - ) + subsurface_samples: IntProperty( + name="Subsurface Samples", + description="Number of subsurface scattering samples to render for each AA sample", + min=1, max=1024, + default=1, + ) - cls.volume_samples = IntProperty( - name="Volume Samples", - description="Number of volume scattering samples to render for each AA sample", - min=1, max=1024, - default=1, - ) + volume_samples: IntProperty( + name="Volume Samples", + description="Number of volume scattering samples to render for each AA sample", + min=1, max=1024, + default=1, + ) - cls.sampling_pattern = EnumProperty( - name="Sampling Pattern", - description="Random sampling pattern used by the integrator", - items=enum_sampling_pattern, - default='SOBOL', - ) + sampling_pattern: EnumProperty( + name="Sampling Pattern", + description="Random sampling pattern used by the integrator", + items=enum_sampling_pattern, + default='SOBOL', + ) - cls.use_layer_samples = EnumProperty( - name="Layer Samples", - description="How to use per render layer sample settings", - items=enum_use_layer_samples, - default='USE', - ) + use_layer_samples: EnumProperty( + name="Layer Samples", + description="How to use per view layer sample settings", + items=enum_use_layer_samples, + default='USE', + ) - cls.sample_all_lights_direct = BoolProperty( - name="Sample All Direct Lights", - description="Sample all lights (for direct samples), rather than randomly picking one", - default=True, - ) + sample_all_lights_direct: BoolProperty( + name="Sample All Direct Lights", + description="Sample all lights (for direct samples), rather than randomly picking one", + default=True, + ) - cls.sample_all_lights_indirect = BoolProperty( - name="Sample All Indirect Lights", - description="Sample all lights (for indirect samples), rather than randomly picking one", - default=True, - ) - cls.light_sampling_threshold = FloatProperty( - name="Light Sampling Threshold", - description="Probabilistically terminate light samples when the light contribution is below this threshold (more noise but faster rendering). " - "Zero disables the test and never ignores lights", - min=0.0, max=1.0, - default=0.01, - ) + sample_all_lights_indirect: BoolProperty( + name="Sample All Indirect Lights", + description="Sample all lights (for indirect samples), rather than randomly picking one", + default=True, + ) + light_sampling_threshold: FloatProperty( + name="Light Sampling Threshold", + description="Probabilistically terminate light samples when the light contribution is below this threshold (more noise but faster rendering). " + "Zero disables the test and never ignores lights", + min=0.0, max=1.0, + default=0.01, + ) - cls.caustics_reflective = BoolProperty( - name="Reflective Caustics", - description="Use reflective caustics, resulting in a brighter image (more noise but added realism)", - default=True, - ) + caustics_reflective: BoolProperty( + name="Reflective Caustics", + description="Use reflective caustics, resulting in a brighter image (more noise but added realism)", + default=True, + ) - cls.caustics_refractive = BoolProperty( - name="Refractive Caustics", - description="Use refractive caustics, resulting in a brighter image (more noise but added realism)", - default=True, - ) + caustics_refractive: BoolProperty( + name="Refractive Caustics", + description="Use refractive caustics, resulting in a brighter image (more noise but added realism)", + default=True, + ) - cls.blur_glossy = FloatProperty( - name="Filter Glossy", - description="Adaptively blur glossy shaders after blurry bounces, " - "to reduce noise at the cost of accuracy", - min=0.0, max=10.0, - default=1.0, - ) + blur_glossy: FloatProperty( + name="Filter Glossy", + description="Adaptively blur glossy shaders after blurry bounces, " + "to reduce noise at the cost of accuracy", + min=0.0, max=10.0, + default=1.0, + ) - cls.max_bounces = IntProperty( - name="Max Bounces", - description="Total maximum number of bounces", - min=0, max=1024, - default=12, - ) + max_bounces: IntProperty( + name="Max Bounces", + description="Total maximum number of bounces", + min=0, max=1024, + default=12, + ) - cls.diffuse_bounces = IntProperty( - name="Diffuse Bounces", - description="Maximum number of diffuse reflection bounces, bounded by total maximum", - min=0, max=1024, - default=4, - ) - cls.glossy_bounces = IntProperty( - name="Glossy Bounces", - description="Maximum number of glossy reflection bounces, bounded by total maximum", - min=0, max=1024, - default=4, - ) - cls.transmission_bounces = IntProperty( - name="Transmission Bounces", - description="Maximum number of transmission bounces, bounded by total maximum", - min=0, max=1024, - default=12, - ) - cls.volume_bounces = IntProperty( - name="Volume Bounces", - description="Maximum number of volumetric scattering events", - min=0, max=1024, - default=0, - ) + diffuse_bounces: IntProperty( + name="Diffuse Bounces", + description="Maximum number of diffuse reflection bounces, bounded by total maximum", + min=0, max=1024, + default=4, + ) + glossy_bounces: IntProperty( + name="Glossy Bounces", + description="Maximum number of glossy reflection bounces, bounded by total maximum", + min=0, max=1024, + default=4, + ) + transmission_bounces: IntProperty( + name="Transmission Bounces", + description="Maximum number of transmission bounces, bounded by total maximum", + min=0, max=1024, + default=12, + ) + volume_bounces: IntProperty( + name="Volume Bounces", + description="Maximum number of volumetric scattering events", + min=0, max=1024, + default=0, + ) - cls.transparent_max_bounces = IntProperty( - name="Transparent Max Bounces", - description="Maximum number of transparent bounces", - min=0, max=1024, - default=8, - ) + transparent_max_bounces: IntProperty( + name="Transparent Max Bounces", + description="Maximum number of transparent bounces", + min=0, max=1024, + default=8, + ) - cls.volume_step_size = FloatProperty( - name="Step Size", - description="Distance between volume shader samples when rendering the volume " - "(lower values give more accurate and detailed results, but also increased render time)", - default=0.1, - min=0.0000001, max=100000.0, soft_min=0.01, soft_max=1.0, precision=4 - ) + volume_step_size: FloatProperty( + name="Step Size", + description="Distance between volume shader samples when rendering the volume " + "(lower values give more accurate and detailed results, but also increased render time)", + default=0.1, + min=0.0000001, max=100000.0, soft_min=0.01, soft_max=1.0, precision=4, + unit='LENGTH' + ) - cls.volume_max_steps = IntProperty( - name="Max Steps", - description="Maximum number of steps through the volume before giving up, " - "to avoid extremely long render times with big objects or small step sizes", - default=1024, - min=2, max=65536 - ) + volume_max_steps: IntProperty( + name="Max Steps", + description="Maximum number of steps through the volume before giving up, " + "to avoid extremely long render times with big objects or small step sizes", + default=1024, + min=2, max=65536 + ) - cls.dicing_rate = FloatProperty( - name="Dicing Rate", - description="Size of a micropolygon in pixels", - min=0.1, max=1000.0, soft_min=0.5, - default=1.0, - subtype="PIXEL" - ) - cls.preview_dicing_rate = FloatProperty( - name="Preview Dicing Rate", - description="Size of a micropolygon in pixels during preview render", - min=0.1, max=1000.0, soft_min=0.5, - default=8.0, - subtype="PIXEL" - ) + dicing_rate: FloatProperty( + name="Dicing Rate", + description="Size of a micropolygon in pixels", + min=0.1, max=1000.0, soft_min=0.5, + default=1.0, + subtype='PIXEL' + ) + preview_dicing_rate: FloatProperty( + name="Preview Dicing Rate", + description="Size of a micropolygon in pixels during preview render", + min=0.1, max=1000.0, soft_min=0.5, + default=8.0, + subtype='PIXEL' + ) - cls.max_subdivisions = IntProperty( - name="Max Subdivisions", - description="Stop subdividing when this level is reached even if the dice rate would produce finer tessellation", - min=0, max=16, - default=12, - ) + max_subdivisions: IntProperty( + name="Max Subdivisions", + description="Stop subdividing when this level is reached even if the dice rate would produce finer tessellation", + min=0, max=16, + default=12, + ) - cls.dicing_camera = PointerProperty( - name="Dicing Camera", - description="Camera to use as reference point when subdividing geometry, useful to avoid crawling " - "artifacts in animations when the scene camera is moving", - type=bpy.types.Object, - poll=lambda self, obj: obj.type == 'CAMERA', - ) - cls.offscreen_dicing_scale = FloatProperty( - name="Offscreen Dicing Scale", - description="Multiplier for dicing rate of geometry outside of the camera view. The dicing rate " - "of objects is gradually increased the further they are outside the camera view. " - "Lower values provide higher quality reflections and shadows for off screen objects, " - "while higher values use less memory", - min=1.0, soft_max=25.0, - default=4.0, - ) + dicing_camera: PointerProperty( + name="Dicing Camera", + description="Camera to use as reference point when subdividing geometry, useful to avoid crawling " + "artifacts in animations when the scene camera is moving", + type=bpy.types.Object, + poll=lambda self, obj: obj.type == 'CAMERA', + ) + offscreen_dicing_scale: FloatProperty( + name="Offscreen Dicing Scale", + description="Multiplier for dicing rate of geometry outside of the camera view. The dicing rate " + "of objects is gradually increased the further they are outside the camera view. " + "Lower values provide higher quality reflections and shadows for off screen objects, " + "while higher values use less memory", + min=1.0, soft_max=25.0, + default=4.0, + ) - cls.film_exposure = FloatProperty( - name="Exposure", - description="Image brightness scale", - min=0.0, max=10.0, - default=1.0, - ) - cls.film_transparent = BoolProperty( - name="Transparent", - description="World background is transparent, for compositing the render over another background", - default=False, - ) - cls.film_transparent_glass = BoolProperty( - name="Transparent Glass", - description="Render transmissive surfaces as transparent, for compositing glass over another background", - default=False, - ) - cls.film_transparent_roughness = FloatProperty( - name="Transparent Roughness Threshold", - description="For transparent transmission, keep surfaces with roughness above the threshold opaque", - min=0.0, max=1.0, - default=0.1, - ) + film_exposure: FloatProperty( + name="Exposure", + description="Image brightness scale", + min=0.0, max=10.0, + default=1.0, + ) + film_transparent: BoolProperty( + name="Transparent", + description="World background is transparent, for compositing the render over another background", + default=False, + ) + film_transparent_glass: BoolProperty( + name="Transparent Glass", + description="Render transmissive surfaces as transparent, for compositing glass over another background", + default=False, + ) + film_transparent_roughness: FloatProperty( + name="Transparent Roughness Threshold", + description="For transparent transmission, keep surfaces with roughness above the threshold opaque", + min=0.0, max=1.0, + default=0.1, + ) - # Really annoyingly, we have to keep it around for a few releases, - # otherwise forward compatibility breaks in really bad manner: CRASH! - # - # TODO(sergey): Remove this during 2.8x series of Blender. - cls.filter_type = EnumProperty( - name="Filter Type", - description="Pixel filter type", - items=enum_filter_types, - default='BLACKMAN_HARRIS', - ) + # Really annoyingly, we have to keep it around for a few releases, + # otherwise forward compatibility breaks in really bad manner: CRASH! + # + # TODO(sergey): Remove this during 2.8x series of Blender. + filter_type: EnumProperty( + name="Filter Type", + description="Pixel filter type", + items=enum_filter_types, + default='BLACKMAN_HARRIS', + ) - cls.pixel_filter_type = EnumProperty( - name="Filter Type", - description="Pixel filter type", - items=enum_filter_types, - default='BLACKMAN_HARRIS', - ) + pixel_filter_type: EnumProperty( + name="Filter Type", + description="Pixel filter type", + items=enum_filter_types, + default='BLACKMAN_HARRIS', + ) - cls.filter_width = FloatProperty( - name="Filter Width", - description="Pixel filter width", - min=0.01, max=10.0, - default=1.5, - ) + filter_width: FloatProperty( + name="Filter Width", + description="Pixel filter width", + min=0.01, max=10.0, + default=1.5, + subtype='PIXEL' + ) - cls.seed = IntProperty( - name="Seed", - description="Seed value for integrator to get different noise patterns", - min=0, max=2147483647, - default=0, - ) + seed: IntProperty( + name="Seed", + description="Seed value for integrator to get different noise patterns", + min=0, max=2147483647, + default=0, + ) - cls.use_animated_seed = BoolProperty( - name="Use Animated Seed", - description="Use different seed values (and hence noise patterns) at different frames", - default=False, - ) + use_animated_seed: BoolProperty( + name="Use Animated Seed", + description="Use different seed values (and hence noise patterns) at different frames", + default=False, + ) - cls.sample_clamp_direct = FloatProperty( - name="Clamp Direct", - description="If non-zero, the maximum value for a direct sample, " - "higher values will be scaled down to avoid too " - "much noise and slow convergence at the cost of accuracy", - min=0.0, max=1e8, - default=0.0, - ) + sample_clamp_direct: FloatProperty( + name="Clamp Direct", + description="If non-zero, the maximum value for a direct sample, " + "higher values will be scaled down to avoid too " + "much noise and slow convergence at the cost of accuracy", + min=0.0, max=1e8, + default=0.0, + ) - cls.sample_clamp_indirect = FloatProperty( - name="Clamp Indirect", - description="If non-zero, the maximum value for an indirect sample, " - "higher values will be scaled down to avoid too " - "much noise and slow convergence at the cost of accuracy", - min=0.0, max=1e8, - default=10.0, - ) + sample_clamp_indirect: FloatProperty( + name="Clamp Indirect", + description="If non-zero, the maximum value for an indirect sample, " + "higher values will be scaled down to avoid too " + "much noise and slow convergence at the cost of accuracy", + min=0.0, max=1e8, + default=10.0, + ) - cls.debug_tile_size = IntProperty( - name="Tile Size", - description="", - min=1, max=4096, - default=1024, - ) + debug_tile_size: IntProperty( + name="Tile Size", + description="", + min=1, max=4096, + default=1024, + ) - cls.preview_start_resolution = IntProperty( - name="Start Resolution", - description="Resolution to start rendering preview at, " - "progressively increasing it to the full viewport size", - min=8, max=16384, - default=64, - ) + preview_start_resolution: IntProperty( + name="Start Resolution", + description="Resolution to start rendering preview at, " + "progressively increasing it to the full viewport size", + min=8, max=16384, + default=64, + subtype='PIXEL' + ) - cls.debug_reset_timeout = FloatProperty( - name="Reset timeout", - description="", - min=0.01, max=10.0, - default=0.1, - ) - cls.debug_cancel_timeout = FloatProperty( - name="Cancel timeout", - description="", - min=0.01, max=10.0, - default=0.1, - ) - cls.debug_text_timeout = FloatProperty( - name="Text timeout", - description="", - min=0.01, max=10.0, - default=1.0, - ) + debug_reset_timeout: FloatProperty( + name="Reset timeout", + description="", + min=0.01, max=10.0, + default=0.1, + ) + debug_cancel_timeout: FloatProperty( + name="Cancel timeout", + description="", + min=0.01, max=10.0, + default=0.1, + ) + debug_text_timeout: FloatProperty( + name="Text timeout", + description="", + min=0.01, max=10.0, + default=1.0, + ) - cls.debug_bvh_type = EnumProperty( - name="Viewport BVH Type", - description="Choose between faster updates, or faster render", - items=enum_bvh_types, - default='DYNAMIC_BVH', - ) - cls.debug_use_spatial_splits = BoolProperty( - name="Use Spatial Splits", - description="Use BVH spatial splits: longer builder time, faster render", - default=False, - ) - cls.debug_use_hair_bvh = BoolProperty( - name="Use Hair BVH", - description="Use special type BVH optimized for hair (uses more ram but renders faster)", - default=True, - ) - cls.use_bvh_embree = BoolProperty( - name="Use Embree", - description="Use Embree as ray accelerator", - default=False, - ) - cls.debug_bvh_time_steps = IntProperty( - name="BVH Time Steps", - description="Split BVH primitives by this number of time steps to speed up render time in cost of memory", - default=0, - min=0, max=16, - ) - cls.tile_order = EnumProperty( - name="Tile Order", - description="Tile order for rendering", - items=enum_tile_order, - default='HILBERT_SPIRAL', - options=set(), # Not animatable! - ) - cls.use_progressive_refine = BoolProperty( - name="Progressive Refine", - description="Instead of rendering each tile until it is finished, " - "refine the whole image progressively " - "(this renders somewhat slower, " - "but time can be saved by manually stopping the render when the noise is low enough)", - default=False, - ) + debug_bvh_type: EnumProperty( + name="Viewport BVH Type", + description="Choose between faster updates, or faster render", + items=enum_bvh_types, + default='DYNAMIC_BVH', + ) + use_bvh_embree: BoolProperty( + name="Use Embree", + description="Use Embree as ray accelerator", + default=False, + ) + debug_use_spatial_splits: BoolProperty( + name="Use Spatial Splits", + description="Use BVH spatial splits: longer builder time, faster render", + default=False, + ) + debug_use_hair_bvh: BoolProperty( + name="Use Hair BVH", + description="Use special type BVH optimized for hair (uses more ram but renders faster)", + default=True, + ) + debug_bvh_time_steps: IntProperty( + name="BVH Time Steps", + description="Split BVH primitives by this number of time steps to speed up render time in cost of memory", + default=0, + min=0, max=16, + ) + tile_order: EnumProperty( + name="Tile Order", + description="Tile order for rendering", + items=enum_tile_order, + default='HILBERT_SPIRAL', + options=set(), # Not animatable! + ) + use_progressive_refine: BoolProperty( + name="Progressive Refine", + description="Instead of rendering each tile until it is finished, " + "refine the whole image progressively " + "(this renders somewhat slower, " + "but time can be saved by manually stopping the render when the noise is low enough)", + default=False, + ) - cls.bake_type = EnumProperty( - name="Bake Type", - default='COMBINED', - description="Type of pass to bake", - items=( - ('COMBINED', "Combined", ""), - ('AO', "Ambient Occlusion", ""), - ('SHADOW', "Shadow", ""), - ('NORMAL', "Normal", ""), - ('UV', "UV", ""), - ('ROUGHNESS', "Roughness", ""), - ('EMIT', "Emit", ""), - ('ENVIRONMENT', "Environment", ""), - ('DIFFUSE', "Diffuse", ""), - ('GLOSSY', "Glossy", ""), - ('TRANSMISSION', "Transmission", ""), - ('SUBSURFACE', "Subsurface", ""), - ), - ) + bake_type: EnumProperty( + name="Bake Type", + default='COMBINED', + description="Type of pass to bake", + items=( + ('COMBINED', "Combined", ""), + ('AO', "Ambient Occlusion", ""), + ('SHADOW', "Shadow", ""), + ('NORMAL', "Normal", ""), + ('UV', "UV", ""), + ('ROUGHNESS', "Roughness", ""), + ('EMIT', "Emit", ""), + ('ENVIRONMENT', "Environment", ""), + ('DIFFUSE', "Diffuse", ""), + ('GLOSSY', "Glossy", ""), + ('TRANSMISSION', "Transmission", ""), + ('SUBSURFACE', "Subsurface", ""), + ), + ) - cls.use_camera_cull = BoolProperty( - name="Use Camera Cull", - description="Allow objects to be culled based on the camera frustum", - default=False, - ) + use_camera_cull: BoolProperty( + name="Use Camera Cull", + description="Allow objects to be culled based on the camera frustum", + default=False, + ) - cls.camera_cull_margin = FloatProperty( - name="Camera Cull Margin", - description="Margin for the camera space culling", - default=0.1, - min=0.0, max=5.0 - ) + camera_cull_margin: FloatProperty( + name="Camera Cull Margin", + description="Margin for the camera space culling", + default=0.1, + min=0.0, max=5.0, + subtype='FACTOR' + ) - cls.use_distance_cull = BoolProperty( - name="Use Distance Cull", - description="Allow objects to be culled based on the distance from camera", - default=False, - ) + use_distance_cull: BoolProperty( + name="Use Distance Cull", + description="Allow objects to be culled based on the distance from camera", + default=False, + ) - cls.distance_cull_margin = FloatProperty( - name="Cull Distance", - description="Cull objects which are further away from camera than this distance", - default=50, - min=0.0 - ) + distance_cull_margin: FloatProperty( + name="Cull Distance", + description="Cull objects which are further away from camera than this distance", + default=50, + min=0.0, + unit='LENGTH' + ) - cls.motion_blur_position = EnumProperty( - name="Motion Blur Position", - default='CENTER', - description="Offset for the shutter's time interval, allows to change the motion blur trails", - items=( - ('START', "Start on Frame", "The shutter opens at the current frame"), - ('CENTER', "Center on Frame", "The shutter is open during the current frame"), - ('END', "End on Frame", "The shutter closes at the current frame"), - ), - ) + motion_blur_position: EnumProperty( + name="Motion Blur Position", + default='CENTER', + description="Offset for the shutter's time interval, allows to change the motion blur trails", + items=( + ('START', "Start on Frame", "The shutter opens at the current frame"), + ('CENTER', "Center on Frame", "The shutter is open during the current frame"), + ('END', "End on Frame", "The shutter closes at the current frame"), + ), + ) - cls.rolling_shutter_type = EnumProperty( - name="Shutter Type", - default='NONE', - description="Type of rolling shutter effect matching CMOS-based cameras", - items=( - ('NONE', "None", "No rolling shutter effect used"), - ('TOP', "Top-Bottom", "Sensor is being scanned from top to bottom") - # TODO(seergey): Are there real cameras with different scanning direction? - ), - ) + rolling_shutter_type: EnumProperty( + name="Shutter Type", + default='NONE', + description="Type of rolling shutter effect matching CMOS-based cameras", + items=( + ('NONE', "None", "No rolling shutter effect used"), + ('TOP', "Top-Bottom", "Sensor is being scanned from top to bottom") + # TODO(seergey): Are there real cameras with different scanning direction? + ), + ) - cls.rolling_shutter_duration = FloatProperty( - name="Rolling Shutter Duration", - description="Scanline \"exposure\" time for the rolling shutter effect", - default=0.1, - min=0.0, max=1.0, - ) + rolling_shutter_duration: FloatProperty( + name="Rolling Shutter Duration", + description="Scanline \"exposure\" time for the rolling shutter effect", + default=0.1, + min=0.0, max=1.0, + ) - cls.texture_limit = EnumProperty( - name="Viewport Texture Limit", - default='OFF', - description="Limit texture size used by viewport rendering", - items=enum_texture_limit - ) + texture_limit: EnumProperty( + name="Viewport Texture Limit", + default='OFF', + description="Limit texture size used by viewport rendering", + items=enum_texture_limit + ) - cls.texture_limit_render = EnumProperty( - name="Render Texture Limit", - default='OFF', - description="Limit texture size used by final rendering", - items=enum_texture_limit - ) + texture_limit_render: EnumProperty( + name="Render Texture Limit", + default='OFF', + description="Limit texture size used by final rendering", + items=enum_texture_limit + ) - cls.ao_bounces = IntProperty( - name="AO Bounces", - default=0, - description="Approximate indirect light with background tinted ambient occlusion at the specified bounce, 0 disables this feature", - min=0, max=1024, - ) + ao_bounces: IntProperty( + name="AO Bounces", + default=0, + description="Approximate indirect light with background tinted ambient occlusion at the specified bounce, 0 disables this feature", + min=0, max=1024, + ) - cls.ao_bounces_render = IntProperty( - name="AO Bounces Render", - default=0, - description="Approximate indirect light with background tinted ambient occlusion at the specified bounce, 0 disables this feature", - min=0, max=1024, - ) + ao_bounces_render: IntProperty( + name="AO Bounces Render", + default=0, + description="Approximate indirect light with background tinted ambient occlusion at the specified bounce, 0 disables this feature", + min=0, max=1024, + ) - # Various fine-tuning debug flags - - def devices_update_callback(self, context): - import _cycles - scene = context.scene.as_pointer() - return _cycles.debug_flags_update(scene) - - cls.debug_use_cpu_avx2 = BoolProperty(name="AVX2", default=True) - cls.debug_use_cpu_avx = BoolProperty(name="AVX", default=True) - cls.debug_use_cpu_sse41 = BoolProperty(name="SSE41", default=True) - cls.debug_use_cpu_sse3 = BoolProperty(name="SSE3", default=True) - cls.debug_use_cpu_sse2 = BoolProperty(name="SSE2", default=True) - cls.debug_bvh_layout = EnumProperty( - name="BVH Layout", - items=enum_bvh_layouts, - default='BVH8', - ) - cls.debug_use_cpu_split_kernel = BoolProperty(name="Split Kernel", default=False) - - cls.debug_use_cuda_adaptive_compile = BoolProperty(name="Adaptive Compile", default=False) - cls.debug_use_cuda_split_kernel = BoolProperty(name="Split Kernel", default=False) - - cls.debug_opencl_kernel_type = EnumProperty( - name="OpenCL Kernel Type", - default='DEFAULT', - items=( - ('DEFAULT', "Default", ""), - ('MEGA', "Mega", ""), - ('SPLIT', "Split", ""), - ), - update=devices_update_callback - ) + # Various fine-tuning debug flags - cls.debug_opencl_device_type = EnumProperty( - name="OpenCL Device Type", - default='ALL', - items=( - ('NONE', "None", ""), - ('ALL', "All", ""), - ('DEFAULT', "Default", ""), - ('CPU', "CPU", ""), - ('GPU', "GPU", ""), - ('ACCELERATOR', "Accelerator", ""), - ), - update=devices_update_callback - ) + def _devices_update_callback(self, context): + import _cycles + scene = context.scene.as_pointer() + return _cycles.debug_flags_update(scene) + + debug_use_cpu_avx2: BoolProperty(name="AVX2", default=True) + debug_use_cpu_avx: BoolProperty(name="AVX", default=True) + debug_use_cpu_sse41: BoolProperty(name="SSE41", default=True) + debug_use_cpu_sse3: BoolProperty(name="SSE3", default=True) + debug_use_cpu_sse2: BoolProperty(name="SSE2", default=True) + debug_bvh_layout: EnumProperty( + name="BVH Layout", + items=enum_bvh_layouts, + default='BVH8', + ) + debug_use_cpu_split_kernel: BoolProperty(name="Split Kernel", default=False) + + debug_use_cuda_adaptive_compile: BoolProperty(name="Adaptive Compile", default=False) + debug_use_cuda_split_kernel: BoolProperty(name="Split Kernel", default=False) + + debug_opencl_kernel_type: EnumProperty( + name="OpenCL Kernel Type", + default='DEFAULT', + items=( + ('DEFAULT', "Default", ""), + ('MEGA', "Mega", ""), + ('SPLIT', "Split", ""), + ), + update=_devices_update_callback + ) - cls.debug_opencl_kernel_single_program = BoolProperty( - name="Single Program", - default=True, - update=devices_update_callback, - ) + debug_opencl_device_type: EnumProperty( + name="OpenCL Device Type", + default='ALL', + items=( + ('NONE', "None", ""), + ('ALL', "All", ""), + ('DEFAULT', "Default", ""), + ('CPU', "CPU", ""), + ('GPU', "GPU", ""), + ('ACCELERATOR', "Accelerator", ""), + ), + update=_devices_update_callback + ) + + debug_opencl_kernel_single_program: BoolProperty( + name="Single Program", + default=True, + update=_devices_update_callback, + ) + del _devices_update_callback - cls.debug_use_opencl_debug = BoolProperty(name="Debug OpenCL", default=False) + debug_use_opencl_debug: BoolProperty(name="Debug OpenCL", default=False) - cls.debug_opencl_mem_limit = IntProperty(name="Memory limit", default=0, - description="Artificial limit on OpenCL memory usage in MB (0 to disable limit)") + debug_opencl_mem_limit: IntProperty( + name="Memory limit", + default=0, + description="Artificial limit on OpenCL memory usage in MB (0 to disable limit)" + ) + + @classmethod + def register(cls): + bpy.types.Scene.cycles = PointerProperty( + name="Cycles Render Settings", + description="Cycles render settings", + type=cls, + ) @classmethod def unregister(cls): @@ -741,113 +750,153 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): class CyclesCameraSettings(bpy.types.PropertyGroup): + + aperture_type: EnumProperty( + name="Aperture Type", + description="Use f-stop number or aperture radius", + items=enum_aperture_types, + default='RADIUS', + ) + aperture_fstop: FloatProperty( + name="Aperture f-stop", + description="F-stop ratio (lower numbers give more defocus, higher numbers give a sharper image)", + min=0.0, soft_min=0.1, soft_max=64.0, + default=5.6, + step=10, + precision=1, + ) + aperture_size: FloatProperty( + name="Aperture Size", + description="Radius of the aperture for depth of field (higher values give more defocus)", + min=0.0, soft_max=10.0, + default=0.0, + step=1, + precision=4, + subtype='DISTANCE', + ) + aperture_blades: IntProperty( + name="Aperture Blades", + description="Number of blades in aperture for polygonal bokeh (at least 3)", + min=0, max=100, + default=0, + ) + aperture_rotation: FloatProperty( + name="Aperture Rotation", + description="Rotation of blades in aperture", + soft_min=-pi, soft_max=pi, + subtype='ANGLE', + default=0, + ) + aperture_ratio: FloatProperty( + name="Aperture Ratio", + description="Distortion to simulate anamorphic lens bokeh", + min=0.01, soft_min=1.0, soft_max=2.0, + default=1.0, + precision=4, + ) + panorama_type: EnumProperty( + name="Panorama Type", + description="Distortion to use for the calculation", + items=enum_panorama_types, + default='FISHEYE_EQUISOLID', + ) + fisheye_fov: FloatProperty( + name="Field of View", + description="Field of view for the fisheye lens", + min=0.1745, soft_max=2.0 * pi, max=10.0 * pi, + subtype='ANGLE', + default=pi, + ) + fisheye_lens: FloatProperty( + name="Fisheye Lens", + description="Lens focal length (mm)", + min=0.01, soft_max=15.0, max=100.0, + default=10.5, + ) + latitude_min: FloatProperty( + name="Min Latitude", + description="Minimum latitude (vertical angle) for the equirectangular lens", + min=-0.5 * pi, max=0.5 * pi, + subtype='ANGLE', + default=-0.5 * pi, + ) + latitude_max: FloatProperty( + name="Max Latitude", + description="Maximum latitude (vertical angle) for the equirectangular lens", + min=-0.5 * pi, max=0.5 * pi, + subtype='ANGLE', + default=0.5 * pi, + ) + longitude_min: FloatProperty( + name="Min Longitude", + description="Minimum longitude (horizontal angle) for the equirectangular lens", + min=-pi, max=pi, + subtype='ANGLE', + default=-pi, + ) + longitude_max: FloatProperty( + name="Max Longitude", + description="Maximum longitude (horizontal angle) for the equirectangular lens", + min=-pi, max=pi, + subtype='ANGLE', + default=pi, + ) + @classmethod def register(cls): - import math - bpy.types.Camera.cycles = PointerProperty( name="Cycles Camera Settings", description="Cycles camera settings", type=cls, ) - cls.aperture_type = EnumProperty( - name="Aperture Type", - description="Use f-stop number or aperture radius", - items=enum_aperture_types, - default='RADIUS', - ) - cls.aperture_fstop = FloatProperty( - name="Aperture f-stop", - description="F-stop ratio (lower numbers give more defocus, higher numbers give a sharper image)", - min=0.0, soft_min=0.1, soft_max=64.0, - default=5.6, - step=10, - precision=1, - ) - cls.aperture_size = FloatProperty( - name="Aperture Size", - description="Radius of the aperture for depth of field (higher values give more defocus)", - min=0.0, soft_max=10.0, - default=0.0, - step=1, - precision=4, - subtype='DISTANCE', - ) - cls.aperture_blades = IntProperty( - name="Aperture Blades", - description="Number of blades in aperture for polygonal bokeh (at least 3)", - min=0, max=100, - default=0, - ) - cls.aperture_rotation = FloatProperty( - name="Aperture Rotation", - description="Rotation of blades in aperture", - soft_min=-math.pi, soft_max=math.pi, - subtype='ANGLE', - default=0, - ) - cls.aperture_ratio = FloatProperty( - name="Aperture Ratio", - description="Distortion to simulate anamorphic lens bokeh", - min=0.01, soft_min=1.0, soft_max=2.0, - default=1.0, - precision=4, - ) - cls.panorama_type = EnumProperty( - name="Panorama Type", - description="Distortion to use for the calculation", - items=enum_panorama_types, - default='FISHEYE_EQUISOLID', - ) - cls.fisheye_fov = FloatProperty( - name="Field of View", - description="Field of view for the fisheye lens", - min=0.1745, soft_max=2.0 * math.pi, max=10.0 * math.pi, - subtype='ANGLE', - default=math.pi, - ) - cls.fisheye_lens = FloatProperty( - name="Fisheye Lens", - description="Lens focal length (mm)", - min=0.01, soft_max=15.0, max=100.0, - default=10.5, - ) - cls.latitude_min = FloatProperty( - name="Min Latitude", - description="Minimum latitude (vertical angle) for the equirectangular lens", - min=-0.5 * math.pi, max=0.5 * math.pi, - subtype='ANGLE', - default=-0.5 * math.pi, - ) - cls.latitude_max = FloatProperty( - name="Max Latitude", - description="Maximum latitude (vertical angle) for the equirectangular lens", - min=-0.5 * math.pi, max=0.5 * math.pi, - subtype='ANGLE', - default=0.5 * math.pi, - ) - cls.longitude_min = FloatProperty( - name="Min Longitude", - description="Minimum longitude (horizontal angle) for the equirectangular lens", - min=-math.pi, max=math.pi, - subtype='ANGLE', - default=-math.pi, - ) - cls.longitude_max = FloatProperty( - name="Max Longitude", - description="Maximum longitude (horizontal angle) for the equirectangular lens", - min=-math.pi, max=math.pi, - subtype='ANGLE', - default=math.pi, - ) - @classmethod def unregister(cls): del bpy.types.Camera.cycles class CyclesMaterialSettings(bpy.types.PropertyGroup): + + sample_as_light: BoolProperty( + name="Multiple Importance Sample", + description="Use multiple importance sampling for this material, " + "disabling may reduce overall noise for large " + "objects that emit little light compared to other light sources", + default=True, + ) + use_transparent_shadow: BoolProperty( + name="Transparent Shadows", + description="Use transparent shadows for this material if it contains a Transparent BSDF, " + "disabling will render faster but not give accurate shadows", + default=True, + ) + homogeneous_volume: BoolProperty( + name="Homogeneous Volume", + description="When using volume rendering, assume volume has the same density everywhere " + "(not using any textures), for faster rendering", + default=False, + ) + volume_sampling: EnumProperty( + name="Volume Sampling", + description="Sampling method to use for volumes", + items=enum_volume_sampling, + default='MULTIPLE_IMPORTANCE', + ) + + volume_interpolation: EnumProperty( + name="Volume Interpolation", + description="Interpolation method to use for smoke/fire volumes", + items=enum_volume_interpolation, + default='LINEAR', + ) + + displacement_method: EnumProperty( + name="Displacement Method", + description="Method to use for the displacement", + items=enum_displacement_methods, + default='BUMP', + ) + @classmethod def register(cls): bpy.types.Material.cycles = PointerProperty( @@ -855,95 +904,103 @@ class CyclesMaterialSettings(bpy.types.PropertyGroup): description="Cycles material settings", type=cls, ) - cls.sample_as_light = BoolProperty( - name="Multiple Importance Sample", - description="Use multiple importance sampling for this material, " - "disabling may reduce overall noise for large " - "objects that emit little light compared to other light sources", - default=True, - ) - cls.use_transparent_shadow = BoolProperty( - name="Transparent Shadows", - description="Use transparent shadows for this material if it contains a Transparent BSDF, " - "disabling will render faster but not give accurate shadows", - default=True, - ) - cls.homogeneous_volume = BoolProperty( - name="Homogeneous Volume", - description="When using volume rendering, assume volume has the same density everywhere " - "(not using any textures), for faster rendering", - default=False, - ) - cls.volume_sampling = EnumProperty( - name="Volume Sampling", - description="Sampling method to use for volumes", - items=enum_volume_sampling, - default='MULTIPLE_IMPORTANCE', - ) - - cls.volume_interpolation = EnumProperty( - name="Volume Interpolation", - description="Interpolation method to use for smoke/fire volumes", - items=enum_volume_interpolation, - default='LINEAR', - ) - - cls.displacement_method = EnumProperty( - name="Displacement Method", - description="Method to use for the displacement", - items=enum_displacement_methods, - default='BUMP', - ) @classmethod def unregister(cls): del bpy.types.Material.cycles -class CyclesLampSettings(bpy.types.PropertyGroup): +class CyclesLightSettings(bpy.types.PropertyGroup): + + cast_shadow: BoolProperty( + name="Cast Shadow", + description="Light casts shadows", + default=True, + ) + samples: IntProperty( + name="Samples", + description="Number of light samples to render for each AA sample", + min=1, max=10000, + default=1, + ) + max_bounces: IntProperty( + name="Max Bounces", + description="Maximum number of bounces the light will contribute to the render", + min=0, max=1024, + default=1024, + ) + use_multiple_importance_sampling: BoolProperty( + name="Multiple Importance Sample", + description="Use multiple importance sampling for the light, " + "reduces noise for area lights and sharp glossy materials", + default=True, + ) + is_portal: BoolProperty( + name="Is Portal", + description="Use this area light to guide sampling of the background, " + "note that this will make the light invisible", + default=False, + ) + @classmethod def register(cls): - bpy.types.Lamp.cycles = PointerProperty( - name="Cycles Lamp Settings", - description="Cycles lamp settings", + bpy.types.Light.cycles = PointerProperty( + name="Cycles Light Settings", + description="Cycles light settings", type=cls, ) - cls.cast_shadow = BoolProperty( - name="Cast Shadow", - description="Lamp casts shadows", - default=True, - ) - cls.samples = IntProperty( - name="Samples", - description="Number of light samples to render for each AA sample", - min=1, max=10000, - default=1, - ) - cls.max_bounces = IntProperty( - name="Max Bounces", - description="Maximum number of bounces the light will contribute to the render", - min=0, max=1024, - default=1024, - ) - cls.use_multiple_importance_sampling = BoolProperty( - name="Multiple Importance Sample", - description="Use multiple importance sampling for the lamp, " - "reduces noise for area lamps and sharp glossy materials", - default=True, - ) - cls.is_portal = BoolProperty( - name="Is Portal", - description="Use this area lamp to guide sampling of the background, " - "note that this will make the lamp invisible", - default=False, - ) @classmethod def unregister(cls): - del bpy.types.Lamp.cycles + del bpy.types.Light.cycles class CyclesWorldSettings(bpy.types.PropertyGroup): + + sampling_method: EnumProperty( + name="Sampling method", + description="How to sample the background light", + items=enum_world_mis, + default='AUTOMATIC', + ) + sample_map_resolution: IntProperty( + name="Map Resolution", + description="Importance map size is resolution x resolution/2; " + "higher values potentially produce less noise, at the cost of memory and speed", + min=4, max=8192, + default=1024, + ) + samples: IntProperty( + name="Samples", + description="Number of light samples to render for each AA sample", + min=1, max=10000, + default=1, + ) + max_bounces: IntProperty( + name="Max Bounces", + description="Maximum number of bounces the background light will contribute to the render", + min=0, max=1024, + default=1024, + ) + homogeneous_volume: BoolProperty( + name="Homogeneous Volume", + description="When using volume rendering, assume volume has the same density everywhere" + "(not using any textures), for faster rendering", + default=False, + ) + volume_sampling: EnumProperty( + name="Volume Sampling", + description="Sampling method to use for volumes", + items=enum_volume_sampling, + default='EQUIANGULAR', + ) + volume_interpolation: EnumProperty( + name="Volume Interpolation", + description="Interpolation method to use for volumes", + items=enum_volume_interpolation, + default='LINEAR', + ) + @classmethod def register(cls): bpy.types.World.cycles = PointerProperty( @@ -951,50 +1008,6 @@ class CyclesWorldSettings(bpy.types.PropertyGroup): description="Cycles world settings", type=cls, ) - cls.sampling_method = EnumProperty( - name="Sampling method", - description="How to sample the background light", - items=enum_world_mis, - default='AUTOMATIC', - ) - cls.sample_map_resolution = IntProperty( - name="Map Resolution", - description="Importance map size is resolution x resolution/2; " - "higher values potentially produce less noise, at the cost of memory and speed", - min=4, max=8192, - default=1024, - ) - cls.samples = IntProperty( - name="Samples", - description="Number of light samples to render for each AA sample", - min=1, max=10000, - default=1, - ) - cls.max_bounces = IntProperty( - name="Max Bounces", - description="Maximum number of bounces the background light will contribute to the render", - min=0, max=1024, - default=1024, - ) - cls.homogeneous_volume = BoolProperty( - name="Homogeneous Volume", - description="When using volume rendering, assume volume has the same density everywhere" - "(not using any textures), for faster rendering", - default=False, - ) - cls.volume_sampling = EnumProperty( - name="Volume Sampling", - description="Sampling method to use for volumes", - items=enum_volume_sampling, - default='EQUIANGULAR', - ) - - cls.volume_interpolation = EnumProperty( - name="Volume Interpolation", - description="Interpolation method to use for volumes", - items=enum_volume_interpolation, - default='LINEAR', - ) @classmethod def unregister(cls): @@ -1002,6 +1015,38 @@ class CyclesWorldSettings(bpy.types.PropertyGroup): class CyclesVisibilitySettings(bpy.types.PropertyGroup): + + camera: BoolProperty( + name="Camera", + description="Object visibility for camera rays", + default=True, + ) + diffuse: BoolProperty( + name="Diffuse", + description="Object visibility for diffuse reflection rays", + default=True, + ) + glossy: BoolProperty( + name="Glossy", + description="Object visibility for glossy reflection rays", + default=True, + ) + transmission: BoolProperty( + name="Transmission", + description="Object visibility for transmission rays", + default=True, + ) + shadow: BoolProperty( + name="Shadow", + description="Object visibility for shadow rays", + default=True, + ) + scatter: BoolProperty( + name="Volume Scatter", + description="Object visibility for volume scatter rays", + default=True, + ) + @classmethod def register(cls): bpy.types.Object.cycles_visibility = PointerProperty( @@ -1016,37 +1061,6 @@ class CyclesVisibilitySettings(bpy.types.PropertyGroup): type=cls, ) - cls.camera = BoolProperty( - name="Camera", - description="Object visibility for camera rays", - default=True, - ) - cls.diffuse = BoolProperty( - name="Diffuse", - description="Object visibility for diffuse reflection rays", - default=True, - ) - cls.glossy = BoolProperty( - name="Glossy", - description="Object visibility for glossy reflection rays", - default=True, - ) - cls.transmission = BoolProperty( - name="Transmission", - description="Object visibility for transmission rays", - default=True, - ) - cls.shadow = BoolProperty( - name="Shadow", - description="Object visibility for shadow rays", - default=True, - ) - cls.scatter = BoolProperty( - name="Volume Scatter", - description="Object visibility for volume scatter rays", - default=True, - ) - @classmethod def unregister(cls): del bpy.types.Object.cycles_visibility @@ -1080,70 +1094,71 @@ class CyclesMeshSettings(bpy.types.PropertyGroup): class CyclesObjectSettings(bpy.types.PropertyGroup): - @classmethod - def register(cls): - bpy.types.Object.cycles = PointerProperty( - name="Cycles Object Settings", - description="Cycles object settings", - type=cls, - ) - cls.use_motion_blur = BoolProperty( - name="Use Motion Blur", - description="Use motion blur for this object", - default=True, - ) + use_motion_blur: BoolProperty( + name="Use Motion Blur", + description="Use motion blur for this object", + default=True, + ) - cls.use_deform_motion = BoolProperty( - name="Use Deformation Motion", - description="Use deformation motion blur for this object", - default=True, - ) + use_deform_motion: BoolProperty( + name="Use Deformation Motion", + description="Use deformation motion blur for this object", + default=True, + ) - cls.motion_steps = IntProperty( - name="Motion Steps", - description="Control accuracy of motion blur, more steps gives more memory usage (actual number of steps is 2^(steps - 1))", - min=1, soft_max=8, - default=1, - ) + motion_steps: IntProperty( + name="Motion Steps", + description="Control accuracy of motion blur, more steps gives more memory usage (actual number of steps is 2^(steps - 1))", + min=1, soft_max=8, + default=1, + ) - cls.use_camera_cull = BoolProperty( - name="Use Camera Cull", - description="Allow this object and its duplicators to be culled by camera space culling", - default=False, - ) + use_camera_cull: BoolProperty( + name="Use Camera Cull", + description="Allow this object and its duplicators to be culled by camera space culling", + default=False, + ) - cls.use_distance_cull = BoolProperty( - name="Use Distance Cull", - description="Allow this object and its duplicators to be culled by distance from camera", - default=False, - ) + use_distance_cull: BoolProperty( + name="Use Distance Cull", + description="Allow this object and its duplicators to be culled by distance from camera", + default=False, + ) - cls.use_adaptive_subdivision = BoolProperty( - name="Use Adaptive Subdivision", - description="Use adaptive render time subdivision", - default=False, - ) + use_adaptive_subdivision: BoolProperty( + name="Use Adaptive Subdivision", + description="Use adaptive render time subdivision", + default=False, + ) - cls.dicing_rate = FloatProperty( - name="Dicing Scale", - description="Multiplier for scene dicing rate (located in the Geometry Panel)", - min=0.1, max=1000.0, soft_min=0.5, - default=1.0, - ) + dicing_rate: FloatProperty( + name="Dicing Scale", + description="Multiplier for scene dicing rate (located in the Subdivision panel)", + min=0.1, max=1000.0, soft_min=0.5, + default=1.0, + ) - cls.is_shadow_catcher = BoolProperty( - name="Shadow Catcher", - description="Only render shadows on this object, for compositing renders into real footage", - default=False, - ) + is_shadow_catcher: BoolProperty( + name="Shadow Catcher", + description="Only render shadows on this object, for compositing renders into real footage", + default=False, + ) + + is_holdout: BoolProperty( + name="Holdout", + description="Render objects as a holdout or matte, creating a " + "hole in the image with zero alpha, to fill out in " + "compositing with real footage or another render", + default=False, + ) - cls.is_holdout = BoolProperty( - name="Holdout", - description="Render objects as a holdout or matte, creating a " - "hole in the image with zero alpha, to fill out in " - "compositing with real footange or another render", - default=False, + @classmethod + def register(cls): + bpy.types.Object.cycles = PointerProperty( + name="Cycles Object Settings", + description="Cycles object settings", + type=cls, ) @classmethod @@ -1152,6 +1167,56 @@ class CyclesObjectSettings(bpy.types.PropertyGroup): class CyclesCurveRenderSettings(bpy.types.PropertyGroup): + + primitive: EnumProperty( + name="Primitive", + description="Type of primitive used for hair rendering", + items=enum_curve_primitives, + default='LINE_SEGMENTS', + ) + shape: EnumProperty( + name="Shape", + description="Form of hair", + items=enum_curve_shape, + default='THICK', + ) + cull_backfacing: BoolProperty( + name="Cull Back-faces", + description="Do not test the back-face of each strand", + default=True, + ) + use_curves: BoolProperty( + name="Use Cycles Hair Rendering", + description="Activate Cycles hair rendering for particle system", + default=True, + ) + resolution: IntProperty( + name="Resolution", + description="Resolution of generated mesh", + min=3, max=64, + default=3, + ) + minimum_width: FloatProperty( + name="Minimal width", + description="Minimal pixel width for strands (0 - deactivated)", + min=0.0, max=100.0, + default=0.0, + subtype='PIXEL' + ) + maximum_width: FloatProperty( + name="Maximal width", + description="Maximum extension that strand radius can be increased by", + min=0.0, max=100.0, + default=0.1, + subtype='PIXEL' + ) + subdivisions: IntProperty( + name="Subdivisions", + description="Number of subdivisions used in Cardinal curve intersection (power of 2)", + min=0, max=24, + default=4, + ) + @classmethod def register(cls): bpy.types.Scene.cycles_curves = PointerProperty( @@ -1159,52 +1224,6 @@ class CyclesCurveRenderSettings(bpy.types.PropertyGroup): description="Cycles hair rendering settings", type=cls, ) - cls.primitive = EnumProperty( - name="Primitive", - description="Type of primitive used for hair rendering", - items=enum_curve_primitives, - default='LINE_SEGMENTS', - ) - cls.shape = EnumProperty( - name="Shape", - description="Form of hair", - items=enum_curve_shape, - default='THICK', - ) - cls.cull_backfacing = BoolProperty( - name="Cull back-faces", - description="Do not test the back-face of each strand", - default=True, - ) - cls.use_curves = BoolProperty( - name="Use Cycles Hair Rendering", - description="Activate Cycles hair rendering for particle system", - default=True, - ) - cls.resolution = IntProperty( - name="Resolution", - description="Resolution of generated mesh", - min=3, max=64, - default=3, - ) - cls.minimum_width = FloatProperty( - name="Minimal width", - description="Minimal pixel width for strands (0 - deactivated)", - min=0.0, max=100.0, - default=0.0, - ) - cls.maximum_width = FloatProperty( - name="Maximal width", - description="Maximum extension that strand radius can be increased by", - min=0.0, max=100.0, - default=0.1, - ) - cls.subdivisions = IntProperty( - name="Subdivisions", - description="Number of subdivisions used in Cardinal curve intersection (power of 2)", - min=0, max=24, - default=4, - ) @classmethod def unregister(cls): @@ -1212,223 +1231,179 @@ class CyclesCurveRenderSettings(bpy.types.PropertyGroup): def update_render_passes(self, context): - scene = context.scene - rd = scene.render - rl = rd.layers.active - rl.update_render_passes() + view_layer = context.view_layer + view_layer.update_render_passes() class CyclesRenderLayerSettings(bpy.types.PropertyGroup): - @classmethod - def register(cls): - bpy.types.SceneRenderLayer.cycles = PointerProperty( - name="Cycles SceneRenderLayer Settings", - description="Cycles SceneRenderLayer Settings", - type=cls, - ) - cls.pass_debug_bvh_traversed_nodes = BoolProperty( - name="Debug BVH Traversed Nodes", - description="Store Debug BVH Traversed Nodes pass", - default=False, - update=update_render_passes, - ) - cls.pass_debug_bvh_traversed_instances = BoolProperty( - name="Debug BVH Traversed Instances", - description="Store Debug BVH Traversed Instances pass", - default=False, - update=update_render_passes, - ) - cls.pass_debug_bvh_intersections = BoolProperty( - name="Debug BVH Intersections", - description="Store Debug BVH Intersections", - default=False, - update=update_render_passes, - ) - cls.pass_debug_ray_bounces = BoolProperty( - name="Debug Ray Bounces", - description="Store Debug Ray Bounces pass", - default=False, - update=update_render_passes, - ) - cls.pass_debug_render_time = BoolProperty( - name="Debug Render Time", - description="Render time in milliseconds per sample and pixel", - default=False, - update=update_render_passes, - ) - cls.use_pass_volume_direct = BoolProperty( - name="Volume Direct", - description="Deliver direct volumetric scattering pass", - default=False, - update=update_render_passes, - ) - cls.use_pass_volume_indirect = BoolProperty( - name="Volume Indirect", - description="Deliver indirect volumetric scattering pass", - default=False, - update=update_render_passes, - ) - cls.use_denoising = BoolProperty( - name="Use Denoising", - description="Denoise the rendered image", - default=False, - update=update_render_passes, - ) - cls.denoising_diffuse_direct = BoolProperty( - name="Diffuse Direct", - description="Denoise the direct diffuse lighting", - default=True, - ) - cls.denoising_diffuse_indirect = BoolProperty( - name="Diffuse Indirect", - description="Denoise the indirect diffuse lighting", - default=True, - ) - cls.denoising_glossy_direct = BoolProperty( - name="Glossy Direct", - description="Denoise the direct glossy lighting", - default=True, - ) - cls.denoising_glossy_indirect = BoolProperty( - name="Glossy Indirect", - description="Denoise the indirect glossy lighting", - default=True, - ) - cls.denoising_transmission_direct = BoolProperty( - name="Transmission Direct", - description="Denoise the direct transmission lighting", - default=True, - ) - cls.denoising_transmission_indirect = BoolProperty( - name="Transmission Indirect", - description="Denoise the indirect transmission lighting", - default=True, - ) - cls.denoising_subsurface_direct = BoolProperty( - name="Subsurface Direct", - description="Denoise the direct subsurface lighting", - default=True, - ) - cls.denoising_subsurface_indirect = BoolProperty( - name="Subsurface Indirect", - description="Denoise the indirect subsurface lighting", - default=True, - ) - cls.denoising_strength = FloatProperty( - name="Denoising Strength", - description="Controls neighbor pixel weighting for the denoising filter (lower values preserve more detail, but aren't as smooth)", - min=0.0, max=1.0, - default=0.5, - ) - cls.denoising_feature_strength = FloatProperty( - name="Denoising Feature Strength", - description="Controls removal of noisy image feature passes (lower values preserve more detail, but aren't as smooth)", - min=0.0, max=1.0, - default=0.5, - ) - cls.denoising_radius = IntProperty( - name="Denoising Radius", - description="Size of the image area that's used to denoise a pixel (higher values are smoother, but might lose detail and are slower)", - min=1, max=25, - default=8, - ) - cls.denoising_relative_pca = BoolProperty( - name="Relative filter", - description="When removing pixels that don't carry information, use a relative threshold instead of an absolute one (can help to reduce artifacts, but might cause detail loss around edges)", - default=False, - ) - cls.denoising_store_passes = BoolProperty( - name="Store denoising passes", - description="Store the denoising feature passes and the noisy image", - default=False, - update=update_render_passes, - ) - cls.use_pass_crypto_object = BoolProperty( - name="Cryptomatte Object", - description="Render cryptomatte object pass, for isolating objects in compositing", - default=False, - update=update_render_passes, - ) - cls.use_pass_crypto_material = BoolProperty( - name="Cryptomatte Material", - description="Render cryptomatte material pass, for isolating materials in compositing", - default=False, - update=update_render_passes, - ) - cls.use_pass_crypto_asset = BoolProperty( - name="Cryptomatte Asset", - description="Render cryptomatte asset pass, for isolating groups of objects with the same parent", - default=False, - update=update_render_passes, - ) - cls.pass_crypto_depth = IntProperty( - name="Cryptomatte Levels", - description="Sets how many unique objects can be distinguished per pixel", - default=6, min=2, max=16, step=2, - update=update_render_passes, - ) - cls.pass_crypto_accurate = BoolProperty( - name="Cryptomatte Accurate", - description="Gerenate a more accurate Cryptomatte pass. CPU only, may render slower and use more memory", - default=True, - update=update_render_passes, - ) - @classmethod - def unregister(cls): - del bpy.types.SceneRenderLayer.cycles + pass_debug_bvh_traversed_nodes: BoolProperty( + name="Debug BVH Traversed Nodes", + description="Store Debug BVH Traversed Nodes pass", + default=False, + update=update_render_passes, + ) + pass_debug_bvh_traversed_instances: BoolProperty( + name="Debug BVH Traversed Instances", + description="Store Debug BVH Traversed Instances pass", + default=False, + update=update_render_passes, + ) + pass_debug_bvh_intersections: BoolProperty( + name="Debug BVH Intersections", + description="Store Debug BVH Intersections", + default=False, + update=update_render_passes, + ) + pass_debug_ray_bounces: BoolProperty( + name="Debug Ray Bounces", + description="Store Debug Ray Bounces pass", + default=False, + update=update_render_passes, + ) + pass_debug_render_time: BoolProperty( + name="Debug Render Time", + description="Render time in milliseconds per sample and pixel", + default=False, + update=update_render_passes, + ) + use_pass_volume_direct: BoolProperty( + name="Volume Direct", + description="Deliver direct volumetric scattering pass", + default=False, + update=update_render_passes, + ) + use_pass_volume_indirect: BoolProperty( + name="Volume Indirect", + description="Deliver indirect volumetric scattering pass", + default=False, + update=update_render_passes, + ) + use_denoising: BoolProperty( + name="Use Denoising", + description="Denoise the rendered image", + default=False, + update=update_render_passes, + ) + denoising_diffuse_direct: BoolProperty( + name="Diffuse Direct", + description="Denoise the direct diffuse lighting", + default=True, + ) + denoising_diffuse_indirect: BoolProperty( + name="Diffuse Indirect", + description="Denoise the indirect diffuse lighting", + default=True, + ) + denoising_glossy_direct: BoolProperty( + name="Glossy Direct", + description="Denoise the direct glossy lighting", + default=True, + ) + denoising_glossy_indirect: BoolProperty( + name="Glossy Indirect", + description="Denoise the indirect glossy lighting", + default=True, + ) + denoising_transmission_direct: BoolProperty( + name="Transmission Direct", + description="Denoise the direct transmission lighting", + default=True, + ) + denoising_transmission_indirect: BoolProperty( + name="Transmission Indirect", + description="Denoise the indirect transmission lighting", + default=True, + ) + denoising_subsurface_direct: BoolProperty( + name="Subsurface Direct", + description="Denoise the direct subsurface lighting", + default=True, + ) + denoising_subsurface_indirect: BoolProperty( + name="Subsurface Indirect", + description="Denoise the indirect subsurface lighting", + default=True, + ) + denoising_strength: FloatProperty( + name="Denoising Strength", + description="Controls neighbor pixel weighting for the denoising filter (lower values preserve more detail, but aren't as smooth)", + min=0.0, max=1.0, + default=0.5, + ) + denoising_feature_strength: FloatProperty( + name="Denoising Feature Strength", + description="Controls removal of noisy image feature passes (lower values preserve more detail, but aren't as smooth)", + min=0.0, max=1.0, + default=0.5, + ) + denoising_radius: IntProperty( + name="Denoising Radius", + description="Size of the image area that's used to denoise a pixel (higher values are smoother, but might lose detail and are slower)", + min=1, max=25, + default=8, + ) + denoising_relative_pca: BoolProperty( + name="Relative filter", + description="When removing pixels that don't carry information, use a relative threshold instead of an absolute one (can help to reduce artifacts, but might cause detail loss around edges)", + default=False, + ) + denoising_store_passes: BoolProperty( + name="Store denoising passes", + description="Store the denoising feature passes and the noisy image", + default=False, + update=update_render_passes, + ) + use_pass_crypto_object: BoolProperty( + name="Cryptomatte Object", + description="Render cryptomatte object pass, for isolating objects in compositing", + default=False, + update=update_render_passes, + ) + use_pass_crypto_material: BoolProperty( + name="Cryptomatte Material", + description="Render cryptomatte material pass, for isolating materials in compositing", + default=False, + update=update_render_passes, + ) + use_pass_crypto_asset: BoolProperty( + name="Cryptomatte Asset", + description="Render cryptomatte asset pass, for isolating groups of objects with the same parent", + default=False, + update=update_render_passes, + ) + pass_crypto_depth: IntProperty( + name="Cryptomatte Levels", + description="Sets how many unique objects can be distinguished per pixel", + default=6, min=2, max=16, step=2, + update=update_render_passes, + ) + pass_crypto_accurate: BoolProperty( + name="Cryptomatte Accurate", + description="Generate a more accurate Cryptomatte pass. CPU only, may render slower and use more memory", + default=True, + update=update_render_passes, + ) -class CyclesCurveSettings(bpy.types.PropertyGroup): @classmethod def register(cls): - bpy.types.ParticleSettings.cycles = PointerProperty( - name="Cycles Hair Settings", - description="Cycles hair settings", + bpy.types.ViewLayer.cycles = PointerProperty( + name="Cycles ViewLayer Settings", + description="Cycles ViewLayer Settings", type=cls, ) - cls.radius_scale = FloatProperty( - name="Radius Scaling", - description="Multiplier of width properties", - min=0.0, max=1000.0, - default=0.01, - ) - cls.root_width = FloatProperty( - name="Root Size", - description="Strand's width at root", - min=0.0, max=1000.0, - default=1.0, - ) - cls.tip_width = FloatProperty( - name="Tip Multiplier", - description="Strand's width at tip", - min=0.0, max=1000.0, - default=0.0, - ) - cls.shape = FloatProperty( - name="Strand Shape", - description="Strand shape parameter", - min=-1.0, max=1.0, - default=0.0, - ) - cls.use_closetip = BoolProperty( - name="Close tip", - description="Set tip radius to zero", - default=True, - ) @classmethod def unregister(cls): - del bpy.types.ParticleSettings.cycles + del bpy.types.ViewLayer.cycles class CyclesDeviceSettings(bpy.types.PropertyGroup): - @classmethod - def register(cls): - cls.id = StringProperty(name="ID") - cls.name = StringProperty(name="Name") - cls.use = BoolProperty(name="Use", default=True) - cls.type = EnumProperty(name="Type", items=enum_device_type, default='CUDA') + id: StringProperty(name="ID") + name: StringProperty(name="Name") + use: BoolProperty(name="Use", default=True) + type: EnumProperty(name="Type", items=enum_device_type, default='CUDA') class CyclesPreferences(bpy.types.AddonPreferences): @@ -1444,13 +1419,13 @@ class CyclesPreferences(bpy.types.AddonPreferences): list.append(('OPENCL', "OpenCL", "Use OpenCL for GPU acceleration", 2)) return list - compute_device_type = EnumProperty( + compute_device_type: EnumProperty( name="Compute Device Type", description="Device to use for computation (rendering with Cycles)", items=get_device_types, ) - devices = bpy.props.CollectionProperty(type=CyclesDeviceSettings) + devices: bpy.props.CollectionProperty(type=CyclesDeviceSettings) def find_existing_device_entry(self, device): for device_entry in self.devices: @@ -1550,13 +1525,12 @@ def register(): bpy.utils.register_class(CyclesRenderSettings) bpy.utils.register_class(CyclesCameraSettings) bpy.utils.register_class(CyclesMaterialSettings) - bpy.utils.register_class(CyclesLampSettings) + bpy.utils.register_class(CyclesLightSettings) bpy.utils.register_class(CyclesWorldSettings) bpy.utils.register_class(CyclesVisibilitySettings) bpy.utils.register_class(CyclesMeshSettings) bpy.utils.register_class(CyclesObjectSettings) bpy.utils.register_class(CyclesCurveRenderSettings) - bpy.utils.register_class(CyclesCurveSettings) bpy.utils.register_class(CyclesDeviceSettings) bpy.utils.register_class(CyclesPreferences) bpy.utils.register_class(CyclesRenderLayerSettings) @@ -1566,13 +1540,12 @@ def unregister(): bpy.utils.unregister_class(CyclesRenderSettings) bpy.utils.unregister_class(CyclesCameraSettings) bpy.utils.unregister_class(CyclesMaterialSettings) - bpy.utils.unregister_class(CyclesLampSettings) + bpy.utils.unregister_class(CyclesLightSettings) bpy.utils.unregister_class(CyclesWorldSettings) bpy.utils.unregister_class(CyclesMeshSettings) bpy.utils.unregister_class(CyclesObjectSettings) bpy.utils.unregister_class(CyclesVisibilitySettings) bpy.utils.unregister_class(CyclesCurveRenderSettings) - bpy.utils.unregister_class(CyclesCurveSettings) bpy.utils.unregister_class(CyclesDeviceSettings) bpy.utils.unregister_class(CyclesPreferences) bpy.utils.unregister_class(CyclesRenderLayerSettings) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 2f1adfe4178..667547633b4 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -17,29 +17,30 @@ # <pep8 compliant> import bpy +from bpy_extras.node_utils import find_node_input +from bl_operators.presets import PresetMenu import _cycles from bpy.types import ( Panel, - Menu, Operator, ) -class CYCLES_MT_sampling_presets(Menu): +class CYCLES_PT_sampling_presets(PresetMenu): bl_label = "Sampling Presets" preset_subdir = "cycles/sampling" preset_operator = "script.execute_preset" + preset_add_operator = "render.cycles_sampling_preset_add" COMPAT_ENGINES = {'CYCLES'} - draw = Menu.draw_preset -class CYCLES_MT_integrator_presets(Menu): +class CYCLES_PT_integrator_presets(PresetMenu): bl_label = "Integrator Presets" preset_subdir = "cycles/integrator" preset_operator = "script.execute_preset" + preset_add_operator = "render.cycles_integrator_preset_add" COMPAT_ENGINES = {'CYCLES'} - draw = Menu.draw_preset class CyclesButtonsPanel: @@ -50,12 +51,21 @@ class CyclesButtonsPanel: @classmethod def poll(cls, context): - rd = context.scene.render - return rd.engine in cls.COMPAT_ENGINES + return context.engine in cls.COMPAT_ENGINES + + +class CyclesNodeButtonsPanel: + bl_space_type = "NODE_EDITOR" + bl_region_type = "UI" + COMPAT_ENGINES = {'CYCLES'} + + @classmethod + def poll(cls, context): + return context.engine in cls.COMPAT_ENGINES def get_device_type(context): - return context.user_preferences.addons[__package__].preferences.compute_device_type + return context.preferences.addons[__package__].preferences.compute_device_type def use_cpu(context): @@ -92,7 +102,7 @@ def show_device_active(context): cscene = context.scene.cycles if cscene.device != 'GPU': return True - return context.user_preferences.addons[__package__].preferences.has_active_device() + return context.preferences.addons[__package__].preferences.has_active_device() def draw_samples_info(layout, context): @@ -129,21 +139,23 @@ def draw_samples_info(layout, context): if use_branched_path(context) or (cscene.use_square_samples and integrator == 'PATH'): col = layout.column(align=True) col.scale_y = 0.6 - col.label("Total Samples:") + col.label(text="Total Samples:") col.separator() if integrator == 'PATH': - col.label("%s AA" % aa) + col.label(text="%s AA" % aa) else: - col.label("%s AA, %s Diffuse, %s Glossy, %s Transmission" % + col.label(text="%s AA, %s Diffuse, %s Glossy, %s Transmission" % (aa, d * aa, g * aa, t * aa)) col.separator() - col.label("%s AO, %s Mesh Light, %s Subsurface, %s Volume" % + col.label(text="%s AO, %s Mesh Light, %s Subsurface, %s Volume" % (ao * aa, ml * aa, sss * aa, vol * aa)) class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel): bl_label = "Sampling" - bl_options = {'DEFAULT_CLOSED'} + + def draw_header_preset(self, context): + CYCLES_PT_sampling_presets.draw_panel_header(self.layout) def draw(self, context): layout = self.layout @@ -151,168 +163,298 @@ class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel): scene = context.scene cscene = scene.cycles - row = layout.row(align=True) - row.menu("CYCLES_MT_sampling_presets", text=bpy.types.CYCLES_MT_sampling_presets.bl_label) - row.operator("render.cycles_sampling_preset_add", text="", icon="ZOOMIN") - row.operator("render.cycles_sampling_preset_add", text="", icon="ZOOMOUT").remove_active = True + layout.use_property_split = True + layout.use_property_decorate = False - row = layout.row() - sub = row.row() - sub.prop(cscene, "progressive", text="") - row.prop(cscene, "use_square_samples") + layout.prop(cscene, "progressive") - split = layout.split() + if cscene.progressive == 'PATH' or use_branched_path(context) is False: + col = layout.column(align=True) + col.prop(cscene, "samples", text="Render") + col.prop(cscene, "preview_samples", text="Viewport") - col = split.column() - sub = col.column(align=True) - sub.label("Settings:") + draw_samples_info(layout, context) + else: + col = layout.column(align=True) + col.prop(cscene, "aa_samples", text="Render") + col.prop(cscene, "preview_aa_samples", text="Viewport") - seed_sub = sub.row(align=True) - seed_sub.prop(cscene, "seed") - seed_sub.prop(cscene, "use_animated_seed", text="", icon="TIME") - sub.prop(cscene, "sample_clamp_direct") - sub.prop(cscene, "sample_clamp_indirect") - sub.prop(cscene, "light_sampling_threshold") +class CYCLES_RENDER_PT_sampling_sub_samples(CyclesButtonsPanel, Panel): + bl_label = "Sub Samples" + bl_parent_id = "CYCLES_RENDER_PT_sampling" - if cscene.progressive == 'PATH' or use_branched_path(context) is False: - col = split.column() - sub = col.column(align=True) - sub.label(text="Samples:") - sub.prop(cscene, "samples", text="Render") - sub.prop(cscene, "preview_samples", text="Preview") - else: - sub.label(text="AA Samples:") - sub.prop(cscene, "aa_samples", text="Render") - sub.prop(cscene, "preview_aa_samples", text="Preview") + @classmethod + def poll(self, context): + scene = context.scene + cscene = scene.cycles + return cscene.progressive != 'PATH' and use_branched_path(context) - col = split.column() - sub = col.column(align=True) - sub.label(text="Samples:") - sub.prop(cscene, "diffuse_samples", text="Diffuse") - sub.prop(cscene, "glossy_samples", text="Glossy") - sub.prop(cscene, "transmission_samples", text="Transmission") - sub.prop(cscene, "ao_samples", text="AO") + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False - subsub = sub.row(align=True) - subsub.active = use_sample_all_lights(context) - subsub.prop(cscene, "mesh_light_samples", text="Mesh Light") + scene = context.scene + cscene = scene.cycles + + col = layout.column(align=True) + col.prop(cscene, "diffuse_samples", text="Diffuse") + col.prop(cscene, "glossy_samples", text="Glossy") + col.prop(cscene, "transmission_samples", text="Transmission") + col.prop(cscene, "ao_samples", text="AO") + + sub = col.row(align=True) + sub.active = use_sample_all_lights(context) + sub.prop(cscene, "mesh_light_samples", text="Mesh Light") + col.prop(cscene, "subsurface_samples", text="Subsurface") + col.prop(cscene, "volume_samples", text="Volume") + + draw_samples_info(layout, context) + + +class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel): + bl_label = "Advanced" + bl_parent_id = "CYCLES_RENDER_PT_sampling" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + scene = context.scene + cscene = scene.cycles - sub.prop(cscene, "subsurface_samples", text="Subsurface") - sub.prop(cscene, "volume_samples", text="Volume") + row = layout.row(align=True) + row.prop(cscene, "seed") + row.prop(cscene, "use_animated_seed", text="", icon='TIME') + + layout.prop(cscene, "sampling_pattern", text="Pattern") + + layout.prop(cscene, "use_square_samples") + layout.separator() + + col = layout.column(align=True) + col.prop(cscene, "light_sampling_threshold", text="Light Threshold") + + if cscene.progressive != 'PATH' and use_branched_path(context): col = layout.column(align=True) col.prop(cscene, "sample_all_lights_direct") col.prop(cscene, "sample_all_lights_indirect") - layout.row().prop(cscene, "sampling_pattern", text="Pattern") - - for rl in scene.render.layers: - if rl.samples > 0: + for view_layer in scene.view_layers: + if view_layer.samples > 0: layout.separator() layout.row().prop(cscene, "use_layer_samples") break - draw_samples_info(layout, context) +class CYCLES_RENDER_PT_sampling_total(CyclesButtonsPanel, Panel): + bl_label = "Total Samples" + bl_parent_id = "CYCLES_RENDER_PT_sampling" + + @classmethod + def poll(self, context): + scene = context.scene + cscene = scene.cycles + + if cscene.use_square_samples: + return True + + return cscene.progressive != 'PATH' and use_branched_path(context) + + def draw(self, context): + layout = self.layout + cscene = context.scene.cycles + integrator = cscene.progressive + + # Calculate sample values + if integrator == 'PATH': + aa = cscene.samples + if cscene.use_square_samples: + aa = aa * aa + else: + aa = cscene.aa_samples + d = cscene.diffuse_samples + g = cscene.glossy_samples + t = cscene.transmission_samples + ao = cscene.ao_samples + ml = cscene.mesh_light_samples + sss = cscene.subsurface_samples + vol = cscene.volume_samples + + if cscene.use_square_samples: + aa = aa * aa + d = d * d + g = g * g + t = t * t + ao = ao * ao + ml = ml * ml + sss = sss * sss + vol = vol * vol + + col = layout.column(align=True) + col.scale_y = 0.6 + if integrator == 'PATH': + col.label(text="%s AA" % aa) + else: + col.label(text="%s AA, %s Diffuse, %s Glossy, %s Transmission" % + (aa, d * aa, g * aa, t * aa)) + col.separator() + col.label(text="%s AO, %s Mesh Light, %s Subsurface, %s Volume" % + (ao * aa, ml * aa, sss * aa, vol * aa)) -class CYCLES_RENDER_PT_geometry(CyclesButtonsPanel, Panel): - bl_label = "Geometry" + +class CYCLES_RENDER_PT_subdivision(CyclesButtonsPanel, Panel): + bl_label = "Subdivision" bl_options = {'DEFAULT_CLOSED'} + @classmethod + def poll(self, context): + return context.scene.cycles.feature_set == 'EXPERIMENTAL' + def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False scene = context.scene cscene = scene.cycles - ccscene = scene.cycles_curves - row = layout.row() - row.label("Volume Sampling:") - row = layout.row() - row.prop(cscene, "volume_step_size") - row.prop(cscene, "volume_max_steps") + col = layout.column() + sub = col.column(align=True) + sub.prop(cscene, "dicing_rate", text="Dicing Rate Render") + sub.prop(cscene, "preview_dicing_rate", text="Preview") - layout.separator() + col.separator() - if cscene.feature_set == 'EXPERIMENTAL': - layout.label("Subdivision Rate:") - split = layout.split() + col.prop(cscene, "offscreen_dicing_scale", text="Offscreen Scale") + col.prop(cscene, "max_subdivisions") - col = split.column() - sub = col.column(align=True) - sub.prop(cscene, "dicing_rate", text="Render") - sub.prop(cscene, "preview_dicing_rate", text="Preview") + col.prop(cscene, "dicing_camera") - col = split.column() - col.prop(cscene, "offscreen_dicing_scale", text="Offscreen Scale") - col.prop(cscene, "max_subdivisions") - layout.prop(cscene, "dicing_camera") +class CYCLES_RENDER_PT_hair(CyclesButtonsPanel, Panel): + bl_label = "Hair" + bl_options = {'DEFAULT_CLOSED'} - layout.separator() + def draw_header(self, context): + layout = self.layout + scene = context.scene + ccscene = scene.cycles_curves - layout.label("Hair:") - layout.prop(ccscene, "use_curves", text="Use Hair") - col = layout.column() - col.active = ccscene.use_curves + layout.prop(ccscene, "use_curves", text="") - col.prop(ccscene, "primitive", text="Primitive") - col.prop(ccscene, "shape", text="Shape") + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + scene = context.scene + ccscene = scene.cycles_curves + + layout.active = ccscene.use_curves + col = layout.column() + col.prop(ccscene, "minimum_width", text="Min Pixels") + col.prop(ccscene, "maximum_width", text="Max Extension") + col.prop(ccscene, "shape", text="Shape") if not (ccscene.primitive in {'CURVE_SEGMENTS', 'LINE_SEGMENTS'} and ccscene.shape == 'RIBBONS'): col.prop(ccscene, "cull_backfacing", text="Cull back-faces") + col.prop(ccscene, "primitive", text="Primitive") if ccscene.primitive == 'TRIANGLES' and ccscene.shape == 'THICK': col.prop(ccscene, "resolution", text="Resolution") elif ccscene.primitive == 'CURVE_SEGMENTS': col.prop(ccscene, "subdivisions", text="Curve subdivisions") - row = col.row() - row.prop(ccscene, "minimum_width", text="Min Pixels") - row.prop(ccscene, "maximum_width", text="Max Extension") + +class CYCLES_RENDER_PT_volumes(CyclesButtonsPanel, Panel): + bl_label = "Volumes" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + scene = context.scene + cscene = scene.cycles + + col = layout.column() + col.prop(cscene, "volume_step_size", text="Step Size") + col.prop(cscene, "volume_max_steps", text="Max Steps") class CYCLES_RENDER_PT_light_paths(CyclesButtonsPanel, Panel): bl_label = "Light Paths" bl_options = {'DEFAULT_CLOSED'} + def draw_header_preset(self, context): + CYCLES_PT_integrator_presets.draw_panel_header(self.layout) + + def draw(self, context): + pass + + +class CYCLES_RENDER_PT_light_paths_max_bounces(CyclesButtonsPanel, Panel): + bl_label = "Max Bounces" + bl_parent_id = "CYCLES_RENDER_PT_light_paths" + def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False scene = context.scene cscene = scene.cycles - row = layout.row(align=True) - row.menu("CYCLES_MT_integrator_presets", text=bpy.types.CYCLES_MT_integrator_presets.bl_label) - row.operator("render.cycles_integrator_preset_add", text="", icon="ZOOMIN") - row.operator("render.cycles_integrator_preset_add", text="", icon="ZOOMOUT").remove_active = True + col = layout.column(align=True) + col.prop(cscene, "max_bounces", text="Total") - split = layout.split() + col = layout.column(align=True) + col.prop(cscene, "diffuse_bounces", text="Diffuse") + col.prop(cscene, "glossy_bounces", text="Glossy") + col.prop(cscene, "transparent_max_bounces", text="Transparency") + col.prop(cscene, "transmission_bounces", text="Transmission") + col.prop(cscene, "volume_bounces", text="Volume") - col = split.column() - sub = col.column(align=True) - sub.label("Transparency:") - sub.prop(cscene, "transparent_max_bounces", text="Max") +class CYCLES_RENDER_PT_light_paths_clamping(CyclesButtonsPanel, Panel): + bl_label = "Clamping" + bl_parent_id = "CYCLES_RENDER_PT_light_paths" - col.separator() + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False - col.prop(cscene, "caustics_reflective") - col.prop(cscene, "caustics_refractive") - col.prop(cscene, "blur_glossy") + scene = context.scene + cscene = scene.cycles - col = split.column() + col = layout.column(align=True) + col.prop(cscene, "sample_clamp_direct", text="Direct Light") + col.prop(cscene, "sample_clamp_indirect", text="Indirect Light") - sub = col.column(align=True) - sub.label(text="Bounces:") - sub.prop(cscene, "max_bounces", text="Max") - sub = col.column(align=True) - sub.prop(cscene, "diffuse_bounces", text="Diffuse") - sub.prop(cscene, "glossy_bounces", text="Glossy") - sub.prop(cscene, "transmission_bounces", text="Transmission") - sub.prop(cscene, "volume_bounces", text="Volume") +class CYCLES_RENDER_PT_light_paths_caustics(CyclesButtonsPanel, Panel): + bl_label = "Caustics" + bl_parent_id = "CYCLES_RENDER_PT_light_paths" + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + scene = context.scene + cscene = scene.cycles + + col = layout.column() + col.prop(cscene, "blur_glossy") + col.prop(cscene, "caustics_reflective") + col.prop(cscene, "caustics_refractive") class CYCLES_RENDER_PT_motion_blur(CyclesButtonsPanel, Panel): @@ -326,6 +468,8 @@ class CYCLES_RENDER_PT_motion_blur(CyclesButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False scene = context.scene cscene = scene.cycles @@ -335,9 +479,29 @@ class CYCLES_RENDER_PT_motion_blur(CyclesButtonsPanel, Panel): col = layout.column() col.prop(cscene, "motion_blur_position", text="Position") col.prop(rd, "motion_blur_shutter") + col.separator() + col.prop(cscene, "rolling_shutter_type", text="Rolling Shutter") + sub = col.column() + sub.active = cscene.rolling_shutter_type != 'NONE' + sub.prop(cscene, "rolling_shutter_duration") + + +class CYCLES_RENDER_PT_motion_blur_curve(CyclesButtonsPanel, Panel): + bl_label = "Shutter Curve" + bl_parent_id = "CYCLES_RENDER_PT_motion_blur" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + scene = context.scene + rd = scene.render + layout.active = rd.use_motion_blur col = layout.column() - col.label("Shutter curve:") + col.template_curve_mapping(rd, "motion_blur_shutter_curve") col = layout.column(align=True) @@ -349,40 +513,66 @@ class CYCLES_RENDER_PT_motion_blur(CyclesButtonsPanel, Panel): row.operator("render.shutter_curve_preset", icon='LINCURVE', text="").shape = 'LINE' row.operator("render.shutter_curve_preset", icon='NOCURVE', text="").shape = 'MAX' - col = layout.column() - col.prop(cscene, "rolling_shutter_type") - row = col.row() - row.active = cscene.rolling_shutter_type != 'NONE' - row.prop(cscene, "rolling_shutter_duration") - class CYCLES_RENDER_PT_film(CyclesButtonsPanel, Panel): bl_label = "Film" + bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + scene = context.scene + cscene = scene.cycles + + col = layout.column() + col.prop(cscene, "film_exposure") + + +class CYCLES_RENDER_PT_film_transparency(CyclesButtonsPanel, Panel): + bl_label = "Transparency" + bl_parent_id = "CYCLES_RENDER_PT_film" + + def draw_header(self, context): + layout = self.layout scene = context.scene cscene = scene.cycles - split = layout.split() + layout.prop(cscene, "film_transparent", text="") - col = split.column() - col.prop(cscene, "film_exposure") - col.separator() - sub = col.column(align=True) - sub.prop(cscene, "pixel_filter_type", text="") - if cscene.pixel_filter_type != 'BOX': - sub.prop(cscene, "filter_width", text="Width") + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + scene = context.scene + cscene = scene.cycles - col = split.column() - col.prop(cscene, "film_transparent") - sub = col.row() - sub.prop(cscene, "film_transparent_glass", text="Transparent Glass") - sub.active = cscene.film_transparent - sub = col.row() - sub.prop(cscene, "film_transparent_roughness", text="Roughness Threshold") + layout.active = cscene.film_transparent + + col = layout.column() + col.prop(cscene, "film_transparent_glass", text="Transparent Glass") + + sub = col.column() sub.active = cscene.film_transparent and cscene.film_transparent_glass + sub.prop(cscene, "film_transparent_roughness", text="Roughness Threshold") + + +class CYCLES_RENDER_PT_film_pixel_filter(CyclesButtonsPanel, Panel): + bl_label = "Pixel Filter" + bl_parent_id = "CYCLES_RENDER_PT_film" + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + scene = context.scene + cscene = scene.cycles + + col = layout.column() + col.prop(cscene, "pixel_filter_type", text="Type") + if cscene.pixel_filter_type != 'BOX': + col.prop(cscene, "filter_width", text="Width") class CYCLES_RENDER_PT_performance(CyclesButtonsPanel, Panel): @@ -390,320 +580,432 @@ class CYCLES_RENDER_PT_performance(CyclesButtonsPanel, Panel): bl_options = {'DEFAULT_CLOSED'} def draw(self, context): + pass + + +class CYCLES_RENDER_PT_performance_threads(CyclesButtonsPanel, Panel): + bl_label = "Threads" + bl_parent_id = "CYCLES_RENDER_PT_performance" + + def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False scene = context.scene rd = scene.render - cscene = scene.cycles - split = layout.split() - - col = split.column(align=True) + col = layout.column() - col.label(text="Threads:") - col.row(align=True).prop(rd, "threads_mode", expand=True) + col.prop(rd, "threads_mode") sub = col.column(align=True) sub.enabled = rd.threads_mode == 'FIXED' sub.prop(rd, "threads") - col.separator() - sub = col.column(align=True) - sub.label(text="Tiles:") - sub.prop(cscene, "tile_order", text="") +class CYCLES_RENDER_PT_performance_tiles(CyclesButtonsPanel, Panel): + bl_label = "Tiles" + bl_parent_id = "CYCLES_RENDER_PT_performance" - sub.prop(rd, "tile_x", text="X") + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + scene = context.scene + rd = scene.render + cscene = scene.cycles + + col = layout.column() + + sub = col.column(align=True) + sub.prop(rd, "tile_x", text="Tiles X") sub.prop(rd, "tile_y", text="Y") + col.prop(cscene, "tile_order", text="Order") - subsub = sub.column() - subsub.active = not rd.use_save_buffers - for rl in rd.layers: - if rl.cycles.use_denoising: - subsub.active = False - subsub.prop(cscene, "use_progressive_refine") + sub = col.column() + sub.active = not rd.use_save_buffers + for view_layer in scene.view_layers: + if view_layer.cycles.use_denoising: + sub.active = False + sub.prop(cscene, "use_progressive_refine") - col = split.column() - col.label(text="Final Render:") - col.prop(rd, "use_save_buffers") - col.prop(rd, "use_persistent_data", text="Persistent Images") +class CYCLES_RENDER_PT_performance_acceleration_structure(CyclesButtonsPanel, Panel): + bl_label = "Acceleration Structure" + bl_parent_id = "CYCLES_RENDER_PT_performance" - col.separator() + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + scene = context.scene + cscene = scene.cycles + + col = layout.column() - col.label(text="Acceleration structure:") if _cycles.with_embree: row = col.row() row.active = use_cpu(context) row.prop(cscene, "use_bvh_embree") - row = col.row() col.prop(cscene, "debug_use_spatial_splits") - row = col.row() - row.active = not cscene.use_bvh_embree or not _cycles.with_embree - row.prop(cscene, "debug_use_hair_bvh") + sub = col.column() + sub.active = not cscene.use_bvh_embree or not _cycles.with_embree + sub.prop(cscene, "debug_use_hair_bvh") + sub = col.column() + sub.active = not cscene.debug_use_spatial_splits and not cscene.use_bvh_embree + sub.prop(cscene, "debug_bvh_time_steps") + + +class CYCLES_RENDER_PT_performance_final_render(CyclesButtonsPanel, Panel): + bl_label = "Final Render" + bl_parent_id = "CYCLES_RENDER_PT_performance" - row = col.row() - row.active = not cscene.debug_use_spatial_splits and not cscene.use_bvh_embree - row.prop(cscene, "debug_bvh_time_steps") + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + scene = context.scene + rd = scene.render col = layout.column() - col.label(text="Viewport Resolution:") - split = col.split() - split.prop(rd, "preview_pixel_size", text="") - split.prop(cscene, "preview_start_resolution") + col.prop(rd, "use_save_buffers") + col.prop(rd, "use_persistent_data", text="Persistent Images") -class CYCLES_RENDER_PT_layer_options(CyclesButtonsPanel, Panel): - bl_label = "Layer" - bl_context = "render_layer" + +class CYCLES_RENDER_PT_performance_viewport(CyclesButtonsPanel, Panel): + bl_label = "Viewport" + bl_parent_id = "CYCLES_RENDER_PT_performance" def draw(self, context): layout = self.layout - with_freestyle = bpy.app.build_options.freestyle + layout.use_property_split = True + layout.use_property_decorate = False scene = context.scene rd = scene.render - rl = rd.layers.active + cscene = scene.cycles - split = layout.split() + col = layout.column() + col.prop(rd, "preview_pixel_size", text="Pixel Size") + col.prop(cscene, "preview_start_resolution", text="Start Pixels") - col = split.column() - col.prop(scene, "layers", text="Scene") - col.prop(rl, "layers_exclude", text="Exclude") - col = split.column() - col.prop(rl, "layers", text="Layer") - col.prop(rl, "layers_zmask", text="Mask Layer") +class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel): + bl_label = "Filter" + bl_options = {'DEFAULT_CLOSED'} + bl_context = "view_layer" - split = layout.split() + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False - col = split.column() - col.label(text="Material:") - col.prop(rl, "material_override", text="") - col.separator() - col.prop(rl, "samples") + with_freestyle = bpy.app.build_options.freestyle - col = split.column() - col.prop(rl, "use_sky", "Use Environment") - col.prop(rl, "use_ao", "Use AO") - col.prop(rl, "use_solid", "Use Surfaces") - col.prop(rl, "use_strand", "Use Hair") + scene = context.scene + rd = scene.render + view_layer = context.view_layer + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + + col = flow.column() + col.prop(view_layer, "use_sky", text="Environment") + col = flow.column() + col.prop(view_layer, "use_ao", text="Ambient Occlusion") + col = flow.column() + col.prop(view_layer, "use_solid", text="Surfaces") + col = flow.column() + col.prop(view_layer, "use_strand", text="Hair") if with_freestyle: - row = col.row() - row.prop(rl, "use_freestyle", "Use Freestyle") - row.active = rd.use_freestyle + col = flow.column() + col.prop(view_layer, "use_freestyle", text="Freestyle") + col.active = rd.use_freestyle + + +class CYCLES_RENDER_PT_override(CyclesButtonsPanel, Panel): + bl_label = "Override" + bl_options = {'DEFAULT_CLOSED'} + bl_context = "view_layer" + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + view_layer = context.view_layer + + layout.prop(view_layer, "material_override") + layout.prop(view_layer, "samples") -class CYCLES_RENDER_PT_layer_passes(CyclesButtonsPanel, Panel): +class CYCLES_RENDER_PT_passes(CyclesButtonsPanel, Panel): bl_label = "Passes" - bl_context = "render_layer" + bl_context = "view_layer" bl_options = {'DEFAULT_CLOSED'} def draw(self, context): + pass + + +class CYCLES_RENDER_PT_passes_data(CyclesButtonsPanel, Panel): + bl_label = "Data" + bl_context = "view_layer" + bl_parent_id = "CYCLES_RENDER_PT_passes" + + def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False scene = context.scene rd = scene.render - rl = rd.layers.active - crl = rl.cycles + view_layer = context.view_layer + cycles_view_layer = view_layer.cycles + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + col = flow.column() + col.prop(view_layer, "use_pass_combined") + col = flow.column() + col.prop(view_layer, "use_pass_z") + col = flow.column() + col.prop(view_layer, "use_pass_mist") + col = flow.column() + col.prop(view_layer, "use_pass_normal") + col = flow.column() + col.prop(view_layer, "use_pass_vector") + col.active = not rd.use_motion_blur + col = flow.column() + col.prop(view_layer, "use_pass_uv") + col = flow.column() + col.prop(view_layer, "use_pass_object_index") + col = flow.column() + col.prop(view_layer, "use_pass_material_index") - split = layout.split() + layout.separator() - col = split.column() - col.prop(rl, "use_pass_combined") - col.prop(rl, "use_pass_z") - col.prop(rl, "use_pass_mist") - col.prop(rl, "use_pass_normal") - row = col.row() - row.prop(rl, "use_pass_vector") - row.active = not rd.use_motion_blur - col.prop(rl, "use_pass_uv") - col.prop(rl, "use_pass_object_index") - col.prop(rl, "use_pass_material_index") - col.separator() - col.prop(rl, "use_pass_shadow") - col.prop(rl, "use_pass_ambient_occlusion") - col.separator() - col.prop(crl, "denoising_store_passes", text="Denoising Data") - col.separator() - col.prop(rl, "pass_alpha_threshold") + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + col = flow.column() + col.prop(cycles_view_layer, "denoising_store_passes", text="Denoising Data") + col = flow.column() + col.prop(cycles_view_layer, "pass_debug_render_time", text="Render Time") - col = split.column() - col.label(text="Diffuse:") - row = col.row(align=True) - row.prop(rl, "use_pass_diffuse_direct", text="Direct", toggle=True) - row.prop(rl, "use_pass_diffuse_indirect", text="Indirect", toggle=True) - row.prop(rl, "use_pass_diffuse_color", text="Color", toggle=True) - col.label(text="Glossy:") - row = col.row(align=True) - row.prop(rl, "use_pass_glossy_direct", text="Direct", toggle=True) - row.prop(rl, "use_pass_glossy_indirect", text="Indirect", toggle=True) - row.prop(rl, "use_pass_glossy_color", text="Color", toggle=True) - col.label(text="Transmission:") - row = col.row(align=True) - row.prop(rl, "use_pass_transmission_direct", text="Direct", toggle=True) - row.prop(rl, "use_pass_transmission_indirect", text="Indirect", toggle=True) - row.prop(rl, "use_pass_transmission_color", text="Color", toggle=True) - col.label(text="Subsurface:") - row = col.row(align=True) - row.prop(rl, "use_pass_subsurface_direct", text="Direct", toggle=True) - row.prop(rl, "use_pass_subsurface_indirect", text="Indirect", toggle=True) - row.prop(rl, "use_pass_subsurface_color", text="Color", toggle=True) - col.label(text="Volume:") - row = col.row(align=True) - row.prop(crl, "use_pass_volume_direct", text="Direct", toggle=True) - row.prop(crl, "use_pass_volume_indirect", text="Indirect", toggle=True) + layout.separator() - col.separator() - col.prop(rl, "use_pass_emit", text="Emission") - col.prop(rl, "use_pass_environment") + layout.prop(view_layer, "pass_alpha_threshold") - col = layout.column() - col.prop(crl, "pass_debug_render_time") - if _cycles.with_cycles_debug: - col.prop(crl, "pass_debug_bvh_traversed_nodes") - col.prop(crl, "pass_debug_bvh_traversed_instances") - col.prop(crl, "pass_debug_bvh_intersections") - col.prop(crl, "pass_debug_ray_bounces") - - crl = rl.cycles - layout.label("Cryptomatte:") - row = layout.row(align=True) - row.prop(crl, "use_pass_crypto_object", text="Object", toggle=True) - row.prop(crl, "use_pass_crypto_material", text="Material", toggle=True) - row.prop(crl, "use_pass_crypto_asset", text="Asset", toggle=True) - row = layout.row(align=True) - row.prop(crl, "pass_crypto_depth") - row = layout.row(align=True) - row.active = use_cpu(context) - row.prop(crl, "pass_crypto_accurate", text="Accurate Mode") -class CYCLES_RENDER_PT_views(CyclesButtonsPanel, Panel): - bl_label = "Views" - bl_context = "render_layer" - bl_options = {'DEFAULT_CLOSED'} +class CYCLES_RENDER_PT_passes_light(CyclesButtonsPanel, Panel): + bl_label = "Light" + bl_context = "view_layer" + bl_parent_id = "CYCLES_RENDER_PT_passes" - def draw_header(self, context): - rd = context.scene.render - self.layout.prop(rd, "use_multiview", text="") + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + view_layer = context.view_layer + cycles_view_layer = view_layer.cycles + + split = layout.split(factor=0.35) + split.use_property_split = False + split.label(text="Diffuse") + row = split.row(align=True) + row.prop(view_layer, "use_pass_diffuse_direct", text="Direct", toggle=True) + row.prop(view_layer, "use_pass_diffuse_indirect", text="Indirect", toggle=True) + row.prop(view_layer, "use_pass_diffuse_color", text="Color", toggle=True) + + split = layout.split(factor=0.35) + split.use_property_split = False + split.label(text="Glossy") + row = split.row(align=True) + row.prop(view_layer, "use_pass_glossy_direct", text="Direct", toggle=True) + row.prop(view_layer, "use_pass_glossy_indirect", text="Indirect", toggle=True) + row.prop(view_layer, "use_pass_glossy_color", text="Color", toggle=True) + + split = layout.split(factor=0.35) + split.use_property_split = False + split.label(text="Transmission") + row = split.row(align=True) + row.prop(view_layer, "use_pass_transmission_direct", text="Direct", toggle=True) + row.prop(view_layer, "use_pass_transmission_indirect", text="Indirect", toggle=True) + row.prop(view_layer, "use_pass_transmission_color", text="Color", toggle=True) + + split = layout.split(factor=0.35) + split.use_property_split = False + split.label(text="Subsurface") + row = split.row(align=True) + row.prop(view_layer, "use_pass_subsurface_direct", text="Direct", toggle=True) + row.prop(view_layer, "use_pass_subsurface_indirect", text="Indirect", toggle=True) + row.prop(view_layer, "use_pass_subsurface_color", text="Color", toggle=True) + + split = layout.split(factor=0.35) + split.use_property_split = False + split.label(text="Volume") + row = split.row(align=True) + row.prop(cycles_view_layer, "use_pass_volume_direct", text="Direct", toggle=True) + row.prop(cycles_view_layer, "use_pass_volume_indirect", text="Indirect", toggle=True) + + col = layout.column(align=True) + col.prop(view_layer, "use_pass_emit", text="Emission") + col.prop(view_layer, "use_pass_environment") + col.prop(view_layer, "use_pass_shadow") + col.prop(view_layer, "use_pass_ambient_occlusion", text="Ambient Occlusion") + + +class CYCLES_RENDER_PT_passes_crypto(CyclesButtonsPanel, Panel): + bl_label = "Cryptomatte" + bl_context = "view_layer" + bl_parent_id = "CYCLES_RENDER_PT_passes" def draw(self, context): + import _cycles + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False - scene = context.scene - rd = scene.render - rv = rd.views.active + cycles_view_layer = context.view_layer.cycles - layout.active = rd.use_multiview - basic_stereo = (rd.views_format == 'STEREO_3D') + row = layout.row(align=True) + row.use_property_split = False + row.prop(cycles_view_layer, "use_pass_crypto_object", text="Object", toggle=True) + row.prop(cycles_view_layer, "use_pass_crypto_material", text="Material", toggle=True) + row.prop(cycles_view_layer, "use_pass_crypto_asset", text="Asset", toggle=True) - row = layout.row() - row.prop(rd, "views_format", expand=True) + layout.prop(cycles_view_layer, "pass_crypto_depth", text="Levels") - if basic_stereo: - row = layout.row() - row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "stereo_views", rd.views, "active_index", rows=2) + row = layout.row(align=True) + row.active = use_cpu(context) + row.prop(cycles_view_layer, "pass_crypto_accurate", text="Accurate Mode") - row = layout.row() - row.label(text="File Suffix:") - row.prop(rv, "file_suffix", text="") - else: - row = layout.row() - row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "views", rd.views, "active_index", rows=2) +class CYCLES_RENDER_PT_passes_debug(CyclesButtonsPanel, Panel): + bl_label = "Debug" + bl_context = "view_layer" + bl_parent_id = "CYCLES_RENDER_PT_passes" - col = row.column(align=True) - col.operator("scene.render_view_add", icon='ZOOMIN', text="") - col.operator("scene.render_view_remove", icon='ZOOMOUT', text="") + @classmethod + def poll(cls, context): + import _cycles + return _cycles.with_cycles_debug - row = layout.row() - row.label(text="Camera Suffix:") - row.prop(rv, "camera_suffix", text="") + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + cycles_view_layer = context.view_layer.cycles + + layout.prop(cycles_view_layer, "pass_debug_bvh_traversed_nodes") + layout.prop(cycles_view_layer, "pass_debug_bvh_traversed_instances") + layout.prop(cycles_view_layer, "pass_debug_bvh_intersections") + layout.prop(cycles_view_layer, "pass_debug_ray_bounces") class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel): bl_label = "Denoising" - bl_context = "render_layer" + bl_context = "view_layer" bl_options = {'DEFAULT_CLOSED'} def draw_header(self, context): - rd = context.scene.render - rl = rd.layers.active - crl = rl.cycles - cscene = context.scene.cycles + scene = context.scene + view_layer = context.view_layer + cycles_view_layer = view_layer.cycles layout = self.layout - layout.prop(crl, "use_denoising", text="") + layout.prop(cycles_view_layer, "use_denoising", text="") def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False scene = context.scene - cscene = scene.cycles - rd = scene.render - rl = rd.layers.active - crl = rl.cycles + view_layer = context.view_layer + cycles_view_layer = view_layer.cycles split = layout.split() - split.active = crl.use_denoising + split.active = cycles_view_layer.use_denoising + + layout = layout.column(align=True) + layout.prop(cycles_view_layer, "denoising_radius", text="Radius") + layout.prop(cycles_view_layer, "denoising_strength", slider=True, text="Strength") + layout.prop(cycles_view_layer, "denoising_feature_strength", slider=True, text="Feature Strength") + layout.prop(cycles_view_layer, "denoising_relative_pca") + + layout.separator() + + split = layout.split(factor=0.5) + split.active = cycles_view_layer.use_denoising or cycles_view_layer.denoising_store_passes col = split.column() - sub = col.column(align=True) - sub.prop(crl, "denoising_radius", text="Radius") - sub.prop(crl, "denoising_strength", slider=True, text="Strength") + col.alignment = 'RIGHT' + col.label(text="Diffuse") + + row = split.row(align=True) + row.use_property_split = False + row.prop(cycles_view_layer, "denoising_diffuse_direct", text="Direct", toggle=True) + row.prop(cycles_view_layer, "denoising_diffuse_indirect", text="Indirect", toggle=True) + + split = layout.split(factor=0.5) + split.active = cycles_view_layer.use_denoising or cycles_view_layer.denoising_store_passes col = split.column() - sub = col.column(align=True) - sub.prop(crl, "denoising_feature_strength", slider=True, text="Feature Strength") - sub.prop(crl, "denoising_relative_pca") + col.alignment = 'RIGHT' + col.label(text="Glossy") - layout.separator() + row = split.row(align=True) + row.use_property_split = False + row.prop(cycles_view_layer, "denoising_glossy_direct", text="Direct", toggle=True) + row.prop(cycles_view_layer, "denoising_glossy_indirect", text="Indirect", toggle=True) - row = layout.row() - row.active = crl.use_denoising or crl.denoising_store_passes - row.label(text="Diffuse:") - sub = row.row(align=True) - sub.prop(crl, "denoising_diffuse_direct", text="Direct", toggle=True) - sub.prop(crl, "denoising_diffuse_indirect", text="Indirect", toggle=True) + split = layout.split(factor=0.5) + split.active = cycles_view_layer.use_denoising or cycles_view_layer.denoising_store_passes - row = layout.row() - row.active = crl.use_denoising or crl.denoising_store_passes - row.label(text="Glossy:") - sub = row.row(align=True) - sub.prop(crl, "denoising_glossy_direct", text="Direct", toggle=True) - sub.prop(crl, "denoising_glossy_indirect", text="Indirect", toggle=True) + col = split.column() + col.alignment = 'RIGHT' + col.label(text="Transmission") - row = layout.row() - row.active = crl.use_denoising or crl.denoising_store_passes - row.label(text="Transmission:") - sub = row.row(align=True) - sub.prop(crl, "denoising_transmission_direct", text="Direct", toggle=True) - sub.prop(crl, "denoising_transmission_indirect", text="Indirect", toggle=True) + row = split.row(align=True) + row.use_property_split = False + row.prop(cycles_view_layer, "denoising_transmission_direct", text="Direct", toggle=True) + row.prop(cycles_view_layer, "denoising_transmission_indirect", text="Indirect", toggle=True) - row = layout.row() - row.active = crl.use_denoising or crl.denoising_store_passes - row.label(text="Subsurface:") - sub = row.row(align=True) - sub.prop(crl, "denoising_subsurface_direct", text="Direct", toggle=True) - sub.prop(crl, "denoising_subsurface_indirect", text="Indirect", toggle=True) + split = layout.split(factor=0.5) + split.active = cycles_view_layer.use_denoising or cycles_view_layer.denoising_store_passes + + col = split.column() + col.alignment = 'RIGHT' + col.label(text="Subsurface") + + row = split.row(align=True) + row.use_property_split = False + row.prop(cycles_view_layer, "denoising_subsurface_direct", text="Direct", toggle=True) + row.prop(cycles_view_layer, "denoising_subsurface_indirect", text="Indirect", toggle=True) class CYCLES_PT_post_processing(CyclesButtonsPanel, Panel): bl_label = "Post Processing" bl_options = {'DEFAULT_CLOSED'} + bl_context = "output" def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False rd = context.scene.render - split = layout.split() - - col = split.column() + col = layout.column(align=True) col.prop(rd, "use_compositing") col.prop(rd, "use_sequencer") - col = split.column() - col.prop(rd, "dither_intensity", text="Dither", slider=True) + layout.prop(rd, "dither_intensity", text="Dither", slider=True) class CYCLES_CAMERA_PT_dof(CyclesButtonsPanel, Panel): @@ -716,45 +1018,69 @@ class CYCLES_CAMERA_PT_dof(CyclesButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True cam = context.camera - ccam = cam.cycles - dof_options = cam.gpu_dof split = layout.split() col = split.column() - col.label("Focus:") - col.prop(cam, "dof_object", text="") + col.prop(cam, "dof_object", text="Focus Object") sub = col.row() sub.active = cam.dof_object is None sub.prop(cam, "dof_distance", text="Distance") - hq_support = dof_options.is_hq_supported - sub = col.column(align=True) - sub.label("Viewport:") - subhq = sub.column() - subhq.active = hq_support - subhq.prop(dof_options, "use_high_quality") - sub.prop(dof_options, "fstop") - if dof_options.use_high_quality and hq_support: - sub.prop(dof_options, "blades") - col = split.column() +class CYCLES_CAMERA_PT_dof_aperture(CyclesButtonsPanel, Panel): + bl_label = "Aperture" + bl_parent_id = "CYCLES_CAMERA_PT_dof" - col.label("Aperture:") - sub = col.column(align=True) - sub.prop(ccam, "aperture_type", text="") + @classmethod + def poll(cls, context): + return context.camera and CyclesButtonsPanel.poll(context) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + + cam = context.camera + ccam = cam.cycles + + col = flow.column() + col.prop(ccam, "aperture_type") if ccam.aperture_type == 'RADIUS': - sub.prop(ccam, "aperture_size", text="Size") + col.prop(ccam, "aperture_size", text="Size") elif ccam.aperture_type == 'FSTOP': - sub.prop(ccam, "aperture_fstop", text="Number") + col.prop(ccam, "aperture_fstop", text="Number") + col.separator() + + col = flow.column() + col.prop(ccam, "aperture_blades", text="Blades") + col.prop(ccam, "aperture_rotation", text="Rotation") + col.prop(ccam, "aperture_ratio", text="Ratio") - sub = col.column(align=True) - sub.prop(ccam, "aperture_blades", text="Blades") - sub.prop(ccam, "aperture_rotation", text="Rotation") - sub.prop(ccam, "aperture_ratio", text="Ratio") + +class CYCLES_CAMERA_PT_dof_viewport(CyclesButtonsPanel, Panel): + bl_label = "Viewport" + bl_parent_id = "CYCLES_CAMERA_PT_dof" + + @classmethod + def poll(cls, context): + return context.camera and CyclesButtonsPanel.poll(context) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + + cam = context.camera + dof_options = cam.gpu_dof + + sub = flow.column(align=True) + sub.prop(dof_options, "fstop") + sub.prop(dof_options, "blades") class CYCLES_PT_context_material(CyclesButtonsPanel, Panel): @@ -764,7 +1090,10 @@ class CYCLES_PT_context_material(CyclesButtonsPanel, Panel): @classmethod def poll(cls, context): - return (context.material or context.object) and CyclesButtonsPanel.poll(context) + if context.active_object and context.active_object.type == 'GPENCIL': + return False + else: + return (context.material or context.object) and CyclesButtonsPanel.poll(context) def draw(self, context): layout = self.layout @@ -785,8 +1114,8 @@ class CYCLES_PT_context_material(CyclesButtonsPanel, Panel): row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=rows) col = row.column(align=True) - col.operator("object.material_slot_add", icon='ZOOMIN', text="") - col.operator("object.material_slot_remove", icon='ZOOMOUT', text="") + col.operator("object.material_slot_add", icon='ADD', text="") + col.operator("object.material_slot_remove", icon='REMOVE', text="") col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="") @@ -802,7 +1131,7 @@ class CYCLES_PT_context_material(CyclesButtonsPanel, Panel): row.operator("object.material_slot_select", text="Select") row.operator("object.material_slot_deselect", text="Deselect") - split = layout.split(percentage=0.65) + split = layout.split(factor=0.65) if ob: split.template_ID(ob, "active_material", new="material.new") @@ -828,7 +1157,7 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel): if CyclesButtonsPanel.poll(context) and ob: if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'CAMERA'}: return True - if ob.dupli_type == 'GROUP' and ob.dupli_group: + if ob.instance_type == 'COLLECTION' and ob.instance_collection: return True # TODO(sergey): More duplicator types here? return False @@ -872,91 +1201,103 @@ class CYCLES_OBJECT_PT_cycles_settings(CyclesButtonsPanel, Panel): def poll(cls, context): ob = context.object return (CyclesButtonsPanel.poll(context) and - ob and ((ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'LAMP'}) or - (ob.dupli_type == 'GROUP' and ob.dupli_group))) + ob and ((ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'LIGHT'}) or + (ob.instance_type == 'COLLECTION' and ob.instance_collection))) + + def draw(self, context): + pass + + +class CYCLES_OBJECT_PT_cycles_settings_ray_visibility(CyclesButtonsPanel, Panel): + bl_label = "Ray Visibility" + bl_parent_id = "CYCLES_OBJECT_PT_cycles_settings" + bl_context = "object" def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False scene = context.scene - cscene = scene.cycles ob = context.object cob = ob.cycles visibility = ob.cycles_visibility - layout.label(text="Ray Visibility:") - flow = layout.column_flow() + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) - flow.prop(visibility, "camera") - flow.prop(visibility, "diffuse") - flow.prop(visibility, "glossy") - flow.prop(visibility, "transmission") - flow.prop(visibility, "scatter") + col = flow.column() + col.prop(visibility, "camera") + col = flow.column() + col.prop(visibility, "diffuse") + col = flow.column() + col.prop(visibility, "glossy") + col = flow.column() + col.prop(visibility, "transmission") + col = flow.column() + col.prop(visibility, "scatter") - if ob.type != 'LAMP': - flow.prop(visibility, "shadow") + if ob.type != 'LIGHT': + col = flow.column() + col.prop(visibility, "shadow") - row = layout.row() - row.prop(cob, "is_shadow_catcher") - row.prop(cob, "is_holdout") + layout.separator() - col = layout.column() - col.label(text="Performance:") - row = col.row() - sub = row.row() - sub.active = scene.render.use_simplify and cscene.use_camera_cull - sub.prop(cob, "use_camera_cull") + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + + col = flow.column() + col.prop(cob, "is_shadow_catcher") + col = flow.column() + col.prop(cob, "is_holdout") + + +class CYCLES_OBJECT_PT_cycles_settings_performance(CyclesButtonsPanel, Panel): + bl_label = "Performance" + bl_parent_id = "CYCLES_OBJECT_PT_cycles_settings" + bl_context = "object" + + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + scene = context.scene + cscene = scene.cycles + ob = context.object + cob = ob.cycles + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + + col = flow.column() + col.active = scene.render.use_simplify and cscene.use_camera_cull + col.prop(cob, "use_camera_cull") - sub = row.row() - sub.active = scene.render.use_simplify and cscene.use_distance_cull - sub.prop(cob, "use_distance_cull") + col = flow.column() + col.active = scene.render.use_simplify and cscene.use_distance_cull + col.prop(cob, "use_distance_cull") class CYCLES_OT_use_shading_nodes(Operator): - """Enable nodes on a material, world or lamp""" + """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, "lamp", False)) + 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.lamp: - context.lamp.use_nodes = True + elif context.light: + context.light.use_nodes = True return {'FINISHED'} -def find_node(material, nodetype): - if material and material.node_tree: - ntree = material.node_tree - - active_output_node = None - for node in ntree.nodes: - if getattr(node, "type", None) == nodetype: - if getattr(node, "is_active_output", True): - return node - if not active_output_node: - active_output_node = node - return active_output_node - - return None - - -def find_node_input(node, name): - for input in node.inputs: - if input.name == name: - return input - - return None - - def panel_node_draw(layout, id_data, output_type, input_name): if not id_data.use_nodes: layout.operator("cycles.use_shading_nodes", icon='NODETREE') @@ -964,127 +1305,127 @@ def panel_node_draw(layout, id_data, output_type, input_name): ntree = id_data.node_tree - node = find_node(id_data, output_type) - if not node: - layout.label(text="No output node") - else: + node = ntree.get_output_node('CYCLES') + if node: input = find_node_input(node, input_name) - layout.template_node_view(ntree, node, input) + if input: + layout.template_node_view(ntree, node, input) + else: + layout.label(text="Incompatible output node") + else: + layout.label(text="No output node") return True -class CYCLES_LAMP_PT_preview(CyclesButtonsPanel, Panel): +class CYCLES_LIGHT_PT_preview(CyclesButtonsPanel, Panel): bl_label = "Preview" bl_context = "data" bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): - return context.lamp and \ - not (context.lamp.type == 'AREA' and - context.lamp.cycles.is_portal) \ - and CyclesButtonsPanel.poll(context) + return ( + context.light and + not ( + context.light.type == 'AREA' and + context.light.cycles.is_portal + ) and + CyclesButtonsPanel.poll(context) + ) def draw(self, context): - self.layout.template_preview(context.lamp) + self.layout.template_preview(context.light) -class CYCLES_LAMP_PT_lamp(CyclesButtonsPanel, Panel): - bl_label = "Lamp" +class CYCLES_LIGHT_PT_light(CyclesButtonsPanel, Panel): + bl_label = "Light" bl_context = "data" @classmethod def poll(cls, context): - return context.lamp and CyclesButtonsPanel.poll(context) + return context.light and CyclesButtonsPanel.poll(context) def draw(self, context): layout = self.layout - lamp = context.lamp - clamp = lamp.cycles + light = context.light + clamp = light.cycles # cscene = context.scene.cycles - layout.prop(lamp, "type", expand=True) + layout.prop(light, "type", expand=True) - split = layout.split() - col = split.column(align=True) + layout.use_property_split = True + layout.use_property_decorate = False - if lamp.type in {'POINT', 'SUN', 'SPOT'}: - col.prop(lamp, "shadow_soft_size", text="Size") - elif lamp.type == 'AREA': - col.prop(lamp, "shape", text="") + col = layout.column() + + if light.type in {'POINT', 'SUN', 'SPOT'}: + col.prop(light, "shadow_soft_size", text="Size") + elif light.type == 'AREA': + col.prop(light, "shape", text="Shape") sub = col.column(align=True) - if lamp.shape == 'SQUARE': - sub.prop(lamp, "size") - elif lamp.shape == 'RECTANGLE': - sub.prop(lamp, "size", text="Size X") - sub.prop(lamp, "size_y", text="Size Y") + if light.shape in {'SQUARE', 'DISK'}: + sub.prop(light, "size") + elif light.shape in {'RECTANGLE', 'ELLIPSE'}: + sub.prop(light, "size", text="Size X") + sub.prop(light, "size_y", text="Y") - if not (lamp.type == 'AREA' and clamp.is_portal): - sub = col.column(align=True) + if not (light.type == 'AREA' and clamp.is_portal): + sub = col.column() if use_branched_path(context): subsub = sub.row(align=True) subsub.active = use_sample_all_lights(context) subsub.prop(clamp, "samples") sub.prop(clamp, "max_bounces") - col = split.column() - sub = col.column(align=True) - sub.active = not (lamp.type == 'AREA' and clamp.is_portal) + sub.active = not (light.type == 'AREA' and clamp.is_portal) sub.prop(clamp, "cast_shadow") sub.prop(clamp, "use_multiple_importance_sampling", text="Multiple Importance") - if lamp.type == 'AREA': + if light.type == 'AREA': col.prop(clamp, "is_portal", text="Portal") - if lamp.type == 'HEMI': - layout.label(text="Not supported, interpreted as sun lamp") - -class CYCLES_LAMP_PT_nodes(CyclesButtonsPanel, Panel): +class CYCLES_LIGHT_PT_nodes(CyclesButtonsPanel, Panel): bl_label = "Nodes" bl_context = "data" @classmethod def poll(cls, context): - return context.lamp and not (context.lamp.type == 'AREA' and - context.lamp.cycles.is_portal) and \ + return context.light and not (context.light.type == 'AREA' and + context.light.cycles.is_portal) and \ CyclesButtonsPanel.poll(context) def draw(self, context): layout = self.layout - lamp = context.lamp - if not panel_node_draw(layout, lamp, 'OUTPUT_LAMP', 'Surface'): - layout.prop(lamp, "color") + light = context.light + if not panel_node_draw(layout, light, 'OUTPUT_LIGHT', 'Surface'): + layout.prop(light, "color") -class CYCLES_LAMP_PT_spot(CyclesButtonsPanel, Panel): +class CYCLES_LIGHT_PT_spot(CyclesButtonsPanel, Panel): bl_label = "Spot Shape" bl_context = "data" @classmethod def poll(cls, context): - lamp = context.lamp - return (lamp and lamp.type == 'SPOT') and CyclesButtonsPanel.poll(context) + light = context.light + return (light and light.type == 'SPOT') and CyclesButtonsPanel.poll(context) def draw(self, context): layout = self.layout + light = context.light + layout.use_property_split = True + layout.use_property_decorate = False - lamp = context.lamp - - split = layout.split() - - col = split.column() - sub = col.column() - sub.prop(lamp, "spot_size", text="Size") - sub.prop(lamp, "spot_blend", text="Blend", slider=True) - - col = split.column() - col.prop(lamp, "show_cone") + col = layout.column() + col.prop(light, "spot_size", text="Size") + col.prop(light, "spot_blend", text="Blend", slider=True) + col.prop(light, "show_cone") class CYCLES_WORLD_PT_preview(CyclesButtonsPanel, Panel): @@ -1114,7 +1455,7 @@ class CYCLES_WORLD_PT_surface(CyclesButtonsPanel, Panel): world = context.world if not panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Surface'): - layout.prop(world, "horizon_color", text="Color") + layout.prop(world, "color") class CYCLES_WORLD_PT_volume(CyclesButtonsPanel, Panel): @@ -1137,6 +1478,7 @@ class CYCLES_WORLD_PT_volume(CyclesButtonsPanel, Panel): class CYCLES_WORLD_PT_ambient_occlusion(CyclesButtonsPanel, Panel): bl_label = "Ambient Occlusion" bl_context = "world" + bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): @@ -1148,15 +1490,17 @@ class CYCLES_WORLD_PT_ambient_occlusion(CyclesButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False light = context.world.light_settings scene = context.scene - row = layout.row() - sub = row.row() + col = layout.column() + sub = col.column() sub.active = light.use_ambient_occlusion or scene.render.use_simplify sub.prop(light, "ao_factor", text="Factor") - row.prop(light, "distance", text="Distance") + col.prop(light, "distance", text="Distance") class CYCLES_WORLD_PT_mist(CyclesButtonsPanel, Panel): @@ -1168,8 +1512,8 @@ class CYCLES_WORLD_PT_mist(CyclesButtonsPanel, Panel): def poll(cls, context): if CyclesButtonsPanel.poll(context): if context.world: - for rl in context.scene.render.layers: - if rl.use_pass_mist: + for view_layer in context.scene.view_layers: + if view_layer.use_pass_mist: return True return False @@ -1221,35 +1565,67 @@ class CYCLES_WORLD_PT_settings(CyclesButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False - world = context.world - cworld = world.cycles - # cscene = context.scene.cycles + layout.column() - split = layout.split() - col = split.column() +class CYCLES_WORLD_PT_settings_surface(CyclesButtonsPanel, Panel): + bl_label = "Surface" + bl_parent_id = "CYCLES_WORLD_PT_settings" + bl_context = "world" + + @classmethod + def poll(cls, context): + return context.world and CyclesButtonsPanel.poll(context) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False - col.label(text="Surface:") + world = context.world + cworld = world.cycles + + col = layout.column() col.prop(cworld, "sampling_method", text="Sampling") - sub = col.column(align=True) + sub = col.column() sub.active = cworld.sampling_method != 'NONE' subsub = sub.row(align=True) subsub.active = cworld.sampling_method == 'MANUAL' subsub.prop(cworld, "sample_map_resolution") if use_branched_path(context): - subsub = sub.row(align=True) + subsub = sub.column(align=True) subsub.active = use_sample_all_lights(context) subsub.prop(cworld, "samples") sub.prop(cworld, "max_bounces") - col = split.column() - col.label(text="Volume:") + +class CYCLES_WORLD_PT_settings_volume(CyclesButtonsPanel, Panel): + bl_label = "Volume" + bl_parent_id = "CYCLES_WORLD_PT_settings" + bl_context = "world" + + @classmethod + def poll(cls, context): + return context.world and CyclesButtonsPanel.poll(context) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + world = context.world + cworld = world.cycles + + col = layout.column() + sub = col.column() sub.active = use_cpu(context) - sub.prop(cworld, "volume_sampling", text="") - col.prop(cworld, "volume_interpolation", text="") + sub.prop(cworld, "volume_sampling", text="Sampling") + col.prop(cworld, "volume_interpolation", text="Interpolation") col.prop(cworld, "homogeneous_volume", text="Homogeneous") @@ -1320,228 +1696,68 @@ class CYCLES_MATERIAL_PT_displacement(CyclesButtonsPanel, Panel): class CYCLES_MATERIAL_PT_settings(CyclesButtonsPanel, Panel): bl_label = "Settings" bl_context = "material" - - @classmethod - def poll(cls, context): - return context.material and CyclesButtonsPanel.poll(context) - - def draw(self, context): - layout = self.layout - - mat = context.material - cmat = mat.cycles - - split = layout.split() - col = split.column() - col.label(text="Surface:") - col.prop(cmat, "sample_as_light", text="Multiple Importance") - col.prop(cmat, "use_transparent_shadow") - - col.separator() - col.label(text="Geometry:") - col.prop(cmat, "displacement_method", text="") - - col = split.column() - col.label(text="Volume:") - sub = col.column() - sub.active = use_cpu(context) - sub.prop(cmat, "volume_sampling", text="") - col.prop(cmat, "volume_interpolation", text="") - col.prop(cmat, "homogeneous_volume", text="Homogeneous") - - col.separator() - col.prop(mat, "pass_index") - - -class CYCLES_MATERIAL_PT_viewport(CyclesButtonsPanel, Panel): - bl_label = "Viewport" - bl_context = "material" bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): return context.material and CyclesButtonsPanel.poll(context) - def draw(self, context): - mat = context.material - + @staticmethod + def draw_shared(self, mat): layout = self.layout - split = layout.split() + layout.use_property_split = True + layout.use_property_decorate = False - col = split.column(align=True) - col.label("Color:") - col.prop(mat, "diffuse_color", text="") - col.prop(mat, "alpha") - - col.separator() - col.label("Alpha:") - col.prop(mat.game_settings, "alpha_blend", text="") - - col = split.column(align=True) - col.label("Specular:") - col.prop(mat, "specular_color", text="") - col.prop(mat, "specular_hardness", text="Hardness") - - -class CYCLES_TEXTURE_PT_context(CyclesButtonsPanel, Panel): - bl_label = "" - bl_context = "texture" - bl_options = {'HIDE_HEADER'} - COMPAT_ENGINES = {'CYCLES'} + layout.prop(mat, "pass_index") def draw(self, context): - layout = self.layout - - tex = context.texture - space = context.space_data - pin_id = space.pin_id - use_pin_id = space.use_pin_id - user = context.texture_user - - space.use_limited_texture_context = False - - if not (use_pin_id and isinstance(pin_id, bpy.types.Texture)): - pin_id = None - - if not pin_id: - layout.template_texture_user() - - if user or pin_id: - layout.separator() + self.draw_shared(self, context.material) - split = layout.split(percentage=0.65) - col = split.column() - if pin_id: - col.template_ID(space, "pin_id") - else: - propname = context.texture_user_property.identifier - col.template_ID(user, propname, new="texture.new") - - if tex: - split = layout.split(percentage=0.2) - split.label(text="Type:") - split.prop(tex, "type", text="") - - -class CYCLES_TEXTURE_PT_node(CyclesButtonsPanel, Panel): - bl_label = "Node" - bl_context = "texture" - - @classmethod - def poll(cls, context): - node = context.texture_node - return node and CyclesButtonsPanel.poll(context) +class CYCLES_MATERIAL_PT_settings_surface(CyclesButtonsPanel, Panel): + bl_label = "Surface" + bl_parent_id = "CYCLES_MATERIAL_PT_settings" + bl_context = "material" - def draw(self, context): + @staticmethod + def draw_shared(self, mat): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False - node = context.texture_node - ntree = node.id_data - layout.template_node_view(ntree, node, None) - - -class CYCLES_TEXTURE_PT_mapping(CyclesButtonsPanel, Panel): - bl_label = "Mapping" - bl_context = "texture" + cmat = mat.cycles - @classmethod - def poll(cls, context): - node = context.texture_node - # TODO(sergey): perform a faster/nicer check? - return node and hasattr(node, 'texture_mapping') and CyclesButtonsPanel.poll(context) + col = layout.column() + col.prop(cmat, "sample_as_light", text="Multiple Importance") + col.prop(cmat, "use_transparent_shadow") + col.prop(cmat, "displacement_method", text="Displacement Method") def draw(self, context): - layout = self.layout - - node = context.texture_node - - mapping = node.texture_mapping - - layout.prop(mapping, "vector_type", expand=True) - - row = layout.row() - - row.column().prop(mapping, "translation") - row.column().prop(mapping, "rotation") - row.column().prop(mapping, "scale") - - layout.label(text="Projection:") - - row = layout.row() - row.prop(mapping, "mapping_x", text="") - row.prop(mapping, "mapping_y", text="") - row.prop(mapping, "mapping_z", text="") + self.draw_shared(self, context.material) -class CYCLES_TEXTURE_PT_colors(CyclesButtonsPanel, Panel): - bl_label = "Color" - bl_context = "texture" - bl_options = {'DEFAULT_CLOSED'} - - @classmethod - def poll(cls, context): - # node = context.texture_node - return False - # return node and CyclesButtonsPanel.poll(context) +class CYCLES_MATERIAL_PT_settings_volume(CyclesButtonsPanel, Panel): + bl_label = "Volume" + bl_parent_id = "CYCLES_MATERIAL_PT_settings" + bl_context = "material" - def draw(self, context): + @staticmethod + def draw_shared(self, context, mat): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False - node = context.texture_node - - mapping = node.color_mapping - - split = layout.split() - - col = split.column() - col.label(text="Blend:") - col.prop(mapping, "blend_type", text="") - col.prop(mapping, "blend_factor", text="Factor") - col.prop(mapping, "blend_color", text="") - - col = split.column() - col.label(text="Adjust:") - col.prop(mapping, "brightness") - col.prop(mapping, "contrast") - col.prop(mapping, "saturation") - - layout.separator() - - layout.prop(mapping, "use_color_ramp", text="Ramp") - if mapping.use_color_ramp: - layout.template_color_ramp(mapping, "color_ramp", expand=True) - - -class CYCLES_PARTICLE_PT_textures(CyclesButtonsPanel, Panel): - bl_label = "Textures" - bl_context = "particle" - bl_options = {'DEFAULT_CLOSED'} + cmat = mat.cycles - @classmethod - def poll(cls, context): - psys = context.particle_system - return psys and CyclesButtonsPanel.poll(context) + col = layout.column() + sub = col.column() + sub.active = use_cpu(context) + sub.prop(cmat, "volume_sampling", text="Sampling") + col.prop(cmat, "volume_interpolation", text="Interpolation") + col.prop(cmat, "homogeneous_volume", text="Homogeneous") def draw(self, context): - layout = self.layout - - psys = context.particle_system - part = psys.settings - - row = layout.row() - row.template_list("TEXTURE_UL_texslots", "", part, "texture_slots", part, "active_texture_index", rows=2) - - col = row.column(align=True) - col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP' - col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN' - col.menu("TEXTURE_MT_specials", icon='DOWNARROW_HLT', text="") - - if not part.active_texture: - layout.template_ID(part, "active_texture", new="texture.new") - else: - slot = part.texture_slots[part.active_texture_index] - layout.template_ID(slot, "texture", new="texture.new") + self.draw_shared(self, context, context.material) class CYCLES_RENDER_PT_bake(CyclesButtonsPanel, Panel): @@ -1552,69 +1768,84 @@ class CYCLES_RENDER_PT_bake(CyclesButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. scene = context.scene cscene = scene.cycles cbk = scene.render.bake - - layout.operator("object.bake", icon='RENDER_STILL').type = cscene.bake_type - - col = layout.column() - col.prop(cscene, "bake_type") + rd = scene.render col = layout.column() + col.prop(rd, "use_bake_multires") + if rd.use_bake_multires: + col.prop(rd, "bake_type") - if cscene.bake_type == 'NORMAL': - col.prop(cbk, "normal_space", text="Space") - - row = col.row(align=True) - row.label(text="Swizzle:") - row.prop(cbk, "normal_r", text="") - row.prop(cbk, "normal_g", text="") - row.prop(cbk, "normal_b", text="") + col = layout.column() + col.prop(rd, "bake_margin") + col.prop(rd, "use_bake_clear") - elif cscene.bake_type == 'COMBINED': - row = col.row(align=True) - row.prop(cbk, "use_pass_direct", toggle=True) - row.prop(cbk, "use_pass_indirect", toggle=True) + if rd.bake_type == 'DISPLACEMENT': + col.prop(rd, "use_bake_lores_mesh") - split = col.split() - split.active = cbk.use_pass_direct or cbk.use_pass_indirect + col.operator("object.bake_image", icon='RENDER_STILL') - col = split.column() - col.prop(cbk, "use_pass_diffuse") - col.prop(cbk, "use_pass_glossy") - col.prop(cbk, "use_pass_transmission") + else: + col.prop(cscene, "bake_type") + + col = layout.column() + + if cscene.bake_type == 'NORMAL': + col.prop(cbk, "normal_space", text="Space") + + sub = col.column(align=True) + sub.prop(cbk, "normal_r", text="Swizzle R") + sub.prop(cbk, "normal_g", text="G") + sub.prop(cbk, "normal_b", text="B") + + elif cscene.bake_type == 'COMBINED': + row = col.row(align=True) + row.use_property_split = False + row.prop(cbk, "use_pass_direct", toggle=True) + row.prop(cbk, "use_pass_indirect", toggle=True) + + col = col.column() + col.active = cbk.use_pass_direct or cbk.use_pass_indirect + col.prop(cbk, "use_pass_diffuse") + col.prop(cbk, "use_pass_glossy") + col.prop(cbk, "use_pass_transmission") + col.prop(cbk, "use_pass_subsurface") + col.prop(cbk, "use_pass_ambient_occlusion") + col.prop(cbk, "use_pass_emit") + + elif cscene.bake_type in {'DIFFUSE', 'GLOSSY', 'TRANSMISSION', 'SUBSURFACE'}: + row = col.row(align=True) + row.use_property_split = False + row.prop(cbk, "use_pass_direct", toggle=True) + row.prop(cbk, "use_pass_indirect", toggle=True) + row.prop(cbk, "use_pass_color", toggle=True) - col = split.column() - col.prop(cbk, "use_pass_subsurface") - col.prop(cbk, "use_pass_ambient_occlusion") - col.prop(cbk, "use_pass_emit") + layout.separator() - elif cscene.bake_type in {'DIFFUSE', 'GLOSSY', 'TRANSMISSION', 'SUBSURFACE'}: - row = col.row(align=True) - row.prop(cbk, "use_pass_direct", toggle=True) - row.prop(cbk, "use_pass_indirect", toggle=True) - row.prop(cbk, "use_pass_color", toggle=True) + col = layout.column() + col.prop(cbk, "margin") + col.prop(cbk, "use_clear", text="Clear Image") - layout.separator() + col.separator() - split = layout.split() + col.prop(cbk, "use_selected_to_active") + sub = col.column() + sub.active = cbk.use_selected_to_active + sub.prop(cbk, "use_cage", text="Cage") + if cbk.use_cage: + sub.prop(cbk, "cage_extrusion", text="Extrusion") + sub.prop(cbk, "cage_object", text="Cage Object") + else: + sub.prop(cbk, "cage_extrusion", text="Ray Distance") - col = split.column() - col.prop(cbk, "margin") - col.prop(cbk, "use_clear") + layout.separator() - col = split.column() - col.prop(cbk, "use_selected_to_active") - sub = col.column() - sub.active = cbk.use_selected_to_active - sub.prop(cbk, "use_cage", text="Cage") - if cbk.use_cage: - sub.prop(cbk, "cage_extrusion", text="Extrusion") - sub.prop_search(cbk, "cage_object", scene, "objects", text="") - else: - sub.prop(cbk, "cage_extrusion", text="Ray Distance") + layout.operator("object.bake", icon='RENDER_STILL').type = cscene.bake_type class CYCLES_RENDER_PT_debug(CyclesButtonsPanel, Panel): @@ -1635,7 +1866,7 @@ class CYCLES_RENDER_PT_debug(CyclesButtonsPanel, Panel): col = layout.column() - col.label('CPU Flags:') + col.label(text="CPU Flags:") row = col.row(align=True) row.prop(cscene, "debug_use_cpu_sse2", toggle=True) row.prop(cscene, "debug_use_cpu_sse3", toggle=True) @@ -1648,14 +1879,14 @@ class CYCLES_RENDER_PT_debug(CyclesButtonsPanel, Panel): col.separator() col = layout.column() - col.label('CUDA Flags:') + col.label(text="CUDA Flags:") col.prop(cscene, "debug_use_cuda_adaptive_compile") col.prop(cscene, "debug_use_cuda_split_kernel") col.separator() col = layout.column() - col.label('OpenCL Flags:') + col.label(text="OpenCL Flags:") col.prop(cscene, "debug_opencl_kernel_type", text="Kernel") col.prop(cscene, "debug_opencl_device_type", text="Device") col.prop(cscene, "debug_opencl_kernel_single_program", text="Single Program") @@ -1668,48 +1899,54 @@ class CYCLES_RENDER_PT_debug(CyclesButtonsPanel, Panel): col.prop(cscene, "debug_bvh_type") -class CYCLES_PARTICLE_PT_curve_settings(CyclesButtonsPanel, Panel): - bl_label = "Cycles Hair Settings" - bl_context = "particle" +class CYCLES_RENDER_PT_simplify(CyclesButtonsPanel, Panel): + bl_label = "Simplify" + bl_context = "render" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'CYCLES'} - @classmethod - def poll(cls, context): - scene = context.scene - ccscene = scene.cycles_curves - psys = context.particle_system - use_curves = ccscene.use_curves and psys - return CyclesButtonsPanel.poll(context) and use_curves and psys.settings.type == 'HAIR' + def draw_header(self, context): + rd = context.scene.render + self.layout.prop(rd, "use_simplify", text="") def draw(self, context): - layout = self.layout + pass - psys = context.particle_settings - cpsys = psys.cycles - row = layout.row() - row.prop(cpsys, "shape", text="Shape") +class CYCLES_RENDER_PT_simplify_viewport(CyclesButtonsPanel, Panel): + bl_label = "Viewport" + bl_context = "render" + bl_parent_id = "CYCLES_RENDER_PT_simplify" + COMPAT_ENGINES = {'CYCLES'} - layout.label(text="Thickness:") - row = layout.row() - row.prop(cpsys, "root_width", text="Root") - row.prop(cpsys, "tip_width", text="Tip") + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False - row = layout.row() - row.prop(cpsys, "radius_scale", text="Scaling") - row.prop(cpsys, "use_closetip", text="Close tip") + scene = context.scene + rd = scene.render + cscene = scene.cycles + layout.active = rd.use_simplify -class CYCLES_SCENE_PT_simplify(CyclesButtonsPanel, Panel): - bl_label = "Simplify" - bl_context = "scene" - COMPAT_ENGINES = {'CYCLES'} + col = layout.column() + col.prop(rd, "simplify_subdivision", text="Max Subdivision") + col.prop(rd, "simplify_child_particles", text="Child Particles") + col.prop(cscene, "texture_limit", text="Texture Limit") + col.prop(cscene, "ao_bounces", text="AO Bounces") - def draw_header(self, context): - rd = context.scene.render - self.layout.prop(rd, "use_simplify", text="") + +class CYCLES_RENDER_PT_simplify_render(CyclesButtonsPanel, Panel): + bl_label = "Render" + bl_context = "render" + bl_parent_id = "CYCLES_RENDER_PT_simplify" + COMPAT_ENGINES = {'CYCLES'} def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False scene = context.scene rd = scene.render @@ -1717,80 +1954,116 @@ class CYCLES_SCENE_PT_simplify(CyclesButtonsPanel, Panel): layout.active = rd.use_simplify - col = layout.column(align=True) - col.label(text="Subdivision") - row = col.row(align=True) - row.prop(rd, "simplify_subdivision", text="Viewport") - row.prop(rd, "simplify_subdivision_render", text="Render") + col = layout.column() - col = layout.column(align=True) - col.label(text="Child Particles") - row = col.row(align=True) - row.prop(rd, "simplify_child_particles", text="Viewport") - row.prop(rd, "simplify_child_particles_render", text="Render") + col.prop(rd, "simplify_subdivision_render", text="Max Subdivision") + col.prop(rd, "simplify_child_particles_render", text="Child Particles") + col.prop(cscene, "texture_limit_render", text="Texture Limit") + col.prop(cscene, "ao_bounces_render", text="AO Bounces") - col = layout.column(align=True) - split = col.split() - sub = split.column() - sub.label(text="Texture Limit Viewport") - sub.prop(cscene, "texture_limit", text="") - sub = split.column() - sub.label(text="Texture Limit Render") - sub.prop(cscene, "texture_limit_render", text="") - split = layout.split() - col = split.column() +class CYCLES_RENDER_PT_simplify_culling(CyclesButtonsPanel, Panel): + bl_label = "Culling" + bl_context = "render" + bl_parent_id = "CYCLES_RENDER_PT_simplify" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'CYCLES'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + scene = context.scene + rd = scene.render + cscene = scene.cycles + + layout.active = rd.use_simplify + + col = layout.column() col.prop(cscene, "use_camera_cull") - row = col.row() - row.active = cscene.use_camera_cull - row.prop(cscene, "camera_cull_margin") + sub = col.column() + sub.active = cscene.use_camera_cull + sub.prop(cscene, "camera_cull_margin") - col = split.column() + col = layout.column() col.prop(cscene, "use_distance_cull") - row = col.row() - row.active = cscene.use_distance_cull - row.prop(cscene, "distance_cull_margin", text="Distance") + sub = col.column() + sub.active = cscene.use_distance_cull + sub.prop(cscene, "distance_cull_margin", text="Distance") - split = layout.split() - col = split.column() - col.prop(cscene, "ao_bounces") - col = split.column() - col.prop(cscene, "ao_bounces_render") +class CYCLES_NODE_PT_settings(CyclesNodeButtonsPanel, Panel): + bl_label = "Settings" + bl_category = "Node" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + snode = context.space_data + return CyclesNodeButtonsPanel.poll(context) and \ + snode.tree_type == 'ShaderNodeTree' and snode.id and \ + snode.id.bl_rna.identifier == 'Material' + + def draw(self, context): + material = context.space_data.id + CYCLES_MATERIAL_PT_settings.draw_shared(self, material) + + +class CYCLES_NODE_PT_settings_surface(CyclesNodeButtonsPanel, Panel): + bl_label = "Surface" + bl_category = "Node" + bl_parent_id = "CYCLES_NODE_PT_settings" + + def draw(self, context): + material = context.space_data.id + CYCLES_MATERIAL_PT_settings_surface.draw_shared(self, material) + + +class CYCLES_NODE_PT_settings_volume(CyclesNodeButtonsPanel, Panel): + bl_label = "Volume" + bl_category = "Node" + bl_parent_id = "CYCLES_NODE_PT_settings" + + def draw(self, context): + material = context.space_data.id + CYCLES_MATERIAL_PT_settings_volume.draw_shared(self, context, material) def draw_device(self, context): scene = context.scene layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False - if scene.render.engine == 'CYCLES': + if context.engine == 'CYCLES': from . import engine cscene = scene.cycles - layout.prop(cscene, "feature_set") + col = layout.column() + col.prop(cscene, "feature_set") - split = layout.split(percentage=1 / 3) - split.label("Device:") - row = split.row() - row.active = show_device_active(context) - row.prop(cscene, "device", text="") + scene = context.scene + col = layout.column() + col.active = show_device_active(context) + col.prop(cscene, "device") + + from . import engine if engine.with_osl() and use_cpu(context): - layout.prop(cscene, "shading_system") + col.prop(cscene, "shading_system") def draw_pause(self, context): layout = self.layout scene = context.scene - if scene.render.engine == "CYCLES": + if context.engine == "CYCLES": view = context.space_data - if view.viewport_shade == 'RENDERED': + if view.shading.type == 'RENDERED': cscene = scene.cycles - layername = scene.render.layers.active.name - layout.prop(cscene, "preview_pause", icon="PAUSE", text="") - layout.prop(cscene, "preview_active_layer", icon="RENDERLAYERS", text=layername) + layout.prop(cscene, "preview_pause", icon='PAUSE', text="") def get_panels(): @@ -1798,49 +2071,15 @@ def get_panels(): 'DATA_PT_area', 'DATA_PT_camera_dof', 'DATA_PT_falloff_curve', - 'DATA_PT_lamp', + 'DATA_PT_light', 'DATA_PT_preview', - 'DATA_PT_shadow', 'DATA_PT_spot', - 'DATA_PT_sunsky', 'MATERIAL_PT_context_material', - 'MATERIAL_PT_diffuse', - 'MATERIAL_PT_flare', - 'MATERIAL_PT_halo', - 'MATERIAL_PT_mirror', - 'MATERIAL_PT_options', - 'MATERIAL_PT_pipeline', 'MATERIAL_PT_preview', - 'MATERIAL_PT_shading', - 'MATERIAL_PT_shadow', - 'MATERIAL_PT_specular', - 'MATERIAL_PT_sss', - 'MATERIAL_PT_strand', - 'MATERIAL_PT_transp', - 'MATERIAL_PT_volume_density', - 'MATERIAL_PT_volume_integration', - 'MATERIAL_PT_volume_lighting', - 'MATERIAL_PT_volume_options', - 'MATERIAL_PT_volume_shading', - 'MATERIAL_PT_volume_transp', - 'RENDERLAYER_PT_layer_options', - 'RENDERLAYER_PT_layer_passes', - 'RENDERLAYER_PT_views', - 'RENDER_PT_antialiasing', - 'RENDER_PT_bake', - 'RENDER_PT_motion_blur', - 'RENDER_PT_performance', + 'VIEWLAYER_PT_filter', + 'VIEWLAYER_PT_layer_passes', 'RENDER_PT_post_processing', - 'RENDER_PT_shading', - 'SCENE_PT_simplify', - 'TEXTURE_PT_context_texture', - 'WORLD_PT_ambient_occlusion', - 'WORLD_PT_environment_lighting', - 'WORLD_PT_gather', - 'WORLD_PT_indirect_lighting', - 'WORLD_PT_mist', - 'WORLD_PT_preview', - 'WORLD_PT_world' + 'RENDER_PT_simplify', } panels = [] @@ -1853,28 +2092,55 @@ def get_panels(): classes = ( - CYCLES_MT_sampling_presets, - CYCLES_MT_integrator_presets, + CYCLES_PT_sampling_presets, + CYCLES_PT_integrator_presets, CYCLES_RENDER_PT_sampling, - CYCLES_RENDER_PT_geometry, + CYCLES_RENDER_PT_sampling_sub_samples, + CYCLES_RENDER_PT_sampling_advanced, CYCLES_RENDER_PT_light_paths, + CYCLES_RENDER_PT_light_paths_max_bounces, + CYCLES_RENDER_PT_light_paths_clamping, + CYCLES_RENDER_PT_light_paths_caustics, + CYCLES_RENDER_PT_volumes, + CYCLES_RENDER_PT_subdivision, + CYCLES_RENDER_PT_hair, + CYCLES_RENDER_PT_simplify, + CYCLES_RENDER_PT_simplify_viewport, + CYCLES_RENDER_PT_simplify_render, + CYCLES_RENDER_PT_simplify_culling, CYCLES_RENDER_PT_motion_blur, + CYCLES_RENDER_PT_motion_blur_curve, CYCLES_RENDER_PT_film, + CYCLES_RENDER_PT_film_pixel_filter, + CYCLES_RENDER_PT_film_transparency, CYCLES_RENDER_PT_performance, - CYCLES_RENDER_PT_layer_options, - CYCLES_RENDER_PT_layer_passes, - CYCLES_RENDER_PT_views, + CYCLES_RENDER_PT_performance_threads, + CYCLES_RENDER_PT_performance_tiles, + CYCLES_RENDER_PT_performance_acceleration_structure, + CYCLES_RENDER_PT_performance_final_render, + CYCLES_RENDER_PT_performance_viewport, + CYCLES_RENDER_PT_filter, + CYCLES_RENDER_PT_override, + CYCLES_RENDER_PT_passes, + CYCLES_RENDER_PT_passes_data, + CYCLES_RENDER_PT_passes_light, + CYCLES_RENDER_PT_passes_crypto, + CYCLES_RENDER_PT_passes_debug, CYCLES_RENDER_PT_denoising, CYCLES_PT_post_processing, CYCLES_CAMERA_PT_dof, + CYCLES_CAMERA_PT_dof_aperture, + CYCLES_CAMERA_PT_dof_viewport, CYCLES_PT_context_material, CYCLES_OBJECT_PT_motion_blur, CYCLES_OBJECT_PT_cycles_settings, + CYCLES_OBJECT_PT_cycles_settings_ray_visibility, + CYCLES_OBJECT_PT_cycles_settings_performance, CYCLES_OT_use_shading_nodes, - CYCLES_LAMP_PT_preview, - CYCLES_LAMP_PT_lamp, - CYCLES_LAMP_PT_nodes, - CYCLES_LAMP_PT_spot, + CYCLES_LIGHT_PT_preview, + CYCLES_LIGHT_PT_light, + CYCLES_LIGHT_PT_nodes, + CYCLES_LIGHT_PT_spot, CYCLES_WORLD_PT_preview, CYCLES_WORLD_PT_surface, CYCLES_WORLD_PT_volume, @@ -1882,28 +2148,27 @@ classes = ( CYCLES_WORLD_PT_mist, CYCLES_WORLD_PT_ray_visibility, CYCLES_WORLD_PT_settings, + CYCLES_WORLD_PT_settings_surface, + CYCLES_WORLD_PT_settings_volume, CYCLES_MATERIAL_PT_preview, CYCLES_MATERIAL_PT_surface, CYCLES_MATERIAL_PT_volume, CYCLES_MATERIAL_PT_displacement, CYCLES_MATERIAL_PT_settings, - CYCLES_MATERIAL_PT_viewport, - CYCLES_TEXTURE_PT_context, - CYCLES_TEXTURE_PT_node, - CYCLES_TEXTURE_PT_mapping, - CYCLES_TEXTURE_PT_colors, - CYCLES_PARTICLE_PT_textures, + CYCLES_MATERIAL_PT_settings_surface, + CYCLES_MATERIAL_PT_settings_volume, CYCLES_RENDER_PT_bake, CYCLES_RENDER_PT_debug, - CYCLES_PARTICLE_PT_curve_settings, - CYCLES_SCENE_PT_simplify, + CYCLES_NODE_PT_settings, + CYCLES_NODE_PT_settings_surface, + CYCLES_NODE_PT_settings_volume, ) def register(): from bpy.utils import register_class - bpy.types.RENDER_PT_render.append(draw_device) + bpy.types.RENDER_PT_context.append(draw_device) bpy.types.VIEW3D_HT_header.append(draw_pause) for panel in get_panels(): @@ -1916,7 +2181,7 @@ def register(): def unregister(): from bpy.utils import unregister_class - bpy.types.RENDER_PT_render.remove(draw_device) + bpy.types.RENDER_PT_context.remove(draw_device) bpy.types.VIEW3D_HT_header.remove(draw_pause) for panel in get_panels(): diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py index 3a4b13ef9d2..178f1162568 100644 --- a/intern/cycles/blender/addon/version_update.py +++ b/intern/cycles/blender/addon/version_update.py @@ -22,45 +22,6 @@ import math from bpy.app.handlers import persistent -def check_is_new_shading_ntree(node_tree): - for node in node_tree.nodes: - # If material has any node with ONLY new shading system - # compatibility then it's considered a Cycles material - # and versioning code would need to perform on it. - # - # We can not check for whether NEW_SHADING in compatibility - # because some nodes could have compatibility with both old - # and new shading system and they can't be used for any - # decision here. - if node.shading_compatibility == {'NEW_SHADING'}: - return True - - # If node is only compatible with old shading system - # then material can not be Cycles material and we - # can stopiterating nodes now. - if node.shading_compatibility == {'OLD_SHADING'}: - return False - return False - - -def check_is_new_shading_material(material): - if not material.node_tree: - return False - return check_is_new_shading_ntree(material.node_tree) - - -def check_is_new_shading_world(world): - if not world.node_tree: - return False - return check_is_new_shading_ntree(world.node_tree) - - -def check_is_new_shading_lamp(lamp): - if not lamp.node_tree: - return False - return check_is_new_shading_ntree(lamp.node_tree) - - def foreach_notree_node(nodetree, callback, traversed): if nodetree in traversed: return @@ -74,23 +35,23 @@ def foreach_notree_node(nodetree, callback, traversed): def foreach_cycles_node(callback): traversed = set() for material in bpy.data.materials: - if check_is_new_shading_material(material): + if material.node_tree: foreach_notree_node( material.node_tree, callback, traversed, ) for world in bpy.data.worlds: - if check_is_new_shading_world(world): + if world.node_tree: foreach_notree_node( world.node_tree, callback, traversed, ) - for lamp in bpy.data.lamps: - if check_is_new_shading_world(lamp): + for light in bpy.data.lights: + if light.node_tree: foreach_notree_node( - lamp.node_tree, + light.node_tree, callback, traversed, ) @@ -109,10 +70,10 @@ def displacement_node_insert(material, nodetree, traversed): displacement_links = [] for link in nodetree.links: if ( - link.to_node.bl_idname == 'ShaderNodeOutputMaterial' and - link.from_node.bl_idname != 'ShaderNodeDisplacement' and - link.to_socket.identifier == 'Displacement' - ): + link.to_node.bl_idname == 'ShaderNodeOutputMaterial' and + link.from_node.bl_idname != 'ShaderNodeDisplacement' and + link.to_socket.identifier == 'Displacement' + ): displacement_links.append(link) # Replace links with displacement node @@ -137,7 +98,7 @@ def displacement_node_insert(material, nodetree, traversed): def displacement_nodes_insert(): traversed = set() for material in bpy.data.materials: - if check_is_new_shading_material(material): + if material.node_tree: displacement_node_insert(material, material.node_tree, traversed) @@ -198,7 +159,7 @@ def square_roughness_node_insert(material, nodetree, traversed): def square_roughness_nodes_insert(): traversed = set() for material in bpy.data.materials: - if check_is_new_shading_material(material): + if material.node_tree: square_roughness_node_insert(material, material.node_tree, traversed) @@ -314,15 +275,15 @@ def ambient_occlusion_node_relink(material, nodetree, traversed): def ambient_occlusion_nodes_relink(): traversed = set() for material in bpy.data.materials: - if check_is_new_shading_material(material): + if material.node_tree: ambient_occlusion_node_relink(material, material.node_tree, traversed) @persistent def do_versions(self): - if bpy.context.user_preferences.version <= (2, 78, 1): - prop = bpy.context.user_preferences.addons[__package__].preferences - system = bpy.context.user_preferences.system + if bpy.context.preferences.version <= (2, 78, 1): + prop = bpy.context.preferences.addons[__package__].preferences + system = bpy.context.preferences.system if not prop.is_property_set("compute_device_type"): # Device might not currently be available so this can fail try: @@ -348,11 +309,9 @@ def do_versions(self): for scene in bpy.data.scenes: cscene = scene.cycles sample_clamp = cscene.get("sample_clamp", False) - if ( - sample_clamp and + if (sample_clamp and not cscene.is_property_set("sample_clamp_direct") and - not cscene.is_property_set("sample_clamp_indirect") - ): + not cscene.is_property_set("sample_clamp_indirect")): cscene.sample_clamp_direct = sample_clamp cscene.sample_clamp_indirect = sample_clamp @@ -368,11 +327,10 @@ def do_versions(self): if bpy.data.version <= (2, 72, 0): for scene in bpy.data.scenes: cscene = scene.cycles - if ( - cscene.get("no_caustics", False) and + if (cscene.get("no_caustics", False) and not cscene.is_property_set("caustics_reflective") and - not cscene.is_property_set("caustics_refractive") - ): + not cscene.is_property_set("caustics_refractive")): + cscene.caustics_reflective = False cscene.caustics_refractive = False @@ -409,12 +367,12 @@ def do_versions(self): if not cscene.is_property_set("tile_order"): cscene.tile_order = 'CENTER' - for lamp in bpy.data.lamps: - clamp = lamp.cycles + for light in bpy.data.lights: + clight = light.cycles # MIS - if not clamp.is_property_set("use_multiple_importance_sampling"): - clamp.use_multiple_importance_sampling = False + if not clight.is_property_set("use_multiple_importance_sampling"): + clight.use_multiple_importance_sampling = False for mat in bpy.data.materials: cmat = mat.cycles @@ -463,7 +421,8 @@ def do_versions(self): if not cscene.is_property_set("sample_clamp_indirect"): cscene.sample_clamp_indirect = 0.0 - if bpy.data.version <= (2, 79, 1): + if bpy.data.version <= (2, 79, 1) or \ + (bpy.data.version >= (2, 80, 0) and bpy.data.version <= (2, 80, 3)): displacement_nodes_insert() if bpy.data.version <= (2, 79, 2): @@ -474,11 +433,24 @@ def do_versions(self): foreach_cycles_node(displacement_principled_nodes) - if bpy.data.version <= (2, 79, 3): + if bpy.data.version <= (2, 79, 3) or \ + (bpy.data.version >= (2, 80, 0) and bpy.data.version <= (2, 80, 4)): # Switch to squared roughness convention square_roughness_nodes_insert() - if bpy.data.version <= (2, 79, 4): + if bpy.data.version <= (2, 80, 15): + # Copy cycles hair settings to internal settings + for part in bpy.data.particles: + cpart = part.get("cycles", None) + if cpart: + part.shape = cpart.get("shape", 0.0) + part.root_radius = cpart.get("root_width", 1.0) + part.tip_radius = cpart.get("tip_width", 0.0) + part.radius_scale = cpart.get("radius_scale", 0.01) + part.use_close_tip = cpart.get("use_closetip", True) + + if bpy.data.version <= (2, 79, 4) or \ + (bpy.data.version >= (2, 80, 0) and bpy.data.version <= (2, 80, 18)): for world in bpy.data.worlds: cworld = world.cycles # World MIS @@ -490,7 +462,8 @@ def do_versions(self): ambient_occlusion_nodes_relink() - if bpy.data.version <= (2, 79, 6): + if bpy.data.version <= (2, 79, 6) or \ + (bpy.data.version >= (2, 80, 0) and bpy.data.version <= (2, 80, 41)): # Change default to bump again. for mat in bpy.data.materials: cmat = mat.cycles diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index 5a447a347a3..21efba4cdf0 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -95,8 +95,8 @@ static void blender_camera_init(BlenderCamera *bcam, bcam->type = CAMERA_PERSPECTIVE; bcam->zoom = 1.0f; bcam->pixelaspect = make_float2(1.0f, 1.0f); - bcam->sensor_width = 32.0f; - bcam->sensor_height = 18.0f; + bcam->sensor_width = 36.0f; + bcam->sensor_height = 24.0f; bcam->sensor_fit = BlenderCamera::AUTO; bcam->shuttertime = 1.0f; bcam->motion_position = Camera::MOTION_POSITION_CENTER; @@ -228,12 +228,17 @@ static void blender_camera_from_object(BlenderCamera *bcam, bcam->sensor_fit = BlenderCamera::HORIZONTAL; else bcam->sensor_fit = BlenderCamera::VERTICAL; - - bcam->motion_steps = object_motion_steps(b_ob, b_ob); } - else { - /* from lamp not implemented yet */ + else if(b_ob_data.is_a(&RNA_Light)) { + /* Can also look through spot light. */ + BL::SpotLight b_light(b_ob_data); + float lens = 16.0f / tanf(b_light.spot_size() * 0.5f); + if (lens > 0.0f) { + bcam->lens = lens; + } } + + bcam->motion_steps = object_motion_steps(b_ob, b_ob); } static Transform blender_camera_matrix(const Transform& tfm, @@ -643,7 +648,7 @@ static void blender_camera_from_view(BlenderCamera *bcam, if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) { /* camera view */ - BL::Object b_ob = (b_v3d.lock_camera_and_layers())? b_scene.camera(): b_v3d.camera(); + BL::Object b_ob = (b_v3d.use_local_camera())? b_v3d.camera(): b_scene.camera(); if(b_ob) { blender_camera_from_object(bcam, b_engine, b_ob, skip_panorama); @@ -779,7 +784,7 @@ static void blender_camera_border(BlenderCamera *bcam, return; } - BL::Object b_ob = (b_v3d.lock_camera_and_layers())? b_scene.camera(): b_v3d.camera(); + BL::Object b_ob = (b_v3d.use_local_camera())? b_v3d.camera(): b_scene.camera(); if(!b_ob) return; diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index b5e49bbeeef..48dc90417ca 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -136,9 +136,9 @@ static bool ObtainCacheParticleData(Mesh *mesh, if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) { int shader = clamp(b_part.material()-1, 0, mesh->used_shaders.size()-1); - int draw_step = background ? b_part.render_step() : b_part.draw_step(); + int display_step = background ? b_part.render_step() : b_part.display_step(); int totparts = b_psys.particles.length(); - int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f); + int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.display_percentage() / 100.0f); int totcurves = totchild; if(b_part.child_type() == 0 || totchild == 0) @@ -147,22 +147,20 @@ static bool ObtainCacheParticleData(Mesh *mesh, if(totcurves == 0) continue; - int ren_step = (1 << draw_step) + 1; + int ren_step = (1 << display_step) + 1; if(b_part.kink() == BL::ParticleSettings::kink_SPIRAL) ren_step += b_part.kink_extra_steps(); - PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles"); - CData->psys_firstcurve.push_back_slow(curvenum); CData->psys_curvenum.push_back_slow(totcurves); CData->psys_shader.push_back_slow(shader); - float radius = get_float(cpsys, "radius_scale") * 0.5f; + float radius = b_part.radius_scale() * 0.5f; - CData->psys_rootradius.push_back_slow(radius * get_float(cpsys, "root_width")); - CData->psys_tipradius.push_back_slow(radius * get_float(cpsys, "tip_width")); - CData->psys_shape.push_back_slow(get_float(cpsys, "shape")); - CData->psys_closetip.push_back_slow(get_boolean(cpsys, "use_closetip")); + CData->psys_rootradius.push_back_slow(radius * b_part.root_radius()); + CData->psys_tipradius.push_back_slow(radius * b_part.tip_radius()); + CData->psys_shape.push_back_slow(b_part.shape()); + CData->psys_closetip.push_back_slow(b_part.use_close_tip()); int pa_no = 0; if(!(b_part.child_type() == 0) && totchild != 0) @@ -231,7 +229,7 @@ static bool ObtainCacheParticleUV(Mesh *mesh, if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) { int totparts = b_psys.particles.length(); - int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f); + int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.display_percentage() / 100.0f); int totcurves = totchild; if(b_part.child_type() == 0 || totchild == 0) @@ -251,11 +249,11 @@ static bool ObtainCacheParticleUV(Mesh *mesh, b_psys.particles.begin(b_pa); for(; pa_no < totparts+totchild; pa_no++) { /* Add UVs */ - BL::Mesh::tessface_uv_textures_iterator l; - b_mesh->tessface_uv_textures.begin(l); + BL::Mesh::uv_layers_iterator l; + b_mesh->uv_layers.begin(l); float3 uv = make_float3(0.0f, 0.0f, 0.0f); - if(b_mesh->tessface_uv_textures.length()) + if(b_mesh->uv_layers.length()) b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x); CData->curve_uv.push_back_slow(uv); @@ -290,7 +288,7 @@ static bool ObtainCacheParticleVcol(Mesh *mesh, if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) { int totparts = b_psys.particles.length(); - int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f); + int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.display_percentage() / 100.0f); int totcurves = totchild; if(b_part.child_type() == 0 || totchild == 0) @@ -310,11 +308,11 @@ static bool ObtainCacheParticleVcol(Mesh *mesh, b_psys.particles.begin(b_pa); for(; pa_no < totparts+totchild; pa_no++) { /* Add vertex colors */ - BL::Mesh::tessface_vertex_colors_iterator l; - b_mesh->tessface_vertex_colors.begin(l); + BL::Mesh::vertex_colors_iterator l; + b_mesh->vertex_colors.begin(l); float3 vcol = make_float3(0.0f, 0.0f, 0.0f); - if(b_mesh->tessface_vertex_colors.length()) + if(b_mesh->vertex_colors.length()) b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x); CData->curve_vcol.push_back_slow(vcol); @@ -328,18 +326,6 @@ static bool ObtainCacheParticleVcol(Mesh *mesh, return true; } -static void set_resolution(BL::BlendData *b_data, BL::Object *b_ob, BL::Scene *scene, bool render) -{ - BL::Object::modifiers_iterator b_mod; - for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) { - if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && ((b_mod->show_viewport()) || (b_mod->show_render()))) { - BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr); - BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr); - b_psys.set_resolution(*b_data, *scene, *b_ob, (render)? 2: 1); - } - } -} - static void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, float3 RotCam, bool is_ortho) { @@ -974,9 +960,6 @@ void BlenderSync::sync_curves(Mesh *mesh, ParticleCurveData CData; - if(!preview) - set_resolution(&b_data, &b_ob, &b_scene, true); - ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, !preview); /* add hair geometry to mesh */ @@ -1039,10 +1022,10 @@ void BlenderSync::sync_curves(Mesh *mesh, /* create vertex color attributes */ if(!motion) { - BL::Mesh::tessface_vertex_colors_iterator l; + BL::Mesh::vertex_colors_iterator l; int vcol_num = 0; - for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) { + for(b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l, vcol_num++) { if(!mesh->need_attribute(scene, ustring(l->name().c_str()))) continue; @@ -1076,10 +1059,10 @@ void BlenderSync::sync_curves(Mesh *mesh, /* create UV attributes */ if(!motion) { - BL::Mesh::tessface_uv_textures_iterator l; + BL::Mesh::uv_layers_iterator l; int uv_num = 0; - for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l, uv_num++) { + for(b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, uv_num++) { bool active_render = l->active_render(); AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE; ustring name = ustring(l->name().c_str()); @@ -1120,9 +1103,6 @@ void BlenderSync::sync_curves(Mesh *mesh, } } - if(!preview) - set_resolution(&b_data, &b_ob, &b_scene, false); - mesh->compute_bounds(); } diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 8d2ade1e30b..8e81e3ac121 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -35,46 +35,6 @@ CCL_NAMESPACE_BEGIN -/* Per-face bit flags. */ -enum { - /* Face has no special flags. */ - FACE_FLAG_NONE = (0 << 0), - /* Quad face was split using 1-3 diagonal. */ - FACE_FLAG_DIVIDE_13 = (1 << 0), - /* Quad face was split using 2-4 diagonal. */ - FACE_FLAG_DIVIDE_24 = (1 << 1), -}; - -/* Get vertex indices to create triangles from a given face. - * - * Two triangles has vertex indices in the original Blender-side face. - * If face is already a quad tri_b will not be initialized. - */ -inline void face_split_tri_indices(const int face_flag, - int tri_a[3], - int tri_b[3]) -{ - if(face_flag & FACE_FLAG_DIVIDE_24) { - tri_a[0] = 0; - tri_a[1] = 1; - tri_a[2] = 3; - - tri_b[0] = 2; - tri_b[1] = 3; - tri_b[2] = 1; - } - else { - /* Quad with FACE_FLAG_DIVIDE_13 or single triangle. */ - tri_a[0] = 0; - tri_a[1] = 1; - tri_a[2] = 2; - - tri_b[0] = 0; - tri_b[1] = 2; - tri_b[2] = 3; - } -} - /* Tangent Space */ struct MikkUserData { @@ -379,8 +339,6 @@ static void create_mesh_volume_attributes(Scene *scene, static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, - const vector<int>& nverts, - const vector<int>& face_flags, bool subdivision) { if(subdivision) { @@ -401,15 +359,15 @@ static void attr_create_vertex_color(Scene *scene, int n = p->loop_total(); for(int i = 0; i < n; i++) { float3 color = get_float3(l->data[p->loop_start() + i].color()); - /* Encode vertex color using the sRGB curve. */ + /* Compress/encode vertex color using the sRGB curve. */ *(cdata++) = color_float_to_byte(color_srgb_to_linear_v3(color)); } } } } else { - BL::Mesh::tessface_vertex_colors_iterator l; - for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) { + BL::Mesh::vertex_colors_iterator l; + for(b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) { if(!mesh->need_attribute(scene, ustring(l->name().c_str()))) continue; @@ -417,35 +375,20 @@ static void attr_create_vertex_color(Scene *scene, TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE); - BL::MeshColorLayer::data_iterator c; + BL::Mesh::loop_triangles_iterator t; uchar4 *cdata = attr->data_uchar4(); - size_t i = 0; - - for(l->data.begin(c); c != l->data.end(); ++c, ++i) { - int tri_a[3], tri_b[3]; - face_split_tri_indices(face_flags[i], tri_a, tri_b); - - /* Encode vertex color using the sRGB curve. */ - uchar4 colors[4]; - colors[0] = color_float_to_byte(color_srgb_to_linear_v3(get_float3(c->color1()))); - colors[1] = color_float_to_byte(color_srgb_to_linear_v3(get_float3(c->color2()))); - colors[2] = color_float_to_byte(color_srgb_to_linear_v3(get_float3(c->color3()))); - if(nverts[i] == 4) { - colors[3] = color_float_to_byte(color_srgb_to_linear_v3(get_float3(c->color4()))); - } - cdata[0] = colors[tri_a[0]]; - cdata[1] = colors[tri_a[1]]; - cdata[2] = colors[tri_a[2]]; - - if(nverts[i] == 4) { - cdata[3] = colors[tri_b[0]]; - cdata[4] = colors[tri_b[1]]; - cdata[5] = colors[tri_b[2]]; - cdata += 6; - } - else - cdata += 3; + for(b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) { + int3 li = get_int3(t->loops()); + float3 c1 = get_float3(l->data[li[0]].color()); + float3 c2 = get_float3(l->data[li[1]].color()); + float3 c3 = get_float3(l->data[li[2]].color()); + + /* Compress/encode vertex color using the sRGB curve. */ + cdata[0] = color_float_to_byte(color_srgb_to_linear_v3(c1)); + cdata[1] = color_float_to_byte(color_srgb_to_linear_v3(c2)); + cdata[2] = color_float_to_byte(color_srgb_to_linear_v3(c3)); + cdata += 3; } } } @@ -454,14 +397,12 @@ static void attr_create_vertex_color(Scene *scene, /* Create uv map attributes. */ static void attr_create_uv_map(Scene *scene, Mesh *mesh, - BL::Mesh& b_mesh, - const vector<int>& nverts, - const vector<int>& face_flags) + BL::Mesh& b_mesh) { - if(b_mesh.tessface_uv_textures.length() != 0) { - BL::Mesh::tessface_uv_textures_iterator l; + if(b_mesh.uv_layers.length() != 0) { + BL::Mesh::uv_layers_iterator l; - for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) { + for(b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l) { const bool active_render = l->active_render(); AttributeStandard uv_std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE; ustring uv_name = ustring(l->name().c_str()); @@ -493,33 +434,15 @@ static void attr_create_uv_map(Scene *scene, ATTR_ELEMENT_CORNER); } - BL::MeshTextureFaceLayer::data_iterator t; + BL::Mesh::loop_triangles_iterator t; float3 *fdata = uv_attr->data_float3(); - size_t i = 0; - - for(l->data.begin(t); t != l->data.end(); ++t, ++i) { - int tri_a[3], tri_b[3]; - face_split_tri_indices(face_flags[i], tri_a, tri_b); - - float3 uvs[4]; - uvs[0] = get_float3(t->uv1()); - uvs[1] = get_float3(t->uv2()); - uvs[2] = get_float3(t->uv3()); - if(nverts[i] == 4) { - uvs[3] = get_float3(t->uv4()); - } - fdata[0] = uvs[tri_a[0]]; - fdata[1] = uvs[tri_a[1]]; - fdata[2] = uvs[tri_a[2]]; + for(b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) { + int3 li = get_int3(t->loops()); + fdata[0] = get_float3(l->data[li[0]].uv()); + fdata[1] = get_float3(l->data[li[1]].uv()); + fdata[2] = get_float3(l->data[li[2]].uv()); fdata += 3; - - if(nverts[i] == 4) { - fdata[0] = uvs[tri_b[0]]; - fdata[1] = uvs[tri_b[1]]; - fdata[2] = uvs[tri_b[2]]; - fdata += 3; - } } } @@ -563,7 +486,7 @@ static void attr_create_subd_uv_map(Scene *scene, int i = 0; for(b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, ++i) { - bool active_render = b_mesh.uv_textures[i].active_render(); + bool active_render = l->active_render(); AttributeStandard uv_std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE; ustring uv_name = ustring(l->name().c_str()); AttributeStandard tangent_std = (active_render)? ATTR_STD_UV_TANGENT @@ -822,7 +745,7 @@ static void create_mesh(Scene *scene, { /* count vertices and faces */ int numverts = b_mesh.vertices.length(); - int numfaces = (!subdivision) ? b_mesh.tessfaces.length() : b_mesh.polygons.length(); + int numfaces = (!subdivision) ? b_mesh.loop_triangles.length() : b_mesh.polygons.length(); int numtris = 0; int numcorners = 0; int numngons = 0; @@ -833,17 +756,11 @@ static void create_mesh(Scene *scene, return; } - BL::Mesh::vertices_iterator v; - BL::Mesh::tessfaces_iterator f; - BL::Mesh::polygons_iterator p; - if(!subdivision) { - for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) { - int4 vi = get_int4(f->vertices_raw()); - numtris += (vi[3] == 0)? 1: 2; - } + numtris = numfaces; } else { + BL::Mesh::polygons_iterator p; for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { numngons += (p->loop_total() == 4)? 0: 1; numcorners += p->loop_total(); @@ -855,6 +772,7 @@ static void create_mesh(Scene *scene, mesh->reserve_subd_faces(numfaces, numngons, numcorners); /* create vertex coordinates and normals */ + BL::Mesh::vertices_iterator v; for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) mesh->add_vertex(get_float3(v->co())); @@ -869,7 +787,7 @@ static void create_mesh(Scene *scene, /* create generated coordinates from undeformed coordinates */ const bool need_default_tangent = (subdivision == false) && - (b_mesh.tessface_uv_textures.length() == 0) && + (b_mesh.uv_layers.length() == 0) && (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)); if(mesh->need_attribute(scene, ATTR_STD_GENERATED) || need_default_tangent) @@ -889,20 +807,19 @@ static void create_mesh(Scene *scene, } /* create faces */ - vector<int> nverts(numfaces); - vector<int> face_flags(numfaces, FACE_FLAG_NONE); - int fi = 0; - if(!subdivision) { - for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) { - int4 vi = get_int4(f->vertices_raw()); - int n = (vi[3] == 0)? 3: 4; - int shader = clamp(f->material_index(), 0, used_shaders.size()-1); - bool smooth = f->use_smooth() || use_loop_normals; + BL::Mesh::loop_triangles_iterator t; + + for(b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) { + BL::MeshPolygon p = b_mesh.polygons[t->polygon_index()]; + int3 vi = get_int3(t->vertices()); + + int shader = clamp(p.material_index(), 0, used_shaders.size()-1); + bool smooth = p.use_smooth() || use_loop_normals; if(use_loop_normals) { - BL::Array<float, 12> loop_normals = f->split_normals(); - for(int i = 0; i < n; i++) { + BL::Array<float, 9> loop_normals = t->split_normals(); + for(int i = 0; i < 3; i++) { N[vi[i]] = make_float3(loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]); @@ -913,28 +830,11 @@ static void create_mesh(Scene *scene, * * NOTE: Autosmooth is already taken care about. */ - if(n == 4) { - if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) || - is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]]))) - { - mesh->add_triangle(vi[0], vi[1], vi[3], shader, smooth); - mesh->add_triangle(vi[2], vi[3], vi[1], shader, smooth); - face_flags[fi] |= FACE_FLAG_DIVIDE_24; - } - else { - mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); - mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth); - face_flags[fi] |= FACE_FLAG_DIVIDE_13; - } - } - else { - mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); - } - - nverts[fi] = n; + mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); } } else { + BL::Mesh::polygons_iterator p; vector<int> vi; for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { @@ -957,13 +857,13 @@ static void create_mesh(Scene *scene, * The calculate functions will check whether they're needed or not. */ attr_create_pointiness(scene, mesh, b_mesh, subdivision); - attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags, subdivision); + attr_create_vertex_color(scene, mesh, b_mesh, subdivision); if(subdivision) { attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs); } else { - attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags); + attr_create_uv_map(scene, mesh, b_mesh); } /* for volume objects, create a matrix to transform from object space to @@ -989,7 +889,7 @@ static void create_subd_mesh(Scene *scene, int max_subdivisions) { BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length()-1]); - bool subdivide_uvs = subsurf_mod.use_subsurf_uv(); + bool subdivide_uvs = subsurf_mod.uv_smooth() != BL::SubsurfModifier::uv_smooth_NONE; create_mesh(scene, mesh, b_mesh, used_shaders, true, subdivide_uvs); @@ -1071,22 +971,17 @@ static void sync_mesh_fluid_motion(BL::Object& b_ob, Scene *scene, Mesh *mesh) } } -Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, +Mesh *BlenderSync::sync_mesh(BL::Depsgraph& b_depsgraph, + BL::Object& b_ob, + BL::Object& b_ob_instance, bool object_updated, - bool hide_tris) + bool show_self, + bool show_particles) { - /* When viewport display is not needed during render we can force some - * caches to be releases from blender side in order to reduce peak memory - * footprint during synchronization process. - */ - const bool is_interface_locked = b_engine.render() && - b_engine.render().use_lock_interface(); - const bool can_free_caches = BlenderSession::headless || is_interface_locked; - /* test if we can instance or if the object is modified */ BL::ID b_ob_data = b_ob.data(); - BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data; - BL::Material material_override = render_layer.material_override; + BL::ID key = (BKE_object_is_modified(b_ob))? b_ob_instance: b_ob_data; + BL::Material material_override = view_layer.material_override; /* find shader indices */ vector<Shader*> used_shaders; @@ -1111,10 +1006,10 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, /* test if we need to sync */ int requested_geometry_flags = Mesh::GEOMETRY_NONE; - if(render_layer.use_surfaces) { + if(view_layer.use_surfaces) { requested_geometry_flags |= Mesh::GEOMETRY_TRIANGLES; } - if(render_layer.use_hair) { + if(view_layer.use_hair) { requested_geometry_flags |= Mesh::GEOMETRY_CURVES; } Mesh *mesh; @@ -1166,36 +1061,27 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, mesh->name = ustring(b_ob_data.name().c_str()); if(requested_geometry_flags != Mesh::GEOMETRY_NONE) { - /* mesh objects does have special handle in the dependency graph, - * they're ensured to have properly updated. - * - * updating meshes here will end up having derived mesh referencing - * freed data from the blender side. - */ - if(preview && b_ob.type() != BL::Object::type_MESH) - b_ob.update_from_editmode(b_data); - - bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED); - - mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental); - - /* Disable adaptive subdivision while baking as the baking system - * currently doesnt support the topology and will crash. - */ + /* Adaptive subdivision setup. Not for baking since that requires + * exact mapping to the Blender mesh. */ if(scene->bake_manager->get_baking()) { mesh->subdivision_type = Mesh::SUBDIVISION_NONE; } + else { + mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental); + } + + /* For some reason, meshes do not need this... */ + bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED); BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, - b_scene, - true, - !preview, + b_depsgraph, need_undeformed, mesh->subdivision_type); if(b_mesh) { - if(render_layer.use_surfaces && !hide_tris) { + /* Sync mesh itself. */ + if(view_layer.use_surfaces && show_self) { if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE) create_subd_mesh(scene, mesh, b_ob, b_mesh, used_shaders, dicing_rate, max_subdivisions); @@ -1205,15 +1091,12 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, create_mesh_volume_attributes(scene, b_ob, mesh, b_scene.frame_current()); } - if(render_layer.use_hair && mesh->subdivision_type == Mesh::SUBDIVISION_NONE) + /* Sync hair curves. */ + if(view_layer.use_hair && show_particles && mesh->subdivision_type == Mesh::SUBDIVISION_NONE) { sync_curves(mesh, b_mesh, b_ob, false); - - if(can_free_caches) { - b_ob.cache_release(); } - /* free derived mesh */ - b_data.meshes.remove(b_mesh, false, true, false); + free_object_to_mesh(b_data, b_ob, b_mesh); } } mesh->geometry_flags = requested_geometry_flags; @@ -1233,7 +1116,8 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, return mesh; } -void BlenderSync::sync_mesh_motion(BL::Object& b_ob, +void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph, + BL::Object& b_ob, Object *object, float motion_time) { @@ -1276,9 +1160,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, /* get derived mesh */ b_mesh = object_to_mesh(b_data, b_ob, - b_scene, - true, - !preview, + b_depsgraph, false, Mesh::SUBDIVISION_NONE); } @@ -1390,7 +1272,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, sync_curves(mesh, b_mesh, b_ob, true, motion_step); /* free derived mesh */ - b_data.meshes.remove(b_mesh, false, true, false); + free_object_to_mesh(b_data, b_ob, b_mesh); } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index a05c982b367..37fea2417ba 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -89,7 +89,7 @@ bool BlenderSync::object_is_light(BL::Object& b_ob) { BL::ID b_ob_data = b_ob.data(); - return (b_ob_data && b_ob_data.is_a(&RNA_Lamp)); + return (b_ob_data && b_ob_data.is_a(&RNA_Light)); } static uint object_ray_visibility(BL::Object& b_ob) @@ -112,13 +112,14 @@ static uint object_ray_visibility(BL::Object& b_ob) void BlenderSync::sync_light(BL::Object& b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object& b_ob, - BL::DupliObject& b_dupli_ob, + BL::Object& b_ob_instance, + int random_id, Transform& tfm, bool *use_portal) { /* test if we need to sync */ Light *light; - ObjectKey key(b_parent, persistent_id, b_ob); + ObjectKey key(b_parent, persistent_id, b_ob_instance); if(!light_map.sync(&light, b_ob, b_parent, key)) { if(light->is_portal) @@ -126,45 +127,60 @@ void BlenderSync::sync_light(BL::Object& b_parent, return; } - BL::Lamp b_lamp(b_ob.data()); + BL::Light b_light(b_ob.data()); /* type */ - switch(b_lamp.type()) { - case BL::Lamp::type_POINT: { - BL::PointLamp b_point_lamp(b_lamp); - light->size = b_point_lamp.shadow_soft_size(); + switch(b_light.type()) { + case BL::Light::type_POINT: { + BL::PointLight b_point_light(b_light); + light->size = b_point_light.shadow_soft_size(); light->type = LIGHT_POINT; break; } - case BL::Lamp::type_SPOT: { - BL::SpotLamp b_spot_lamp(b_lamp); - light->size = b_spot_lamp.shadow_soft_size(); + case BL::Light::type_SPOT: { + BL::SpotLight b_spot_light(b_light); + light->size = b_spot_light.shadow_soft_size(); light->type = LIGHT_SPOT; - light->spot_angle = b_spot_lamp.spot_size(); - light->spot_smooth = b_spot_lamp.spot_blend(); + light->spot_angle = b_spot_light.spot_size(); + light->spot_smooth = b_spot_light.spot_blend(); break; } - case BL::Lamp::type_HEMI: { + /* Hemi were removed from 2.8 */ + // case BL::Light::type_HEMI: { + // light->type = LIGHT_DISTANT; + // light->size = 0.0f; + // break; + // } + case BL::Light::type_SUN: { + BL::SunLight b_sun_light(b_light); + light->size = b_sun_light.shadow_soft_size(); light->type = LIGHT_DISTANT; - light->size = 0.0f; break; } - case BL::Lamp::type_SUN: { - BL::SunLamp b_sun_lamp(b_lamp); - light->size = b_sun_lamp.shadow_soft_size(); - light->type = LIGHT_DISTANT; - break; - } - case BL::Lamp::type_AREA: { - BL::AreaLamp b_area_lamp(b_lamp); + case BL::Light::type_AREA: { + BL::AreaLight b_area_light(b_light); light->size = 1.0f; light->axisu = transform_get_column(&tfm, 0); light->axisv = transform_get_column(&tfm, 1); - light->sizeu = b_area_lamp.size(); - if(b_area_lamp.shape() == BL::AreaLamp::shape_RECTANGLE) - light->sizev = b_area_lamp.size_y(); - else - light->sizev = light->sizeu; + light->sizeu = b_area_light.size(); + switch(b_area_light.shape()) { + case BL::AreaLight::shape_SQUARE: + light->sizev = light->sizeu; + light->round = false; + break; + case BL::AreaLight::shape_RECTANGLE: + light->sizev = b_area_light.size_y(); + light->round = false; + break; + case BL::AreaLight::shape_DISK: + light->sizev = light->sizeu; + light->round = true; + break; + case BL::AreaLight::shape_ELLIPSE: + light->sizev = b_area_light.size_y(); + light->round = true; + break; + } light->type = LIGHT_AREA; break; } @@ -177,32 +193,32 @@ void BlenderSync::sync_light(BL::Object& b_parent, /* shader */ vector<Shader*> used_shaders; - find_shader(b_lamp, used_shaders, scene->default_light); + find_shader(b_light, used_shaders, scene->default_light); light->shader = used_shaders[0]; /* shadow */ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - PointerRNA clamp = RNA_pointer_get(&b_lamp.ptr, "cycles"); - light->cast_shadow = get_boolean(clamp, "cast_shadow"); - light->use_mis = get_boolean(clamp, "use_multiple_importance_sampling"); + PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles"); + light->cast_shadow = get_boolean(clight, "cast_shadow"); + light->use_mis = get_boolean(clight, "use_multiple_importance_sampling"); - int samples = get_int(clamp, "samples"); + int samples = get_int(clight, "samples"); if(get_boolean(cscene, "use_square_samples")) light->samples = samples * samples; else light->samples = samples; - light->max_bounces = get_int(clamp, "max_bounces"); + light->max_bounces = get_int(clight, "max_bounces"); - if(b_dupli_ob) { - light->random_id = b_dupli_ob.random_id(); + if(b_ob != b_ob_instance) { + light->random_id = random_id; } else { light->random_id = hash_int_2d(hash_string(b_ob.name().c_str()), 0); } if(light->type == LIGHT_AREA) - light->is_portal = get_boolean(clamp, "is_portal"); + light->is_portal = get_boolean(clight, "is_portal"); else light->is_portal = false; @@ -275,24 +291,47 @@ void BlenderSync::sync_background_light(bool use_portal) /* Object */ -Object *BlenderSync::sync_object(BL::Object& b_parent, - int persistent_id[OBJECT_PERSISTENT_ID_SIZE], - BL::DupliObject& b_dupli_ob, - Transform& tfm, - uint layer_flag, +Object *BlenderSync::sync_object(BL::Depsgraph& b_depsgraph, + BL::ViewLayer& b_view_layer, + BL::DepsgraphObjectInstance& b_instance, float motion_time, - bool hide_tris, + bool show_self, + bool show_particles, BlenderObjectCulling& culling, bool *use_portal) { - BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent); - bool motion = motion_time != 0.0f; + const bool is_instance = b_instance.is_instance(); + BL::Object b_ob = b_instance.object(); + BL::Object b_parent = is_instance ? b_instance.parent() + : b_instance.object(); + BL::Object b_ob_instance = is_instance ? b_instance.instance_object() + : b_ob; + const bool motion = motion_time != 0.0f; + /*const*/ Transform tfm = get_transform(b_ob.matrix_world()); + int *persistent_id = NULL; + BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id_array; + if(is_instance) { + persistent_id_array = b_instance.persistent_id(); + persistent_id = persistent_id_array.data; + } /* light is handled separately */ - if(object_is_light(b_ob)) { - /* don't use lamps for excluded layers used as mask layer */ - if(!motion && !((layer_flag & render_layer.holdout_layer) && (layer_flag & render_layer.exclude_layer))) - sync_light(b_parent, persistent_id, b_ob, b_dupli_ob, tfm, use_portal); + if(!motion && object_is_light(b_ob)) { + /* TODO: don't use lights for excluded layers used as mask layer, + * when dynamic overrides are back. */ +#if 0 + if(!((layer_flag & view_layer.holdout_layer) && + (layer_flag & view_layer.exclude_layer))) +#endif + { + sync_light(b_parent, + persistent_id, + b_ob, + b_ob_instance, + is_instance ? b_instance.random_id() : 0, + tfm, + use_portal); + } return NULL; } @@ -309,21 +348,24 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, /* Visibility flags for both parent and child. */ PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); - bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0 || - get_boolean(cobject, "is_holdout"); + bool use_holdout = get_boolean(cobject, "is_holdout") || + b_parent.holdout_get(b_view_layer); uint visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL_VISIBILITY; if(b_parent.ptr.data != b_ob.ptr.data) { visibility &= object_ray_visibility(b_parent); } - /* Make holdout objects on excluded layer invisible for non-camera rays. */ - if(use_holdout && (layer_flag & render_layer.exclude_layer)) { + /* TODO: make holdout objects on excluded layer invisible for non-camera rays. */ +#if 0 + if(use_holdout && (layer_flag & view_layer.exclude_layer)) { visibility &= ~(PATH_RAY_ALL_VISIBILITY - PATH_RAY_CAMERA); } +#endif - /* Hide objects not on render layer from camera rays. */ - if(!(layer_flag & render_layer.layer)) { + /* Clear camera visibility for indirect only objects. */ + bool use_indirect_only = b_parent.indirect_only_get(b_view_layer); + if(use_indirect_only) { visibility &= ~PATH_RAY_CAMERA; } @@ -333,7 +375,7 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, } /* key to lookup object */ - ObjectKey key(b_parent, persistent_id, b_ob); + ObjectKey key(b_parent, persistent_id, b_ob_instance); Object *object; /* motion vector case */ @@ -349,7 +391,7 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, /* mesh deformation */ if(object->mesh) - sync_mesh_motion(b_ob, object, motion_time); + sync_mesh_motion(b_depsgraph, b_ob, object, motion_time); } return object; @@ -362,7 +404,7 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, object_updated = true; /* mesh sync */ - object->mesh = sync_mesh(b_ob, object_updated, hide_tris); + object->mesh = sync_mesh(b_depsgraph, b_ob, b_ob_instance, object_updated, show_self, show_particles); /* special case not tracked by object update flags */ @@ -444,10 +486,10 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, } /* dupli texture coordinates and random_id */ - if(b_dupli_ob) { - object->dupli_generated = 0.5f*get_float3(b_dupli_ob.orco()) - make_float3(0.5f, 0.5f, 0.5f); - object->dupli_uv = get_float2(b_dupli_ob.uv()); - object->random_id = b_dupli_ob.random_id(); + if(is_instance) { + object->dupli_generated = 0.5f*get_float3(b_instance.orco()) - make_float3(0.5f, 0.5f, 0.5f); + object->dupli_uv = get_float2(b_instance.uv()); + object->random_id = b_instance.random_id(); } else { object->dupli_generated = make_float3(0.0f, 0.0f, 0.0f); @@ -458,94 +500,19 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, object->tag_update(scene); } - return object; -} - -static bool object_render_hide_original(BL::Object::type_enum ob_type, - BL::Object::dupli_type_enum dupli_type) -{ - /* metaball exception, they duplicate self */ - if(ob_type == BL::Object::type_META) - return false; - - return (dupli_type == BL::Object::dupli_type_VERTS || - dupli_type == BL::Object::dupli_type_FACES || - dupli_type == BL::Object::dupli_type_FRAMES); -} - -static bool object_render_hide(BL::Object& b_ob, - bool top_level, - bool parent_hide, - bool& hide_triangles) -{ - /* check if we should render or hide particle emitter */ - BL::Object::particle_systems_iterator b_psys; - - bool hair_present = false; - bool show_emitter = false; - bool hide_emitter = false; - bool hide_as_dupli_parent = false; - bool hide_as_dupli_child_original = false; - - for(b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end(); ++b_psys) { - if((b_psys->settings().render_type() == BL::ParticleSettings::render_type_PATH) && - (b_psys->settings().type()==BL::ParticleSettings::type_HAIR)) - hair_present = true; - - if(b_psys->settings().use_render_emitter()) - show_emitter = true; - else - hide_emitter = true; + if(is_instance) { + /* Sync possible particle data. */ + sync_dupli_particle(b_parent, b_instance, object); } - if(show_emitter) - hide_emitter = false; - - /* duplicators hidden by default, except dupliframes which duplicate self */ - if(b_ob.is_duplicator()) - if(top_level || b_ob.dupli_type() != BL::Object::dupli_type_FRAMES) - hide_as_dupli_parent = true; - - /* hide original object for duplis */ - BL::Object parent = b_ob.parent(); - while(parent) { - if(object_render_hide_original(b_ob.type(), - parent.dupli_type())) - { - if(parent_hide) { - hide_as_dupli_child_original = true; - break; - } - } - parent = parent.parent(); - } - - hide_triangles = hide_emitter; - - if(show_emitter) { - return false; - } - else if(hair_present) { - return hide_as_dupli_child_original; - } - else { - return (hide_as_dupli_parent || hide_as_dupli_child_original); - } -} - -static bool object_render_hide_duplis(BL::Object& b_ob) -{ - BL::Object parent = b_ob.parent(); - - return (parent && object_render_hide_original(b_ob.type(), parent.dupli_type())); + return object; } /* Object Loop */ -void BlenderSync::sync_objects(float motion_time) +void BlenderSync::sync_objects(BL::Depsgraph& b_depsgraph, float motion_time) { /* layer data */ - uint scene_layer = render_layer.scene_layer; bool motion = motion_time != 0.0f; if(!motion) { @@ -564,100 +531,41 @@ void BlenderSync::sync_objects(float motion_time) BlenderObjectCulling culling(scene, b_scene); /* object loop */ - BL::Scene::object_bases_iterator b_base; - BL::Scene b_sce = b_scene; - /* modifier result type (not exposed as enum in C++ API) - * 1 : DAG_EVAL_PREVIEW - * 2 : DAG_EVAL_RENDER - */ - int dupli_settings = (render_layer.use_viewport_visibility) ? 1 : 2; - bool cancel = false; bool use_portal = false; - uint layer_override = get_layer(b_engine.layer_override()); - for(; b_sce && !cancel; b_sce = b_sce.background_set()) { - /* Render layer's scene_layer is affected by local view already, - * which is not a desired behavior here. - */ - uint scene_layers = layer_override ? layer_override : get_layer(b_scene.layers()); - for(b_sce.object_bases.begin(b_base); b_base != b_sce.object_bases.end() && !cancel; ++b_base) { - BL::Object b_ob = b_base->object(); - bool hide = (render_layer.use_viewport_visibility)? b_ob.hide(): b_ob.hide_render(); - uint ob_layer = get_layer(b_base->layers(), - b_base->layers_local_view(), - object_is_light(b_ob), - scene_layers); - hide = hide || !(ob_layer & scene_layer); - - if(!hide) { - progress.set_sync_status("Synchronizing object", b_ob.name()); - - /* load per-object culling data */ - culling.init_object(scene, b_ob); - - if(b_ob.is_duplicator() && !object_render_hide_duplis(b_ob)) { - /* dupli objects */ - b_ob.dupli_list_create(b_data, b_scene, dupli_settings); - - BL::Object::dupli_list_iterator b_dup; - - for(b_ob.dupli_list.begin(b_dup); b_dup != b_ob.dupli_list.end(); ++b_dup) { - Transform tfm = get_transform(b_dup->matrix()); - BL::Object b_dup_ob = b_dup->object(); - bool dup_hide = (render_layer.use_viewport_visibility)? b_dup_ob.hide(): b_dup_ob.hide_render(); - bool in_dupli_group = (b_dup->type() == BL::DupliObject::type_GROUP); - bool hide_tris; - - if(!(b_dup->hide() || dup_hide || object_render_hide(b_dup_ob, false, in_dupli_group, hide_tris))) { - /* the persistent_id allows us to match dupli objects - * between frames and updates */ - BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup->persistent_id(); - - /* sync object and mesh or light data */ - Object *object = sync_object(b_ob, - persistent_id.data, - *b_dup, - tfm, - ob_layer, - motion_time, - hide_tris, - culling, - &use_portal); - - /* sync possible particle data, note particle_id - * starts counting at 1, first is dummy particle */ - if(!motion && object) { - sync_dupli_particle(b_ob, *b_dup, object); - } - - } - } - - b_ob.dupli_list_clear(); - } + BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); - /* test if object needs to be hidden */ - bool hide_tris; - - if(!object_render_hide(b_ob, true, true, hide_tris)) { - /* object itself */ - Transform tfm = get_transform(b_ob.matrix_world()); - BL::DupliObject b_empty_dupli_ob(PointerRNA_NULL); - sync_object(b_ob, - NULL, - b_empty_dupli_ob, - tfm, - ob_layer, - motion_time, - hide_tris, - culling, - &use_portal); - } - } + BL::Depsgraph::object_instances_iterator b_instance_iter; + for(b_depsgraph.object_instances.begin(b_instance_iter); + b_instance_iter != b_depsgraph.object_instances.end() && !cancel; + ++b_instance_iter) + { + BL::DepsgraphObjectInstance b_instance = *b_instance_iter; + BL::Object b_ob = b_instance.object(); - cancel = progress.get_cancel(); - } + progress.set_sync_status("Synchronizing object", b_ob.name()); + + /* load per-object culling data */ + culling.init_object(scene, b_ob); + + /* test if object needs to be hidden */ + const bool show_self = b_instance.show_self(); + const bool show_particles = b_instance.show_particles(); + + if(show_self || show_particles) { + /* object itself */ + sync_object(b_depsgraph, + b_view_layer, + b_instance, + motion_time, + show_self, + show_particles, + culling, + &use_portal); + } + + cancel = progress.get_cancel(); } progress.set_sync_status(""); @@ -681,6 +589,7 @@ void BlenderSync::sync_objects(float motion_time) } void BlenderSync::sync_motion(BL::RenderSettings& b_render, + BL::Depsgraph& b_depsgraph, BL::Object& b_override, int width, int height, void **python_thread_state) @@ -710,6 +619,7 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render, assert(scene->camera->motion_position == Camera::MOTION_POSITION_START); frame_center_delta = shuttertime * 0.5f; } + float time = frame_center + subframe_center + frame_center_delta; int frame = (int)floorf(time); float subframe = time - frame; @@ -717,7 +627,7 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render, b_engine.frame_set(frame, subframe); python_thread_state_save(python_thread_state); sync_camera_motion(b_render, b_cam, width, height, 0.0f); - sync_objects(0.0f); + sync_objects(b_depsgraph, 0.0f); } /* always sample these times for camera motion */ @@ -756,7 +666,7 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render, } /* sync object */ - sync_objects(relative_time); + sync_objects(b_depsgraph, relative_time); } /* we need to set the python thread state again because this diff --git a/intern/cycles/blender/blender_particles.cpp b/intern/cycles/blender/blender_particles.cpp index 727d9acf729..a733a499826 100644 --- a/intern/cycles/blender/blender_particles.cpp +++ b/intern/cycles/blender/blender_particles.cpp @@ -28,11 +28,11 @@ CCL_NAMESPACE_BEGIN /* Utilities */ bool BlenderSync::sync_dupli_particle(BL::Object& b_ob, - BL::DupliObject& b_dup, + BL::DepsgraphObjectInstance& b_instance, Object *object) { /* test if this dupli was generated from a particle sytem */ - BL::ParticleSystem b_psys = b_dup.particle_system(); + BL::ParticleSystem b_psys = b_instance.particle_system(); if(!b_psys) return false; @@ -43,7 +43,7 @@ bool BlenderSync::sync_dupli_particle(BL::Object& b_ob, return false; /* don't handle child particles yet */ - BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup.persistent_id(); + BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_instance.persistent_id(); if(persistent_id[0] >= b_psys.particles.length()) return false; @@ -53,7 +53,7 @@ bool BlenderSync::sync_dupli_particle(BL::Object& b_ob, ParticleSystem *psys; bool first_use = !particle_system_map.is_used(key); - bool need_update = particle_system_map.sync(&psys, b_ob, b_dup.object(), key); + bool need_update = particle_system_map.sync(&psys, b_ob, b_instance.object(), key); /* no update needed? */ if(!need_update && !object->mesh->need_update && !scene->object_manager->need_update) diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp index 9dd0cd4c0bc..d111a1c1f1d 100644 --- a/intern/cycles/blender/blender_python.cpp +++ b/intern/cycles/blender/blender_python.cpp @@ -203,10 +203,10 @@ static PyObject *exit_func(PyObject * /*self*/, PyObject * /*args*/) static PyObject *create_func(PyObject * /*self*/, PyObject *args) { - PyObject *pyengine, *pyuserpref, *pydata, *pyscene, *pyregion, *pyv3d, *pyrv3d; + PyObject *pyengine, *pyuserpref, *pydata, *pyregion, *pyv3d, *pyrv3d; int preview_osl; - if(!PyArg_ParseTuple(args, "OOOOOOOi", &pyengine, &pyuserpref, &pydata, &pyscene, + if(!PyArg_ParseTuple(args, "OOOOOOi", &pyengine, &pyuserpref, &pydata, &pyregion, &pyv3d, &pyrv3d, &preview_osl)) { return NULL; @@ -218,17 +218,13 @@ static PyObject *create_func(PyObject * /*self*/, PyObject *args) BL::RenderEngine engine(engineptr); PointerRNA userprefptr; - RNA_pointer_create(NULL, &RNA_UserPreferences, (void*)PyLong_AsVoidPtr(pyuserpref), &userprefptr); - BL::UserPreferences userpref(userprefptr); + RNA_pointer_create(NULL, &RNA_Preferences, (void*)PyLong_AsVoidPtr(pyuserpref), &userprefptr); + BL::Preferences userpref(userprefptr); PointerRNA dataptr; RNA_main_pointer_create((Main*)PyLong_AsVoidPtr(pydata), &dataptr); BL::BlendData data(dataptr); - PointerRNA sceneptr; - RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr); - BL::Scene scene(sceneptr); - PointerRNA regionptr; RNA_pointer_create(NULL, &RNA_Region, pylong_as_voidptr_typesafe(pyregion), ®ionptr); BL::Region region(regionptr); @@ -249,27 +245,13 @@ static PyObject *create_func(PyObject * /*self*/, PyObject *args) int width = region.width(); int height = region.height(); - session = new BlenderSession(engine, userpref, data, scene, v3d, rv3d, width, height); + session = new BlenderSession(engine, userpref, data, v3d, rv3d, width, height); } else { - /* override some settings for preview */ - if(engine.is_preview()) { - PointerRNA cscene = RNA_pointer_get(&sceneptr, "cycles"); - - RNA_boolean_set(&cscene, "shading_system", preview_osl); - RNA_boolean_set(&cscene, "use_progressive_refine", true); - } - /* offline session or preview render */ - session = new BlenderSession(engine, userpref, data, scene); + session = new BlenderSession(engine, userpref, data, preview_osl); } - python_thread_state_save(&session->python_thread_state); - - session->create(); - - python_thread_state_restore(&session->python_thread_state); - return PyLong_FromVoidPtr(session); } @@ -280,13 +262,22 @@ static PyObject *free_func(PyObject * /*self*/, PyObject *value) Py_RETURN_NONE; } -static PyObject *render_func(PyObject * /*self*/, PyObject *value) +static PyObject *render_func(PyObject * /*self*/, PyObject *args) { - BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(value); + PyObject *pysession, *pydepsgraph; + + if(!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph)) + return NULL; + + BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession); + + PointerRNA depsgraphptr; + RNA_pointer_create(NULL, &RNA_Depsgraph, (ID*)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr); + BL::Depsgraph b_depsgraph(depsgraphptr); python_thread_state_save(&session->python_thread_state); - session->render(); + session->render(b_depsgraph); python_thread_state_restore(&session->python_thread_state); @@ -296,16 +287,20 @@ static PyObject *render_func(PyObject * /*self*/, PyObject *value) /* pixel_array and result passed as pointers */ static PyObject *bake_func(PyObject * /*self*/, PyObject *args) { - PyObject *pysession, *pyobject; + PyObject *pysession, *pydepsgraph, *pyobject; PyObject *pypixel_array, *pyresult; const char *pass_type; int num_pixels, depth, object_id, pass_filter; - if(!PyArg_ParseTuple(args, "OOsiiOiiO", &pysession, &pyobject, &pass_type, &pass_filter, &object_id, &pypixel_array, &num_pixels, &depth, &pyresult)) + if(!PyArg_ParseTuple(args, "OOOsiiOiiO", &pysession, &pydepsgraph, &pyobject, &pass_type, &pass_filter, &object_id, &pypixel_array, &num_pixels, &depth, &pyresult)) return NULL; BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession); + PointerRNA depsgraphptr; + RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr); + BL::Depsgraph b_depsgraph(depsgraphptr); + PointerRNA objectptr; RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyobject), &objectptr); BL::Object b_object(objectptr); @@ -318,7 +313,7 @@ static PyObject *bake_func(PyObject * /*self*/, PyObject *args) python_thread_state_save(&session->python_thread_state); - session->bake(b_object, pass_type, pass_filter, object_id, b_bake_pixel, (size_t)num_pixels, depth, (float *)b_result); + session->bake(b_depsgraph, b_object, pass_type, pass_filter, object_id, b_bake_pixel, (size_t)num_pixels, depth, (float *)b_result); python_thread_state_restore(&session->python_thread_state); @@ -327,9 +322,9 @@ static PyObject *bake_func(PyObject * /*self*/, PyObject *args) static PyObject *draw_func(PyObject * /*self*/, PyObject *args) { - PyObject *pysession, *pyv3d, *pyrv3d; + PyObject *pysession, *pygraph, *pyv3d, *pyrv3d; - if(!PyArg_ParseTuple(args, "OOO", &pysession, &pyv3d, &pyrv3d)) + if(!PyArg_ParseTuple(args, "OOOO", &pysession, &pygraph, &pyv3d, &pyrv3d)) return NULL; BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession); @@ -347,9 +342,9 @@ static PyObject *draw_func(PyObject * /*self*/, PyObject *args) static PyObject *reset_func(PyObject * /*self*/, PyObject *args) { - PyObject *pysession, *pydata, *pyscene; + PyObject *pysession, *pydata, *pydepsgraph; - if(!PyArg_ParseTuple(args, "OOO", &pysession, &pydata, &pyscene)) + if(!PyArg_ParseTuple(args, "OOO", &pysession, &pydata, &pydepsgraph)) return NULL; BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession); @@ -358,26 +353,35 @@ static PyObject *reset_func(PyObject * /*self*/, PyObject *args) RNA_main_pointer_create((Main*)PyLong_AsVoidPtr(pydata), &dataptr); BL::BlendData b_data(dataptr); - PointerRNA sceneptr; - RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr); - BL::Scene b_scene(sceneptr); + PointerRNA depsgraphptr; + RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr); + BL::Depsgraph b_depsgraph(depsgraphptr); python_thread_state_save(&session->python_thread_state); - session->reset_session(b_data, b_scene); + session->reset_session(b_data, b_depsgraph); python_thread_state_restore(&session->python_thread_state); Py_RETURN_NONE; } -static PyObject *sync_func(PyObject * /*self*/, PyObject *value) +static PyObject *sync_func(PyObject * /*self*/, PyObject *args) { - BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(value); + PyObject *pysession, *pydepsgraph; + + if(!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph)) + return NULL; + + BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession); + + PointerRNA depsgraphptr; + RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr); + BL::Depsgraph b_depsgraph(depsgraphptr); python_thread_state_save(&session->python_thread_state); - session->synchronize(); + session->synchronize(b_depsgraph); python_thread_state_restore(&session->python_thread_state); @@ -768,10 +772,10 @@ static PyMethodDef methods[] = { {"exit", exit_func, METH_VARARGS, ""}, {"create", create_func, METH_VARARGS, ""}, {"free", free_func, METH_O, ""}, - {"render", render_func, METH_O, ""}, + {"render", render_func, METH_VARARGS, ""}, {"bake", bake_func, METH_VARARGS, ""}, {"draw", draw_func, METH_VARARGS, ""}, - {"sync", sync_func, METH_O, ""}, + {"sync", sync_func, METH_VARARGS, ""}, {"reset", reset_func, METH_VARARGS, ""}, #ifdef WITH_OSL {"osl_update_node", osl_update_node_func, METH_VARARGS, ""}, @@ -806,7 +810,7 @@ static struct PyModuleDef module = { "Blender cycles render integration", -1, methods, - NULL, NULL, NULL, NULL + NULL, NULL, NULL, NULL, }; CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 50ac35069a9..6e6d98b19dd 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -30,6 +30,7 @@ #include "render/shader.h" #include "render/stats.h" +#include "util/util_algorithm.h" #include "util/util_color.h" #include "util/util_foreach.h" #include "util/util_function.h" @@ -53,23 +54,25 @@ int BlenderSession::end_resumable_chunk = 0; bool BlenderSession::print_render_stats = false; BlenderSession::BlenderSession(BL::RenderEngine& b_engine, - BL::UserPreferences& b_userpref, + BL::Preferences& b_userpref, BL::BlendData& b_data, - BL::Scene& b_scene) -: b_engine(b_engine), + bool preview_osl) +: session(NULL), + sync(NULL), + b_engine(b_engine), b_userpref(b_userpref), b_data(b_data), b_render(b_engine.render()), - b_scene(b_scene), + b_depsgraph(PointerRNA_NULL), + b_scene(PointerRNA_NULL), b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL), + width(0), + height(0), + preview_osl(preview_osl), python_thread_state(NULL) { /* offline render */ - - width = render_resolution_x(b_render); - height = render_resolution_y(b_render); - background = true; last_redraw_time = 0.0; start_resize_time = 0.0; @@ -77,25 +80,27 @@ BlenderSession::BlenderSession(BL::RenderEngine& b_engine, } BlenderSession::BlenderSession(BL::RenderEngine& b_engine, - BL::UserPreferences& b_userpref, + BL::Preferences& b_userpref, BL::BlendData& b_data, - BL::Scene& b_scene, BL::SpaceView3D& b_v3d, BL::RegionView3D& b_rv3d, int width, int height) -: b_engine(b_engine), +: session(NULL), + sync(NULL), + b_engine(b_engine), b_userpref(b_userpref), b_data(b_data), - b_render(b_scene.render()), - b_scene(b_scene), + b_render(b_engine.render()), + b_depsgraph(PointerRNA_NULL), + b_scene(PointerRNA_NULL), b_v3d(b_v3d), b_rv3d(b_rv3d), width(width), height(height), + preview_osl(false), python_thread_state(NULL) { /* 3d view render */ - background = false; last_redraw_time = 0.0; start_resize_time = 0.0; @@ -133,6 +138,7 @@ void BlenderSession::create_session() /* create scene */ scene = new Scene(scene_params, session->device); + scene->name = b_scene.name(); /* setup callbacks for builtin image support */ scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3); @@ -141,26 +147,19 @@ void BlenderSession::create_session() session->scene = scene; + /* There is no single depsgraph to use for the entire render. + * So we need to handle this differently. + * + * We could loop over the final render result render layers in pipeline and keep Cycles unaware of multiple layers, + * or perhaps move syncing further down in the pipeline. + */ /* create sync */ sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress); BL::Object b_camera_override(b_engine.camera_override()); if(b_v3d) { - if(session_pause == false) { - /* full data sync */ - sync->sync_view(b_v3d, b_rv3d, width, height); - sync->sync_data(b_render, - b_v3d, - b_camera_override, - width, height, - &python_thread_state, - b_rlay_name.c_str()); - } + sync->sync_view(b_v3d, b_rv3d, width, height); } else { - /* for final render we will do full data sync per render layer, only - * do some basic syncing here, no objects or materials for speed */ - sync->sync_render_layers(b_v3d, NULL); - sync->sync_integrator(); sync->sync_camera(b_render, b_camera_override, width, height, ""); } @@ -173,18 +172,40 @@ void BlenderSession::create_session() update_resumable_tile_manager(session_params.samples); } -void BlenderSession::reset_session(BL::BlendData& b_data_, BL::Scene& b_scene_) +void BlenderSession::reset_session(BL::BlendData& b_data, BL::Depsgraph& b_depsgraph) { - b_data = b_data_; - b_render = b_engine.render(); - b_scene = b_scene_; + this->b_data = b_data; + this->b_depsgraph = b_depsgraph; + this->b_scene = b_depsgraph.scene_eval(); + + if(preview_osl) { + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + RNA_boolean_set(&cscene, "shading_system", preview_osl); + } + + if(b_v3d) { + this->b_render = b_scene.render(); + } + else { + this->b_render = b_engine.render(); + width = render_resolution_x(b_render); + height = render_resolution_y(b_render); + } + + if(session == NULL) { + create(); + } + + if(b_v3d) { + /* NOTE: We need to create session, but all the code from below + * will make viewport render to stuck on initialization. + */ + return; + } SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background); SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background); - width = render_resolution_x(b_render); - height = render_resolution_y(b_render); - if(scene->params.modified(scene_params) || session->params.modified(session_params) || !scene_params.persistent_data) @@ -192,11 +213,8 @@ void BlenderSession::reset_session(BL::BlendData& b_data_, BL::Scene& b_scene_) /* if scene or session parameters changed, it's easier to simply re-create * them rather than trying to distinguish which settings need to be updated */ - - delete session; - + free_session(); create_session(); - return; } @@ -210,16 +228,12 @@ void BlenderSession::reset_session(BL::BlendData& b_data_, BL::Scene& b_scene_) */ session->stats.mem_peak = session->stats.mem_used; + /* There is no single depsgraph to use for the entire render. + * See note on create_session(). + */ /* sync object should be re-created */ sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress); - /* for final render we will do full data sync per render layer, only - * do some basic syncing here, no objects or materials for speed */ - BL::Object b_camera_override(b_engine.camera_override()); - sync->sync_render_layers(b_v3d, NULL); - sync->sync_integrator(); - sync->sync_camera(b_render, b_camera_override, width, height, ""); - BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL); BL::RegionView3D b_null_region_view3d(PointerRNA_NULL); BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, @@ -379,8 +393,10 @@ static void add_cryptomatte_layer(BL::RenderResult& b_rr, string name, string ma render_add_metadata(b_rr, prefix+"manifest", manifest); } -void BlenderSession::render() +void BlenderSession::render(BL::Depsgraph& b_depsgraph_) { + b_depsgraph = b_depsgraph_; + /* set callback to write out render results */ session->write_render_tile_cb = function_bind(&BlenderSession::write_render_tile, this, _1); session->update_render_tile_cb = function_bind(&BlenderSession::update_render_tile, this, _1, _2); @@ -390,131 +406,114 @@ void BlenderSession::render() BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height); /* render each layer */ - BL::RenderSettings r = b_scene.render(); - BL::RenderSettings::layers_iterator b_layer_iter; - BL::RenderResult::views_iterator b_view_iter; + BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); /* We do some special meta attributes when we only have single layer. */ - const bool is_single_layer = (r.layers.length() == 1); + const bool is_single_layer = (b_scene.view_layers.length() == 1); - for(r.layers.begin(b_layer_iter); b_layer_iter != r.layers.end(); ++b_layer_iter) { - b_rlay_name = b_layer_iter->name(); - - /* temporary render result to find needed passes and views */ - BL::RenderResult b_rr = begin_render_result(b_engine, 0, 0, 1, 1, b_rlay_name.c_str(), NULL); - BL::RenderResult::layers_iterator b_single_rlay; - b_rr.layers.begin(b_single_rlay); + /* temporary render result to find needed passes and views */ + BL::RenderResult b_rr = begin_render_result(b_engine, 0, 0, 1, 1, b_view_layer.name().c_str(), NULL); + BL::RenderResult::layers_iterator b_single_rlay; + b_rr.layers.begin(b_single_rlay); + BL::RenderLayer b_rlay = *b_single_rlay; + b_rlay_name = b_view_layer.name(); + + /* add passes */ + vector<Pass> passes = sync->sync_render_passes(b_rlay, b_view_layer, session_params); + buffer_params.passes = passes; + + PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles"); + bool full_denoising = get_boolean(crl, "use_denoising"); + bool write_denoising_passes = get_boolean(crl, "denoising_store_passes"); + + bool run_denoising = full_denoising || write_denoising_passes; + + session->tile_manager.schedule_denoising = run_denoising; + buffer_params.denoising_data_pass = run_denoising; + buffer_params.denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES); + buffer_params.denoising_prefiltered_pass = write_denoising_passes; + + session->params.run_denoising = run_denoising; + session->params.full_denoising = full_denoising; + session->params.write_denoising_passes = write_denoising_passes; + session->params.denoising_radius = get_int(crl, "denoising_radius"); + session->params.denoising_strength = get_float(crl, "denoising_strength"); + session->params.denoising_feature_strength = get_float(crl, "denoising_feature_strength"); + session->params.denoising_relative_pca = get_boolean(crl, "denoising_relative_pca"); + + scene->film->denoising_data_pass = buffer_params.denoising_data_pass; + scene->film->denoising_clean_pass = buffer_params.denoising_clean_pass; + scene->film->denoising_prefiltered_pass = buffer_params.denoising_prefiltered_pass; + session->params.denoising_radius = get_int(crl, "denoising_radius"); + session->params.denoising_strength = get_float(crl, "denoising_strength"); + session->params.denoising_feature_strength = get_float(crl, "denoising_feature_strength"); + session->params.denoising_relative_pca = get_boolean(crl, "denoising_relative_pca"); + + scene->film->pass_alpha_threshold = b_view_layer.pass_alpha_threshold(); + scene->film->tag_passes_update(scene, passes); + scene->film->tag_update(scene); + scene->integrator->tag_update(scene); - /* layer will be missing if it was disabled in the UI */ - if(b_single_rlay == b_rr.layers.end()) { - end_render_result(b_engine, b_rr, true, true, false); - continue; - } + BL::RenderResult::views_iterator b_view_iter; - BL::RenderLayer b_rlay = *b_single_rlay; - - /* add passes */ - vector<Pass> passes = sync->sync_render_passes(b_rlay, *b_layer_iter, session_params); - buffer_params.passes = passes; - - PointerRNA crl = RNA_pointer_get(&b_layer_iter->ptr, "cycles"); - bool full_denoising = get_boolean(crl, "use_denoising"); - bool write_denoising_passes = get_boolean(crl, "denoising_store_passes"); - - bool run_denoising = full_denoising || write_denoising_passes; - - session->tile_manager.schedule_denoising = run_denoising; - buffer_params.denoising_data_pass = run_denoising; - buffer_params.denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES); - buffer_params.denoising_prefiltered_pass = write_denoising_passes; - - session->params.run_denoising = run_denoising; - session->params.full_denoising = full_denoising; - session->params.write_denoising_passes = write_denoising_passes; - session->params.denoising_radius = get_int(crl, "denoising_radius"); - session->params.denoising_strength = get_float(crl, "denoising_strength"); - session->params.denoising_feature_strength = get_float(crl, "denoising_feature_strength"); - session->params.denoising_relative_pca = get_boolean(crl, "denoising_relative_pca"); - - scene->film->denoising_data_pass = buffer_params.denoising_data_pass; - scene->film->denoising_clean_pass = buffer_params.denoising_clean_pass; - scene->film->denoising_prefiltered_pass = buffer_params.denoising_prefiltered_pass; - scene->film->pass_alpha_threshold = b_layer_iter->pass_alpha_threshold(); - scene->film->tag_passes_update(scene, passes); - scene->film->tag_update(scene); - scene->integrator->tag_update(scene); - - int view_index = 0; - for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter, ++view_index) { - b_rview_name = b_view_iter->name(); - - /* set the current view */ - b_engine.active_view_set(b_rview_name.c_str()); - - /* update scene */ - BL::Object b_camera_override(b_engine.camera_override()); - sync->sync_camera(b_render, b_camera_override, width, height, b_rview_name.c_str()); - sync->sync_data(b_render, - b_v3d, - b_camera_override, - width, height, - &python_thread_state, - b_rlay_name.c_str()); - - /* Make sure all views have different noise patterns. - hardcoded value just to make it random */ - if(view_index != 0) { - scene->integrator->seed += hash_int_2d(scene->integrator->seed, hash_int(view_index * 0xdeadbeef)); - scene->integrator->tag_update(scene); - } + int num_views = 0; + for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter) { + num_views++; + } - /* Update number of samples per layer. */ - int samples = sync->get_layer_samples(); - bool bound_samples = sync->get_layer_bound_samples(); - int effective_layer_samples; + int view_index = 0; + for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter, ++view_index) { + b_rview_name = b_view_iter->name(); - if(samples != 0 && (!bound_samples || (samples < session_params.samples))) - effective_layer_samples = samples; - else - effective_layer_samples = session_params.samples; + /* set the current view */ + b_engine.active_view_set(b_rview_name.c_str()); - /* Update tile manager if we're doing resumable render. */ - update_resumable_tile_manager(effective_layer_samples); + /* update scene */ + BL::Object b_camera_override(b_engine.camera_override()); + sync->sync_camera(b_render, b_camera_override, width, height, b_rview_name.c_str()); + sync->sync_data(b_render, + b_depsgraph, + b_v3d, + b_camera_override, + width, height, + &python_thread_state); + builtin_images_load(); + + /* Attempt to free all data which is held by Blender side, since at this + * point we knwo that we've got everything to render current view layer. + */ + /* At the moment we only free if we are not doing multi-view (or if we are rendering the last view). + * See T58142/D4239 for discussion. + */ + if(view_index == num_views - 1) { + free_blender_memory_if_possible(); + } - /* Update session itself. */ - session->reset(buffer_params, effective_layer_samples); + /* Make sure all views have different noise patterns. - hardcoded value just to make it random */ + if(view_index != 0) { + scene->integrator->seed += hash_int_2d(scene->integrator->seed, hash_int(view_index * 0xdeadbeef)); + scene->integrator->tag_update(scene); + } - /* render */ - session->start(); - session->wait(); + /* Update number of samples per layer. */ + int samples = sync->get_layer_samples(); + bool bound_samples = sync->get_layer_bound_samples(); + int effective_layer_samples; - if(session->progress.get_cancel()) - break; - } + if(samples != 0 && (!bound_samples || (samples < session_params.samples))) + effective_layer_samples = samples; + else + effective_layer_samples = session_params.samples; - BL::RenderResult b_full_rr = b_engine.get_result(); - if(is_single_layer) { - string num_aa_samples = string_printf("%d", session->params.samples); - render_add_metadata(b_full_rr, "Cycles Samples", num_aa_samples); - /* TODO(sergey): Report whether we're doing resumable render - * and also start/end sample if so. - */ - } + /* Update tile manager if we're doing resumable render. */ + update_resumable_tile_manager(effective_layer_samples); - if(scene->film->cryptomatte_passes & CRYPT_OBJECT) { - add_cryptomatte_layer(b_full_rr, b_rlay_name+".CryptoObject", - scene->object_manager->get_cryptomatte_objects(scene)); - } - if(scene->film->cryptomatte_passes & CRYPT_MATERIAL) { - add_cryptomatte_layer(b_full_rr, b_rlay_name+".CryptoMaterial", - scene->shader_manager->get_cryptomatte_materials(scene)); - } - if(scene->film->cryptomatte_passes & CRYPT_ASSET) { - add_cryptomatte_layer(b_full_rr, b_rlay_name+".CryptoAsset", - scene->object_manager->get_cryptomatte_assets(scene)); - } + /* Update session itself. */ + session->reset(buffer_params, effective_layer_samples); - /* free result without merging */ - end_render_result(b_engine, b_rr, true, true, false); + /* render */ + session->start(); + session->wait(); if(!b_engine.is_preview() && background && print_render_stats) { RenderStats stats; @@ -526,6 +525,32 @@ void BlenderSession::render() break; } + if(is_single_layer) { + BL::RenderResult b_rr = b_engine.get_result(); + string num_aa_samples = string_printf("%d", session->params.samples); + b_rr.stamp_data_add_field("Cycles Samples", num_aa_samples.c_str()); + /* TODO(sergey): Report whether we're doing resumable render + * and also start/end sample if so. + */ + } + + /* Write cryptomatte metadata. */ + if(scene->film->cryptomatte_passes & CRYPT_OBJECT) { + add_cryptomatte_layer(b_rr, b_rlay_name+".CryptoObject", + scene->object_manager->get_cryptomatte_objects(scene)); + } + if(scene->film->cryptomatte_passes & CRYPT_MATERIAL) { + add_cryptomatte_layer(b_rr, b_rlay_name+".CryptoMaterial", + scene->shader_manager->get_cryptomatte_materials(scene)); + } + if(scene->film->cryptomatte_passes & CRYPT_ASSET) { + add_cryptomatte_layer(b_rr, b_rlay_name+".CryptoAsset", + scene->object_manager->get_cryptomatte_assets(scene)); + } + + /* free result without merging */ + end_render_result(b_engine, b_rr, true, true, false); + double total_time, render_time; session->progress.get_time(total_time, render_time); VLOG(1) << "Total render time: " << total_time; @@ -535,6 +560,8 @@ void BlenderSession::render() session->write_render_tile_cb = function_null; session->update_render_tile_cb = function_null; + /* TODO: find a way to clear this data for persistent data render */ +#if 0 /* free all memory used (host and device), so we wouldn't leave render * engine with extra memory allocated */ @@ -543,6 +570,7 @@ void BlenderSession::render() delete sync; sync = NULL; +#endif } static void populate_bake_data(BakeData *data, const @@ -591,7 +619,8 @@ static int bake_pass_filter_get(const int pass_filter) return flag; } -void BlenderSession::bake(BL::Object& b_object, +void BlenderSession::bake(BL::Depsgraph& b_depsgraph_, + BL::Object& b_object, const string& pass_type, const int pass_filter, const int object_id, @@ -600,6 +629,8 @@ void BlenderSession::bake(BL::Object& b_object, const int /*depth*/, float result[]) { + b_depsgraph = b_depsgraph_; + ShaderEvalType shader_type = get_shader_type(pass_type); /* Set baking flag in advance, so kernel loading can check if we need @@ -632,11 +663,12 @@ void BlenderSession::bake(BL::Object& b_object, BL::Object b_camera_override(b_engine.camera_override()); sync->sync_camera(b_render, b_camera_override, width, height, ""); sync->sync_data(b_render, - b_v3d, - b_camera_override, - width, height, - &python_thread_state, - b_rlay_name.c_str()); + b_depsgraph, + b_v3d, + b_camera_override, + width, height, + &python_thread_state); + builtin_images_load(); } BakeData *bake_data = NULL; @@ -665,10 +697,14 @@ void BlenderSession::bake(BL::Object& b_object, } } - int object = object_index; + /* Object might have been disabled for rendering or excluded in some + * other way, in that case Blender will report a warning afterwards. */ + if (object_index != OBJECT_NONE) { + int object = object_index; - bake_data = scene->bake_manager->init(object, tri_offset, num_pixels); - populate_bake_data(bake_data, object_id, pixel_array, num_pixels); + bake_data = scene->bake_manager->init(object, tri_offset, num_pixels); + populate_bake_data(bake_data, object_id, pixel_array, num_pixels); + } /* set number of samples */ session->tile_manager.set_samples(session_params.samples); @@ -679,7 +715,7 @@ void BlenderSession::bake(BL::Object& b_object, } /* Perform bake. Check cancel to avoid crash with incomplete scene data. */ - if(!session->progress.get_cancel()) { + if(!session->progress.get_cancel() && bake_data) { scene->bake_manager->bake(scene->device, &scene->dscene, scene, session->progress, shader_type, bake_pass_filter, bake_data, result); } @@ -770,7 +806,7 @@ void BlenderSession::update_render_result(BL::RenderResult& b_rr, do_write_update_render_result(b_rr, b_rlay, rtile, true); } -void BlenderSession::synchronize() +void BlenderSession::synchronize(BL::Depsgraph& b_depsgraph_) { /* only used for viewport render */ if(!b_v3d) @@ -795,7 +831,7 @@ void BlenderSession::synchronize() /* copy recalc flags, outside of mutex so we can decide to do the real * synchronization at a later time to not block on running updates */ - sync->sync_recalc(); + sync->sync_recalc(b_depsgraph_); /* don't do synchronization if on pause */ if(session_pause) { @@ -810,19 +846,23 @@ void BlenderSession::synchronize() } /* data and camera synchronize */ + b_depsgraph = b_depsgraph_; + BL::Object b_camera_override(b_engine.camera_override()); sync->sync_data(b_render, + b_depsgraph, b_v3d, b_camera_override, width, height, - &python_thread_state, - b_rlay_name.c_str()); + &python_thread_state); if(b_rv3d) sync->sync_view(b_v3d, b_rv3d, width, height); else sync->sync_camera(b_render, b_camera_override, width, height, ""); + builtin_images_load(); + /* unlock */ session->scene->mutex.unlock(); @@ -939,7 +979,7 @@ void BlenderSession::update_bake_progress() void BlenderSession::update_status_progress() { string timestatus, status, substatus; - string scene = ""; + string scene_status = ""; float progress; double total_time, remaining_time = 0, render_time; char time_str[128]; @@ -953,35 +993,31 @@ void BlenderSession::update_status_progress() remaining_time = (1.0 - (double)progress) * (render_time / (double)progress); if(background) { - scene += " | " + b_scene.name(); + scene_status += " | " + scene->name; if(b_rlay_name != "") - scene += ", " + b_rlay_name; + scene_status += ", " + b_rlay_name; if(b_rview_name != "") - scene += ", " + b_rview_name; - } - else { - BLI_timecode_string_from_time_simple(time_str, sizeof(time_str), total_time); - timestatus = "Time:" + string(time_str) + " | "; - } + scene_status += ", " + b_rview_name; - if(remaining_time > 0) { - BLI_timecode_string_from_time_simple(time_str, sizeof(time_str), remaining_time); - timestatus += "Remaining:" + string(time_str) + " | "; - } + if(remaining_time > 0) { + BLI_timecode_string_from_time_simple(time_str, sizeof(time_str), remaining_time); + timestatus += "Remaining:" + string(time_str) + " | "; + } - timestatus += string_printf("Mem:%.2fM, Peak:%.2fM", (double)mem_used, (double)mem_peak); + timestatus += string_printf("Mem:%.2fM, Peak:%.2fM", (double)mem_used, (double)mem_peak); - if(status.size() > 0) - status = " | " + status; - if(substatus.size() > 0) - status += " | " + substatus; + if(status.size() > 0) + status = " | " + status; + if(substatus.size() > 0) + status += " | " + substatus; + } double current_time = time_dt(); /* When rendering in a window, redraw the status at least once per second to keep the elapsed and remaining time up-to-date. * For headless rendering, only report when something significant changes to keep the console output readable. */ if(status != last_status || (!headless && (current_time - last_status_time) > 1.0)) { - b_engine.update_stats("", (timestatus + scene + status).c_str()); + b_engine.update_stats("", (timestatus + scene_status + status).c_str()); b_engine.update_memory_stats(mem_used, mem_peak); last_status = status; last_status_time = current_time; @@ -1334,6 +1370,9 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n"); } else { + /* We originally were passing view_layer here but in reality we need a + * a depsgraph to pass to the RE_point_density_minmax() function. + */ /* TODO(sergey): Check we're indeed in shader node tree. */ PointerRNA ptr; RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr); @@ -1341,14 +1380,23 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) { BL::ShaderNodeTexPointDensity b_point_density_node(b_node); int length; - int settings = background ? 1 : 0; /* 1 - render settings, 0 - vewport settings. */ - b_point_density_node.calc_point_density(b_scene, settings, &length, &pixels); + b_point_density_node.calc_point_density(b_depsgraph, &length, &pixels); } } return false; } +void BlenderSession::builtin_images_load() +{ + /* Force builtin images to be loaded along with Blender data sync. This + * is needed because we may be reading from depsgraph evaluated data which + * can be freed by Blender before Cycles reads it. */ + ImageManager *manager = session->scene->image_manager; + Device *device = session->device; + manager->device_load_builtin(device, session->scene, session->progress); +} + void BlenderSession::update_resumable_tile_manager(int num_samples) { const int num_resumable_chunks = BlenderSession::num_resumable_chunks, @@ -1357,9 +1405,15 @@ void BlenderSession::update_resumable_tile_manager(int num_samples) return; } - const int num_samples_per_chunk = (int)ceilf((float)num_samples / num_resumable_chunks); + if (num_resumable_chunks > num_samples) { + fprintf(stderr, "Cycles warning: more sample chunks (%d) than samples (%d), " + "this will cause some samples to be included in multiple chunks.\n", + num_resumable_chunks, num_samples); + } + + const float num_samples_per_chunk = (float)num_samples / num_resumable_chunks; - int range_start_sample, range_num_samples; + float range_start_sample, range_num_samples; if(current_resumable_chunk != 0) { /* Single chunk rendering. */ range_start_sample = num_samples_per_chunk * (current_resumable_chunk - 1); @@ -1371,19 +1425,37 @@ void BlenderSession::update_resumable_tile_manager(int num_samples) range_start_sample = num_samples_per_chunk * (start_resumable_chunk - 1); range_num_samples = num_chunks * num_samples_per_chunk; } + + /* Round after doing the multiplications with num_chunks and num_samples_per_chunk + * to allow for many small chunks. */ + int rounded_range_start_sample = (int)floor(range_start_sample + 0.5f); + int rounded_range_num_samples = max((int)floor(range_num_samples + 0.5f), 1); + /* Make sure we don't overshoot. */ - if(range_start_sample + range_num_samples > num_samples) { - range_num_samples = num_samples - range_num_samples; + if(rounded_range_start_sample + rounded_range_num_samples > num_samples) { + rounded_range_num_samples = num_samples - rounded_range_num_samples; } VLOG(1) << "Samples range start is " << range_start_sample << ", " << "number of samples to render is " << range_num_samples; - scene->integrator->start_sample = range_start_sample; + scene->integrator->start_sample = rounded_range_start_sample; scene->integrator->tag_update(scene); - session->tile_manager.range_start_sample = range_start_sample; - session->tile_manager.range_num_samples = range_num_samples; + session->tile_manager.range_start_sample = rounded_range_start_sample; + session->tile_manager.range_num_samples = rounded_range_num_samples; +} + +void BlenderSession::free_blender_memory_if_possible() +{ + if(!background) { + /* During interactive render we can not free anything: attempts to save + * memory would cause things to be allocated and evaluated for every + * updated sample. + */ + return; + } + b_engine.free_blender_memory(); } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h index b8a9096b354..96ffc06a3db 100644 --- a/intern/cycles/blender/blender_session.h +++ b/intern/cycles/blender/blender_session.h @@ -35,14 +35,13 @@ class RenderTile; class BlenderSession { public: BlenderSession(BL::RenderEngine& b_engine, - BL::UserPreferences& b_userpref, + BL::Preferences& b_userpref, BL::BlendData& b_data, - BL::Scene& b_scene); + bool preview_osl); BlenderSession(BL::RenderEngine& b_engine, - BL::UserPreferences& b_userpref, + BL::Preferences& b_userpref, BL::BlendData& b_data, - BL::Scene& b_scene, BL::SpaceView3D& b_v3d, BL::RegionView3D& b_rv3d, int width, int height); @@ -56,12 +55,13 @@ public: void free_session(); void reset_session(BL::BlendData& b_data, - BL::Scene& b_scene); + BL::Depsgraph& b_depsgraph); /* offline render */ - void render(); + void render(BL::Depsgraph& b_depsgraph); - void bake(BL::Object& b_object, + void bake(BL::Depsgraph& b_depsgrah, + BL::Object& b_object, const string& pass_type, const int custom_flag, const int object_id, @@ -83,7 +83,7 @@ public: void update_render_tile(RenderTile& rtile, bool highlight); /* interactive updates */ - void synchronize(); + void synchronize(BL::Depsgraph& b_depsgraph); /* drawing */ bool draw(int w, int h); @@ -102,9 +102,13 @@ public: double last_redraw_time; BL::RenderEngine b_engine; - BL::UserPreferences b_userpref; + BL::Preferences b_userpref; BL::BlendData b_data; BL::RenderSettings b_render; + BL::Depsgraph b_depsgraph; + /* NOTE: Blender's scene might become invalid after call + * free_blender_memory_if_possible(). + */ BL::Scene b_scene; BL::SpaceView3D b_v3d; BL::RegionView3D b_rv3d; @@ -117,6 +121,7 @@ public: double last_status_time; int width, height; + bool preview_osl; double start_resize_time; void *python_thread_state; @@ -166,9 +171,16 @@ protected: float *pixels, const size_t pixels_size, const bool free_cache); + void builtin_images_load(); /* Update tile manager to reflect resumable render settings. */ void update_resumable_tile_manager(int num_samples); + + /* Is used after each render layer synchronization is done with the goal + * of freeing render engine data which is held from Blender side (for + * example, dependency graph). + */ + void free_blender_memory_if_possible(); }; CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index e33a6c20a52..b04a0394141 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -231,18 +231,11 @@ static void get_tex_mapping(TextureMapping *mapping, mapping->max = get_float3(b_mapping.max()); } -static bool is_output_node(BL::Node& b_node) -{ - return (b_node.is_a(&RNA_ShaderNodeOutputMaterial) - || b_node.is_a(&RNA_ShaderNodeOutputWorld) - || b_node.is_a(&RNA_ShaderNodeOutputLamp)); -} - static ShaderNode *add_node(Scene *scene, BL::RenderEngine& b_engine, BL::BlendData& b_data, + BL::Depsgraph& b_depsgraph, BL::Scene& b_scene, - const bool background, ShaderGraph *graph, BL::ShaderNodeTree& b_ntree, BL::ShaderNode& b_node) @@ -677,7 +670,9 @@ static ShaderNode *add_node(Scene *scene, image->animated = b_image_node.image_user().use_auto_refresh(); image->use_alpha = b_image.use_alpha(); + /* TODO: restore */ /* TODO(sergey): Does not work properly when we change builtin type. */ +#if 0 if(b_image.is_updated()) { scene->image_manager->tag_reload_image( image->filename.string(), @@ -686,6 +681,7 @@ static ShaderNode *add_node(Scene *scene, get_image_extension(b_image_node), image->use_alpha); } +#endif } image->color_space = (NodeImageColorSpace)b_image_node.color_space(); image->projection = (NodeImageProjection)b_image_node.projection(); @@ -725,7 +721,9 @@ static ShaderNode *add_node(Scene *scene, env->animated = b_env_node.image_user().use_auto_refresh(); env->use_alpha = b_image.use_alpha(); + /* TODO: restore */ /* TODO(sergey): Does not work properly when we change builtin type. */ +#if 0 if(b_image.is_updated()) { scene->image_manager->tag_reload_image( env->filename.string(), @@ -734,6 +732,7 @@ static ShaderNode *add_node(Scene *scene, EXTENSION_REPEAT, env->use_alpha); } +#endif } env->color_space = (NodeImageColorSpace)b_env_node.color_space(); env->interpolation = get_image_interpolation(b_env_node); @@ -813,7 +812,7 @@ static ShaderNode *add_node(Scene *scene, else if(b_node.is_a(&RNA_ShaderNodeTexCoord)) { BL::ShaderNodeTexCoord b_tex_coord_node(b_node); TextureCoordinateNode *tex_coord = new TextureCoordinateNode(); - tex_coord->from_dupli = b_tex_coord_node.from_dupli(); + tex_coord->from_dupli = b_tex_coord_node.from_instancer(); if(b_tex_coord_node.object()) { tex_coord->use_transform = true; tex_coord->ob_tfm = get_transform(b_tex_coord_node.object().matrix_world()); @@ -866,7 +865,7 @@ static ShaderNode *add_node(Scene *scene, BL::ShaderNodeUVMap b_uvmap_node(b_node); UVMapNode *uvm = new UVMapNode(); uvm->attribute = b_uvmap_node.uv_map(); - uvm->from_dupli = b_uvmap_node.from_dupli(); + uvm->from_dupli = b_uvmap_node.from_instancer(); node = uvm; } else if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) { @@ -876,13 +875,12 @@ static ShaderNode *add_node(Scene *scene, point_density->space = (NodeTexVoxelSpace)b_point_density_node.space(); point_density->interpolation = get_image_interpolation(b_point_density_node); point_density->builtin_data = b_point_density_node.ptr.data; - - /* 1 - render settings, 0 - vewport settings. */ - int settings = background ? 1 : 0; + point_density->image_manager = scene->image_manager; /* TODO(sergey): Use more proper update flag. */ if(true) { - b_point_density_node.cache_point_density(b_scene, settings); + point_density->add_image(); + b_point_density_node.cache_point_density(b_depsgraph); scene->image_manager->tag_reload_image( point_density->filename.string(), point_density->builtin_data, @@ -900,9 +898,8 @@ static ShaderNode *add_node(Scene *scene, BL::Object b_ob(b_point_density_node.object()); if(b_ob) { float3 loc, size; - point_density_texture_space(b_scene, + point_density_texture_space(b_depsgraph, b_point_density_node, - settings, loc, size); point_density->tfm = @@ -1015,8 +1012,8 @@ static ShaderOutput *node_find_output_by_name(ShaderNode *node, static void add_nodes(Scene *scene, BL::RenderEngine& b_engine, BL::BlendData& b_data, + BL::Depsgraph& b_depsgraph, BL::Scene& b_scene, - const bool background, ShaderGraph *graph, BL::ShaderNodeTree& b_ntree, const ProxyMap &proxy_input_map, @@ -1031,23 +1028,7 @@ static void add_nodes(Scene *scene, BL::Node::outputs_iterator b_output; /* find the node to use for output if there are multiple */ - bool found_active_output = false; - BL::ShaderNode output_node(PointerRNA_NULL); - - for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) { - if(is_output_node(*b_node)) { - BL::ShaderNodeOutputMaterial b_output_node(*b_node); - - if(b_output_node.is_active_output()) { - output_node = b_output_node; - found_active_output = true; - break; - } - else if(!output_node.ptr.data && !found_active_output) { - output_node = b_output_node; - } - } - } + BL::ShaderNode output_node = b_ntree.get_output_node(BL::ShaderNodeOutputMaterial::target_CYCLES); /* add nodes */ for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) { @@ -1117,8 +1098,8 @@ static void add_nodes(Scene *scene, add_nodes(scene, b_engine, b_data, + b_depsgraph, b_scene, - background, graph, b_group_ntree, group_proxy_input_map, @@ -1156,18 +1137,16 @@ static void add_nodes(Scene *scene, else { ShaderNode *node = NULL; - if(is_output_node(*b_node)) { - if(b_node->ptr.data == output_node.ptr.data) { - node = graph->output(); - } + if(b_node->ptr.data == output_node.ptr.data) { + node = graph->output(); } else { BL::ShaderNode b_shader_node(*b_node); node = add_node(scene, b_engine, b_data, + b_depsgraph, b_scene, - background, graph, b_ntree, b_shader_node); @@ -1229,8 +1208,8 @@ static void add_nodes(Scene *scene, static void add_nodes(Scene *scene, BL::RenderEngine& b_engine, BL::BlendData& b_data, + BL::Depsgraph& b_depsgraph, BL::Scene& b_scene, - const bool background, ShaderGraph *graph, BL::ShaderNodeTree& b_ntree) { @@ -1238,8 +1217,8 @@ static void add_nodes(Scene *scene, add_nodes(scene, b_engine, b_data, + b_depsgraph, b_scene, - background, graph, b_ntree, empty_proxy_map, @@ -1248,35 +1227,39 @@ static void add_nodes(Scene *scene, /* Sync Materials */ -void BlenderSync::sync_materials(bool update_all) +void BlenderSync::sync_materials(BL::Depsgraph& b_depsgraph, bool update_all) { shader_map.set_default(scene->default_surface); - /* material loop */ - BL::BlendData::materials_iterator b_mat; - TaskPool pool; set<Shader*> updated_shaders; - for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat) { + BL::Depsgraph::ids_iterator b_id; + for(b_depsgraph.ids.begin(b_id); b_id != b_depsgraph.ids.end(); ++b_id) { + if(!b_id->is_a(&RNA_Material)) { + continue; + } + + BL::Material b_mat(*b_id); Shader *shader; /* test if we need to sync */ - if(shader_map.sync(&shader, *b_mat) || update_all) { + if(shader_map.sync(&shader, b_mat) || shader->need_sync_object || update_all) { ShaderGraph *graph = new ShaderGraph(); - shader->name = b_mat->name().c_str(); - shader->pass_id = b_mat->pass_index(); + shader->name = b_mat.name().c_str(); + shader->pass_id = b_mat.pass_index(); + shader->need_sync_object = false; /* create nodes */ - if(b_mat->use_nodes() && b_mat->node_tree()) { - BL::ShaderNodeTree b_ntree(b_mat->node_tree()); + if(b_mat.use_nodes() && b_mat.node_tree()) { + BL::ShaderNodeTree b_ntree(b_mat.node_tree()); - add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree); + add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree); } else { DiffuseBsdfNode *diffuse = new DiffuseBsdfNode(); - diffuse->color = get_float3(b_mat->diffuse_color()); + diffuse->color = get_float3(b_mat.diffuse_color()); graph->add(diffuse); ShaderNode *out = graph->output(); @@ -1284,7 +1267,7 @@ void BlenderSync::sync_materials(bool update_all) } /* settings */ - PointerRNA cmat = RNA_pointer_get(&b_mat->ptr, "cycles"); + PointerRNA cmat = RNA_pointer_get(&b_mat.ptr, "cycles"); shader->use_mis = get_boolean(cmat, "sample_as_light"); shader->use_transparent_shadow = get_boolean(cmat, "use_transparent_shadow"); shader->heterogeneous_volume = !get_boolean(cmat, "homogeneous_volume"); @@ -1328,7 +1311,7 @@ void BlenderSync::sync_materials(bool update_all) /* Sync World */ -void BlenderSync::sync_world(bool update_all) +void BlenderSync::sync_world(BL::Depsgraph& b_depsgraph, bool update_all) { Background *background = scene->background; Background prevbackground = *background; @@ -1343,7 +1326,7 @@ void BlenderSync::sync_world(bool update_all) if(b_world && b_world.use_nodes() && b_world.node_tree()) { BL::ShaderNodeTree b_ntree(b_world.node_tree()); - add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree); + add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree); /* volume */ PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles"); @@ -1353,7 +1336,7 @@ void BlenderSync::sync_world(bool update_all) } else if(b_world) { BackgroundNode *background = new BackgroundNode(); - background->color = get_float3(b_world.horizon_color()); + background->color = get_float3(b_world.color()); graph->add(background); ShaderNode *out = graph->output(); @@ -1411,49 +1394,52 @@ void BlenderSync::sync_world(bool update_all) background->transparent_roughness_threshold = 0.0f; } - background->use_shader = render_layer.use_background_shader; - background->use_ao = background->use_ao && render_layer.use_background_ao; + background->use_shader = view_layer.use_background_shader; + background->use_ao = background->use_ao && view_layer.use_background_ao; if(background->modified(prevbackground)) background->tag_update(scene); } -/* Sync Lamps */ +/* Sync Lights */ -void BlenderSync::sync_lamps(bool update_all) +void BlenderSync::sync_lights(BL::Depsgraph& b_depsgraph, bool update_all) { shader_map.set_default(scene->default_light); - /* lamp loop */ - BL::BlendData::lamps_iterator b_lamp; + BL::Depsgraph::ids_iterator b_id; + for(b_depsgraph.ids.begin(b_id); b_id != b_depsgraph.ids.end(); ++b_id) { + if(!b_id->is_a(&RNA_Light)) { + continue; + } - for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp) { + BL::Light b_light(*b_id); Shader *shader; /* test if we need to sync */ - if(shader_map.sync(&shader, *b_lamp) || update_all) { + if(shader_map.sync(&shader, b_light) || update_all) { ShaderGraph *graph = new ShaderGraph(); /* create nodes */ - if(b_lamp->use_nodes() && b_lamp->node_tree()) { - shader->name = b_lamp->name().c_str(); + if(b_light.use_nodes() && b_light.node_tree()) { + shader->name = b_light.name().c_str(); - BL::ShaderNodeTree b_ntree(b_lamp->node_tree()); + BL::ShaderNodeTree b_ntree(b_light.node_tree()); - add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree); + add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree); } else { float strength = 1.0f; - if(b_lamp->type() == BL::Lamp::type_POINT || - b_lamp->type() == BL::Lamp::type_SPOT || - b_lamp->type() == BL::Lamp::type_AREA) + if(b_light.type() == BL::Light::type_POINT || + b_light.type() == BL::Light::type_SPOT || + b_light.type() == BL::Light::type_AREA) { strength = 100.0f; } EmissionNode *emission = new EmissionNode(); - emission->color = get_float3(b_lamp->color()); + emission->color = get_float3(b_light.color()); emission->strength = strength; graph->add(emission); @@ -1467,7 +1453,7 @@ void BlenderSync::sync_lamps(bool update_all) } } -void BlenderSync::sync_shaders() +void BlenderSync::sync_shaders(BL::Depsgraph& b_depsgraph) { /* for auto refresh images */ bool auto_refresh_update = false; @@ -1480,9 +1466,9 @@ void BlenderSync::sync_shaders() shader_map.pre_sync(); - sync_world(auto_refresh_update); - sync_lamps(auto_refresh_update); - sync_materials(auto_refresh_update); + sync_world(b_depsgraph, auto_refresh_update); + sync_lights(b_depsgraph, auto_refresh_update); + sync_materials(b_depsgraph, auto_refresh_update); /* false = don't delete unused shaders, not supported */ shader_map.post_sync(false); diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index a6050b66040..072af281a73 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -78,31 +78,12 @@ BlenderSync::~BlenderSync() /* Sync */ -bool BlenderSync::sync_recalc() +void BlenderSync::sync_recalc(BL::Depsgraph& b_depsgraph) { - /* sync recalc flags from blender to cycles. actual update is done separate, - * so we can do it later on if doing it immediate is not suitable */ - - BL::BlendData::materials_iterator b_mat; - bool has_updated_objects = b_data.objects.is_updated(); - for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat) { - if(b_mat->is_updated() || (b_mat->node_tree() && b_mat->node_tree().is_updated())) { - shader_map.set_recalc(*b_mat); - } - else { - Shader *shader = shader_map.find(*b_mat); - if(has_updated_objects && shader != NULL && shader->has_object_dependency) { - shader_map.set_recalc(*b_mat); - } - } - } - - BL::BlendData::lamps_iterator b_lamp; - - for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp) - if(b_lamp->is_updated() || (b_lamp->node_tree() && b_lamp->node_tree().is_updated())) - shader_map.set_recalc(*b_lamp); + /* Sync recalc flags from blender to cycles. Actual update is done separate, + * so we can do it later on if doing it immediate is not suitable. */ + bool has_updated_objects = b_depsgraph.id_type_updated(BL::DriverTarget::id_type_OBJECT); bool dicing_prop_changed = false; if(experimental) { @@ -124,83 +105,92 @@ bool BlenderSync::sync_recalc() } } - BL::BlendData::objects_iterator b_ob; + /* Iterate over all IDs in this depsgraph. */ + BL::Depsgraph::updates_iterator b_update; + for(b_depsgraph.updates.begin(b_update); b_update != b_depsgraph.updates.end(); ++b_update) { + BL::ID b_id(b_update->id()); - for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) { - if(b_ob->is_updated()) { - object_map.set_recalc(*b_ob); - light_map.set_recalc(*b_ob); + /* Material */ + if(b_id.is_a(&RNA_Material)) { + BL::Material b_mat(b_id); + shader_map.set_recalc(b_mat); + } + /* Light */ + else if(b_id.is_a(&RNA_Light)) { + BL::Light b_light(b_id); + shader_map.set_recalc(b_light); } + /* Object */ + else if(b_id.is_a(&RNA_Object)) { + BL::Object b_ob(b_id); + const bool updated_geometry = b_update->is_updated_geometry(); + + if(b_update->is_updated_transform()) { + object_map.set_recalc(b_ob); + light_map.set_recalc(b_ob); + } - if(object_is_mesh(*b_ob)) { - if(b_ob->is_updated_data() || b_ob->data().is_updated() || - (dicing_prop_changed && object_subdivision_type(*b_ob, preview, experimental) != Mesh::SUBDIVISION_NONE)) - { - BL::ID key = BKE_object_is_modified(*b_ob)? *b_ob: b_ob->data(); - mesh_map.set_recalc(key); + if(object_is_mesh(b_ob)) { + if(updated_geometry || + (dicing_prop_changed && object_subdivision_type(b_ob, preview, experimental) != Mesh::SUBDIVISION_NONE)) + { + BL::ID key = BKE_object_is_modified(b_ob)? b_ob: b_ob.data(); + mesh_map.set_recalc(key); + } + } + else if(object_is_light(b_ob)) { + if(updated_geometry) { + light_map.set_recalc(b_ob); + } + } + + if(updated_geometry) { + BL::Object::particle_systems_iterator b_psys; + for(b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end(); ++b_psys) + particle_system_map.set_recalc(b_ob); } } - else if(object_is_light(*b_ob)) { - if(b_ob->is_updated_data() || b_ob->data().is_updated()) - light_map.set_recalc(*b_ob); + /* Mesh */ + else if(b_id.is_a(&RNA_Mesh)) { + BL::Mesh b_mesh(b_id); + mesh_map.set_recalc(b_mesh); } - - if(b_ob->is_updated_data()) { - BL::Object::particle_systems_iterator b_psys; - for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) - particle_system_map.set_recalc(*b_ob); + /* World */ + else if(b_id.is_a(&RNA_World)) { + BL::World b_world(b_id); + if(world_map == b_world.ptr.data) { + world_recalc = true; + } } } - BL::BlendData::meshes_iterator b_mesh; - - for(b_data.meshes.begin(b_mesh); b_mesh != b_data.meshes.end(); ++b_mesh) { - if(b_mesh->is_updated()) { - mesh_map.set_recalc(*b_mesh); + /* Updates shader with object dependency if objects changed. */ + if(has_updated_objects) { + if(scene->default_background->has_object_dependency) { + world_recalc = true; } - } - BL::BlendData::worlds_iterator b_world; - - for(b_data.worlds.begin(b_world); b_world != b_data.worlds.end(); ++b_world) { - if(world_map == b_world->ptr.data) { - if(b_world->is_updated() || - (b_world->node_tree() && b_world->node_tree().is_updated())) - { - world_recalc = true; - } - else if(b_world->node_tree() && b_world->use_nodes()) { - Shader *shader = scene->default_background; - if(has_updated_objects && shader->has_object_dependency) { - world_recalc = true; - } + foreach(Shader *shader, scene->shaders) { + if(shader->has_object_dependency) { + shader->need_sync_object = true; } } } - - bool recalc = - shader_map.has_recalc() || - object_map.has_recalc() || - light_map.has_recalc() || - mesh_map.has_recalc() || - particle_system_map.has_recalc() || - BlendDataObjects_is_updated_get(&b_data.ptr) || - world_recalc; - - return recalc; } void BlenderSync::sync_data(BL::RenderSettings& b_render, + BL::Depsgraph& b_depsgraph, BL::SpaceView3D& b_v3d, BL::Object& b_override, int width, int height, - void **python_thread_state, - const char *layer) + void **python_thread_state) { - sync_render_layers(b_v3d, layer); + BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); + + sync_view_layer(b_v3d, b_view_layer); sync_integrator(); sync_film(); - sync_shaders(); + sync_shaders(b_depsgraph); sync_images(); sync_curve_settings(); @@ -210,14 +200,17 @@ void BlenderSync::sync_data(BL::RenderSettings& b_render, scene->need_motion() == Scene::MOTION_NONE || scene->camera->motion_position == Camera::MOTION_POSITION_CENTER) { - sync_objects(); + sync_objects(b_depsgraph); } sync_motion(b_render, + b_depsgraph, b_override, width, height, python_thread_state); mesh_synced.clear(); + + free_data_after_sync(b_depsgraph); } /* Integrator */ @@ -371,75 +364,33 @@ void BlenderSync::sync_film() /* Render Layer */ -void BlenderSync::sync_render_layers(BL::SpaceView3D& b_v3d, const char *layer) +void BlenderSync::sync_view_layer(BL::SpaceView3D& /*b_v3d*/, BL::ViewLayer& b_view_layer) { - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - string layername; - - /* 3d view */ - if(b_v3d) { - if(RNA_boolean_get(&cscene, "preview_active_layer")) { - BL::RenderLayers layers(b_scene.render().ptr); - layername = layers.active().name(); - layer = layername.c_str(); - } - else { - render_layer.scene_layer = get_layer(b_v3d.layers(), b_v3d.layers_local_view()); - render_layer.layer = render_layer.scene_layer; - render_layer.exclude_layer = 0; - render_layer.holdout_layer = 0; - render_layer.material_override = PointerRNA_NULL; - render_layer.use_background_shader = true; - render_layer.use_background_ao = true; - render_layer.use_hair = true; - render_layer.use_surfaces = true; - render_layer.use_viewport_visibility = true; - render_layer.samples = 0; - render_layer.bound_samples = false; - return; - } - } - /* render layer */ - BL::RenderSettings r = b_scene.render(); - BL::RenderSettings::layers_iterator b_rlay; + view_layer.name = b_view_layer.name(); + view_layer.use_background_shader = b_view_layer.use_sky(); + view_layer.use_background_ao = b_view_layer.use_ao(); + view_layer.use_surfaces = b_view_layer.use_solid(); + view_layer.use_hair = b_view_layer.use_strand(); + + /* Material override. */ + view_layer.material_override = b_view_layer.material_override(); + + /* Sample override. */ + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); int use_layer_samples = get_enum(cscene, "use_layer_samples"); - bool first_layer = true; - uint layer_override = get_layer(b_engine.layer_override()); - uint scene_layers = layer_override ? layer_override : get_layer(b_scene.layers()); - - for(r.layers.begin(b_rlay); b_rlay != r.layers.end(); ++b_rlay) { - if((!layer && first_layer) || (layer && b_rlay->name() == layer)) { - render_layer.name = b_rlay->name(); - - render_layer.holdout_layer = get_layer(b_rlay->layers_zmask()); - render_layer.exclude_layer = get_layer(b_rlay->layers_exclude()); - - render_layer.scene_layer = scene_layers & ~render_layer.exclude_layer; - render_layer.scene_layer |= render_layer.exclude_layer & render_layer.holdout_layer; - - render_layer.layer = get_layer(b_rlay->layers()); - render_layer.layer |= render_layer.holdout_layer; - - render_layer.material_override = b_rlay->material_override(); - render_layer.use_background_shader = b_rlay->use_sky(); - render_layer.use_background_ao = b_rlay->use_ao(); - render_layer.use_surfaces = b_rlay->use_solid(); - render_layer.use_hair = b_rlay->use_strand(); - render_layer.use_viewport_visibility = false; - - render_layer.bound_samples = (use_layer_samples == 1); - if(use_layer_samples != 2) { - int samples = b_rlay->samples(); - if(get_boolean(cscene, "use_square_samples")) - render_layer.samples = samples * samples; - else - render_layer.samples = samples; - } - } - first_layer = false; + view_layer.bound_samples = (use_layer_samples == 1); + view_layer.samples = 0; + + if(use_layer_samples != 2) { + int samples = b_view_layer.samples(); + if(get_boolean(cscene, "use_square_samples")) + view_layer.samples = samples * samples; + else + view_layer.samples = samples; } + } /* Images */ @@ -552,7 +503,7 @@ int BlenderSync::get_denoising_pass(BL::RenderPass& b_pass) } vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay, - BL::SceneRenderLayer& b_srlay, + BL::ViewLayer& b_view_layer, const SessionParams &session_params) { vector<Pass> passes; @@ -575,7 +526,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay, Pass::add(pass_type, passes); } - PointerRNA crp = RNA_pointer_get(&b_srlay.ptr, "cycles"); + PointerRNA crp = RNA_pointer_get(&b_view_layer.ptr, "cycles"); bool full_denoising = get_boolean(crp, "use_denoising"); bool write_denoising_passes = get_boolean(crp, "denoising_store_passes"); @@ -591,49 +542,49 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay, MAP_OPTION("denoising_subsurface_direct", DENOISING_CLEAN_SUBSURFACE_DIR); MAP_OPTION("denoising_subsurface_indirect", DENOISING_CLEAN_SUBSURFACE_IND); #undef MAP_OPTION - b_engine.add_pass("Noisy Image", 4, "RGBA", b_srlay.name().c_str()); + b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str()); } if(write_denoising_passes) { - b_engine.add_pass("Denoising Normal", 3, "XYZ", b_srlay.name().c_str()); - b_engine.add_pass("Denoising Albedo", 3, "RGB", b_srlay.name().c_str()); - b_engine.add_pass("Denoising Depth", 1, "Z", b_srlay.name().c_str()); - b_engine.add_pass("Denoising Shadowing", 1, "X", b_srlay.name().c_str()); - b_engine.add_pass("Denoising Variance", 3, "RGB", b_srlay.name().c_str()); - b_engine.add_pass("Denoising Intensity", 1, "X", b_srlay.name().c_str()); + b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str()); + b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str()); + b_engine.add_pass("Denoising Depth", 1, "Z", b_view_layer.name().c_str()); + b_engine.add_pass("Denoising Shadowing", 1, "X", b_view_layer.name().c_str()); + b_engine.add_pass("Denoising Variance", 3, "RGB", b_view_layer.name().c_str()); + b_engine.add_pass("Denoising Intensity", 1, "X", b_view_layer.name().c_str()); if(scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES) { - b_engine.add_pass("Denoising Clean", 3, "RGB", b_srlay.name().c_str()); + b_engine.add_pass("Denoising Clean", 3, "RGB", b_view_layer.name().c_str()); } } #ifdef __KERNEL_DEBUG__ if(get_boolean(crp, "pass_debug_bvh_traversed_nodes")) { - b_engine.add_pass("Debug BVH Traversed Nodes", 1, "X", b_srlay.name().c_str()); + b_engine.add_pass("Debug BVH Traversed Nodes", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_BVH_TRAVERSED_NODES, passes); } if(get_boolean(crp, "pass_debug_bvh_traversed_instances")) { - b_engine.add_pass("Debug BVH Traversed Instances", 1, "X", b_srlay.name().c_str()); + b_engine.add_pass("Debug BVH Traversed Instances", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_BVH_TRAVERSED_INSTANCES, passes); } if(get_boolean(crp, "pass_debug_bvh_intersections")) { - b_engine.add_pass("Debug BVH Intersections", 1, "X", b_srlay.name().c_str()); + b_engine.add_pass("Debug BVH Intersections", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_BVH_INTERSECTIONS, passes); } if(get_boolean(crp, "pass_debug_ray_bounces")) { - b_engine.add_pass("Debug Ray Bounces", 1, "X", b_srlay.name().c_str()); + b_engine.add_pass("Debug Ray Bounces", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_RAY_BOUNCES, passes); } #endif if(get_boolean(crp, "pass_debug_render_time")) { - b_engine.add_pass("Debug Render Time", 1, "X", b_srlay.name().c_str()); + b_engine.add_pass("Debug Render Time", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_RENDER_TIME, passes); } if(get_boolean(crp, "use_pass_volume_direct")) { - b_engine.add_pass("VolumeDir", 3, "RGB", b_srlay.name().c_str()); + b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str()); Pass::add(PASS_VOLUME_DIRECT, passes); } if(get_boolean(crp, "use_pass_volume_indirect")) { - b_engine.add_pass("VolumeInd", 3, "RGB", b_srlay.name().c_str()); + b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str()); Pass::add(PASS_VOLUME_INDIRECT, passes); } @@ -645,7 +596,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay, if(get_boolean(crp, "use_pass_crypto_object")) { for(int i = 0; i < crypto_depth; ++i) { string passname = cryptomatte_prefix + string_printf("Object%02d", i); - b_engine.add_pass(passname.c_str(), 4, "RGBA", b_srlay.name().c_str()); + b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str()); Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str()); } scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_OBJECT); @@ -653,7 +604,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay, if(get_boolean(crp, "use_pass_crypto_material")) { for(int i = 0; i < crypto_depth; ++i) { string passname = cryptomatte_prefix + string_printf("Material%02d", i); - b_engine.add_pass(passname.c_str(), 4, "RGBA", b_srlay.name().c_str()); + b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str()); Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str()); } scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_MATERIAL); @@ -661,7 +612,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay, if(get_boolean(crp, "use_pass_crypto_asset")) { for(int i = 0; i < crypto_depth; ++i) { string passname = cryptomatte_prefix + string_printf("Asset%02d", i); - b_engine.add_pass(passname.c_str(), 4, "RGBA", b_srlay.name().c_str()); + b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str()); Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str()); } scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_ASSET); @@ -673,6 +624,30 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay, return passes; } +void BlenderSync::free_data_after_sync(BL::Depsgraph& b_depsgraph) +{ + /* When viewport display is not needed during render we can force some + * caches to be releases from blender side in order to reduce peak memory + * footprint during synchronization process. + */ + const bool is_interface_locked = b_engine.render() && + b_engine.render().use_lock_interface(); + const bool can_free_caches = BlenderSession::headless || is_interface_locked; + if(!can_free_caches) { + return; + } + /* TODO(sergey): We can actually remove the whole dependency graph, + * but that will need some API support first. + */ + BL::Depsgraph::objects_iterator b_ob; + for(b_depsgraph.objects.begin(b_ob); + b_ob != b_depsgraph.objects.end(); + ++b_ob) + { + b_ob->cache_release(); + } +} + /* Scene Parameters */ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene, @@ -741,7 +716,7 @@ bool BlenderSync::get_session_pause(BL::Scene& b_scene, bool background) } SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine, - BL::UserPreferences& b_userpref, + BL::Preferences& b_userpref, BL::Scene& b_scene, bool background) { @@ -775,7 +750,7 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine, /* Find cycles preferences. */ PointerRNA b_preferences; - BL::UserPreferences::addons_iterator b_addon_iter; + BL::Preferences::addons_iterator b_addon_iter; for(b_userpref.addons.begin(b_addon_iter); b_addon_iter != b_userpref.addons.end(); ++b_addon_iter) { if(b_addon_iter->module() == "cycles") { b_preferences = b_addon_iter->preferences().ptr; @@ -900,13 +875,14 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine, params.text_timeout = (double)get_float(cscene, "debug_text_timeout"); /* progressive refine */ - params.progressive_refine = get_boolean(cscene, "use_progressive_refine") && + params.progressive_refine = (b_engine.is_preview() || + get_boolean(cscene, "use_progressive_refine")) && !b_r.use_save_buffers(); if(params.progressive_refine) { - BL::RenderSettings::layers_iterator b_rlay; - for(b_r.layers.begin(b_rlay); b_rlay != b_r.layers.end(); ++b_rlay) { - PointerRNA crl = RNA_pointer_get(&b_rlay->ptr, "cycles"); + BL::Scene::view_layers_iterator b_view_layer; + for(b_scene.view_layers.begin(b_view_layer); b_view_layer != b_scene.view_layers.end(); ++b_view_layer) { + PointerRNA crl = RNA_pointer_get(&b_view_layer->ptr, "cycles"); if(get_boolean(crl, "use_denoising")) { params.progressive_refine = false; } @@ -934,17 +910,7 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine, params.shadingsystem = SHADINGSYSTEM_OSL; /* color managagement */ -#ifdef GLEW_MX - /* When using GLEW MX we need to check whether we've got an OpenGL - * context for current window. This is because command line rendering - * doesn't have OpenGL context actually. - */ - if(glewGetContext() != NULL) -#endif - { - params.display_buffer_linear = GLEW_ARB_half_float_pixel && - b_engine.support_display_space_shader(b_scene); - } + params.display_buffer_linear = b_engine.support_display_space_shader(b_scene); if(b_engine.is_preview()) { /* For preview rendering we're using same timeout as diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 6d78f62c7d0..bf16de4a9c9 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -43,6 +43,7 @@ class Mesh; class Object; class ParticleSystem; class Scene; +class ViewLayer; class Shader; class ShaderGraph; class ShaderNode; @@ -58,16 +59,16 @@ public: ~BlenderSync(); /* sync */ - bool sync_recalc(); + void sync_recalc(BL::Depsgraph& b_depsgraph); void sync_data(BL::RenderSettings& b_render, + BL::Depsgraph& b_depsgraph, BL::SpaceView3D& b_v3d, BL::Object& b_override, int width, int height, - void **python_thread_state, - const char *layer = 0); - void sync_render_layers(BL::SpaceView3D& b_v3d, const char *layer); - vector<Pass> sync_render_passes(BL::RenderLayer& b_rlay, - BL::SceneRenderLayer& b_srlay, + void **python_thread_state); + void sync_view_layer(BL::SpaceView3D& b_v3d, BL::ViewLayer& b_view_layer); + vector<Pass> sync_render_passes(BL::RenderLayer& b_render_layer, + BL::ViewLayer& b_view_layer, const SessionParams &session_params); void sync_integrator(); void sync_camera(BL::RenderSettings& b_render, @@ -77,14 +78,14 @@ public: void sync_view(BL::SpaceView3D& b_v3d, BL::RegionView3D& b_rv3d, int width, int height); - inline int get_layer_samples() { return render_layer.samples; } - inline int get_layer_bound_samples() { return render_layer.bound_samples; } + inline int get_layer_samples() { return view_layer.samples; } + inline int get_layer_bound_samples() { return view_layer.bound_samples; } /* get parameters */ static SceneParams get_scene_params(BL::Scene& b_scene, bool background); static SessionParams get_session_params(BL::RenderEngine& b_engine, - BL::UserPreferences& b_userpref, + BL::Preferences& b_userpref, BL::Scene& b_scene, bool background); static bool get_session_pause(BL::Scene& b_scene, bool background); @@ -99,43 +100,50 @@ public: private: /* sync */ - void sync_lamps(bool update_all); - void sync_materials(bool update_all); - void sync_objects(float motion_time = 0.0f); + void sync_lights(BL::Depsgraph& b_depsgraph, bool update_all); + void sync_materials(BL::Depsgraph& b_depsgraph, bool update_all); + void sync_objects(BL::Depsgraph& b_depsgraph, float motion_time = 0.0f); void sync_motion(BL::RenderSettings& b_render, + BL::Depsgraph& b_depsgraph, BL::Object& b_override, int width, int height, void **python_thread_state); void sync_film(); void sync_view(); - void sync_world(bool update_all); - void sync_shaders(); + void sync_world(BL::Depsgraph& b_depsgraph, bool update_all); + void sync_shaders(BL::Depsgraph& b_depsgraph); void sync_curve_settings(); void sync_nodes(Shader *shader, BL::ShaderNodeTree& b_ntree); - Mesh *sync_mesh(BL::Object& b_ob, bool object_updated, bool hide_tris); + Mesh *sync_mesh(BL::Depsgraph& b_depsgrpah, + BL::Object& b_ob, + BL::Object& b_ob_instance, + bool object_updated, + bool show_self, + bool show_particles); void sync_curves(Mesh *mesh, BL::Mesh& b_mesh, BL::Object& b_ob, bool motion, int motion_step = 0); - Object *sync_object(BL::Object& b_parent, - int persistent_id[OBJECT_PERSISTENT_ID_SIZE], - BL::DupliObject& b_dupli_ob, - Transform& tfm, - uint layer_flag, + Object *sync_object(BL::Depsgraph& b_depsgraph, + BL::ViewLayer& b_view_layer, + BL::DepsgraphObjectInstance& b_instance, float motion_time, - bool hide_tris, + bool show_self, + bool show_particles, BlenderObjectCulling& culling, bool *use_portal); void sync_light(BL::Object& b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object& b_ob, - BL::DupliObject& b_dupli_ob, + BL::Object& b_ob_instance, + int random_id, Transform& tfm, bool *use_portal); void sync_background_light(bool use_portal); - void sync_mesh_motion(BL::Object& b_ob, + void sync_mesh_motion(BL::Depsgraph& b_depsgraph, + BL::Object& b_ob, Object *object, float motion_time); void sync_camera_motion(BL::RenderSettings& b_render, @@ -145,12 +153,15 @@ private: /* particles */ bool sync_dupli_particle(BL::Object& b_ob, - BL::DupliObject& b_dup, + BL::DepsgraphObjectInstance& b_instance, Object *object); /* Images. */ void sync_images(); + /* Early data free. */ + void free_data_after_sync(BL::Depsgraph& b_depsgraph); + /* util */ void find_shader(BL::ID& id, vector<Shader*>& used_shaders, Shader *default_shader); bool BKE_object_is_modified(BL::Object& b_ob); @@ -182,31 +193,24 @@ private: struct RenderLayerInfo { RenderLayerInfo() - : scene_layer(0), layer(0), - holdout_layer(0), exclude_layer(0), - material_override(PointerRNA_NULL), + : material_override(PointerRNA_NULL), use_background_shader(true), use_background_ao(true), use_surfaces(true), use_hair(true), - use_viewport_visibility(false), - samples(0), bound_samples(false) + samples(0), + bound_samples(false) {} string name; - uint scene_layer; - uint layer; - uint holdout_layer; - uint exclude_layer; BL::Material material_override; bool use_background_shader; bool use_background_ao; bool use_surfaces; bool use_hair; - bool use_viewport_visibility; int samples; bool bound_samples; - } render_layer; + } view_layer; Progress &progress; }; diff --git a/intern/cycles/blender/blender_texture.cpp b/intern/cycles/blender/blender_texture.cpp index b2e27b76189..a0371a7eed8 100644 --- a/intern/cycles/blender/blender_texture.cpp +++ b/intern/cycles/blender/blender_texture.cpp @@ -34,9 +34,8 @@ void density_texture_space_invert(float3& loc, } /* namespace */ -void point_density_texture_space(BL::Scene& b_scene, +void point_density_texture_space(BL::Depsgraph& b_depsgraph, BL::ShaderNodeTexPointDensity& b_point_density_node, - int settings, float3& loc, float3& size) { @@ -47,8 +46,7 @@ void point_density_texture_space(BL::Scene& b_scene, return; } float3 min, max; - b_point_density_node.calc_point_density_minmax(b_scene, - settings, + b_point_density_node.calc_point_density_minmax(b_depsgraph, &min[0], &max[0]); loc = (min + max) * 0.5f; diff --git a/intern/cycles/blender/blender_texture.h b/intern/cycles/blender/blender_texture.h index 734231a85ec..b4e166c5cdd 100644 --- a/intern/cycles/blender/blender_texture.h +++ b/intern/cycles/blender/blender_texture.h @@ -22,9 +22,8 @@ CCL_NAMESPACE_BEGIN -void point_density_texture_space(BL::Scene& b_scene, +void point_density_texture_space(BL::Depsgraph& b_depsgraph, BL::ShaderNodeTexPointDensity& b_point_density_node, - const int settings, float3& loc, float3& size); diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index eb7019f45bc..1b9e1911591 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -33,7 +33,7 @@ extern "C" { size_t BLI_timecode_string_from_time_simple(char *str, size_t maxlen, double time_seconds); -void BKE_image_user_frame_calc(void *iuser, int cfra, int fieldnr); +void BKE_image_user_frame_calc(void *iuser, int cfra); void BKE_image_user_file_path(void *iuser, void *ima, char *path); unsigned char *BKE_image_get_pixels_for_frame(void *image, int frame); float *BKE_image_get_float_pixels_for_frame(void *image, int frame); @@ -46,12 +46,12 @@ void python_thread_state_restore(void **python_thread_state); static inline BL::Mesh object_to_mesh(BL::BlendData& data, BL::Object& object, - BL::Scene& scene, - bool apply_modifiers, - bool render, + BL::Depsgraph& depsgraph, bool calc_undeformed, Mesh::SubdivisionType subdivision_type) { + /* TODO: make this work with copy-on-write, modifiers are already evaluated. */ +#if 0 bool subsurf_mod_show_render = false; bool subsurf_mod_show_viewport = false; @@ -64,30 +64,54 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, subsurf_mod.show_render(false); subsurf_mod.show_viewport(false); } +#endif - BL::Mesh me = data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed); + BL::Mesh mesh(PointerRNA_NULL); + if(object.type() == BL::Object::type_MESH) { + /* TODO: calc_undeformed is not used. */ + mesh = BL::Mesh(object.data()); + /* Make a copy to split faces if we use autosmooth, otherwise not needed. + * Also in edit mode do we need to make a copy, to ensure data layers like + * UV are not empty. */ + if (mesh.is_editmode() || + (mesh.use_auto_smooth() && subdivision_type == Mesh::SUBDIVISION_NONE)) + { + mesh = data.meshes.new_from_object(depsgraph, object, false, false); + } + } + else { + mesh = data.meshes.new_from_object(depsgraph, object, true, calc_undeformed); + } + +#if 0 if(subdivision_type != Mesh::SUBDIVISION_NONE) { BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1]; subsurf_mod.show_render(subsurf_mod_show_render); subsurf_mod.show_viewport(subsurf_mod_show_viewport); } +#endif - if((bool)me) { - if(me.use_auto_smooth()) { - if(subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK) { - me.calc_normals_split(); - } - else { - me.split_faces(false); - } - } - if(subdivision_type == Mesh::SUBDIVISION_NONE) { - me.calc_tessface(true); + if((bool)mesh && subdivision_type == Mesh::SUBDIVISION_NONE) { + if(mesh.use_auto_smooth()) { + mesh.split_faces(false); } + + mesh.calc_loop_triangles(); + } + + return mesh; +} + +static inline void free_object_to_mesh(BL::BlendData& data, + BL::Object& object, + BL::Mesh& mesh) +{ + /* Free mesh if we didn't just use the existing one. */ + if(object.data().ptr.data != mesh.ptr.data) { + data.meshes.remove(mesh, false, true, false); } - return me; } static inline void colorramp_to_array(BL::ColorRamp& ramp, @@ -221,14 +245,14 @@ static inline string image_user_file_path(BL::ImageUser& iuser, int cfra) { char filepath[1024]; - BKE_image_user_frame_calc(iuser.ptr.data, cfra, 0); + BKE_image_user_frame_calc(iuser.ptr.data, cfra); BKE_image_user_file_path(iuser.ptr.data, ima.ptr.data, filepath); return string(filepath); } static inline int image_user_frame_number(BL::ImageUser& iuser, int cfra) { - BKE_image_user_frame_calc(iuser.ptr.data, cfra, 0); + BKE_image_user_frame_calc(iuser.ptr.data, cfra); return iuser.frame_current(); } @@ -314,7 +338,7 @@ static inline uint get_layer(const BL::Array<bool, 20>& array) static inline uint get_layer(const BL::Array<bool, 20>& array, const BL::Array<bool, 8>& local_array, bool is_light = false, - uint scene_layers = (1 << 20) - 1) + uint view_layers = (1 << 20) - 1) { uint layer = 0; @@ -326,7 +350,7 @@ static inline uint get_layer(const BL::Array<bool, 20>& array, /* Consider light is visible if it was visible without layer * override, which matches behavior of Blender Internal. */ - if(layer & scene_layers) { + if(layer & view_layers) { for(uint i = 0; i < 8; i++) layer |= (1 << (20+i)); } |