diff options
Diffstat (limited to 'intern/cycles/blender')
-rw-r--r-- | intern/cycles/blender/CMakeLists.txt | 11 | ||||
-rw-r--r-- | intern/cycles/blender/addon/engine.py | 3 | ||||
-rw-r--r-- | intern/cycles/blender/addon/properties.py | 125 | ||||
-rw-r--r-- | intern/cycles/blender/addon/ui.py | 132 | ||||
-rw-r--r-- | intern/cycles/blender/blender_camera.cpp | 9 | ||||
-rw-r--r-- | intern/cycles/blender/blender_curves.cpp | 681 | ||||
-rw-r--r-- | intern/cycles/blender/blender_device.cpp | 50 | ||||
-rw-r--r-- | intern/cycles/blender/blender_geometry.cpp | 24 | ||||
-rw-r--r-- | intern/cycles/blender/blender_mesh.cpp | 76 | ||||
-rw-r--r-- | intern/cycles/blender/blender_object.cpp | 4 | ||||
-rw-r--r-- | intern/cycles/blender/blender_python.cpp | 11 | ||||
-rw-r--r-- | intern/cycles/blender/blender_session.cpp | 75 | ||||
-rw-r--r-- | intern/cycles/blender/blender_shader.cpp | 8 | ||||
-rw-r--r-- | intern/cycles/blender/blender_sync.cpp | 141 | ||||
-rw-r--r-- | intern/cycles/blender/blender_sync.h | 33 | ||||
-rw-r--r-- | intern/cycles/blender/blender_viewport.cpp | 16 | ||||
-rw-r--r-- | intern/cycles/blender/blender_viewport.h | 4 | ||||
-rw-r--r-- | intern/cycles/blender/blender_volume.cpp | 57 |
18 files changed, 466 insertions, 994 deletions
diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt index 496e8e9310b..2316800e21e 100644 --- a/intern/cycles/blender/CMakeLists.txt +++ b/intern/cycles/blender/CMakeLists.txt @@ -92,10 +92,6 @@ if(WITH_MOD_FLUID) add_definitions(-DWITH_FLUID) endif() -if(WITH_NEW_OBJECT_TYPES) - add_definitions(-DWITH_NEW_OBJECT_TYPES) -endif() - if(WITH_OPENVDB) add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS}) list(APPEND INC_SYS @@ -106,6 +102,13 @@ if(WITH_OPENVDB) ) endif() +if(WITH_OPENIMAGEDENOISE) + add_definitions(-DWITH_OPENIMAGEDENOISE) + list(APPEND INC_SYS + ${OPENIMAGEDENOISE_INCLUDE_DIRS} + ) +endif() + blender_add_lib(bf_intern_cycles "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") # avoid link failure with clang 3.4 debug diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py index e7ea5e7a1f6..7566ca28dd7 100644 --- a/intern/cycles/blender/addon/engine.py +++ b/intern/cycles/blender/addon/engine.py @@ -179,7 +179,8 @@ def reset(engine, data, depsgraph): import _cycles import bpy - if bpy.app.debug_value == 256: + prefs = bpy.context.preferences + if prefs.experimental.use_cycles_debug and prefs.view.show_developer_ui: _cycles.debug_flags_update(depsgraph.scene.as_pointer()) else: _cycles.debug_flags_reset() diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 1635afab210..840efb65d96 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -55,8 +55,7 @@ enum_displacement_methods = ( enum_bvh_layouts = ( ('BVH2', "BVH2", "", 1), - ('BVH4', "BVH4", "", 2), - ('BVH8', "BVH8", "", 4), + ('EMBREE', "Embree", "", 4), ) enum_bvh_types = ( @@ -78,20 +77,9 @@ enum_panorama_types = ( ('MIRRORBALL', "Mirror Ball", "Uses the mirror ball mapping"), ) -enum_curve_primitives = ( - ('TRIANGLES', "Triangles", "Create triangle geometry around strands"), - ('LINE_SEGMENTS', "Line Segments", "Use line segment primitives"), - ('CURVE_SEGMENTS', "Curve Segments", "Use segmented cardinal curve primitives"), -) - -enum_triangle_curves = ( - ('CAMERA_TRIANGLES', "Planes", "Create individual triangles forming planes that face camera"), - ('TESSELLATED_TRIANGLES', "Tessellated", "Create mesh surrounding each strand"), -) - enum_curve_shape = ( - ('RIBBONS', "Ribbons", "Ignore thickness of each strand"), - ('THICK', "Thick", "Use thickness of strand when rendering"), + ('RIBBONS', "Rounded Ribbons", "Render hair as flat ribbon with rounded normals, for fast rendering"), + ('THICK', "3D Curves", "Render hair as 3D curve, for accurate results when viewing hair close up"), ) enum_tile_order = ( @@ -194,10 +182,36 @@ enum_aov_types = ( ('COLOR', "Color", "Write a Color pass", 1), ) -enum_viewport_denoising = ( - ('NONE', "None", "Disable viewport denoising", 0), - ('OPTIX', "OptiX AI-Accelerated", "Use the OptiX denoiser running on the GPU (requires at least one compatible OptiX device)", 1), -) +def enum_openimagedenoise_denoiser(self, context): + if _cycles.with_openimagedenoise: + return [('OPENIMAGEDENOISE', "OpenImageDenoise", "Use Intel OpenImageDenoise AI denoiser running on the CPU", 4)] + return [] + +def enum_optix_denoiser(self, context): + if not context or bool(context.preferences.addons[__package__].preferences.get_devices_for_type('OPTIX')): + return [('OPTIX', "OptiX", "Use the OptiX AI denoiser with GPU acceleration, only available on NVIDIA GPUs", 2)] + return [] + +def enum_preview_denoiser(self, context): + optix_items = enum_optix_denoiser(self, context) + oidn_items = enum_openimagedenoise_denoiser(self, context) + + if len(optix_items): + auto_label = "Fastest (Optix)" + elif len(oidn_items): + auto_label = "Fastest (OpenImageDenoise)" + else: + auto_label = "None" + + items = [('AUTO', auto_label, "Use the fastest available denoiser for viewport rendering", 0)] + items += optix_items + items += oidn_items + return items + +def enum_denoiser(self, context): + items = [('NLM', "NLM", "Cycles native non-local means denoiser, running on any compute device", 1)] + items += enum_optix_denoiser(self, context) + return items enum_denoising_optix_input_passes = ( ('RGB', "Color", "Use only color as input", 1), @@ -236,11 +250,29 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): description="Pause all viewport preview renders", default=False, ) - preview_denoising: EnumProperty( - name="Viewport Denoising", - description="Denoise the image after each preview update with the selected denoiser engine", - items=enum_viewport_denoising, - default='NONE', + + use_denoising: BoolProperty( + name="Use Denoising", + description="Denoise the rendered image", + default=False, + ) + use_preview_denoising: BoolProperty( + name="Use Viewport Denoising", + description="Denoise the image in the 3D viewport", + default=False, + ) + + denoiser: EnumProperty( + name="Denoiser", + description="Denoise the image with the selected denoiser", + items=enum_denoiser, + default=1, + ) + preview_denoiser: EnumProperty( + name="Viewport Denoiser", + description="Denoise the image after each preview update with the selected denoiser", + items=enum_preview_denoiser, + default=0, ) use_square_samples: BoolProperty( @@ -256,7 +288,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): default=128, ) preview_samples: IntProperty( - name="Preview Samples", + name="Viewport Samples", description="Number of samples to render in the viewport, unlimited if 0", min=0, max=(1 << 24), default=32, @@ -476,7 +508,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): subtype='PIXEL' ) preview_dicing_rate: FloatProperty( - name="Preview Dicing Rate", + name="Viewport 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, @@ -629,11 +661,6 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): 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", @@ -786,7 +813,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): debug_bvh_layout: EnumProperty( name="BVH Layout", items=enum_bvh_layouts, - default='BVH8', + default='EMBREE', ) debug_use_cpu_split_kernel: BoolProperty(name="Split Kernel", default=False) @@ -1241,39 +1268,17 @@ 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, + default='RIBBONS', ) subdivisions: IntProperty( name="Subdivisions", description="Number of subdivisions used in Cardinal curve intersection (power of 2)", min=0, max=24, - default=4, + default=2, ) @classmethod @@ -1369,7 +1374,7 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup): use_denoising: BoolProperty( name="Use Denoising", description="Denoise the rendered image", - default=False, + default=True, update=update_render_passes, ) denoising_diffuse_direct: BoolProperty( @@ -1439,12 +1444,6 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup): default=0, ) - use_optix_denoising: BoolProperty( - name="OptiX AI-Accelerated", - description="Use the OptiX denoiser to denoise the rendered image", - default=False, - update=update_render_passes, - ) denoising_optix_input_passes: EnumProperty( name="Input Passes", description="Passes handed over to the OptiX denoiser (this can have different effects on the denoised image)", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 78a44881743..b049d0bf2b4 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -112,10 +112,6 @@ def show_device_active(context): return True return context.preferences.addons[__package__].preferences.has_active_device() -def show_optix_denoising(context): - # OptiX AI denoiser can be used when at least one device supports OptiX - return bool(context.preferences.addons[__package__].preferences.get_devices_for_type('OPTIX')) - def draw_samples_info(layout, context): cscene = context.scene.cycles @@ -190,11 +186,6 @@ class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel): col.prop(cscene, "aa_samples", text="Render") col.prop(cscene, "preview_aa_samples", text="Viewport") - # Viewport denoising is currently only supported with OptiX - if show_optix_denoising(context): - col = layout.column() - col.prop(cscene, "preview_denoising") - if not use_branched_path(context): draw_samples_info(layout, context) @@ -256,6 +247,39 @@ class CYCLES_RENDER_PT_sampling_adaptive(CyclesButtonsPanel, Panel): col.prop(cscene, "adaptive_threshold", text="Noise Threshold") col.prop(cscene, "adaptive_min_samples", text="Min Samples") + +class CYCLES_RENDER_PT_sampling_denoising(CyclesButtonsPanel, Panel): + bl_label = "Denoising" + 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 + + heading = layout.column(align=True, heading="Render") + row = heading.row(align=True) + row.prop(cscene, "use_denoising", text="") + sub = row.row() + sub.active = cscene.use_denoising + sub.prop(cscene, "denoiser", text="") + + heading = layout.column(align=False, heading="Viewport") + row = heading.row(align=True) + row.prop(cscene, "use_preview_denoising", text="") + sub = row.row() + sub.active = cscene.use_preview_denoising + sub.prop(cscene, "preview_denoiser", text="") + + sub = heading.row(align=True) + sub.active = cscene.use_preview_denoising + sub.prop(cscene, "preview_denoising_start_sample", text="Start Sample") + + class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel): bl_label = "Advanced" bl_parent_id = "CYCLES_RENDER_PT_sampling" @@ -387,13 +411,6 @@ class CYCLES_RENDER_PT_hair(CyclesButtonsPanel, Panel): bl_label = "Hair" bl_options = {'DEFAULT_CLOSED'} - def draw_header(self, context): - layout = self.layout - scene = context.scene - ccscene = scene.cycles_curves - - layout.prop(ccscene, "use_curves", text="") - def draw(self, context): layout = self.layout layout.use_property_split = True @@ -402,18 +419,10 @@ class CYCLES_RENDER_PT_hair(CyclesButtonsPanel, Panel): scene = context.scene ccscene = scene.cycles_curves - layout.active = ccscene.use_curves - col = layout.column() 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") + if ccscene.shape == 'RIBBONS': + col.prop(ccscene, "subdivisions", text="Curve Subdivisions") class CYCLES_RENDER_PT_volumes(CyclesButtonsPanel, Panel): @@ -693,16 +702,20 @@ class CYCLES_RENDER_PT_performance_acceleration_structure(CyclesButtonsPanel, Pa col = layout.column() - if _cycles.with_embree: - row = col.row() - row.active = use_cpu(context) - row.prop(cscene, "use_bvh_embree") + use_embree = False + if use_cpu(context): + use_embree = _cycles.with_embree + if not use_embree: + sub = col.column(align=True) + sub.label(text="Cycles built without Embree support") + sub.label(text="CPU raytracing performance will be poor") + col.prop(cscene, "debug_use_spatial_splits") sub = col.column() - sub.active = not cscene.use_bvh_embree or not _cycles.with_embree + sub.active = not use_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.active = not cscene.debug_use_spatial_splits and not use_embree sub.prop(cscene, "debug_bvh_time_steps") @@ -741,11 +754,6 @@ class CYCLES_RENDER_PT_performance_viewport(CyclesButtonsPanel, Panel): col.prop(rd, "preview_pixel_size", text="Pixel Size") col.prop(cscene, "preview_start_resolution", text="Start Pixels") - if show_optix_denoising(context): - sub = col.row(align=True) - sub.active = cscene.preview_denoising != 'NONE' - sub.prop(cscene, "preview_denoising_start_sample", text="Denoising Start Sample") - class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel): bl_label = "Filter" @@ -968,12 +976,17 @@ class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel): bl_context = "view_layer" bl_options = {'DEFAULT_CLOSED'} + @classmethod + def poll(cls, context): + cscene = context.scene.cycles + return CyclesButtonsPanel.poll(context) and cscene.use_denoising + def draw_header(self, context): scene = context.scene view_layer = context.view_layer cycles_view_layer = view_layer.cycles - layout = self.layout + layout = self.layout layout.prop(cycles_view_layer, "use_denoising", text="") def draw(self, context): @@ -984,18 +997,17 @@ class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel): scene = context.scene view_layer = context.view_layer cycles_view_layer = view_layer.cycles + denoiser = scene.cycles.denoiser - layout.active = cycles_view_layer.use_denoising + layout.active = denoiser != 'NONE' and cycles_view_layer.use_denoising col = layout.column() - if show_optix_denoising(context): - col.prop(cycles_view_layer, "use_optix_denoising") - col.separator(factor=2.0) - - if cycles_view_layer.use_optix_denoising: - col.prop(cycles_view_layer, "denoising_optix_input_passes") - return + if denoiser == 'OPTIX': + col.prop(cycles_view_layer, "denoising_optix_input_passes") + return + elif denoiser == 'OPENIMAGEDENOISE': + return col.prop(cycles_view_layer, "denoising_radius", text="Radius") @@ -1190,6 +1202,7 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True rd = context.scene.render # scene = context.scene @@ -1199,10 +1212,10 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel): layout.active = (rd.use_motion_blur and cob.use_motion_blur) - row = layout.row() + col = layout.column() + col.prop(cob, "motion_steps", text="Steps") if ob.type != 'CAMERA': - row.prop(cob, "use_deform_motion", text="Deformation") - row.prop(cob, "motion_steps", text="Steps") + col.prop(cob, "use_deform_motion", text="Deformation") def has_geometry_visibility(ob): @@ -1575,17 +1588,18 @@ class CYCLES_WORLD_PT_ray_visibility(CyclesButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False world = context.world visibility = world.cycles_visibility - flow = layout.column_flow() - - flow.prop(visibility, "camera") - flow.prop(visibility, "diffuse") - flow.prop(visibility, "glossy") - flow.prop(visibility, "transmission") - flow.prop(visibility, "scatter") + col = layout.column() + col.prop(visibility, "camera") + col.prop(visibility, "diffuse") + col.prop(visibility, "glossy") + col.prop(visibility, "transmission") + col.prop(visibility, "scatter") class CYCLES_WORLD_PT_settings(CyclesButtonsPanel, Panel): @@ -1975,7 +1989,10 @@ class CYCLES_RENDER_PT_debug(CyclesButtonsPanel, Panel): @classmethod def poll(cls, context): - return CyclesButtonsPanel.poll(context) and bpy.app.debug_value == 256 + prefs = bpy.context.preferences + return (CyclesButtonsPanel.poll(context) + and prefs.experimental.use_cycles_debug + and prefs.view.show_developer_ui) def draw(self, context): layout = self.layout @@ -2248,6 +2265,7 @@ classes = ( CYCLES_RENDER_PT_sampling, CYCLES_RENDER_PT_sampling_sub_samples, CYCLES_RENDER_PT_sampling_adaptive, + CYCLES_RENDER_PT_sampling_denoising, CYCLES_RENDER_PT_sampling_advanced, CYCLES_RENDER_PT_light_paths, CYCLES_RENDER_PT_light_paths_max_bounces, diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index 40a1a2c2edc..011678a7a65 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -867,13 +867,13 @@ void BlenderSync::sync_view(BL::SpaceView3D &b_v3d, } } -BufferParams BlenderSync::get_buffer_params(BL::Scene &b_scene, - BL::RenderSettings &b_render, +BufferParams BlenderSync::get_buffer_params(BL::RenderSettings &b_render, BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, int width, - int height) + int height, + const bool use_denoiser) { BufferParams params; bool use_border = false; @@ -907,8 +907,7 @@ BufferParams BlenderSync::get_buffer_params(BL::Scene &b_scene, PassType display_pass = update_viewport_display_passes(b_v3d, params.passes); /* Can only denoise the combined image pass */ - params.denoising_data_pass = display_pass == PASS_COMBINED && - update_viewport_display_denoising(b_v3d, b_scene); + params.denoising_data_pass = display_pass == PASS_COMBINED && use_denoiser; return params; } diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index 847a43c5f34..82c99631a89 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -18,7 +18,6 @@ #include "render/camera.h" #include "render/curves.h" #include "render/hair.h" -#include "render/mesh.h" #include "render/object.h" #include "render/scene.h" @@ -39,27 +38,6 @@ ParticleCurveData::~ParticleCurveData() { } -static void interp_weights(float t, float data[4]) -{ - /* Cardinal curve interpolation */ - float t2 = t * t; - float t3 = t2 * t; - float fc = 0.71f; - - data[0] = -fc * t3 + 2.0f * fc * t2 - fc * t; - data[1] = (2.0f - fc) * t3 + (fc - 3.0f) * t2 + 1.0f; - data[2] = (fc - 2.0f) * t3 + (3.0f - 2.0f * fc) * t2 + fc * t; - data[3] = fc * t3 - fc * t2; -} - -static void curveinterp_v3_v3v3v3v3( - float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4]) -{ - p->x = v1->x * w[0] + v2->x * w[1] + v3->x * w[2] + v4->x * w[3]; - p->y = v1->y * w[0] + v2->y * w[1] + v3->y * w[2] + v4->y * w[3]; - p->z = v1->z * w[0] + v2->z * w[1] + v3->z * w[2] + v4->z * w[3]; -} - static float shaperadius(float shape, float root, float tip, float time) { assert(time >= 0.0f); @@ -77,43 +55,13 @@ static float shaperadius(float shape, float root, float tip, float time) /* curve functions */ -static void InterpolateKeySegments( - int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData) -{ - float3 ckey_loc1 = CData->curvekey_co[key]; - float3 ckey_loc2 = ckey_loc1; - float3 ckey_loc3 = CData->curvekey_co[key + 1]; - float3 ckey_loc4 = ckey_loc3; - - if (key > CData->curve_firstkey[curve]) - ckey_loc1 = CData->curvekey_co[key - 1]; - - if (key < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) - ckey_loc4 = CData->curvekey_co[key + 2]; - - float time1 = CData->curvekey_time[key] / CData->curve_length[curve]; - float time2 = CData->curvekey_time[key + 1] / CData->curve_length[curve]; - - float dfra = (time2 - time1) / (float)segno; - - if (time) - *time = (dfra * seg) + time1; - - float t[4]; - - interp_weights((float)seg / (float)segno, t); - - if (keyloc) - curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t); -} - static bool ObtainCacheParticleData( - Geometry *geom, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background) + Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background) { int curvenum = 0; int keyno = 0; - if (!(geom && b_mesh && b_ob && CData)) + if (!(hair && b_mesh && b_ob && CData)) return false; Transform tfm = get_transform(b_ob->matrix_world()); @@ -129,7 +77,7 @@ static bool ObtainCacheParticleData( 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, geom->used_shaders.size() - 1); + int shader = clamp(b_part.material() - 1, 0, hair->used_shaders.size() - 1); 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() : @@ -203,14 +151,14 @@ static bool ObtainCacheParticleData( return true; } -static bool ObtainCacheParticleUV(Geometry *geom, +static bool ObtainCacheParticleUV(Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num) { - if (!(geom && b_mesh && b_ob && CData)) + if (!(hair && b_mesh && b_ob && CData)) return false; CData->curve_uv.clear(); @@ -266,14 +214,14 @@ static bool ObtainCacheParticleUV(Geometry *geom, return true; } -static bool ObtainCacheParticleVcol(Geometry *geom, +static bool ObtainCacheParticleVcol(Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num) { - if (!(geom && b_mesh && b_ob && CData)) + if (!(hair && b_mesh && b_ob && CData)) return false; CData->curve_vcol.clear(); @@ -314,7 +262,7 @@ static bool ObtainCacheParticleVcol(Geometry *geom, BL::Mesh::vertex_colors_iterator l; b_mesh->vertex_colors.begin(l); - float3 vcol = make_float3(0.0f, 0.0f, 0.0f); + float4 vcol = make_float4(0.0f, 0.0f, 0.0f, 1.0f); 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); @@ -329,272 +277,6 @@ static bool ObtainCacheParticleVcol(Geometry *geom, return true; } -static void ExportCurveTrianglePlanes(Mesh *mesh, - ParticleCurveData *CData, - float3 RotCam, - bool is_ortho) -{ - int vertexno = mesh->verts.size(); - int vertexindex = vertexno; - int numverts = 0, numtris = 0; - - /* compute and reserve size of arrays */ - for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { - for (int curve = CData->psys_firstcurve[sys]; - curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; - curve++) { - numverts += 2 + (CData->curve_keynum[curve] - 1) * 2; - numtris += (CData->curve_keynum[curve] - 1) * 2; - } - } - - mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris); - - /* actually export */ - for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { - for (int curve = CData->psys_firstcurve[sys]; - curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; - curve++) { - float3 xbasis; - float3 v1; - float time = 0.0f; - float3 ickey_loc = CData->curvekey_co[CData->curve_firstkey[curve]]; - float radius = shaperadius( - CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.0f); - v1 = CData->curvekey_co[CData->curve_firstkey[curve] + 1] - - CData->curvekey_co[CData->curve_firstkey[curve]]; - if (is_ortho) - xbasis = normalize(cross(RotCam, v1)); - else - xbasis = normalize(cross(RotCam - ickey_loc, v1)); - float3 ickey_loc_shfl = ickey_loc - radius * xbasis; - float3 ickey_loc_shfr = ickey_loc + radius * xbasis; - mesh->add_vertex(ickey_loc_shfl); - mesh->add_vertex(ickey_loc_shfr); - vertexindex += 2; - - for (int curvekey = CData->curve_firstkey[curve] + 1; - curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; - curvekey++) { - ickey_loc = CData->curvekey_co[curvekey]; - - if (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) - v1 = CData->curvekey_co[curvekey] - - CData->curvekey_co[max(curvekey - 1, CData->curve_firstkey[curve])]; - else - v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1]; - - time = CData->curvekey_time[curvekey] / CData->curve_length[curve]; - radius = shaperadius( - CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); - - if (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) - radius = shaperadius(CData->psys_shape[sys], - CData->psys_rootradius[sys], - CData->psys_tipradius[sys], - 0.95f); - - if (CData->psys_closetip[sys] && - (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) - radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); - - if (is_ortho) - xbasis = normalize(cross(RotCam, v1)); - else - xbasis = normalize(cross(RotCam - ickey_loc, v1)); - float3 ickey_loc_shfl = ickey_loc - radius * xbasis; - float3 ickey_loc_shfr = ickey_loc + radius * xbasis; - mesh->add_vertex(ickey_loc_shfl); - mesh->add_vertex(ickey_loc_shfr); - mesh->add_triangle( - vertexindex - 2, vertexindex, vertexindex - 1, CData->psys_shader[sys], true); - mesh->add_triangle( - vertexindex + 1, vertexindex - 1, vertexindex, CData->psys_shader[sys], true); - vertexindex += 2; - } - } - } - - mesh->resize_mesh(mesh->verts.size(), mesh->num_triangles()); - mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); - mesh->attributes.remove(ATTR_STD_FACE_NORMAL); - mesh->add_face_normals(); - mesh->add_vertex_normals(); - mesh->attributes.remove(ATTR_STD_FACE_NORMAL); - - /* texture coords still needed */ -} - -static void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resolution) -{ - int vertexno = mesh->verts.size(); - int vertexindex = vertexno; - int numverts = 0, numtris = 0; - - /* compute and reserve size of arrays */ - for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { - for (int curve = CData->psys_firstcurve[sys]; - curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; - curve++) { - numverts += (CData->curve_keynum[curve] - 1) * resolution + resolution; - numtris += (CData->curve_keynum[curve] - 1) * 2 * resolution; - } - } - - mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris); - - /* actually export */ - for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { - for (int curve = CData->psys_firstcurve[sys]; - curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; - curve++) { - float3 firstxbasis = cross(make_float3(1.0f, 0.0f, 0.0f), - CData->curvekey_co[CData->curve_firstkey[curve] + 1] - - CData->curvekey_co[CData->curve_firstkey[curve]]); - if (!is_zero(firstxbasis)) - firstxbasis = normalize(firstxbasis); - else - firstxbasis = normalize(cross(make_float3(0.0f, 1.0f, 0.0f), - CData->curvekey_co[CData->curve_firstkey[curve] + 1] - - CData->curvekey_co[CData->curve_firstkey[curve]])); - - for (int curvekey = CData->curve_firstkey[curve]; - curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; - curvekey++) { - float3 xbasis = firstxbasis; - float3 v1; - float3 v2; - - if (curvekey == CData->curve_firstkey[curve]) { - v1 = CData->curvekey_co[min( - curvekey + 2, CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - - CData->curvekey_co[curvekey + 1]; - v2 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey]; - } - else if (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { - v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 1]; - v2 = CData->curvekey_co[curvekey - 1] - - CData->curvekey_co[max(curvekey - 2, CData->curve_firstkey[curve])]; - } - else { - v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey]; - v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 1]; - } - - xbasis = cross(v1, v2); - - if (len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { - firstxbasis = normalize(xbasis); - break; - } - } - - for (int curvekey = CData->curve_firstkey[curve]; - curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; - curvekey++) { - int subv = 1; - float3 xbasis; - float3 ybasis; - float3 v1; - float3 v2; - - if (curvekey == CData->curve_firstkey[curve]) { - subv = 0; - v1 = CData->curvekey_co[min( - curvekey + 2, CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - - CData->curvekey_co[curvekey + 1]; - v2 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey]; - } - else if (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { - v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 1]; - v2 = CData->curvekey_co[curvekey - 1] - - CData->curvekey_co[max(curvekey - 2, CData->curve_firstkey[curve])]; - } - else { - v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey]; - v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 1]; - } - - xbasis = cross(v1, v2); - - if (len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { - xbasis = normalize(xbasis); - firstxbasis = xbasis; - } - else - xbasis = firstxbasis; - - ybasis = normalize(cross(xbasis, v2)); - - for (; subv <= 1; subv++) { - float3 ickey_loc = make_float3(0.0f, 0.0f, 0.0f); - float time = 0.0f; - - InterpolateKeySegments(subv, 1, curvekey, curve, &ickey_loc, &time, CData); - - float radius = shaperadius(CData->psys_shape[sys], - CData->psys_rootradius[sys], - CData->psys_tipradius[sys], - time); - - if ((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && - (subv == 1)) - radius = shaperadius(CData->psys_shape[sys], - CData->psys_rootradius[sys], - CData->psys_tipradius[sys], - 0.95f); - - if (CData->psys_closetip[sys] && (subv == 1) && - (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2)) - radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); - - float angle = M_2PI_F / (float)resolution; - for (int section = 0; section < resolution; section++) { - float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + - sinf(angle * section) * ybasis); - mesh->add_vertex(ickey_loc_shf); - } - - if (subv != 0) { - for (int section = 0; section < resolution - 1; section++) { - mesh->add_triangle(vertexindex - resolution + section, - vertexindex + section, - vertexindex - resolution + section + 1, - CData->psys_shader[sys], - true); - mesh->add_triangle(vertexindex + section + 1, - vertexindex - resolution + section + 1, - vertexindex + section, - CData->psys_shader[sys], - true); - } - mesh->add_triangle(vertexindex - 1, - vertexindex + resolution - 1, - vertexindex - resolution, - CData->psys_shader[sys], - true); - mesh->add_triangle(vertexindex, - vertexindex - resolution, - vertexindex + resolution - 1, - CData->psys_shader[sys], - true); - } - vertexindex += resolution; - } - } - } - } - - mesh->resize_mesh(mesh->verts.size(), mesh->num_triangles()); - mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); - mesh->attributes.remove(ATTR_STD_FACE_NORMAL); - mesh->add_face_normals(); - mesh->add_vertex_normals(); - mesh->attributes.remove(ATTR_STD_FACE_NORMAL); - - /* texture coords still needed */ -} - static void ExportCurveSegments(Scene *scene, Hair *hair, ParticleCurveData *CData) { int num_keys = 0; @@ -823,154 +505,8 @@ static void ExportCurveSegmentsMotion(Hair *hair, ParticleCurveData *CData, int } } -static void ExportCurveTriangleUV(ParticleCurveData *CData, int resol, float2 *uvdata) -{ - if (uvdata == NULL) - return; - int vertexindex = 0; - - for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { - for (int curve = CData->psys_firstcurve[sys]; - curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; - curve++) { - for (int curvekey = CData->curve_firstkey[curve]; - curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; - curvekey++) { - for (int section = 0; section < resol; section++) { - uvdata[vertexindex] = CData->curve_uv[curve]; - vertexindex++; - uvdata[vertexindex] = CData->curve_uv[curve]; - vertexindex++; - uvdata[vertexindex] = CData->curve_uv[curve]; - vertexindex++; - uvdata[vertexindex] = CData->curve_uv[curve]; - vertexindex++; - uvdata[vertexindex] = CData->curve_uv[curve]; - vertexindex++; - uvdata[vertexindex] = CData->curve_uv[curve]; - vertexindex++; - } - } - } - } -} - -static void ExportCurveTriangleVcol(ParticleCurveData *CData, int resol, uchar4 *cdata) -{ - if (cdata == NULL) - return; - - int vertexindex = 0; - - for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { - for (int curve = CData->psys_firstcurve[sys]; - curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; - curve++) { - for (int curvekey = CData->curve_firstkey[curve]; - curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; - curvekey++) { - for (int section = 0; section < resol; section++) { - /* Encode vertex color using the sRGB curve. */ - cdata[vertexindex] = color_float_to_byte( - color_srgb_to_linear_v3(CData->curve_vcol[curve])); - vertexindex++; - cdata[vertexindex] = color_float_to_byte( - color_srgb_to_linear_v3(CData->curve_vcol[curve])); - vertexindex++; - cdata[vertexindex] = color_float_to_byte( - color_srgb_to_linear_v3(CData->curve_vcol[curve])); - vertexindex++; - cdata[vertexindex] = color_float_to_byte( - color_srgb_to_linear_v3(CData->curve_vcol[curve])); - vertexindex++; - cdata[vertexindex] = color_float_to_byte( - color_srgb_to_linear_v3(CData->curve_vcol[curve])); - vertexindex++; - cdata[vertexindex] = color_float_to_byte( - color_srgb_to_linear_v3(CData->curve_vcol[curve])); - vertexindex++; - } - } - } - } -} - /* Hair Curve Sync */ -void BlenderSync::sync_curve_settings(BL::Depsgraph &b_depsgraph) -{ - PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves"); - - CurveSystemManager *curve_system_manager = scene->curve_system_manager; - CurveSystemManager prev_curve_system_manager = *curve_system_manager; - - curve_system_manager->use_curves = get_boolean(csscene, "use_curves"); - - curve_system_manager->primitive = (CurvePrimitiveType)get_enum( - csscene, "primitive", CURVE_NUM_PRIMITIVE_TYPES, CURVE_LINE_SEGMENTS); - curve_system_manager->curve_shape = (CurveShapeType)get_enum( - csscene, "shape", CURVE_NUM_SHAPE_TYPES, CURVE_THICK); - curve_system_manager->resolution = get_int(csscene, "resolution"); - curve_system_manager->subdivisions = get_int(csscene, "subdivisions"); - curve_system_manager->use_backfacing = !get_boolean(csscene, "cull_backfacing"); - - /* Triangles */ - if (curve_system_manager->primitive == CURVE_TRIANGLES) { - /* camera facing planes */ - if (curve_system_manager->curve_shape == CURVE_RIBBON) { - curve_system_manager->triangle_method = CURVE_CAMERA_TRIANGLES; - curve_system_manager->resolution = 1; - } - else if (curve_system_manager->curve_shape == CURVE_THICK) { - curve_system_manager->triangle_method = CURVE_TESSELATED_TRIANGLES; - } - } - /* Line Segments */ - else if (curve_system_manager->primitive == CURVE_LINE_SEGMENTS) { - if (curve_system_manager->curve_shape == CURVE_RIBBON) { - /* tangent shading */ - curve_system_manager->line_method = CURVE_UNCORRECTED; - curve_system_manager->use_encasing = true; - curve_system_manager->use_backfacing = false; - curve_system_manager->use_tangent_normal_geometry = true; - } - else if (curve_system_manager->curve_shape == CURVE_THICK) { - curve_system_manager->line_method = CURVE_ACCURATE; - curve_system_manager->use_encasing = false; - curve_system_manager->use_tangent_normal_geometry = false; - } - } - /* Curve Segments */ - else if (curve_system_manager->primitive == CURVE_SEGMENTS) { - if (curve_system_manager->curve_shape == CURVE_RIBBON) { - curve_system_manager->primitive = CURVE_RIBBONS; - curve_system_manager->use_backfacing = false; - } - } - - if (curve_system_manager->modified_mesh(prev_curve_system_manager)) { - BL::Depsgraph::objects_iterator b_ob; - - for (b_depsgraph.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) { - if (object_is_mesh(*b_ob)) { - BL::Object::particle_systems_iterator b_psys; - for (b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); - ++b_psys) { - if ((b_psys->settings().render_type() == BL::ParticleSettings::render_type_PATH) && - (b_psys->settings().type() == BL::ParticleSettings::type_HAIR)) { - BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data(); - geometry_map.set_recalc(key); - object_map.set_recalc(*b_ob); - } - } - } - } - } - - if (curve_system_manager->modified(prev_curve_system_manager)) - curve_system_manager->tag_update(scene); -} - bool BlenderSync::object_has_particle_hair(BL::Object b_ob) { /* Test if the object has a particle modifier with hair. */ @@ -994,78 +530,38 @@ bool BlenderSync::object_has_particle_hair(BL::Object b_ob) /* Old particle hair. */ void BlenderSync::sync_particle_hair( - Geometry *geom, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step) + Hair *hair, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step) { - Hair *hair = (geom->type == Geometry::HAIR) ? static_cast<Hair *>(geom) : NULL; - Mesh *mesh = (geom->type == Geometry::MESH) ? static_cast<Mesh *>(geom) : NULL; - /* obtain general settings */ if (b_ob.mode() == b_ob.mode_PARTICLE_EDIT || b_ob.mode() == b_ob.mode_EDIT) { return; } - const int triangle_method = scene->curve_system_manager->triangle_method; - const int resolution = scene->curve_system_manager->resolution; - int used_res = 1; - /* extract particle hair data - should be combined with connecting to mesh later*/ ParticleCurveData CData; - ObtainCacheParticleData(geom, &b_mesh, &b_ob, &CData, !preview); - - /* add hair geometry to mesh */ - if (mesh) { - if (triangle_method == CURVE_CAMERA_TRIANGLES) { - /* obtain camera parameters */ - float3 RotCam; - Camera *camera = scene->camera; - Transform &ctfm = camera->matrix; - if (camera->type == CAMERA_ORTHOGRAPHIC) { - RotCam = -make_float3(ctfm.x.z, ctfm.y.z, ctfm.z.z); - } - else { - Transform tfm = get_transform(b_ob.matrix_world()); - Transform itfm = transform_quick_inverse(tfm); - RotCam = transform_point(&itfm, make_float3(ctfm.x.w, ctfm.y.w, ctfm.z.w)); - } - bool is_ortho = camera->type == CAMERA_ORTHOGRAPHIC; - ExportCurveTrianglePlanes(mesh, &CData, RotCam, is_ortho); - } - else { - ExportCurveTriangleGeometry(mesh, &CData, resolution); - used_res = resolution; - } - } - else { - if (motion) - ExportCurveSegmentsMotion(hair, &CData, motion_step); - else - ExportCurveSegments(scene, hair, &CData); - } + ObtainCacheParticleData(hair, &b_mesh, &b_ob, &CData, !preview); + + /* add hair geometry */ + if (motion) + ExportCurveSegmentsMotion(hair, &CData, motion_step); + else + ExportCurveSegments(scene, hair, &CData); /* generated coordinates from first key. we should ideally get this from * blender to handle deforming objects */ if (!motion) { - if (geom->need_attribute(scene, ATTR_STD_GENERATED)) { + if (hair->need_attribute(scene, ATTR_STD_GENERATED)) { float3 loc, size; mesh_texture_space(b_mesh, loc, size); - if (mesh) { - Attribute *attr_generated = mesh->attributes.add(ATTR_STD_GENERATED); - float3 *generated = attr_generated->data_float3(); - - for (size_t i = 0; i < mesh->verts.size(); i++) - generated[i] = mesh->verts[i] * size - loc; - } - else { - Attribute *attr_generated = hair->attributes.add(ATTR_STD_GENERATED); - float3 *generated = attr_generated->data_float3(); + Attribute *attr_generated = hair->attributes.add(ATTR_STD_GENERATED); + float3 *generated = attr_generated->data_float3(); - for (size_t i = 0; i < hair->num_curves(); i++) { - float3 co = hair->curve_keys[hair->get_curve(i).first_key]; - generated[i] = co * size - loc; - } + for (size_t i = 0; i < hair->num_curves(); i++) { + float3 co = hair->curve_keys[hair->get_curve(i).first_key]; + generated[i] = co * size - loc; } } } @@ -1076,32 +572,22 @@ void BlenderSync::sync_particle_hair( int vcol_num = 0; for (b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l, vcol_num++) { - if (!geom->need_attribute(scene, ustring(l->name().c_str()))) + if (!hair->need_attribute(scene, ustring(l->name().c_str()))) continue; - ObtainCacheParticleVcol(geom, &b_mesh, &b_ob, &CData, !preview, vcol_num); + ObtainCacheParticleVcol(hair, &b_mesh, &b_ob, &CData, !preview, vcol_num); - if (mesh) { - Attribute *attr_vcol = mesh->attributes.add( - ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE); + Attribute *attr_vcol = hair->attributes.add( + ustring(l->name().c_str()), TypeRGBA, ATTR_ELEMENT_CURVE); - uchar4 *cdata = attr_vcol->data_uchar4(); + float4 *fdata = attr_vcol->data_float4(); - ExportCurveTriangleVcol(&CData, used_res, cdata); - } - else { - Attribute *attr_vcol = hair->attributes.add( - ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE); - - float3 *fdata = attr_vcol->data_float3(); + if (fdata) { + size_t i = 0; - if (fdata) { - size_t i = 0; - - /* Encode vertex color using the sRGB curve. */ - for (size_t curve = 0; curve < CData.curve_vcol.size(); curve++) { - fdata[i++] = color_srgb_to_linear_v3(CData.curve_vcol[curve]); - } + /* Encode vertex color using the sRGB curve. */ + for (size_t curve = 0; curve < CData.curve_vcol.size(); curve++) { + fdata[i++] = color_srgb_to_linear_v4(CData.curve_vcol[curve]); } } } @@ -1118,35 +604,23 @@ void BlenderSync::sync_particle_hair( ustring name = ustring(l->name().c_str()); /* UV map */ - if (geom->need_attribute(scene, name) || geom->need_attribute(scene, std)) { + if (hair->need_attribute(scene, name) || hair->need_attribute(scene, std)) { Attribute *attr_uv; - ObtainCacheParticleUV(geom, &b_mesh, &b_ob, &CData, !preview, uv_num); + ObtainCacheParticleUV(hair, &b_mesh, &b_ob, &CData, !preview, uv_num); - if (mesh) { - if (active_render) - attr_uv = mesh->attributes.add(std, name); - else - attr_uv = mesh->attributes.add(name, TypeFloat2, ATTR_ELEMENT_CORNER); - - float2 *uv = attr_uv->data_float2(); - - ExportCurveTriangleUV(&CData, used_res, uv); - } - else { - if (active_render) - attr_uv = hair->attributes.add(std, name); - else - attr_uv = hair->attributes.add(name, TypeFloat2, ATTR_ELEMENT_CURVE); + if (active_render) + attr_uv = hair->attributes.add(std, name); + else + attr_uv = hair->attributes.add(name, TypeFloat2, ATTR_ELEMENT_CURVE); - float2 *uv = attr_uv->data_float2(); + float2 *uv = attr_uv->data_float2(); - if (uv) { - size_t i = 0; + if (uv) { + size_t i = 0; - for (size_t curve = 0; curve < CData.curve_uv.size(); curve++) { - uv[i++] = CData.curve_uv[curve]; - } + for (size_t curve = 0; curve < CData.curve_uv.size(); curve++) { + uv[i++] = CData.curve_uv[curve]; } } } @@ -1154,7 +628,6 @@ void BlenderSync::sync_particle_hair( } } -#ifdef WITH_NEW_OBJECT_TYPES static float4 hair_point_as_float4(BL::HairPoint b_point) { float4 mP = float3_to_float4(get_float3(b_point.co())); @@ -1320,12 +793,10 @@ static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_st export_hair_motion_validate_attribute(hair, motion_step, num_motion_keys, have_motion); } } -#endif /* WITH_NEW_OBJECT_TYPES */ /* Hair object. */ void BlenderSync::sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motion_step) { -#ifdef WITH_NEW_OBJECT_TYPES /* Convert Blender hair to Cycles curves. */ BL::Hair b_hair(b_ob.data()); if (motion) { @@ -1334,97 +805,70 @@ void BlenderSync::sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motio else { export_hair_curves(scene, hair, b_hair); } -#else - (void)hair; - (void)b_ob; - (void)motion; - (void)motion_step; -#endif /* WITH_NEW_OBJECT_TYPES */ } void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, - Geometry *geom, + Hair *hair, const vector<Shader *> &used_shaders) { - Hair *hair = (geom->type == Geometry::HAIR) ? static_cast<Hair *>(geom) : NULL; - Mesh *mesh = (geom->type == Geometry::MESH) ? static_cast<Mesh *>(geom) : NULL; - /* Compares curve_keys rather than strands in order to handle quick hair * adjustments in dynamic BVH - other methods could probably do this better. */ array<float3> oldcurve_keys; array<float> oldcurve_radius; - array<int> oldtriangles; - if (hair) { - oldcurve_keys.steal_data(hair->curve_keys); - oldcurve_radius.steal_data(hair->curve_radius); - } - else { - oldtriangles.steal_data(mesh->triangles); - } + oldcurve_keys.steal_data(hair->curve_keys); + oldcurve_radius.steal_data(hair->curve_radius); - geom->clear(); - geom->used_shaders = used_shaders; + hair->clear(); + hair->used_shaders = used_shaders; - if (view_layer.use_hair && scene->curve_system_manager->use_curves) { -#ifdef WITH_NEW_OBJECT_TYPES + if (view_layer.use_hair) { if (b_ob.type() == BL::Object::type_HAIR) { /* Hair object. */ sync_hair(hair, b_ob, false); - assert(mesh == NULL); } - else -#endif - { + else { /* Particle hair. */ - bool need_undeformed = geom->need_attribute(scene, ATTR_STD_GENERATED); + bool need_undeformed = hair->need_attribute(scene, ATTR_STD_GENERATED); BL::Mesh b_mesh = object_to_mesh( b_data, b_ob, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE); if (b_mesh) { - sync_particle_hair(geom, b_mesh, b_ob, false); + sync_particle_hair(hair, b_mesh, b_ob, false); free_object_to_mesh(b_data, b_ob, b_mesh); } } } /* tag update */ - const bool rebuild = (hair && ((oldcurve_keys != hair->curve_keys) || - (oldcurve_radius != hair->curve_radius))) || - (mesh && (oldtriangles != mesh->triangles)); + const bool rebuild = ((oldcurve_keys != hair->curve_keys) || + (oldcurve_radius != hair->curve_radius)); - geom->tag_update(scene, rebuild); + hair->tag_update(scene, rebuild); } void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, - Geometry *geom, + Hair *hair, int motion_step) { - Hair *hair = (geom->type == Geometry::HAIR) ? static_cast<Hair *>(geom) : NULL; - Mesh *mesh = (geom->type == Geometry::MESH) ? static_cast<Mesh *>(geom) : NULL; - /* Skip if nothing exported. */ - if ((hair && hair->num_keys() == 0) || (mesh && mesh->verts.size() == 0)) { + if (hair->num_keys() == 0) { return; } /* Export deformed coordinates. */ if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) { -#ifdef WITH_NEW_OBJECT_TYPES if (b_ob.type() == BL::Object::type_HAIR) { /* Hair object. */ sync_hair(hair, b_ob, true, motion_step); - assert(mesh == NULL); return; } - else -#endif - { + else { /* Particle hair. */ BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_depsgraph, false, Mesh::SUBDIVISION_NONE); if (b_mesh) { - sync_particle_hair(geom, b_mesh, b_ob, true, motion_step); + sync_particle_hair(hair, b_mesh, b_ob, true, motion_step); free_object_to_mesh(b_data, b_ob, b_mesh); return; } @@ -1432,12 +876,7 @@ void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph, } /* No deformation on this frame, copy coordinates if other frames did have it. */ - if (hair) { - hair->copy_center_to_motion_step(motion_step); - } - else { - mesh->copy_center_to_motion_step(motion_step); - } + hair->copy_center_to_motion_step(motion_step); } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_device.cpp b/intern/cycles/blender/blender_device.cpp index ac52948806c..fb9ab9e8c97 100644 --- a/intern/cycles/blender/blender_device.cpp +++ b/intern/cycles/blender/blender_device.cpp @@ -21,13 +21,6 @@ CCL_NAMESPACE_BEGIN -enum DenoiserType { - DENOISER_NONE = 0, - DENOISER_OPTIX = 1, - - DENOISER_NUM -}; - enum ComputeDevice { COMPUTE_DEVICE_CPU = 0, COMPUTE_DEVICE_CUDA = 1, @@ -120,49 +113,6 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen } } - /* Ensure there is an OptiX device when using the OptiX denoiser. */ - bool use_optix_denoising = get_enum(cscene, "preview_denoising", DENOISER_NUM, DENOISER_NONE) == - DENOISER_OPTIX && - !background; - 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_optix_denoising")) { - use_optix_denoising = true; - } - } - - if (use_optix_denoising && device.type != DEVICE_OPTIX) { - vector<DeviceInfo> optix_devices = Device::available_devices(DEVICE_MASK_OPTIX); - if (!optix_devices.empty()) { - /* Convert to a special multi device with separate denoising devices. */ - if (device.multi_devices.empty()) { - device.multi_devices.push_back(device); - } - - /* Try to use the same physical devices for denoising. */ - for (const DeviceInfo &cuda_device : device.multi_devices) { - if (cuda_device.type == DEVICE_CUDA) { - for (const DeviceInfo &optix_device : optix_devices) { - if (cuda_device.num == optix_device.num) { - device.id += optix_device.id; - device.denoising_devices.push_back(optix_device); - break; - } - } - } - } - - if (device.denoising_devices.empty()) { - /* Simply use the first available OptiX device. */ - const DeviceInfo optix_device = optix_devices.front(); - device.id += optix_device.id; /* Uniquely identify this special multi device. */ - device.denoising_devices.push_back(optix_device); - } - } - } - return device; } diff --git a/intern/cycles/blender/blender_geometry.cpp b/intern/cycles/blender/blender_geometry.cpp index 7ca35cff961..f7e4623024d 100644 --- a/intern/cycles/blender/blender_geometry.cpp +++ b/intern/cycles/blender/blender_geometry.cpp @@ -40,17 +40,9 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, BL::Material material_override = view_layer.material_override; Shader *default_shader = (b_ob.type() == BL::Object::type_VOLUME) ? scene->default_volume : scene->default_surface; -#ifdef WITH_NEW_OBJECT_TYPES - Geometry::Type geom_type = ((b_ob.type() == BL::Object::type_HAIR || use_particle_hair) && - (scene->curve_system_manager->primitive != CURVE_TRIANGLES)) ? + Geometry::Type geom_type = (b_ob.type() == BL::Object::type_HAIR || use_particle_hair) ? Geometry::HAIR : Geometry::MESH; -#else - Geometry::Type geom_type = ((use_particle_hair) && - (scene->curve_system_manager->primitive != CURVE_TRIANGLES)) ? - Geometry::HAIR : - Geometry::MESH; -#endif /* Find shader indices. */ vector<Shader *> used_shaders; @@ -129,12 +121,9 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, geom->name = ustring(b_ob_data.name().c_str()); -#ifdef WITH_NEW_OBJECT_TYPES if (b_ob.type() == BL::Object::type_HAIR || use_particle_hair) { -#else - if (use_particle_hair) { -#endif - sync_hair(b_depsgraph, b_ob, geom, used_shaders); + Hair *hair = static_cast<Hair *>(geom); + sync_hair(b_depsgraph, b_ob, hair, used_shaders); } else if (b_ob.type() == BL::Object::type_VOLUME || object_fluid_gas_domain_find(b_ob)) { Mesh *mesh = static_cast<Mesh *>(geom); @@ -173,12 +162,9 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph, return; } -#ifdef WITH_NEW_OBJECT_TYPES if (b_ob.type() == BL::Object::type_HAIR || use_particle_hair) { -#else - if (use_particle_hair) { -#endif - sync_hair_motion(b_depsgraph, b_ob, geom, motion_step); + Hair *hair = static_cast<Hair *>(geom); + sync_hair_motion(b_depsgraph, b_ob, hair, motion_step); } else if (b_ob.type() == BL::Object::type_VOLUME || object_fluid_gas_domain_find(b_ob)) { /* No volume motion blur support yet. */ diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index a6f380a9ae7..49407799fcd 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -278,25 +278,59 @@ static void mikk_compute_tangents( genTangSpaceDefault(&context); } +/* Create sculpt vertex color attributes. */ +static void attr_create_sculpt_vertex_color(Scene *scene, + Mesh *mesh, + BL::Mesh &b_mesh, + bool subdivision) +{ + BL::Mesh::sculpt_vertex_colors_iterator l; + + for (b_mesh.sculpt_vertex_colors.begin(l); l != b_mesh.sculpt_vertex_colors.end(); ++l) { + const bool active_render = l->active_render(); + AttributeStandard vcol_std = (active_render) ? ATTR_STD_VERTEX_COLOR : ATTR_STD_NONE; + ustring vcol_name = ustring(l->name().c_str()); + + const bool need_vcol = mesh->need_attribute(scene, vcol_name) || + mesh->need_attribute(scene, vcol_std); + + if (!need_vcol) { + continue; + } + + AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes; + Attribute *vcol_attr = attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_VERTEX); + vcol_attr->std = vcol_std; + + float4 *cdata = vcol_attr->data_float4(); + int numverts = b_mesh.vertices.length(); + + for (int i = 0; i < numverts; i++) { + *(cdata++) = get_float4(l->data[i].color()); + } + } +} + /* Create vertex color attributes. */ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision) { - if (subdivision) { - BL::Mesh::vertex_colors_iterator l; + BL::Mesh::vertex_colors_iterator l; - for (b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) { - const bool active_render = l->active_render(); - AttributeStandard vcol_std = (active_render) ? ATTR_STD_VERTEX_COLOR : ATTR_STD_NONE; - ustring vcol_name = ustring(l->name().c_str()); + for (b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) { + const bool active_render = l->active_render(); + AttributeStandard vcol_std = (active_render) ? ATTR_STD_VERTEX_COLOR : ATTR_STD_NONE; + ustring vcol_name = ustring(l->name().c_str()); - const bool need_vcol = mesh->need_attribute(scene, vcol_name) || - mesh->need_attribute(scene, vcol_std); + const bool need_vcol = mesh->need_attribute(scene, vcol_name) || + mesh->need_attribute(scene, vcol_std); - if (!need_vcol) { - continue; - } + if (!need_vcol) { + continue; + } - Attribute *vcol_attr = NULL; + Attribute *vcol_attr = NULL; + + if (subdivision) { if (active_render) { vcol_attr = mesh->subd_attributes.add(vcol_std, vcol_name); } @@ -316,22 +350,7 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, } } } - } - else { - BL::Mesh::vertex_colors_iterator l; - for (b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) { - const bool active_render = l->active_render(); - AttributeStandard vcol_std = (active_render) ? ATTR_STD_VERTEX_COLOR : ATTR_STD_NONE; - ustring vcol_name = ustring(l->name().c_str()); - - const bool need_vcol = mesh->need_attribute(scene, vcol_name) || - mesh->need_attribute(scene, vcol_std); - - if (!need_vcol) { - continue; - } - - Attribute *vcol_attr = NULL; + else { if (active_render) { vcol_attr = mesh->attributes.add(vcol_std, vcol_name); } @@ -828,6 +847,7 @@ static void create_mesh(Scene *scene, */ attr_create_pointiness(scene, mesh, b_mesh, subdivision); attr_create_vertex_color(scene, mesh, b_mesh, subdivision); + attr_create_sculpt_vertex_color(scene, mesh, b_mesh, subdivision); attr_create_random_per_island(scene, mesh, b_mesh, subdivision); if (subdivision) { diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index c28586d0f63..d3a37563ef4 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -69,11 +69,7 @@ bool BlenderSync::object_is_mesh(BL::Object &b_ob) BL::Object::type_enum type = b_ob.type(); -#ifdef WITH_NEW_OBJECT_TYPES if (type == BL::Object::type_VOLUME || type == BL::Object::type_HAIR) { -#else - if (type == BL::Object::type_VOLUME) { -#endif /* Will be exported attached to mesh. */ return true; } diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp index 0be19dbffd1..3e595c3ee52 100644 --- a/intern/cycles/blender/blender_python.cpp +++ b/intern/cycles/blender/blender_python.cpp @@ -31,8 +31,10 @@ #include "util/util_logging.h" #include "util/util_md5.h" #include "util/util_opengl.h" +#include "util/util_openimagedenoise.h" #include "util/util_path.h" #include "util/util_string.h" +#include "util/util_task.h" #include "util/util_types.h" #ifdef WITH_OSL @@ -1075,5 +1077,14 @@ void *CCL_python_module_init() Py_INCREF(Py_False); #endif /* WITH_EMBREE */ + if (ccl::openimagedenoise_supported()) { + PyModule_AddObject(mod, "with_openimagedenoise", Py_True); + Py_INCREF(Py_True); + } + else { + PyModule_AddObject(mod, "with_openimagedenoise", Py_False); + Py_INCREF(Py_False); + } + return (void *)mod; } diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index dbe87ce2b13..391a1b8f473 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -158,7 +158,7 @@ void BlenderSession::create_session() /* set buffer parameters */ BufferParams buffer_params = BlenderSync::get_buffer_params( - b_scene, b_render, b_v3d, b_rv3d, scene->camera, width, height); + b_render, b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use); session->reset(buffer_params, session_params.samples); b_engine.use_highlight_tiles(session_params.progressive_refine == false); @@ -239,8 +239,13 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL); BL::RegionView3D b_null_region_view3d(PointerRNA_NULL); - BufferParams buffer_params = BlenderSync::get_buffer_params( - b_scene, b_render, b_null_space_view3d, b_null_region_view3d, scene->camera, width, height); + BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, + b_null_space_view3d, + b_null_region_view3d, + scene->camera, + width, + height, + session_params.denoising.use); session->reset(buffer_params, session_params.samples); b_engine.use_highlight_tiles(session_params.progressive_refine == false); @@ -468,14 +473,13 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_) session->update_render_tile_cb = function_bind( &BlenderSession::update_render_tile, this, _1, _2); + BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); + /* get buffer parameters */ SessionParams session_params = BlenderSync::get_session_params( - b_engine, b_userpref, b_scene, background); + b_engine, b_userpref, b_scene, background, b_view_layer); BufferParams buffer_params = BlenderSync::get_buffer_params( - b_scene, b_render, b_v3d, b_rv3d, scene->camera, width, height); - - /* render each layer */ - BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); + b_render, b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use); /* temporary render result to find needed passes and views */ BL::RenderResult b_rr = begin_render_result( @@ -485,35 +489,26 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_) 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.adaptive_sampling); - buffer_params.passes = passes; + /* Update denoising parameters. */ + session->set_denoising(session_params.denoising); - PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles"); - bool use_denoising = get_boolean(crl, "use_denoising"); - bool use_optix_denoising = get_boolean(crl, "use_optix_denoising"); - bool write_denoising_passes = get_boolean(crl, "denoising_store_passes"); + bool use_denoising = session_params.denoising.use; + bool store_denoising_passes = session_params.denoising.store_passes; - buffer_params.denoising_data_pass = use_denoising || write_denoising_passes; + buffer_params.denoising_data_pass = use_denoising || store_denoising_passes; buffer_params.denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES); - buffer_params.denoising_prefiltered_pass = write_denoising_passes && !use_optix_denoising; - - session->params.run_denoising = use_denoising || write_denoising_passes; - session->params.full_denoising = use_denoising && !use_optix_denoising; - session->params.optix_denoising = use_denoising && use_optix_denoising; - session->params.write_denoising_passes = write_denoising_passes && !use_optix_denoising; - 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"); - session->params.denoising.optix_input_passes = get_enum(crl, "denoising_optix_input_passes"); - session->tile_manager.schedule_denoising = session->params.run_denoising; + buffer_params.denoising_prefiltered_pass = store_denoising_passes && + session_params.denoising.type == DENOISER_NLM; scene->film->denoising_data_pass = buffer_params.denoising_data_pass; scene->film->denoising_clean_pass = buffer_params.denoising_clean_pass; scene->film->denoising_prefiltered_pass = buffer_params.denoising_prefiltered_pass; + /* Add passes */ + vector<Pass> passes = sync->sync_render_passes( + b_rlay, b_view_layer, session_params.adaptive_sampling, session_params.denoising); + buffer_params.passes = passes; + scene->film->pass_alpha_threshold = b_view_layer.pass_alpha_threshold(); scene->film->tag_passes_update(scene, passes); scene->film->tag_update(scene); @@ -798,7 +793,7 @@ void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_) /* increase samples, but never decrease */ session->set_samples(session_params.samples); - session->set_denoising_start_sample(session_params.denoising_start_sample); + session->set_denoising_start_sample(session_params.denoising.start_sample); session->set_pause(session_pause); /* copy recalc flags, outside of mutex so we can decide to do the real @@ -831,21 +826,17 @@ void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_) /* get buffer parameters */ BufferParams buffer_params = BlenderSync::get_buffer_params( - b_scene, b_render, b_v3d, b_rv3d, scene->camera, width, height); + b_render, b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use); - if (session_params.device.type != DEVICE_OPTIX && - session_params.device.denoising_devices.empty()) { - /* cannot use OptiX denoising when it is not supported by the device. */ - buffer_params.denoising_data_pass = false; - } - else { - session->set_denoising(buffer_params.denoising_data_pass, true); + if (!buffer_params.denoising_data_pass) { + session_params.denoising.use = false; } + session->set_denoising(session_params.denoising); + + /* Update film if denoising data was enabled or disabled. */ if (scene->film->denoising_data_pass != buffer_params.denoising_data_pass) { scene->film->denoising_data_pass = buffer_params.denoising_data_pass; - - /* Force a scene and session reset below. */ scene->film->tag_update(scene); } @@ -917,7 +908,7 @@ bool BlenderSession::draw(int w, int h) SessionParams session_params = BlenderSync::get_session_params( b_engine, b_userpref, b_scene, background); BufferParams buffer_params = BlenderSync::get_buffer_params( - b_scene, b_render, b_v3d, b_rv3d, scene->camera, width, height); + b_render, b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use); bool session_pause = BlenderSync::get_session_pause(b_scene, background); if (session_pause == false) { @@ -935,7 +926,7 @@ bool BlenderSession::draw(int w, int h) /* draw */ BufferParams buffer_params = BlenderSync::get_buffer_params( - b_scene, b_render, b_v3d, b_rv3d, scene->camera, width, height); + b_render, b_v3d, b_rv3d, scene->camera, width, height, session->params.denoising.use); DeviceDrawParams draw_params; if (session->params.display_buffer_linear) { diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index f207d8ae07f..19d2730dc93 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -813,6 +813,14 @@ static ShaderNode *add_node(Scene *scene, sky->sun_direction = normalize(get_float3(b_sky_node.sun_direction())); sky->turbidity = b_sky_node.turbidity(); sky->ground_albedo = b_sky_node.ground_albedo(); + sky->sun_disc = b_sky_node.sun_disc(); + sky->sun_size = b_sky_node.sun_size(); + sky->sun_elevation = b_sky_node.sun_elevation(); + sky->sun_rotation = b_sky_node.sun_rotation(); + sky->altitude = b_sky_node.altitude(); + sky->air_density = b_sky_node.air_density(); + sky->dust_density = b_sky_node.dust_density(); + sky->ozone_density = b_sky_node.ozone_density(); BL::TexMapping b_texture_mapping(b_sky_node.texture_mapping()); get_tex_mapping(&sky->tex_mapping, b_texture_mapping); node = sky; diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 09813dc8c05..bf065cc5492 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -38,6 +38,7 @@ #include "util/util_foreach.h" #include "util/util_hash.h" #include "util/util_opengl.h" +#include "util/util_openimagedenoise.h" CCL_NAMESPACE_BEGIN @@ -212,7 +213,6 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render, sync_film(b_v3d); sync_shaders(b_depsgraph, b_v3d); sync_images(); - sync_curve_settings(b_depsgraph); geometry_synced.clear(); /* use for objects and motion sync */ @@ -538,7 +538,8 @@ int BlenderSync::get_denoising_pass(BL::RenderPass &b_pass) vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_view_layer, - bool adaptive_sampling) + bool adaptive_sampling, + const DenoiseParams &denoising) { vector<Pass> passes; @@ -555,16 +556,13 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, Pass::add(pass_type, passes, b_pass.name().c_str()); } - PointerRNA crp = RNA_pointer_get(&b_view_layer.ptr, "cycles"); - bool use_denoising = get_boolean(crp, "use_denoising"); - bool use_optix_denoising = get_boolean(crp, "use_optix_denoising"); - bool write_denoising_passes = get_boolean(crp, "denoising_store_passes"); + PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles"); scene->film->denoising_flags = 0; - if (use_denoising || write_denoising_passes) { - if (!use_optix_denoising) { + if (denoising.use || denoising.store_passes) { + if (denoising.type == DENOISER_NLM) { #define MAP_OPTION(name, flag) \ - if (!get_boolean(crp, name)) \ + if (!get_boolean(crl, name)) \ scene->film->denoising_flags |= flag; MAP_OPTION("denoising_diffuse_direct", DENOISING_CLEAN_DIFFUSE_DIR); MAP_OPTION("denoising_diffuse_indirect", DENOISING_CLEAN_DIFFUSE_IND); @@ -577,11 +575,11 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str()); } - if (write_denoising_passes) { + if (denoising.store_passes) { b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str()); b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str()); b_engine.add_pass("Denoising Depth", 1, "Z", b_view_layer.name().c_str()); - if (!use_optix_denoising) { + if (denoising.type == DENOISER_NLM) { b_engine.add_pass("Denoising Shadowing", 1, "X", b_view_layer.name().c_str()); b_engine.add_pass("Denoising Variance", 3, "RGB", b_view_layer.name().c_str()); b_engine.add_pass("Denoising Intensity", 1, "X", b_view_layer.name().c_str()); @@ -593,46 +591,46 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, } #ifdef __KERNEL_DEBUG__ - if (get_boolean(crp, "pass_debug_bvh_traversed_nodes")) { + if (get_boolean(crl, "pass_debug_bvh_traversed_nodes")) { b_engine.add_pass("Debug BVH Traversed Nodes", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_BVH_TRAVERSED_NODES, passes, "Debug BVH Traversed Nodes"); } - if (get_boolean(crp, "pass_debug_bvh_traversed_instances")) { + if (get_boolean(crl, "pass_debug_bvh_traversed_instances")) { b_engine.add_pass("Debug BVH Traversed Instances", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_BVH_TRAVERSED_INSTANCES, passes, "Debug BVH Traversed Instances"); } - if (get_boolean(crp, "pass_debug_bvh_intersections")) { + if (get_boolean(crl, "pass_debug_bvh_intersections")) { b_engine.add_pass("Debug BVH Intersections", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_BVH_INTERSECTIONS, passes, "Debug BVH Intersections"); } - if (get_boolean(crp, "pass_debug_ray_bounces")) { + if (get_boolean(crl, "pass_debug_ray_bounces")) { b_engine.add_pass("Debug Ray Bounces", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_RAY_BOUNCES, passes, "Debug Ray Bounces"); } #endif - if (get_boolean(crp, "pass_debug_render_time")) { + if (get_boolean(crl, "pass_debug_render_time")) { b_engine.add_pass("Debug Render Time", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_RENDER_TIME, passes, "Debug Render Time"); } - if (get_boolean(crp, "pass_debug_sample_count")) { + if (get_boolean(crl, "pass_debug_sample_count")) { b_engine.add_pass("Debug Sample Count", 1, "X", b_view_layer.name().c_str()); Pass::add(PASS_SAMPLE_COUNT, passes, "Debug Sample Count"); } - if (get_boolean(crp, "use_pass_volume_direct")) { + if (get_boolean(crl, "use_pass_volume_direct")) { b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str()); Pass::add(PASS_VOLUME_DIRECT, passes, "VolumeDir"); } - if (get_boolean(crp, "use_pass_volume_indirect")) { + if (get_boolean(crl, "use_pass_volume_indirect")) { b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str()); Pass::add(PASS_VOLUME_INDIRECT, passes, "VolumeInd"); } /* Cryptomatte stores two ID/weight pairs per RGBA layer. * User facing parameter is the number of pairs. */ - int crypto_depth = divide_up(min(16, get_int(crp, "pass_crypto_depth")), 2); + int crypto_depth = divide_up(min(16, get_int(crl, "pass_crypto_depth")), 2); scene->film->cryptomatte_depth = crypto_depth; scene->film->cryptomatte_passes = CRYPT_NONE; - if (get_boolean(crp, "use_pass_crypto_object")) { + if (get_boolean(crl, "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_view_layer.name().c_str()); @@ -641,7 +639,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_OBJECT); } - if (get_boolean(crp, "use_pass_crypto_material")) { + if (get_boolean(crl, "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_view_layer.name().c_str()); @@ -650,7 +648,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_MATERIAL); } - if (get_boolean(crp, "use_pass_crypto_asset")) { + if (get_boolean(crl, "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_view_layer.name().c_str()); @@ -659,19 +657,19 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_ASSET); } - if (get_boolean(crp, "pass_crypto_accurate") && scene->film->cryptomatte_passes != CRYPT_NONE) { + if (get_boolean(crl, "pass_crypto_accurate") && scene->film->cryptomatte_passes != CRYPT_NONE) { scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_ACCURATE); } if (adaptive_sampling) { Pass::add(PASS_ADAPTIVE_AUX_BUFFER, passes); - if (!get_boolean(crp, "pass_debug_sample_count")) { + if (!get_boolean(crl, "pass_debug_sample_count")) { Pass::add(PASS_SAMPLE_COUNT, passes); } } - RNA_BEGIN (&crp, b_aov, "aovs") { + RNA_BEGIN (&crl, b_aov, "aovs") { bool is_color = (get_enum(b_aov, "type") == 1); string name = get_string(b_aov, "name"); @@ -732,6 +730,11 @@ SceneParams BlenderSync::get_scene_params(BL::Scene &b_scene, bool background) params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh"); params.num_bvh_time_steps = RNA_int_get(&cscene, "debug_bvh_time_steps"); + PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves"); + params.hair_subdivisions = get_int(csscene, "subdivisions"); + params.hair_shape = (CurveShapeType)get_enum( + csscene, "shape", CURVE_NUM_SHAPE_TYPES, CURVE_THICK); + if (background && params.shadingsystem != SHADINGSYSTEM_OSL) params.persistent_data = r.use_persistent_data(); else @@ -751,20 +754,7 @@ SceneParams BlenderSync::get_scene_params(BL::Scene &b_scene, bool background) params.texture_limit = 0; } - /* TODO(sergey): Once OSL supports per-microarchitecture optimization get - * rid of this. - */ - if (params.shadingsystem == SHADINGSYSTEM_OSL) { - params.bvh_layout = BVH_LAYOUT_BVH4; - } - else { - params.bvh_layout = DebugFlags().cpu.bvh_layout; - } - -#ifdef WITH_EMBREE - params.bvh_layout = RNA_boolean_get(&cscene, "use_bvh_embree") ? BVH_LAYOUT_EMBREE : - params.bvh_layout; -#endif + params.bvh_layout = DebugFlags().cpu.bvh_layout; params.background = background; @@ -782,7 +772,8 @@ bool BlenderSync::get_session_pause(BL::Scene &b_scene, bool background) SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine, BL::Preferences &b_preferences, BL::Scene &b_scene, - bool background) + bool background, + BL::ViewLayer b_view_layer) { SessionParams params; PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); @@ -860,9 +851,22 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine, params.tile_order = TILE_BOTTOM_TO_TOP; } - /* other parameters */ + /* Denoising */ + params.denoising = get_denoise_params(b_scene, b_view_layer, background); + + if (params.denoising.use) { + /* Add additional denoising devices if we are rendering and denoising + * with different devices. */ + params.device.add_denoising_devices(params.denoising.type); + + /* Check if denoiser is supported by device. */ + if (!(params.device.denoisers & params.denoising.type)) { + params.denoising.use = false; + } + } + + /* Viewport Performance */ params.start_resolution = get_int(cscene, "preview_start_resolution"); - params.denoising_start_sample = get_int(cscene, "preview_denoising_start_sample"); params.pixel_size = b_engine.get_preview_pixel_size(b_scene); /* other parameters */ @@ -915,4 +919,55 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine, return params; } +DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene, + BL::ViewLayer &b_view_layer, + bool background) +{ + DenoiseParams denoising; + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + + if (background) { + /* Final Render Denoising */ + denoising.use = get_boolean(cscene, "use_denoising"); + denoising.type = (DenoiserType)get_enum(cscene, "denoiser", DENOISER_NUM, DENOISER_NONE); + + if (b_view_layer) { + PointerRNA clayer = RNA_pointer_get(&b_view_layer.ptr, "cycles"); + if (!get_boolean(clayer, "use_denoising")) { + denoising.use = false; + } + + denoising.radius = get_int(clayer, "denoising_radius"); + denoising.strength = get_float(clayer, "denoising_strength"); + denoising.feature_strength = get_float(clayer, "denoising_feature_strength"); + denoising.relative_pca = get_boolean(clayer, "denoising_relative_pca"); + denoising.optix_input_passes = get_enum(clayer, "denoising_optix_input_passes"); + + denoising.store_passes = get_boolean(clayer, "denoising_store_passes"); + } + } + else { + /* Viewport Denoising */ + denoising.use = get_boolean(cscene, "use_preview_denoising"); + denoising.type = (DenoiserType)get_enum( + cscene, "preview_denoiser", DENOISER_NUM, DENOISER_NONE); + denoising.start_sample = get_int(cscene, "preview_denoising_start_sample"); + + /* Auto select fastest denoiser. */ + if (denoising.type == DENOISER_NONE) { + if (!Device::available_devices(DEVICE_MASK_OPTIX).empty()) { + denoising.type = DENOISER_OPTIX; + } + else if (openimagedenoise_supported()) { + denoising.type = DENOISER_OPENIMAGEDENOISE; + } + else { + denoising.use = false; + } + } + } + + return denoising; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 341281b18ee..0214d9eb3b8 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -75,7 +75,8 @@ class BlenderSync { 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, - bool adaptive_sampling); + bool adaptive_sampling, + const DenoiseParams &denoising); void sync_integrator(); void sync_camera(BL::RenderSettings &b_render, BL::Object &b_override, @@ -94,23 +95,29 @@ class BlenderSync { /* get parameters */ static SceneParams get_scene_params(BL::Scene &b_scene, bool background); - static SessionParams get_session_params(BL::RenderEngine &b_engine, - BL::Preferences &b_userpref, - BL::Scene &b_scene, - bool background); + static SessionParams get_session_params( + BL::RenderEngine &b_engine, + BL::Preferences &b_userpref, + BL::Scene &b_scene, + bool background, + BL::ViewLayer b_view_layer = BL::ViewLayer(PointerRNA_NULL)); static bool get_session_pause(BL::Scene &b_scene, bool background); - static BufferParams get_buffer_params(BL::Scene &b_scene, - BL::RenderSettings &b_render, + static BufferParams get_buffer_params(BL::RenderSettings &b_render, BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, int width, - int height); + int height, + const bool use_denoiser); static PassType get_pass_type(BL::RenderPass &b_pass); static int get_denoising_pass(BL::RenderPass &b_pass); private: + static DenoiseParams get_denoise_params(BL::Scene &b_scene, + BL::ViewLayer &b_view_layer, + bool background); + /* sync */ void sync_lights(BL::Depsgraph &b_depsgraph, bool update_all); void sync_materials(BL::Depsgraph &b_depsgraph, bool update_all); @@ -153,16 +160,12 @@ class BlenderSync { /* Hair */ void sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, - Geometry *geom, + Hair *hair, const vector<Shader *> &used_shaders); - void sync_hair_motion(BL::Depsgraph b_depsgraph, - BL::Object b_ob, - Geometry *geom, - int motion_step); + void sync_hair_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *hair, int motion_step); void sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motion_step = 0); void sync_particle_hair( - Geometry *geom, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step = 0); - void sync_curve_settings(BL::Depsgraph &b_depsgraph); + Hair *hair, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step = 0); bool object_has_particle_hair(BL::Object b_ob); /* Camera */ diff --git a/intern/cycles/blender/blender_viewport.cpp b/intern/cycles/blender/blender_viewport.cpp index 93e84e28032..73ef5f94720 100644 --- a/intern/cycles/blender/blender_viewport.cpp +++ b/intern/cycles/blender/blender_viewport.cpp @@ -61,17 +61,6 @@ const bool BlenderViewportParameters::custom_viewport_parameters() const return !(use_scene_world && use_scene_lights); } -bool BlenderViewportParameters::get_viewport_display_denoising(BL::SpaceView3D &b_v3d, - BL::Scene &b_scene) -{ - bool use_denoising = false; - if (b_v3d) { - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - use_denoising = get_enum(cscene, "preview_denoising") != 0; - } - return use_denoising; -} - PassType BlenderViewportParameters::get_viewport_display_render_pass(BL::SpaceView3D &b_v3d) { PassType display_pass = PASS_NONE; @@ -83,11 +72,6 @@ PassType BlenderViewportParameters::get_viewport_display_render_pass(BL::SpaceVi return display_pass; } -bool update_viewport_display_denoising(BL::SpaceView3D &b_v3d, BL::Scene &b_scene) -{ - return BlenderViewportParameters::get_viewport_display_denoising(b_v3d, b_scene); -} - PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d, vector<Pass> &passes) { if (b_v3d) { diff --git a/intern/cycles/blender/blender_viewport.h b/intern/cycles/blender/blender_viewport.h index 3e44e552f1d..7c6c9c4d274 100644 --- a/intern/cycles/blender/blender_viewport.h +++ b/intern/cycles/blender/blender_viewport.h @@ -44,15 +44,11 @@ class BlenderViewportParameters { friend class BlenderSync; public: - /* Get whether to enable denoising data pass in viewport. */ - static bool get_viewport_display_denoising(BL::SpaceView3D &b_v3d, BL::Scene &b_scene); /* Retrieve the render pass that needs to be displayed on the given `SpaceView3D` * When the `b_v3d` parameter is not given `PASS_NONE` will be returned. */ static PassType get_viewport_display_render_pass(BL::SpaceView3D &b_v3d); }; -bool update_viewport_display_denoising(BL::SpaceView3D &b_v3d, BL::Scene &b_scene); - PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d, vector<Pass> &passes); CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_volume.cpp b/intern/cycles/blender/blender_volume.cpp index 4eed6be8c7c..80591e0eec8 100644 --- a/intern/cycles/blender/blender_volume.cpp +++ b/intern/cycles/blender/blender_volume.cpp @@ -35,8 +35,10 @@ CCL_NAMESPACE_BEGIN class BlenderSmokeLoader : public ImageLoader { public: BlenderSmokeLoader(BL::Object &b_ob, AttributeStandard attribute) - : b_domain(object_fluid_gas_domain_find(b_ob)), b_mesh(b_ob.data()), attribute(attribute) + : b_domain(object_fluid_gas_domain_find(b_ob)), attribute(attribute) { + BL::Mesh b_mesh(b_ob.data()); + mesh_texture_space(b_mesh, texspace_loc, texspace_size); } bool load_metadata(ImageMetaData &metadata) override @@ -77,9 +79,7 @@ class BlenderSmokeLoader : public ImageLoader { /* Create a matrix to transform from object space to mesh texture space. * This does not work with deformations but that can probably only be done * well with a volume grid mapping of coordinates. */ - float3 loc, size; - mesh_texture_space(b_mesh, loc, size); - metadata.transform_3d = transform_translate(-loc) * transform_scale(size); + metadata.transform_3d = transform_translate(-texspace_loc) * transform_scale(texspace_size); metadata.use_transform_3d = true; return true; @@ -177,7 +177,7 @@ class BlenderSmokeLoader : public ImageLoader { } BL::FluidDomainSettings b_domain; - BL::Mesh b_mesh; + float3 texspace_loc, texspace_size; AttributeStandard attribute; }; @@ -216,25 +216,16 @@ static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Mesh *mesh, float class BlenderVolumeLoader : public VDBImageLoader { public: - BlenderVolumeLoader(BL::Volume b_volume, const string &grid_name) - : VDBImageLoader(grid_name), - b_volume(b_volume), - b_volume_grid(PointerRNA_NULL), - unload(false) + BlenderVolumeLoader(BL::BlendData &b_data, BL::Volume &b_volume, const string &grid_name) + : VDBImageLoader(grid_name), b_data(b_data), b_volume(b_volume), unload(false) { -#ifdef WITH_OPENVDB - /* Find grid with matching name. */ - BL::Volume::grids_iterator b_grid_iter; - for (b_volume.grids.begin(b_grid_iter); b_grid_iter != b_volume.grids.end(); ++b_grid_iter) { - if (b_grid_iter->name() == grid_name) { - b_volume_grid = *b_grid_iter; - } - } -#endif } bool load_metadata(ImageMetaData &metadata) override { + b_volume.grids.load(b_data.ptr.data); + BL::VolumeGrid b_volume_grid = find_grid(); + if (!b_volume_grid) { return false; } @@ -255,6 +246,9 @@ class BlenderVolumeLoader : public VDBImageLoader { const size_t pixel_size, const bool associate_alpha) override { + b_volume.grids.load(b_data.ptr.data); + BL::VolumeGrid b_volume_grid = find_grid(); + if (!b_volume_grid) { return false; } @@ -266,19 +260,38 @@ class BlenderVolumeLoader : public VDBImageLoader { { /* TODO: detect multiple volume datablocks with the same filepath. */ const BlenderVolumeLoader &other_loader = (const BlenderVolumeLoader &)other; - return b_volume == other_loader.b_volume && b_volume_grid == other_loader.b_volume_grid; + return b_volume == other_loader.b_volume && grid_name == other_loader.grid_name; } void cleanup() override { VDBImageLoader::cleanup(); + + BL::VolumeGrid b_volume_grid = find_grid(); if (b_volume_grid && unload) { b_volume_grid.unload(); } } + /* Find grid with matching name. Grid point not stored in the class since + * grids may be unloaded before we load the pixels, for example for motion + * blur where we move between frames. */ + BL::VolumeGrid find_grid() + { +#ifdef WITH_OPENVDB + BL::Volume::grids_iterator b_grid_iter; + for (b_volume.grids.begin(b_grid_iter); b_grid_iter != b_volume.grids.end(); ++b_grid_iter) { + if (b_grid_iter->name() == grid_name) { + return *b_grid_iter; + } + } +#endif + + return BL::VolumeGrid(PointerRNA_NULL); + } + + BL::BlendData b_data; BL::Volume b_volume; - BL::VolumeGrid b_volume_grid; bool unload; }; @@ -325,7 +338,7 @@ static void sync_volume_object(BL::BlendData &b_data, BL::Object &b_ob, Scene *s mesh->attributes.add(std) : mesh->attributes.add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL); - ImageLoader *loader = new BlenderVolumeLoader(b_volume, name.string()); + ImageLoader *loader = new BlenderVolumeLoader(b_data, b_volume, name.string()); ImageParams params; params.frame = b_volume.grids.frame(); |