diff options
Diffstat (limited to 'intern/cycles')
40 files changed, 3431 insertions, 3189 deletions
diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt index 2c1367a86dc..35c54fff8a4 100644 --- a/intern/cycles/app/CMakeLists.txt +++ b/intern/cycles/app/CMakeLists.txt @@ -60,6 +60,10 @@ link_directories(${OPENIMAGEIO_LIBPATH} ${TIFF_LIBPATH} ${OPENEXR_LIBPATH}) +if(WITH_OPENCOLORIO) + link_directories(${OPENCOLORIO_LIBPATH}) +endif() + add_definitions(${GL_DEFINITIONS}) include_directories(${INC}) @@ -84,7 +88,6 @@ macro(cycles_target_link_libraries target) target_link_libraries(${target} ${OPENSUBDIV_LIBRARIES}) endif() if(WITH_OPENCOLORIO) - link_directories(${OPENCOLORIO_LIBPATH}) target_link_libraries(${target} ${OPENCOLORIO_LIBRARIES}) endif() target_link_libraries( diff --git a/intern/cycles/app/io_export_cycles_xml.py b/intern/cycles/app/io_export_cycles_xml.py index 816536c0071..437a504d014 100644 --- a/intern/cycles/app/io_export_cycles_xml.py +++ b/intern/cycles/app/io_export_cycles_xml.py @@ -66,8 +66,7 @@ class RenderButtonsPanel(): @classmethod def poll(self, context): - rd = context.scene.render - return rd.engine == 'CYCLES' + return context.engine == 'CYCLES' class PHYSICS_PT_fluid_export(RenderButtonsPanel, bpy.types.Panel): 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 23239ee4352..0b74150f981 100644 --- a/intern/cycles/blender/addon/engine.py +++ b/intern/cycles/blender/addon/engine.py @@ -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() 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(), userpref, 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(): diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index d986ba8c7a8..0d68138ffb4 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,586 @@ 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 render 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 + ) - 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, + ) - 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, + ) - 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 + ) - 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 + ) - 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,6 +745,98 @@ 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 @@ -751,103 +847,53 @@ class CyclesCameraSettings(bpy.types.PropertyGroup): 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='DISPLACEMENT', + ) + @classmethod def register(cls): bpy.types.Material.cycles = PointerProperty( @@ -855,95 +901,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='DISPLACEMENT', - ) @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 +1005,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 +1012,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 +1058,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 +1091,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 Geometry 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 footange 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 +1164,54 @@ 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, + ) + 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, + ) + 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 +1219,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): @@ -1214,221 +1228,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 +1416,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: @@ -1540,13 +1512,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) @@ -1556,13 +1527,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..6372a2f5eba 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -17,6 +17,8 @@ # <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 ( @@ -26,20 +28,20 @@ from bpy.types import ( ) -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,8 +52,7 @@ 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 def get_device_type(context): @@ -129,21 +130,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 +154,295 @@ 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 + + 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") - sub.prop(cscene, "subsurface_samples", text="Subsurface") - sub.prop(cscene, "volume_samples", text="Volume") + 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: - layout.separator() - layout.row().prop(cscene, "use_layer_samples") - break +class CYCLES_RENDER_PT_sampling_total(CyclesButtonsPanel, Panel): + bl_label = "Total Samples" + bl_parent_id = "CYCLES_RENDER_PT_sampling" - draw_samples_info(layout, context) + @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 + cscene = scene.cycles + 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 + cscene = scene.cycles + 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 + ccscene = scene.cycles_curves + + 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 +456,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 +467,30 @@ 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 + cscene = scene.cycles + 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 +502,67 @@ 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 + rd = context.scene.render 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 +570,420 @@ 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" + + 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 - sub.prop(rd, "tile_x", text="X") + 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 + rd = scene.render + 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") - row = col.row() - row.active = not cscene.debug_use_spatial_splits and not cscene.use_bvh_embree - row.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" + + 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() - 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_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 - - split = layout.split() + 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") - 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") + layout.separator() - 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) + 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.separator() - col.prop(rl, "use_pass_emit", text="Emission") - col.prop(rl, "use_pass_environment") + layout.separator() - 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") + layout.prop(view_layer, "pass_alpha_threshold") -class CYCLES_RENDER_PT_views(CyclesButtonsPanel, Panel): - bl_label = "Views" - bl_context = "render_layer" - bl_options = {'DEFAULT_CLOSED'} - def draw_header(self, context): - rd = context.scene.render - self.layout.prop(rd, "use_multiview", text="") +class CYCLES_RENDER_PT_passes_light(CyclesButtonsPanel, Panel): + bl_label = "Light" + 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 - rv = rd.views.active + 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) - layout.active = rd.use_multiview - basic_stereo = (rd.views_format == 'STEREO_3D') + 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") - row = layout.row() - row.prop(rd, "views_format", expand=True) - if basic_stereo: - row = layout.row() - row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "stereo_views", rd.views, "active_index", rows=2) +class CYCLES_RENDER_PT_passes_crypto(CyclesButtonsPanel, Panel): + bl_label = "Cryptomatte" + bl_context = "view_layer" + bl_parent_id = "CYCLES_RENDER_PT_passes" - row = layout.row() - row.label(text="File Suffix:") - row.prop(rv, "file_suffix", text="") + def draw(self, context): + import _cycles - else: - row = layout.row() - row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "views", rd.views, "active_index", rows=2) + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False - col = row.column(align=True) - col.operator("scene.render_view_add", icon='ZOOMIN', text="") - col.operator("scene.render_view_remove", icon='ZOOMOUT', text="") + cycles_view_layer = context.view_layer.cycles - row = layout.row() - row.label(text="Camera Suffix:") - row.prop(rv, "camera_suffix", text="") + 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) + + layout.prop(cycles_view_layer, "pass_crypto_depth", text="Levels") + + row = layout.row(align=True) + row.active = use_cpu(context) + row.prop(cycles_view_layer, "pass_crypto_accurate", text="Accurate Mode") + + +class CYCLES_RENDER_PT_passes_debug(CyclesButtonsPanel, Panel): + bl_label = "Debug" + bl_context = "view_layer" + bl_parent_id = "CYCLES_RENDER_PT_passes" + + @classmethod + def poll(cls, context): + import _cycles + return _cycles.with_cycles_debug + + 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 + cscene = scene.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_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,6 +996,7 @@ 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 @@ -724,37 +1005,63 @@ class CYCLES_CAMERA_PT_dof(CyclesButtonsPanel, Panel): 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 + dof_options = cam.gpu_dof + + 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 +1071,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 +1095,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 +1112,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 +1138,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.dupli_type == 'COLLECTION' and ob.dupli_group: return True # TODO(sergey): More duplicator types here? return False @@ -872,11 +1182,22 @@ 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.dupli_type == 'COLLECTION' and ob.dupli_group))) + + 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 @@ -884,79 +1205,82 @@ class CYCLES_OBJECT_PT_cycles_settings(CyclesButtonsPanel, Panel): 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() + + 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" - 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") - sub = row.row() - sub.active = scene.render.use_simplify and cscene.use_distance_cull - sub.prop(cob, "use_distance_cull") + 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 + + 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") + + 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 +1288,130 @@ 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 + + col = layout.column() - if lamp.type in {'POINT', 'SUN', 'SPOT'}: - col.prop(lamp, "shadow_soft_size", text="Size") - elif lamp.type == 'AREA': - col.prop(lamp, "shape", text="") + 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") + if light.type == 'HEMI': + layout.label(text="Not supported, interpreted as sun light") -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 +1441,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 +1464,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 +1476,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 +1498,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 +1551,71 @@ 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 - split = layout.split() + col = layout.column() - col = split.column() - col.label(text="Surface:") +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 + + 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,6 +1686,7 @@ class CYCLES_MATERIAL_PT_displacement(CyclesButtonsPanel, Panel): class CYCLES_MATERIAL_PT_settings(CyclesButtonsPanel, Panel): bl_label = "Settings" bl_context = "material" + bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): @@ -1327,221 +1694,61 @@ class CYCLES_MATERIAL_PT_settings(CyclesButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False 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") + layout.prop(mat, "pass_index") - 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" +class CYCLES_MATERIAL_PT_settings_surface(CyclesButtonsPanel, Panel): + bl_label = "Surface" + bl_parent_id = "CYCLES_MATERIAL_PT_settings" 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 - layout = self.layout - split = layout.split() - - col = split.column(align=True) - col.label("Color:") - col.prop(mat, "diffuse_color", text="") - col.prop(mat, "alpha") + layout.use_property_split = True + layout.use_property_decorate = False - 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'} - - 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() - - 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) - - def draw(self, context): - layout = self.layout - - 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" - - @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) - - 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="") - - -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) - - def draw(self, context): - layout = self.layout - - 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() + mat = context.material + cmat = mat.cycles - layout.prop(mapping, "use_color_ramp", text="Ramp") - if mapping.use_color_ramp: - layout.template_color_ramp(mapping, "color_ramp", expand=True) + 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") -class CYCLES_PARTICLE_PT_textures(CyclesButtonsPanel, Panel): - bl_label = "Textures" - bl_context = "particle" - bl_options = {'DEFAULT_CLOSED'} +class CYCLES_MATERIAL_PT_settings_volume(CyclesButtonsPanel, Panel): + bl_label = "Volume" + bl_parent_id = "CYCLES_MATERIAL_PT_settings" + bl_context = "material" @classmethod def poll(cls, context): - psys = context.particle_system - return psys and CyclesButtonsPanel.poll(context) + return context.material and CyclesButtonsPanel.poll(context) def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False - 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="") + mat = context.material + cmat = mat.cycles - 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") + 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") class CYCLES_RENDER_PT_bake(CyclesButtonsPanel, Panel): @@ -1552,69 +1759,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") + col = layout.column() + col.prop(rd, "bake_margin") + col.prop(rd, "use_bake_clear") - 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="") + if rd.bake_type == 'DISPLACEMENT': + col.prop(rd, "use_bake_lores_mesh") - 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) + col.operator("object.bake_image", icon='RENDER_STILL') - split = col.split() - split.active = cbk.use_pass_direct or cbk.use_pass_indirect + 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_diffuse") - col.prop(cbk, "use_pass_glossy") - col.prop(cbk, "use_pass_transmission") + layout.separator() - col = split.column() - col.prop(cbk, "use_pass_subsurface") - col.prop(cbk, "use_pass_ambient_occlusion") - col.prop(cbk, "use_pass_emit") + col = layout.column() + col.prop(cbk, "margin") + col.prop(cbk, "use_clear", text="Clear Image") - 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.separator() - layout.separator() + 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="Cage Object") + else: + sub.prop(cbk, "cage_extrusion", text="Ray Distance") - split = layout.split() + layout.separator() - col = split.column() - col.prop(cbk, "margin") - col.prop(cbk, "use_clear") - - 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 +1857,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 +1870,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 +1890,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 +1945,79 @@ 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() - col.prop(cscene, "use_camera_cull") - row = col.row() - row.active = cscene.use_camera_cull - row.prop(cscene, "camera_cull_margin") +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'} - col = split.column() - col.prop(cscene, "use_distance_cull") - row = col.row() - row.active = cscene.use_distance_cull - row.prop(cscene, "distance_cull_margin", text="Distance") + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False - split = layout.split() - col = split.column() - col.prop(cscene, "ao_bounces") + scene = context.scene + rd = scene.render + cscene = scene.cycles - col = split.column() - col.prop(cscene, "ao_bounces_render") + layout.active = rd.use_simplify + + col = layout.column() + col.prop(cscene, "use_camera_cull") + sub = col.column() + sub.active = cscene.use_camera_cull + sub.prop(cscene, "camera_cull_margin") + + col = layout.column() + col.prop(cscene, "use_distance_cull") + sub = col.column() + sub.active = cscene.use_distance_cull + sub.prop(cscene, "distance_cull_margin", text="Distance") 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 +2025,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 +2046,54 @@ 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_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 +2101,24 @@ 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, ) 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 +2131,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 f14fe9abc3d..0564f2a7456 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,7 +275,7 @@ 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) @@ -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 diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index 5a447a347a3..fc86094949f 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; @@ -232,7 +232,7 @@ static void blender_camera_from_object(BlenderCamera *bcam, bcam->motion_steps = object_motion_steps(b_ob, b_ob); } else { - /* from lamp not implemented yet */ + /* from light not implemented yet */ } } diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index 5fd3455061d..5e4522af6e1 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -134,9 +134,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) @@ -145,22 +145,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) @@ -229,7 +227,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) @@ -249,11 +247,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); @@ -288,7 +286,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) @@ -308,11 +306,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); @@ -326,18 +324,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) { @@ -920,9 +906,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 */ @@ -985,10 +968,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; @@ -1022,10 +1005,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()); @@ -1066,9 +1049,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..b97c250adf6 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; @@ -834,14 +757,10 @@ static void create_mesh(Scene *scene, } 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 { for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { @@ -869,7 +788,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) @@ -890,19 +809,21 @@ 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; + int ti = 0; + + for(b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t, ++ti) { + 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,25 +834,8 @@ 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); + nverts[ti] = 3; } } else { @@ -957,13 +861,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 +893,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,50 +975,35 @@ 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) { - /* 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; /* find shader indices */ vector<Shader*> used_shaders; BL::Object::material_slots_iterator slot; for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) { - if(material_override) { - find_shader(material_override, used_shaders, scene->default_surface); - } - else { - BL::ID b_material(slot->material()); - find_shader(b_material, used_shaders, scene->default_surface); - } + BL::ID b_material(slot->material()); + find_shader(b_material, used_shaders, scene->default_surface); } if(used_shaders.size() == 0) { - if(material_override) - find_shader(material_override, used_shaders, scene->default_surface); - else - used_shaders.push_back(scene->default_surface); + used_shaders.push_back(scene->default_surface); } /* 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; @@ -1188,14 +1077,13 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, - b_scene, - true, - !preview, + b_depsgraph, + false, need_undeformed, mesh->subdivision_type); if(b_mesh) { - if(render_layer.use_surfaces && !hide_tris) { + if(view_layer.use_surfaces && !hide_tris) { if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE) create_subd_mesh(scene, mesh, b_ob, b_mesh, used_shaders, dicing_rate, max_subdivisions); @@ -1205,13 +1093,9 @@ 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) + if(view_layer.use_hair && 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); } @@ -1233,7 +1117,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 +1161,8 @@ 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, false, Mesh::SUBDIVISION_NONE); } diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index a05c982b367..dcadc735b8e 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,59 @@ 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: { + case BL::Light::type_HEMI: { 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(); + case BL::Light::type_SUN: { + BL::SunLight b_sun_light(b_light); + light->size = b_sun_light.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 +192,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 +290,46 @@ 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, 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 +346,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 +373,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 +389,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 +402,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, hide_tris); /* special case not tracked by object update flags */ @@ -444,10 +484,13 @@ 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(); + + /* Sync possible particle data. */ + sync_dupli_particle(b_ob, b_instance, object); } else { object->dupli_generated = make_float3(0.0f, 0.0f, 0.0f); @@ -476,12 +519,14 @@ static bool object_render_hide_original(BL::Object::type_enum ob_type, static bool object_render_hide(BL::Object& b_ob, bool top_level, bool parent_hide, - bool& hide_triangles) + bool& hide_triangles, + BL::Depsgraph::mode_enum depsgraph_mode) { /* check if we should render or hide particle emitter */ BL::Object::particle_systems_iterator b_psys; bool hair_present = false; + bool has_particles = false; bool show_emitter = false; bool hide_emitter = false; bool hide_as_dupli_parent = false; @@ -491,20 +536,22 @@ static bool object_render_hide(BL::Object& b_ob, 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; + has_particles = true; } - if(show_emitter) - hide_emitter = false; + /* Both mode_PREVIEW and mode_VIEWPORT are treated the same here.*/ + const bool show_duplicator = depsgraph_mode == BL::Depsgraph::mode_RENDER + ? b_ob.show_duplicator_for_render() + : b_ob.show_duplicator_for_viewport(); - /* 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) + if(has_particles) { + show_emitter = show_duplicator; + hide_emitter = !show_emitter; + } else if(b_ob.is_duplicator()) { + if(top_level || show_duplicator) { hide_as_dupli_parent = true; + } + } /* hide original object for duplis */ BL::Object parent = b_ob.parent(); @@ -533,19 +580,11 @@ static bool object_render_hide(BL::Object& b_ob, } } -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())); -} - /* 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 +603,40 @@ 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(); + BL::Depsgraph::mode_enum depsgraph_mode = b_depsgraph.mode(); - /* 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 */ + bool hide_tris; + + if(!object_render_hide(b_ob, true, true, hide_tris, depsgraph_mode)) { + /* object itself */ + sync_object(b_depsgraph, + b_view_layer, + b_instance, + motion_time, + hide_tris, + culling, + &use_portal); + } + + cancel = progress.get_cancel(); } progress.set_sync_status(""); @@ -681,6 +660,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 +690,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 +698,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 +737,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 997176f9d44..2a0a7895763 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; @@ -225,10 +225,6 @@ static PyObject *create_func(PyObject * /*self*/, PyObject *args) 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); @@ -759,10 +763,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, ""}, diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 75c7dcee05e..b639dcc4b00 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -55,21 +55,23 @@ bool BlenderSession::print_render_stats = false; BlenderSession::BlenderSession(BL::RenderEngine& b_engine, BL::UserPreferences& 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; @@ -79,23 +81,25 @@ BlenderSession::BlenderSession(BL::RenderEngine& b_engine, BlenderSession::BlenderSession(BL::RenderEngine& b_engine, BL::UserPreferences& 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; @@ -144,26 +148,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, ""); } @@ -176,18 +173,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) @@ -195,11 +214,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; } @@ -213,16 +229,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, @@ -382,8 +394,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); @@ -393,126 +407,91 @@ 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); - - for(r.layers.begin(b_layer_iter); b_layer_iter != r.layers.end(); ++b_layer_iter) { - b_rlay_name = b_layer_iter->name(); + const bool is_single_layer = (b_scene.view_layers.length() == 1); - /* 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); - - /* 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::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 use_denoising = get_boolean(crl, "use_denoising"); - bool denoising_passes = use_denoising || get_boolean(crl, "denoising_store_passes"); - - session->tile_manager.schedule_denoising = use_denoising; - buffer_params.denoising_data_pass = denoising_passes; - buffer_params.denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES); - - session->params.use_denoising = use_denoising; - session->params.denoising_passes = 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->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); - } - - /* Update number of samples per layer. */ - int samples = sync->get_layer_samples(); - bool bound_samples = sync->get_layer_bound_samples(); - int effective_layer_samples; + /* 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 use_denoising = get_boolean(crl, "use_denoising"); + bool denoising_passes = use_denoising || get_boolean(crl, "denoising_store_passes"); + + session->tile_manager.schedule_denoising = use_denoising; + buffer_params.denoising_data_pass = denoising_passes; + buffer_params.denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES); + + session->params.use_denoising = use_denoising; + session->params.denoising_passes = 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; + 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); - if(samples != 0 && (!bound_samples || (samples < session_params.samples))) - effective_layer_samples = samples; - else - effective_layer_samples = session_params.samples; + BL::RenderResult::views_iterator b_view_iter; + 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(); - /* Update tile manager if we're doing resumable render. */ - update_resumable_tile_manager(effective_layer_samples); + /* set the current view */ + b_engine.active_view_set(b_rview_name.c_str()); - /* Update session itself. */ - session->reset(buffer_params, 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(); + + /* 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(); + int effective_layer_samples = session_params.samples; - if(session->progress.get_cancel()) - break; - } + /* TODO: Update number of samples per layer. */ +#if 0 + if(samples != 0 && (!bound_samples || (samples < session_params.samples))) + effective_layer_samples = samples; +#endif - 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; @@ -524,6 +503,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; @@ -533,6 +538,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 */ @@ -541,6 +548,7 @@ void BlenderSession::render() delete sync; sync = NULL; +#endif } static void populate_bake_data(BakeData *data, const @@ -589,7 +597,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, @@ -598,6 +607,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 @@ -630,11 +641,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; @@ -768,7 +780,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) @@ -794,7 +806,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) { @@ -809,19 +821,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(); @@ -1329,6 +1345,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); @@ -1336,14 +1355,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, diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h index 540fa6a8a84..c83d3ee9aa3 100644 --- a/intern/cycles/blender/blender_session.h +++ b/intern/cycles/blender/blender_session.h @@ -37,12 +37,11 @@ public: BlenderSession(BL::RenderEngine& b_engine, BL::UserPreferences& b_userpref, BL::BlendData& b_data, - BL::Scene& b_scene); + bool preview_osl); BlenderSession(BL::RenderEngine& b_engine, BL::UserPreferences& 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); @@ -105,6 +105,7 @@ public: BL::UserPreferences b_userpref; BL::BlendData b_data; BL::RenderSettings b_render; + BL::Depsgraph b_depsgraph; BL::Scene b_scene; BL::SpaceView3D b_v3d; BL::RegionView3D b_rv3d; @@ -117,6 +118,7 @@ public: double last_status_time; int width, height; + bool preview_osl; double start_resize_time; void *python_thread_state; @@ -166,6 +168,7 @@ 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); diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 3eefb92f6af..439f6bdd32e 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); @@ -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 832847c179f..33c45de8d70 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_dirty_geometry(); + + if (!b_update->is_dirty_transform()) { + object_map.set_recalc(b_ob); + light_map.set_recalc(b_ob); + } + + 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(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(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,14 @@ 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; - 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.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(); } /* Images */ @@ -555,7 +487,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; @@ -578,7 +510,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 use_denoising = get_boolean(crp, "use_denoising"); bool store_denoising_passes = get_boolean(crp, "denoising_store_passes"); scene->film->denoising_flags = 0; @@ -593,52 +525,52 @@ 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(store_denoising_passes) { - b_engine.add_pass("Denoising Normal", 3, "XYZ", b_srlay.name().c_str()); - b_engine.add_pass("Denoising Normal Variance", 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 Albedo Variance", 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 Depth Variance", 1, "Z", b_srlay.name().c_str()); - b_engine.add_pass("Denoising Shadow A", 3, "XYV", b_srlay.name().c_str()); - b_engine.add_pass("Denoising Shadow B", 3, "XYV", b_srlay.name().c_str()); - b_engine.add_pass("Denoising Image Variance", 3, "RGB", b_srlay.name().c_str()); + b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str()); + b_engine.add_pass("Denoising Normal Variance", 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 Albedo Variance", 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 Depth Variance", 1, "Z", b_view_layer.name().c_str()); + b_engine.add_pass("Denoising Shadow A", 3, "XYV", b_view_layer.name().c_str()); + b_engine.add_pass("Denoising Shadow B", 3, "XYV", b_view_layer.name().c_str()); + b_engine.add_pass("Denoising Image Variance", 3, "RGB", 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); } @@ -650,7 +582,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); @@ -658,7 +590,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); @@ -666,7 +598,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); @@ -678,6 +610,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, @@ -907,13 +863,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; } @@ -941,17 +898,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 eb84bedb118..d2b362be24d 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,8 +78,6 @@ 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; } /* get parameters */ static SceneParams get_scene_params(BL::Scene& b_scene, @@ -99,31 +98,34 @@ 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 hide_tris); 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, BlenderObjectCulling& culling, @@ -131,11 +133,13 @@ private: 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 +149,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 +189,19 @@ private: struct RenderLayerInfo { RenderLayerInfo() - : scene_layer(0), layer(0), - holdout_layer(0), exclude_layer(0), - material_override(PointerRNA_NULL), - use_background_shader(true), + : use_background_shader(true), use_background_ao(true), use_surfaces(true), - use_hair(true), - use_viewport_visibility(false), - samples(0), bound_samples(false) + use_hair(true) {} string name; - uint scene_layer; - uint layer; - uint holdout_layer; - uint exclude_layer; - BL::Material material_override; + uint view_layer; 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 09ae9bea313..02e3c292349 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -32,7 +32,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); @@ -45,15 +45,15 @@ 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, + BL::Depsgraph& depsgraph, bool apply_modifiers, - bool render, bool calc_undeformed, Mesh::SubdivisionType subdivision_type) { bool subsurf_mod_show_render = false; bool subsurf_mod_show_viewport = false; + /* TODO: make this work with copy-on-write, modifiers are already evaluated. */ if(subdivision_type != Mesh::SUBDIVISION_NONE) { BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1]; @@ -64,7 +64,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, subsurf_mod.show_viewport(false); } - BL::Mesh me = data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed); + BL::Mesh me = data.meshes.new_from_object(depsgraph, object, apply_modifiers, calc_undeformed); if(subdivision_type != Mesh::SUBDIVISION_NONE) { BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1]; @@ -83,7 +83,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, } } if(subdivision_type == Mesh::SUBDIVISION_NONE) { - me.calc_tessface(true); + me.calc_loop_triangles(); } } return me; @@ -220,14 +220,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(); } @@ -313,7 +313,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; @@ -325,7 +325,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)); } diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index 7e20bb449c3..428cd4158bc 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -78,132 +78,275 @@ std::ostream& operator <<(std::ostream &os, Device::~Device() { - if(!background && vertex_buffer != 0) { - glDeleteBuffers(1, &vertex_buffer); + if(!background) { + if(vertex_buffer != 0) { + glDeleteBuffers(1, &vertex_buffer); + } + if(fallback_shader_program != 0) { + glDeleteProgram(fallback_shader_program); + } } } -void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int dx, int dy, int width, int height, bool transparent, - const DeviceDrawParams &draw_params) +/* TODO move shaders to standalone .glsl file. */ +const char *FALLBACK_VERTEX_SHADER = +"#version 330\n" +"uniform vec2 fullscreen;\n" +"in vec2 texCoord;\n" +"in vec2 pos;\n" +"out vec2 texCoord_interp;\n" +"\n" +"vec2 normalize_coordinates()\n" +"{\n" +" return (vec2(2.0) * (pos / fullscreen)) - vec2(1.0);\n" +"}\n" +"\n" +"void main()\n" +"{\n" +" gl_Position = vec4(normalize_coordinates(), 0.0, 1.0);\n" +" texCoord_interp = texCoord;\n" +"}\n\0"; + +const char *FALLBACK_FRAGMENT_SHADER = +"#version 330\n" +"uniform sampler2D image_texture;\n" +"in vec2 texCoord_interp;\n" +"out vec4 fragColor;\n" +"\n" +"void main()\n" +"{\n" +" fragColor = texture(image_texture, texCoord_interp);\n" +"}\n\0"; + +static void shader_print_errors(const char *task, const char *log, const char *code) { - assert(rgba.type == MEM_PIXELS); + LOG(ERROR) << "Shader: " << task << " error:"; + LOG(ERROR) << "===== shader string ===="; - mem_copy_from(rgba, y, w, h, rgba.memory_elements_size(1)); + stringstream stream(code); + string partial; - if(transparent) { - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + int line = 1; + while(getline(stream, partial, '\n')) { + if(line < 10) { + LOG(ERROR) << " " << line << " " << partial; + } + else { + LOG(ERROR) << line << " " << partial; + } + line++; } + LOG(ERROR) << log; +} - glColor3f(1.0f, 1.0f, 1.0f); +static int bind_fallback_shader(void) +{ + GLint status; + GLchar log[5000]; + GLsizei length = 0; + GLuint program = 0; - if(rgba.data_type == TYPE_HALF) { - /* for multi devices, this assumes the inefficient method that we allocate - * all pixels on the device even though we only render to a subset */ - GLhalf *host_pointer = (GLhalf*)rgba.host_pointer; - float vbuffer[16], *basep; - float *vp = NULL; - - host_pointer += 4*y*w; - - /* draw half float texture, GLSL shader for display transform assumed to be bound */ - GLuint texid; - glGenTextures(1, &texid); - glBindTexture(GL_TEXTURE_2D, texid); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, w, h, 0, GL_RGBA, GL_HALF_FLOAT, host_pointer); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glEnable(GL_TEXTURE_2D); - - if(draw_params.bind_display_space_shader_cb) { - draw_params.bind_display_space_shader_cb(); + struct Shader { + const char *source; + GLenum type; + } shaders[2] = { + {FALLBACK_VERTEX_SHADER, GL_VERTEX_SHADER}, + {FALLBACK_FRAGMENT_SHADER, GL_FRAGMENT_SHADER} + }; + + program = glCreateProgram(); + + for(int i = 0; i < 2; i++) { + GLuint shader = glCreateShader(shaders[i].type); + + string source_str = shaders[i].source; + const char *c_str = source_str.c_str(); + + glShaderSource(shader, 1, &c_str, NULL); + glCompileShader(shader); + + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + + if(!status) { + glGetShaderInfoLog(shader, sizeof(log), &length, log); + shader_print_errors("compile", log, c_str); + return 0; } - if(GLEW_VERSION_1_5) { - if(!vertex_buffer) - glGenBuffers(1, &vertex_buffer); + glAttachShader(program, shader); + } + + /* Link output. */ + glBindFragDataLocation(program, 0, "fragColor"); - glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); - /* invalidate old contents - avoids stalling if buffer is still waiting in queue to be rendered */ - glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW); + /* Link and error check. */ + glLinkProgram(program); + + glGetProgramiv(program, GL_LINK_STATUS, &status); + if(!status) { + glGetShaderInfoLog(program, sizeof(log), &length, log); + shader_print_errors("linking", log, FALLBACK_VERTEX_SHADER); + shader_print_errors("linking", log, FALLBACK_FRAGMENT_SHADER); + return 0; + } + + return program; +} + +bool Device::bind_fallback_display_space_shader(const float width, const float height) +{ + if(fallback_status == FALLBACK_SHADER_STATUS_ERROR) { + return false; + } - vp = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); + if(fallback_status == FALLBACK_SHADER_STATUS_NONE) { + fallback_shader_program = bind_fallback_shader(); + fallback_status = FALLBACK_SHADER_STATUS_ERROR; - basep = NULL; + if (fallback_shader_program == 0) { + return false; } - else { - basep = vbuffer; - vp = vbuffer; + + glUseProgram(fallback_shader_program); + image_texture_location = glGetUniformLocation(fallback_shader_program, "image_texture"); + if(image_texture_location < 0) { + LOG(ERROR) << "Shader doesn't containt the 'image_texture' uniform."; + return false; } - if(vp) { - /* texture coordinate - vertex pair */ - vp[0] = 0.0f; - vp[1] = 0.0f; - vp[2] = dx; - vp[3] = dy; - - vp[4] = 1.0f; - vp[5] = 0.0f; - vp[6] = (float)width + dx; - vp[7] = dy; - - vp[8] = 1.0f; - vp[9] = 1.0f; - vp[10] = (float)width + dx; - vp[11] = (float)height + dy; - - vp[12] = 0.0f; - vp[13] = 1.0f; - vp[14] = dx; - vp[15] = (float)height + dy; - - if(vertex_buffer) - glUnmapBuffer(GL_ARRAY_BUFFER); + fullscreen_location = glGetUniformLocation(fallback_shader_program, "fullscreen"); + if(fullscreen_location < 0) { + LOG(ERROR) << "Shader doesn't containt the 'fullscreen' uniform."; + return false; } - glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), basep); - glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), ((char *)basep) + 2 * sizeof(float)); + fallback_status = FALLBACK_SHADER_STATUS_SUCCESS; + } - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + /* Run this every time. */ + glUseProgram(fallback_shader_program); + glUniform1i(image_texture_location, 0); + glUniform2f(fullscreen_location, width, height); + return true; +} - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +void Device::draw_pixels( + device_memory& rgba, int y, + int w, int h, int width, int height, + int dx, int dy, int dw, int dh, + bool transparent, const DeviceDrawParams &draw_params) +{ + const bool use_fallback_shader = (draw_params.bind_display_space_shader_cb == NULL); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + assert(rgba.type == MEM_PIXELS); + mem_copy_from(rgba, y, w, h, rgba.memory_elements_size(1)); - if(vertex_buffer) { - glBindBuffer(GL_ARRAY_BUFFER, 0); - } + GLuint texid; + glGenTextures(1, &texid); + glBindTexture(GL_TEXTURE_2D, texid); - if(draw_params.unbind_display_space_shader_cb) { - draw_params.unbind_display_space_shader_cb(); - } + if(rgba.data_type == TYPE_HALF) { + GLhalf *data_pointer = (GLhalf*)rgba.host_pointer; + data_pointer += 4 * y * w; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, w, h, 0, GL_RGBA, GL_HALF_FLOAT, data_pointer); + } + else { + uint8_t *data_pointer = (uint8_t*)rgba.host_pointer; + data_pointer += 4 * y * w; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data_pointer); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + if(transparent) { + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } - glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); - glDeleteTextures(1, &texid); + GLint shader_program; + if(use_fallback_shader) { + if (!bind_fallback_display_space_shader(dw, dh)) { + return; + } + shader_program = fallback_shader_program; } else { - /* fallback for old graphics cards that don't support GLSL, half float, - * and non-power-of-two textures */ - glPixelZoom((float)width/(float)w, (float)height/(float)h); - glRasterPos2f(dx, dy); + draw_params.bind_display_space_shader_cb(); + glGetIntegerv(GL_CURRENT_PROGRAM, &shader_program); + } + + if(!vertex_buffer) { + glGenBuffers(1, &vertex_buffer); + } + + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); + /* invalidate old contents - avoids stalling if buffer is still waiting in queue to be rendered */ + glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW); + + float *vpointer = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); - uint8_t *pixels = (uint8_t*)rgba.host_pointer; + if(vpointer) { + /* texture coordinate - vertex pair */ + vpointer[0] = 0.0f; + vpointer[1] = 0.0f; + vpointer[2] = dx; + vpointer[3] = dy; - pixels += 4*y*w; + vpointer[4] = 1.0f; + vpointer[5] = 0.0f; + vpointer[6] = (float)width + dx; + vpointer[7] = dy; - glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + vpointer[8] = 1.0f; + vpointer[9] = 1.0f; + vpointer[10] = (float)width + dx; + vpointer[11] = (float)height + dy; - glRasterPos2f(0.0f, 0.0f); - glPixelZoom(1.0f, 1.0f); + vpointer[12] = 0.0f; + vpointer[13] = 1.0f; + vpointer[14] = dx; + vpointer[15] = (float)height + dy; + + if(vertex_buffer) { + glUnmapBuffer(GL_ARRAY_BUFFER); + } + } + + GLuint vertex_array_object; + GLuint position_attribute, texcoord_attribute; + + glGenVertexArrays(1, &vertex_array_object); + glBindVertexArray(vertex_array_object); + + texcoord_attribute = glGetAttribLocation(shader_program, "texCoord"); + position_attribute = glGetAttribLocation(shader_program, "pos"); + + glEnableVertexAttribArray(texcoord_attribute); + glEnableVertexAttribArray(position_attribute); + + glVertexAttribPointer(texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)0); + glVertexAttribPointer(position_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)(sizeof(float) * 2)); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + if(vertex_buffer) { + glBindBuffer(GL_ARRAY_BUFFER, 0); } - if(transparent) + if(use_fallback_shader) { + glUseProgram(0); + } + else { + draw_params.unbind_display_space_shader_cb(); + } + + glBindTexture(GL_TEXTURE_2D, 0); + glDeleteTextures(1, &texid); + + if(transparent) { glDisable(GL_BLEND); + } } Device *Device::create(DeviceInfo& info, Stats &stats, bool background) diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 54a3ae1fe9f..b09843e9f12 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -247,13 +247,26 @@ struct DeviceDrawParams { class Device { friend class device_sub_ptr; protected: - Device(DeviceInfo& info_, Stats &stats_, bool background) : background(background), vertex_buffer(0), info(info_), stats(stats_) {} + enum { + FALLBACK_SHADER_STATUS_NONE = 0, + FALLBACK_SHADER_STATUS_ERROR, + FALLBACK_SHADER_STATUS_SUCCESS, + }; + + Device(DeviceInfo& info_, Stats &stats_, bool background) : background(background), + vertex_buffer(0), + fallback_status(FALLBACK_SHADER_STATUS_NONE), fallback_shader_program(0), + info(info_), stats(stats_) {} bool background; string error_msg; /* used for real time display */ unsigned int vertex_buffer; + int fallback_status, fallback_shader_program; + int image_texture_location, fullscreen_location; + + bool bind_fallback_display_space_shader(const float width, const float height); virtual device_ptr mem_alloc_sub_ptr(device_memory& /*mem*/, int /*offset*/, int /*size*/) { @@ -305,9 +318,10 @@ public: virtual void task_cancel() = 0; /* opengl drawing */ - virtual void draw_pixels(device_memory& mem, int y, int w, int h, - int dx, int dy, int width, int height, bool transparent, - const DeviceDrawParams &draw_params); + virtual void draw_pixels(device_memory& mem, int y, + int w, int h, int width, int height, + int dx, int dy, int dw, int dh, + bool transparent, const DeviceDrawParams &draw_params); #ifdef WITH_NETWORK /* networking */ diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index f0e58f22ad4..1c2d35061cc 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -1864,7 +1864,7 @@ public: glGenTextures(1, &pmem.cuTexId); glBindTexture(GL_TEXTURE_2D, pmem.cuTexId); if(mem.data_type == TYPE_HALF) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, pmem.w, pmem.h, 0, GL_RGBA, GL_HALF_FLOAT, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, pmem.w, pmem.h, 0, GL_RGBA, GL_HALF_FLOAT, NULL); else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, pmem.w, pmem.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -1924,12 +1924,16 @@ public: } } - void draw_pixels(device_memory& mem, int y, int w, int h, int dx, int dy, int width, int height, bool transparent, + void draw_pixels( + device_memory& mem, int y, + int w, int h, int width, int height, + int dx, int dy, int dw, int dh, bool transparent, const DeviceDrawParams &draw_params) { assert(mem.type == MEM_PIXELS); if(!background) { + const bool use_fallback_shader = (draw_params.bind_display_space_shader_cb == NULL); PixelMem pmem = pixel_mem_map[mem.device_pointer]; float *vpointer; @@ -1946,27 +1950,34 @@ public: glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO); glBindTexture(GL_TEXTURE_2D, pmem.cuTexId); - if(mem.data_type == TYPE_HALF) + if(mem.data_type == TYPE_HALF) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_HALF_FLOAT, (void*)offset); - else + } + else { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)offset); + } glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - glEnable(GL_TEXTURE_2D); - if(transparent) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } - glColor3f(1.0f, 1.0f, 1.0f); - - if(draw_params.bind_display_space_shader_cb) { + GLint shader_program; + if(use_fallback_shader) { + if(!bind_fallback_display_space_shader(dw, dh)) { + return; + } + shader_program = fallback_shader_program; + } + else { draw_params.bind_display_space_shader_cb(); + glGetIntegerv(GL_CURRENT_PROGRAM, &shader_program); } - if(!vertex_buffer) + if(!vertex_buffer) { glGenBuffers(1, &vertex_buffer); + } glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); /* invalidate old contents - avoids stalling if buffer is still waiting in queue to be rendered */ @@ -1999,33 +2010,40 @@ public: glUnmapBuffer(GL_ARRAY_BUFFER); } - glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), 0); - glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), (char *)NULL + 2 * sizeof(float)); + GLuint vertex_array_object; + GLuint position_attribute, texcoord_attribute; - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glGenVertexArrays(1, &vertex_array_object); + glBindVertexArray(vertex_array_object); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + texcoord_attribute = glGetAttribLocation(shader_program, "texCoord"); + position_attribute = glGetAttribLocation(shader_program, "pos"); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + glEnableVertexAttribArray(texcoord_attribute); + glEnableVertexAttribArray(position_attribute); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glVertexAttribPointer(texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)0); + glVertexAttribPointer(position_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)(sizeof(float) * 2)); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - if(draw_params.unbind_display_space_shader_cb) { + if(use_fallback_shader) { + glUseProgram(0); + } + else { draw_params.unbind_display_space_shader_cb(); } - if(transparent) + if(transparent) { glDisable(GL_BLEND); + } glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); return; } - Device::draw_pixels(mem, y, w, h, dx, dy, width, height, transparent, draw_params); + Device::draw_pixels(mem, y, w, h, width, height, dx, dy, dw, dh, transparent, draw_params); } void thread_run(DeviceTask *task) diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp index 490ee3951c9..67f0f880287 100644 --- a/intern/cycles/device/device_multi.cpp +++ b/intern/cycles/device/device_multi.cpp @@ -224,8 +224,11 @@ public: sub.device->const_copy_to(name, host, size); } - void draw_pixels(device_memory& rgba, int y, int w, int h, int dx, int dy, int width, int height, bool transparent, - const DeviceDrawParams &draw_params) + void draw_pixels( + device_memory& rgba, int y, + int w, int h, int width, int height, + int dx, int dy, int dw, int dh, + bool transparent, const DeviceDrawParams &draw_params) { device_ptr key = rgba.device_pointer; int i = 0, sub_h = h/devices.size(); @@ -239,7 +242,7 @@ public: /* adjust math for w/width */ rgba.device_pointer = sub.ptr_map[key]; - sub.device->draw_pixels(rgba, sy, w, sh, dx, sdy, width, sheight, transparent, draw_params); + sub.device->draw_pixels(rgba, sy, w, sh, width, sheight, dx, sdy, dw, dh, transparent, draw_params); i++; } diff --git a/intern/cycles/kernel/kernel_id_passes.h b/intern/cycles/kernel/kernel_id_passes.h index 486c61d2ae5..8d092374d8b 100644 --- a/intern/cycles/kernel/kernel_id_passes.h +++ b/intern/cycles/kernel/kernel_id_passes.h @@ -22,7 +22,7 @@ ccl_device_inline void kernel_write_id_slots(ccl_global float *buffer, int num_s if(weight == 0.0f) { return; } - + for(int slot = 0; slot < num_slots; slot++) { ccl_global float2 *id_buffer = (ccl_global float2*)buffer; #ifdef __ATOMIC_PASS_WRITE__ diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index 2a300d3419e..262d7df1364 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -44,7 +44,7 @@ typedef struct LightSample { * * Note: light_p is modified when sample_coord is true. */ -ccl_device_inline float area_light_sample(float3 P, +ccl_device_inline float rect_light_sample(float3 P, float3 *light_p, float3 axisu, float3 axisv, float randu, float randv, @@ -118,6 +118,60 @@ ccl_device_inline float area_light_sample(float3 P, return 0.0f; } +ccl_device_inline float3 ellipse_sample(float3 ru, float3 rv, float randu, float randv) +{ + to_unit_disk(&randu, &randv); + return ru*randu + rv*randv; +} + +ccl_device float3 disk_light_sample(float3 v, float randu, float randv) +{ + float3 ru, rv; + + make_orthonormals(v, &ru, &rv); + + return ellipse_sample(ru, rv, randu, randv); +} + +ccl_device float3 distant_light_sample(float3 D, float radius, float randu, float randv) +{ + return normalize(D + disk_light_sample(D, randu, randv)*radius); +} + +ccl_device float3 sphere_light_sample(float3 P, float3 center, float radius, float randu, float randv) +{ + return disk_light_sample(normalize(P - center), randu, randv)*radius; +} + +ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot_smooth, LightSample *ls) +{ + float3 I = ls->Ng; + + float attenuation = dot(dir, I); + + if(attenuation <= spot_angle) { + attenuation = 0.0f; + } + else { + float t = attenuation - spot_angle; + + if(t < spot_smooth && spot_smooth != 0.0f) + attenuation *= smoothstepf(t/spot_smooth); + } + + return attenuation; +} + +ccl_device float lamp_light_pdf(KernelGlobals *kg, const float3 Ng, const float3 I, float t) +{ + float cos_pi = dot(Ng, I); + + if(cos_pi <= 0.0f) + return 0.0f; + + return t*t/cos_pi; +} + /* Background Light */ #ifdef __BACKGROUND_MIS__ @@ -291,11 +345,19 @@ ccl_device_inline float background_portal_pdf(KernelGlobals *kg, const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal); float3 axisu = make_float3(klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); float3 axisv = make_float3(klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); + bool is_round = (klight->area.invarea < 0.0f); - if(!ray_quad_intersect(P, direction, 1e-4f, FLT_MAX, lightpos, axisu, axisv, dir, NULL, NULL, NULL, NULL)) + if(!ray_quad_intersect(P, direction, 1e-4f, FLT_MAX, lightpos, axisu, axisv, dir, NULL, NULL, NULL, NULL, is_round)) continue; - portal_pdf += area_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false); + if(is_round) { + float t; + float3 D = normalize_len(lightpos - P, &t); + portal_pdf += fabsf(klight->area.invarea) * lamp_light_pdf(kg, dir, -D, t); + } + else { + portal_pdf += rect_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false); + } } if(ignore_portal >= 0) { @@ -345,15 +407,26 @@ ccl_device float3 background_portal_sample(KernelGlobals *kg, const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal); float3 axisu = make_float3(klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); float3 axisv = make_float3(klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); - - *pdf = area_light_sample(P, &lightpos, - axisu, axisv, - randu, randv, - true); + bool is_round = (klight->area.invarea < 0.0f); + + float3 D; + if(is_round) { + lightpos += ellipse_sample(axisu*0.5f, axisv*0.5f, randu, randv); + float t; + D = normalize_len(lightpos - P, &t); + *pdf = fabsf(klight->area.invarea) * lamp_light_pdf(kg, dir, -D, t); + } + else { + *pdf = rect_light_sample(P, &lightpos, + axisu, axisv, + randu, randv, + true); + D = normalize(lightpos - P); + } *pdf /= num_possible; *sampled_portal = p; - return normalize(lightpos - P); + return D; } portal--; @@ -454,55 +527,6 @@ ccl_device float background_light_pdf(KernelGlobals *kg, float3 P, float3 direct /* Regular Light */ -ccl_device float3 disk_light_sample(float3 v, float randu, float randv) -{ - float3 ru, rv; - - make_orthonormals(v, &ru, &rv); - to_unit_disk(&randu, &randv); - - return ru*randu + rv*randv; -} - -ccl_device float3 distant_light_sample(float3 D, float radius, float randu, float randv) -{ - return normalize(D + disk_light_sample(D, randu, randv)*radius); -} - -ccl_device float3 sphere_light_sample(float3 P, float3 center, float radius, float randu, float randv) -{ - return disk_light_sample(normalize(P - center), randu, randv)*radius; -} - -ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot_smooth, LightSample *ls) -{ - float3 I = ls->Ng; - - float attenuation = dot(dir, I); - - if(attenuation <= spot_angle) { - attenuation = 0.0f; - } - else { - float t = attenuation - spot_angle; - - if(t < spot_smooth && spot_smooth != 0.0f) - attenuation *= smoothstepf(t/spot_smooth); - } - - return attenuation; -} - -ccl_device float lamp_light_pdf(KernelGlobals *kg, const float3 Ng, const float3 I, float t) -{ - float cos_pi = dot(Ng, I); - - if(cos_pi <= 0.0f) - return 0.0f; - - return t*t/cos_pi; -} - ccl_device_inline bool lamp_light_sample(KernelGlobals *kg, int lamp, float randu, float randv, @@ -597,26 +621,39 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg, float3 D = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]); + float invarea = fabsf(klight->area.invarea); + bool is_round = (klight->area.invarea < 0.0f); if(dot(ls->P - P, D) > 0.0f) { return false; } - float3 inplane = ls->P; - ls->pdf = area_light_sample(P, &ls->P, - axisu, axisv, - randu, randv, - true); + float3 inplane; + + if(is_round) { + inplane = ellipse_sample(axisu*0.5f, axisv*0.5f, randu, randv); + ls->P += inplane; + ls->pdf = invarea; + } + else { + inplane = ls->P; + ls->pdf = rect_light_sample(P, &ls->P, + axisu, axisv, + randu, randv, + true); + inplane = ls->P - inplane; + } - inplane = ls->P - inplane; ls->u = dot(inplane, axisu) * (1.0f / dot(axisu, axisu)) + 0.5f; ls->v = dot(inplane, axisv) * (1.0f / dot(axisv, axisv)) + 0.5f; ls->Ng = D; ls->D = normalize_len(ls->P - P, &ls->t); - float invarea = klight->area.invarea; ls->eval_fac = 0.25f*invarea; + if(is_round) { + ls->pdf *= lamp_light_pdf(kg, D, -ls->D, ls->t); + } } } @@ -727,7 +764,8 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, } else if(type == LIGHT_AREA) { /* area light */ - float invarea = klight->area.invarea; + float invarea = fabsf(klight->area.invarea); + bool is_round = (klight->area.invarea < 0.0f); if(invarea == 0.0f) return false; @@ -750,14 +788,20 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, if(!ray_quad_intersect(P, D, 0.0f, t, light_P, axisu, axisv, Ng, &ls->P, &ls->t, - &ls->u, &ls->v)) + &ls->u, &ls->v, + is_round)) { return false; } ls->D = D; ls->Ng = Ng; - ls->pdf = area_light_sample(P, &light_P, axisu, axisv, 0, 0, false); + if(is_round) { + ls->pdf = invarea * lamp_light_pdf(kg, Ng, -D, ls->t); + } + else { + ls->pdf = rect_light_sample(P, &light_P, axisu, axisv, 0, 0, false); + } ls->eval_fac = 0.25f*invarea; } else { diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h index e256a1819ed..49a1b2c848e 100644 --- a/intern/cycles/kernel/kernel_passes.h +++ b/intern/cycles/kernel/kernel_passes.h @@ -200,7 +200,7 @@ ccl_device_inline size_t kernel_write_id_pass_cpu(float *buffer, size_t depth, f return 0; } #else /* __KERNEL_CPU__ */ -#define WRITE_ID_SLOT(buffer, depth, id, matte_weight, name) kernel_write_id_slots_gpu(buffer, depth * 2, id, matte_weight) +#define WRITE_ID_SLOT(buffer, depth, id, matte_weight, name) kernel_write_id_slots_gpu(buffer, depth * 2, id, matte_weight) ccl_device_inline size_t kernel_write_id_slots_gpu(ccl_global float *buffer, size_t depth, float id, float matte_weight) { #endif /* __KERNEL_CPU__ */ diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp index f901885e679..b4e3c18e894 100644 --- a/intern/cycles/render/buffers.cpp +++ b/intern/cycles/render/buffers.cpp @@ -472,7 +472,11 @@ void DisplayBuffer::draw(Device *device, const DeviceDrawParams& draw_params) device_memory& rgba = (half_float)? (device_memory&)rgba_half: (device_memory&)rgba_byte; - device->draw_pixels(rgba, 0, draw_width, draw_height, params.full_x, params.full_y, params.width, params.height, transparent, draw_params); + device->draw_pixels( + rgba, 0, + draw_width, draw_height, params.width, params.height, + params.full_x, params.full_y, params.full_width, params.full_height, + transparent, draw_params); } } diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index e6ef19cc3be..2865b0e5e97 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -1023,6 +1023,39 @@ void ImageManager::device_update_slot(Device *device, } } +void ImageManager::device_load_builtin(Device *device, + Scene *scene, + Progress& progress) +{ + /* Load only builtin images, Blender needs this to load evaluated + * scene data from depsgraph before it is freed. */ + if(!need_update) { + return; + } + + TaskPool pool; + for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { + for(size_t slot = 0; slot < images[type].size(); slot++) { + if(!images[type][slot]) + continue; + + if(images[type][slot]->need_load) { + if(images[type][slot]->builtin_data) { + pool.push(function_bind(&ImageManager::device_load_image, + this, + device, + scene, + (ImageDataType)type, + slot, + &progress)); + } + } + } + } + + pool.wait_work(); +} + void ImageManager::device_free_builtin(Device *device) { for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index d94ebe564e3..0bf06c322d0 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -83,6 +83,10 @@ public: int flat_slot, Progress *progress); void device_free(Device *device); + + void device_load_builtin(Device *device, + Scene *scene, + Progress& progress); void device_free_builtin(Device *device); void set_osl_texture_system(void *texture_system); diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index 3580f4a8eeb..a5854f022cd 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -118,6 +118,7 @@ NODE_DEFINE(Light) SOCKET_FLOAT(sizeu, "Size U", 1.0f); SOCKET_VECTOR(axisv, "Axis V", make_float3(0.0f, 0.0f, 0.0f)); SOCKET_FLOAT(sizev, "Size V", 1.0f); + SOCKET_BOOLEAN(round, "Round", false); SOCKET_INT(map_resolution, "Map Resolution", 0); @@ -757,12 +758,15 @@ void LightManager::device_update_points(Device *, float3 axisu = light->axisu*(light->sizeu*light->size); float3 axisv = light->axisv*(light->sizev*light->size); float area = len(axisu)*len(axisv); - float invarea = (area > 0.0f)? 1.0f/area: 1.0f; + if(light->round) { + area *= -M_PI_4_F; + } + float invarea = (area != 0.0f)? 1.0f/area: 1.0f; float3 dir = light->dir; dir = safe_normalize(dir); - if(light->use_mis && area > 0.0f) + if(light->use_mis && area != 0.0f) shader_id |= SHADER_USE_MIS; klights[light_index].co[0] = co.x; @@ -830,7 +834,10 @@ void LightManager::device_update_points(Device *, float3 axisu = light->axisu*(light->sizeu*light->size); float3 axisv = light->axisv*(light->sizev*light->size); float area = len(axisu)*len(axisv); - float invarea = (area > 0.0f)? 1.0f/area: 1.0f; + if(light->round) { + area *= -M_PI_4_F; + } + float invarea = (area != 0.0f)? 1.0f/area: 1.0f; float3 dir = light->dir; dir = safe_normalize(dir); diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h index 32a911dc256..ec957c7cc68 100644 --- a/intern/cycles/render/light.h +++ b/intern/cycles/render/light.h @@ -51,6 +51,7 @@ public: float sizeu; float3 axisv; float sizev; + bool round; Transform tfm; diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 1943f8c3e2b..06a2baa8a38 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -1520,6 +1520,19 @@ void PointDensityTextureNode::attributes(Shader *shader, ShaderNode::attributes(shader, attributes); } +void PointDensityTextureNode::add_image() +{ + if(slot == -1) { + ImageMetaData metadata; + slot = image_manager->add_image(filename.string(), builtin_data, + false, 0, + interpolation, + EXTENSION_CLIP, + true, + metadata); + } +} + void PointDensityTextureNode::compile(SVMCompiler& compiler) { ShaderInput *vector_in = input("Vector"); @@ -1532,15 +1545,7 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler) image_manager = compiler.image_manager; if(use_density || use_color) { - if(slot == -1) { - ImageMetaData metadata; - slot = image_manager->add_image(filename.string(), builtin_data, - false, 0, - interpolation, - EXTENSION_CLIP, - true, - metadata); - } + add_image(); if(slot != -1) { compiler.stack_assign(vector_in); @@ -1583,15 +1588,7 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler) image_manager = compiler.image_manager; if(use_density || use_color) { - if(slot == -1) { - ImageMetaData metadata; - slot = image_manager->add_image(filename.string(), builtin_data, - false, 0, - interpolation, - EXTENSION_CLIP, - true, - metadata); - } + add_image(); if(slot != -1) { compiler.parameter("filename", string_printf("@i%d", slot).c_str()); diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 28bbe2de05a..c2cf13ad020 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -267,6 +267,8 @@ public: bool has_spatial_varying() { return true; } bool has_object_dependency() { return true; } + void add_image(); + ustring filename; NodeTexVoxelSpace space; InterpolationType interpolation; diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index a827f611583..86860bbc8ac 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -208,6 +208,7 @@ Shader::Shader() need_update = true; need_update_mesh = true; + need_sync_object = false; } Shader::~Shader() @@ -525,7 +526,7 @@ void ShaderManager::device_update_common(Device *device, flag |= SD_HAS_CONSTANT_EMISSION; uint32_t cryptomatte_id = util_murmur_hash3(shader->name.c_str(), shader->name.length(), 0); - + /* regular shader */ kshader->flags = flag; kshader->pass_id = shader->pass_id; diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h index 80731384048..890208c4bf8 100644 --- a/intern/cycles/render/shader.h +++ b/intern/cycles/render/shader.h @@ -99,6 +99,7 @@ public: /* synchronization */ bool need_update; bool need_update_mesh; + bool need_sync_object; /* If the shader has only volume components, the surface is assumed to * be transparent. diff --git a/intern/cycles/util/util_math_intersect.h b/intern/cycles/util/util_math_intersect.h index b5fbb24091f..bc3dd1500a9 100644 --- a/intern/cycles/util/util_math_intersect.h +++ b/intern/cycles/util/util_math_intersect.h @@ -186,12 +186,17 @@ ccl_device_forceinline bool ray_triangle_intersect( #undef dot3 } +/* Tests for an intersection between a ray and a quad defined by + * its midpoint, normal and sides. + * If ellipse is true, hits outside the ellipse that's enclosed by the + * quad are rejected. + */ ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_mint, float ray_maxt, float3 quad_P, float3 quad_u, float3 quad_v, float3 quad_n, float3 *isect_P, float *isect_t, - float *isect_u, float *isect_v) + float *isect_u, float *isect_v, bool ellipse) { /* Perform intersection test. */ float t = -(dot(ray_P, quad_n) - dot(quad_P, quad_n)) / dot(ray_D, quad_n); @@ -200,20 +205,23 @@ ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, } const float3 hit = ray_P + t*ray_D; const float3 inplane = hit - quad_P; - const float u = dot(inplane, quad_u) / dot(quad_u, quad_u) + 0.5f; - if(u < 0.0f || u > 1.0f) { + const float u = dot(inplane, quad_u) / dot(quad_u, quad_u); + if(u < -0.5f || u > 0.5f) { + return false; + } + const float v = dot(inplane, quad_v) / dot(quad_v, quad_v); + if(v < -0.5f || v > 0.5f) { return false; } - const float v = dot(inplane, quad_v) / dot(quad_v, quad_v) + 0.5f; - if(v < 0.0f || v > 1.0f) { + if(ellipse && (u*u + v*v > 0.25f)) { return false; } /* Store the result. */ /* TODO(sergey): Check whether we can avoid some checks here. */ if(isect_P != NULL) *isect_P = hit; if(isect_t != NULL) *isect_t = t; - if(isect_u != NULL) *isect_u = u; - if(isect_v != NULL) *isect_v = v; + if(isect_u != NULL) *isect_u = u + 0.5f; + if(isect_v != NULL) *isect_v = v + 0.5f; return true; } diff --git a/intern/cycles/util/util_opengl.h b/intern/cycles/util/util_opengl.h index 0b5462e0a09..7a8d5eec1f9 100644 --- a/intern/cycles/util/util_opengl.h +++ b/intern/cycles/util/util_opengl.h @@ -20,12 +20,6 @@ /* OpenGL header includes, used everywhere we use OpenGL, to deal with * platform differences in one central place. */ -#ifdef WITH_GLEW_MX -# include "glew-mx.h" -#else -# include <GL/glew.h> -# define mxCreateContext() glewInit() -# define mxMakeCurrentContext(x) (x) -#endif +#include <GL/glew.h> #endif /* __UTIL_OPENGL_H__ */ diff --git a/intern/cycles/util/util_view.cpp b/intern/cycles/util/util_view.cpp index 3836cc86ee0..05094c7b327 100644 --- a/intern/cycles/util/util_view.cpp +++ b/intern/cycles/util/util_view.cpp @@ -252,7 +252,7 @@ void view_main_loop(const char *title, int width, int height, glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH); glutCreateWindow(title); - mxMakeCurrentContext(mxCreateContext()); + glewInit(); view_reshape(width, height); |