diff options
Diffstat (limited to 'intern')
45 files changed, 1775 insertions, 1790 deletions
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index eb89e76dc75..ee284dd899a 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -296,7 +296,6 @@ class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel): row.prop(cscene, "use_animated_seed", text="", icon='TIME') col = layout.column(align=True) - col.active = not (cscene.use_adaptive_sampling and cscene.use_preview_adaptive_sampling) col.prop(cscene, "sampling_pattern", text="Pattern") col = layout.column(align=True) @@ -305,7 +304,7 @@ class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel): layout.separator() heading = layout.column(align=True, heading="Scrambling Distance") - heading.active = cscene.sampling_pattern != 'SOBOL_BURLEY' + heading.active = cscene.sampling_pattern != 'SOBOL' heading.prop(cscene, "auto_scrambling_distance", text="Automatic") heading.prop(cscene, "preview_scrambling_distance", text="Viewport") heading.prop(cscene, "scrambling_distance", text="Multiplier") diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index f32a810786d..6d84357b699 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -225,15 +225,18 @@ set(SRC_KERNEL_CAMERA_HEADERS ) set(SRC_KERNEL_FILM_HEADERS - film/accumulate.h film/adaptive_sampling.h - film/id_passes.h - film/passes.h + film/aov_passes.h + film/data_passes.h + film/denoising_passes.h + film/cryptomatte_passes.h + film/light_passes.h film/read.h - film/write_passes.h + film/write.h ) set(SRC_KERNEL_INTEGRATOR_HEADERS + integrator/displacement_shader.h integrator/init_from_bake.h integrator/init_from_camera.h integrator/intersect_closest.h @@ -245,7 +248,6 @@ set(SRC_KERNEL_INTEGRATOR_HEADERS integrator/path_state.h integrator/shade_background.h integrator/shade_light.h - integrator/shader_eval.h integrator/shade_shadow.h integrator/shade_surface.h integrator/shade_volume.h @@ -258,6 +260,8 @@ set(SRC_KERNEL_INTEGRATOR_HEADERS integrator/subsurface_disk.h integrator/subsurface.h integrator/subsurface_random_walk.h + integrator/surface_shader.h + integrator/volume_shader.h integrator/volume_stack.h ) diff --git a/intern/cycles/kernel/bake/bake.h b/intern/cycles/kernel/bake/bake.h index 9d53d71b431..384ca9168f0 100644 --- a/intern/cycles/kernel/bake/bake.h +++ b/intern/cycles/kernel/bake/bake.h @@ -4,7 +4,8 @@ #pragma once #include "kernel/camera/projection.h" -#include "kernel/integrator/shader_eval.h" +#include "kernel/integrator/displacement_shader.h" +#include "kernel/integrator/surface_shader.h" #include "kernel/geom/geom.h" @@ -25,7 +26,7 @@ ccl_device void kernel_displace_evaluate(KernelGlobals kg, /* Evaluate displacement shader. */ const float3 P = sd.P; - shader_eval_displacement(kg, INTEGRATOR_STATE_NULL, &sd); + displacement_shader_eval(kg, INTEGRATOR_STATE_NULL, &sd); float3 D = sd.P - P; object_inverse_dir_transform(kg, &sd, &D); @@ -64,10 +65,10 @@ ccl_device void kernel_background_evaluate(KernelGlobals kg, /* Evaluate shader. * This is being evaluated for all BSDFs, so path flag does not contain a specific type. */ const uint32_t path_flag = PATH_RAY_EMISSION; - shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT & + surface_shader_eval<KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT & ~(KERNEL_FEATURE_NODE_RAYTRACE | KERNEL_FEATURE_NODE_LIGHT_PATH)>( kg, INTEGRATOR_STATE_NULL, &sd, NULL, path_flag); - Spectrum color = shader_background_eval(&sd); + Spectrum color = surface_shader_background(&sd); #ifdef __KERNEL_DEBUG_NAN__ if (!isfinite_safe(color)) { @@ -99,12 +100,12 @@ ccl_device void kernel_curve_shadow_transparency_evaluate( shader_setup_from_curve(kg, &sd, in.object, in.prim, __float_as_int(in.v), in.u); /* Evaluate transparency. */ - shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW & + surface_shader_eval<KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW & ~(KERNEL_FEATURE_NODE_RAYTRACE | KERNEL_FEATURE_NODE_LIGHT_PATH)>( kg, INTEGRATOR_STATE_NULL, &sd, NULL, PATH_RAY_SHADOW); /* Write output. */ - output[offset] = clamp(average(shader_bsdf_transparency(kg, &sd)), 0.0f, 1.0f); + output[offset] = clamp(average(surface_shader_transparency(kg, &sd)), 0.0f, 1.0f); } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/camera/camera.h b/intern/cycles/kernel/camera/camera.h index 926ccf7b86f..27876677281 100644 --- a/intern/cycles/kernel/camera/camera.h +++ b/intern/cycles/kernel/camera/camera.h @@ -45,7 +45,6 @@ ccl_device void camera_sample_perspective(KernelGlobals kg, float3 raster = make_float3(raster_x, raster_y, 0.0f); float3 Pcamera = transform_perspective(&rastertocamera, raster); -#ifdef __CAMERA_MOTION__ if (kernel_data.cam.have_perspective_motion) { /* TODO(sergey): Currently we interpolate projected coordinate which * gives nice looking result and which is simple, but is in fact a bit @@ -63,7 +62,6 @@ ccl_device void camera_sample_perspective(KernelGlobals kg, Pcamera = interp(Pcamera, Pcamera_post, (ray->time - 0.5f) * 2.0f); } } -#endif float3 P = zero_float3(); float3 D = Pcamera; @@ -87,14 +85,12 @@ ccl_device void camera_sample_perspective(KernelGlobals kg, /* transform ray from camera to world */ Transform cameratoworld = kernel_data.cam.cameratoworld; -#ifdef __CAMERA_MOTION__ if (kernel_data.cam.num_motion_steps) { transform_motion_array_interpolate(&cameratoworld, kernel_data_array(camera_motion), kernel_data.cam.num_motion_steps, ray->time); } -#endif P = transform_point(&cameratoworld, P); D = normalize(transform_direction(&cameratoworld, D)); @@ -159,7 +155,6 @@ ccl_device void camera_sample_perspective(KernelGlobals kg, #endif } -#ifdef __CAMERA_CLIPPING__ /* clipping */ float z_inv = 1.0f / normalize(Pcamera).z; float nearclip = kernel_data.cam.nearclip * z_inv; @@ -167,10 +162,6 @@ ccl_device void camera_sample_perspective(KernelGlobals kg, ray->dP += nearclip * ray->dD; ray->tmin = 0.0f; ray->tmax = kernel_data.cam.cliplength * z_inv; -#else - ray->tmin = 0.0f; - ray->tmax = FLT_MAX; -#endif } /* Orthographic Camera */ @@ -209,14 +200,12 @@ ccl_device void camera_sample_orthographic(KernelGlobals kg, /* transform ray from camera to world */ Transform cameratoworld = kernel_data.cam.cameratoworld; -#ifdef __CAMERA_MOTION__ if (kernel_data.cam.num_motion_steps) { transform_motion_array_interpolate(&cameratoworld, kernel_data_array(camera_motion), kernel_data.cam.num_motion_steps, ray->time); } -#endif ray->P = transform_point(&cameratoworld, P); ray->D = normalize(transform_direction(&cameratoworld, D)); @@ -231,22 +220,15 @@ ccl_device void camera_sample_orthographic(KernelGlobals kg, ray->dD = differential_zero_compact(); #endif -#ifdef __CAMERA_CLIPPING__ /* clipping */ ray->tmin = 0.0f; ray->tmax = kernel_data.cam.cliplength; -#else - ray->tmin = 0.0f; - ray->tmax = FLT_MAX; -#endif } /* Panorama Camera */ ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam, -#ifdef __CAMERA_MOTION__ ccl_global const DecomposedTransform *cam_motion, -#endif float raster_x, float raster_y, float lens_u, @@ -290,12 +272,10 @@ ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam, /* transform ray from camera to world */ Transform cameratoworld = cam->cameratoworld; -#ifdef __CAMERA_MOTION__ if (cam->num_motion_steps) { transform_motion_array_interpolate( &cameratoworld, cam_motion, cam->num_motion_steps, ray->time); } -#endif /* Stereo transform */ bool use_stereo = cam->interocular_offset != 0.0f; @@ -348,17 +328,12 @@ ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam, ray->dP = differential_make_compact(dP); #endif -#ifdef __CAMERA_CLIPPING__ /* clipping */ float nearclip = cam->nearclip; ray->P += nearclip * ray->D; ray->dP += nearclip * ray->dD; ray->tmin = 0.0f; ray->tmax = cam->cliplength; -#else - ray->tmin = 0.0f; - ray->tmax = FLT_MAX; -#endif } /* Common */ @@ -378,7 +353,6 @@ ccl_device_inline void camera_sample(KernelGlobals kg, float raster_x = x + lookup_table_read(kg, filter_u, filter_table_offset, FILTER_TABLE_SIZE); float raster_y = y + lookup_table_read(kg, filter_v, filter_table_offset, FILTER_TABLE_SIZE); -#ifdef __CAMERA_MOTION__ /* motion blur */ if (kernel_data.cam.shuttertime == -1.0f) { ray->time = 0.5f; @@ -416,7 +390,6 @@ ccl_device_inline void camera_sample(KernelGlobals kg, } } } -#endif /* sample */ if (kernel_data.cam.type == CAMERA_PERSPECTIVE) { @@ -426,12 +399,8 @@ ccl_device_inline void camera_sample(KernelGlobals kg, camera_sample_orthographic(kg, raster_x, raster_y, lens_u, lens_v, ray); } else { -#ifdef __CAMERA_MOTION__ ccl_global const DecomposedTransform *cam_motion = kernel_data_array(camera_motion); camera_sample_panorama(&kernel_data.cam, cam_motion, raster_x, raster_y, lens_u, lens_v, ray); -#else - camera_sample_panorama(&kernel_data.cam, raster_x, raster_y, lens_u, lens_v, ray); -#endif } } diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index d6b7e7bfa88..02cf8bfe3e2 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -182,14 +182,12 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg, case CLOSURE_BSDF_HAIR_PRINCIPLED_ID: label = bsdf_principled_hair_sample(kg, sc, sd, randu, randv, eval, omega_in, pdf); break; -# ifdef __PRINCIPLED__ case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID: label = bsdf_principled_diffuse_sample(sc, Ng, sd->I, randu, randv, eval, omega_in, pdf); break; case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID: label = bsdf_principled_sheen_sample(sc, Ng, sd->I, randu, randv, eval, omega_in, pdf); break; -# endif /* __PRINCIPLED__ */ #endif default: label = LABEL_NONE; @@ -312,14 +310,12 @@ ccl_device_inline case CLOSURE_BSDF_HAIR_TRANSMISSION_ID: eval = bsdf_hair_transmission_eval_reflect(sc, sd->I, omega_in, pdf); break; -# ifdef __PRINCIPLED__ case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID: eval = bsdf_principled_diffuse_eval_reflect(sc, sd->I, omega_in, pdf); break; case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID: eval = bsdf_principled_sheen_eval_reflect(sc, sd->I, omega_in, pdf); break; -# endif /* __PRINCIPLED__ */ #endif default: break; @@ -397,14 +393,12 @@ ccl_device_inline case CLOSURE_BSDF_HAIR_TRANSMISSION_ID: eval = bsdf_hair_transmission_eval_transmit(sc, sd->I, omega_in, pdf); break; -# ifdef __PRINCIPLED__ case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID: eval = bsdf_principled_diffuse_eval_transmit(sc, sd->I, omega_in, pdf); break; case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID: eval = bsdf_principled_sheen_eval_transmit(sc, sd->I, omega_in, pdf); break; -# endif /* __PRINCIPLED__ */ #endif default: break; diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h index cdd4d128c1f..7131d9d8f38 100644 --- a/intern/cycles/kernel/closure/bssrdf.h +++ b/intern/cycles/kernel/closure/bssrdf.h @@ -312,7 +312,6 @@ ccl_device int bssrdf_setup(ccl_private ShaderData *sd, if (bssrdf_channels < SPECTRUM_CHANNELS) { /* Add diffuse BSDF if any radius too small. */ -#ifdef __PRINCIPLED__ if (bssrdf->roughness != FLT_MAX) { ccl_private PrincipledDiffuseBsdf *bsdf = (ccl_private PrincipledDiffuseBsdf *)bsdf_alloc( sd, sizeof(PrincipledDiffuseBsdf), diffuse_weight); @@ -323,9 +322,7 @@ ccl_device int bssrdf_setup(ccl_private ShaderData *sd, flag |= bsdf_principled_diffuse_setup(bsdf, PRINCIPLED_DIFFUSE_LAMBERT); } } - else -#endif /* __PRINCIPLED__ */ - { + else { ccl_private DiffuseBsdf *bsdf = (ccl_private DiffuseBsdf *)bsdf_alloc( sd, sizeof(DiffuseBsdf), diffuse_weight); diff --git a/intern/cycles/kernel/device/cpu/kernel_arch_impl.h b/intern/cycles/kernel/device/cpu/kernel_arch_impl.h index 0e5f7b4a2fd..0d7c06f4fc6 100644 --- a/intern/cycles/kernel/device/cpu/kernel_arch_impl.h +++ b/intern/cycles/kernel/device/cpu/kernel_arch_impl.h @@ -34,7 +34,7 @@ # include "kernel/integrator/megakernel.h" # include "kernel/film/adaptive_sampling.h" -# include "kernel/film/id_passes.h" +# include "kernel/film/cryptomatte_passes.h" # include "kernel/film/read.h" # include "kernel/bake/bake.h" @@ -169,7 +169,7 @@ bool KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_convergence_check)( STUB_ASSERT(KERNEL_ARCH, adaptive_sampling_convergence_check); return false; #else - return kernel_adaptive_sampling_convergence_check( + return film_adaptive_sampling_convergence_check( kg, render_buffer, x, y, threshold, reset, offset, stride); #endif } @@ -185,7 +185,7 @@ void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_x)(const KernelGlobalsCP #ifdef KERNEL_STUB STUB_ASSERT(KERNEL_ARCH, adaptive_sampling_filter_x); #else - kernel_adaptive_sampling_filter_x(kg, render_buffer, y, start_x, width, offset, stride); + film_adaptive_sampling_filter_x(kg, render_buffer, y, start_x, width, offset, stride); #endif } @@ -200,7 +200,7 @@ void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_y)(const KernelGlobalsCP #ifdef KERNEL_STUB STUB_ASSERT(KERNEL_ARCH, adaptive_sampling_filter_y); #else - kernel_adaptive_sampling_filter_y(kg, render_buffer, x, start_y, height, offset, stride); + film_adaptive_sampling_filter_y(kg, render_buffer, x, start_y, height, offset, stride); #endif } @@ -215,7 +215,7 @@ void KERNEL_FUNCTION_FULL_NAME(cryptomatte_postprocess)(const KernelGlobalsCPU * #ifdef KERNEL_STUB STUB_ASSERT(KERNEL_ARCH, cryptomatte_postprocess); #else - kernel_cryptomatte_post(kg, render_buffer, pixel_index); + film_cryptomatte_post(kg, render_buffer, pixel_index); #endif } diff --git a/intern/cycles/kernel/device/gpu/kernel.h b/intern/cycles/kernel/device/gpu/kernel.h index e1ab802aa80..d7d2000775f 100644 --- a/intern/cycles/kernel/device/gpu/kernel.h +++ b/intern/cycles/kernel/device/gpu/kernel.h @@ -526,7 +526,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) bool converged = true; if (x < sw && y < sh) { - converged = ccl_gpu_kernel_call(kernel_adaptive_sampling_convergence_check( + converged = ccl_gpu_kernel_call(film_adaptive_sampling_convergence_check( nullptr, render_buffer, sx + x, sy + y, threshold, reset, offset, stride)); } @@ -553,7 +553,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) if (y < sh) { ccl_gpu_kernel_call( - kernel_adaptive_sampling_filter_x(NULL, render_buffer, sy + y, sx, sw, offset, stride)); + film_adaptive_sampling_filter_x(NULL, render_buffer, sy + y, sx, sw, offset, stride)); } } ccl_gpu_kernel_postfix @@ -572,7 +572,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) if (x < sw) { ccl_gpu_kernel_call( - kernel_adaptive_sampling_filter_y(NULL, render_buffer, sx + x, sy, sh, offset, stride)); + film_adaptive_sampling_filter_y(NULL, render_buffer, sx + x, sy, sh, offset, stride)); } } ccl_gpu_kernel_postfix @@ -589,7 +589,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) const int pixel_index = ccl_gpu_global_id_x(); if (pixel_index < num_pixels) { - ccl_gpu_kernel_call(kernel_cryptomatte_post(nullptr, render_buffer, pixel_index)); + ccl_gpu_kernel_call(film_cryptomatte_post(nullptr, render_buffer, pixel_index)); } } ccl_gpu_kernel_postfix diff --git a/intern/cycles/kernel/film/adaptive_sampling.h b/intern/cycles/kernel/film/adaptive_sampling.h index 16867c39d99..d28c87747c3 100644 --- a/intern/cycles/kernel/film/adaptive_sampling.h +++ b/intern/cycles/kernel/film/adaptive_sampling.h @@ -3,15 +3,15 @@ #pragma once -#include "kernel/film/write_passes.h" +#include "kernel/film/write.h" CCL_NAMESPACE_BEGIN /* Check whether the pixel has converged and should not be sampled anymore. */ -ccl_device_forceinline bool kernel_need_sample_pixel(KernelGlobals kg, - ConstIntegratorState state, - ccl_global float *render_buffer) +ccl_device_forceinline bool film_need_sample_pixel(KernelGlobals kg, + ConstIntegratorState state, + ccl_global float *render_buffer) { if (kernel_data.film.pass_adaptive_aux_buffer == PASS_UNUSED) { return true; @@ -28,14 +28,14 @@ ccl_device_forceinline bool kernel_need_sample_pixel(KernelGlobals kg, /* Determines whether to continue sampling a given pixel or if it has sufficiently converged. */ -ccl_device bool kernel_adaptive_sampling_convergence_check(KernelGlobals kg, - ccl_global float *render_buffer, - int x, - int y, - float threshold, - bool reset, - int offset, - int stride) +ccl_device bool film_adaptive_sampling_convergence_check(KernelGlobals kg, + ccl_global float *render_buffer, + int x, + int y, + float threshold, + bool reset, + int offset, + int stride) { kernel_assert(kernel_data.film.pass_adaptive_aux_buffer != PASS_UNUSED); kernel_assert(kernel_data.film.pass_sample_count != PASS_UNUSED); @@ -78,13 +78,13 @@ ccl_device bool kernel_adaptive_sampling_convergence_check(KernelGlobals kg, /* This is a simple box filter in two passes. * When a pixel demands more adaptive samples, let its neighboring pixels draw more samples too. */ -ccl_device void kernel_adaptive_sampling_filter_x(KernelGlobals kg, - ccl_global float *render_buffer, - int y, - int start_x, - int width, - int offset, - int stride) +ccl_device void film_adaptive_sampling_filter_x(KernelGlobals kg, + ccl_global float *render_buffer, + int y, + int start_x, + int width, + int offset, + int stride) { kernel_assert(kernel_data.film.pass_adaptive_aux_buffer != PASS_UNUSED); @@ -111,13 +111,13 @@ ccl_device void kernel_adaptive_sampling_filter_x(KernelGlobals kg, } } -ccl_device void kernel_adaptive_sampling_filter_y(KernelGlobals kg, - ccl_global float *render_buffer, - int x, - int start_y, - int height, - int offset, - int stride) +ccl_device void film_adaptive_sampling_filter_y(KernelGlobals kg, + ccl_global float *render_buffer, + int x, + int start_y, + int height, + int offset, + int stride) { kernel_assert(kernel_data.film.pass_adaptive_aux_buffer != PASS_UNUSED); diff --git a/intern/cycles/kernel/film/aov_passes.h b/intern/cycles/kernel/film/aov_passes.h new file mode 100644 index 00000000000..3fbb250340f --- /dev/null +++ b/intern/cycles/kernel/film/aov_passes.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#pragma once + +#include "kernel/geom/geom.h" + +#include "kernel/film/write.h" + +CCL_NAMESPACE_BEGIN + +ccl_device_inline void film_write_aov_pass_value(KernelGlobals kg, + ConstIntegratorState state, + ccl_global float *ccl_restrict render_buffer, + const int aov_id, + const float value) +{ + ccl_global float *buffer = film_pass_pixel_render_buffer(kg, state, render_buffer); + film_write_pass_float(buffer + kernel_data.film.pass_aov_value + aov_id, value); +} + +ccl_device_inline void film_write_aov_pass_color(KernelGlobals kg, + ConstIntegratorState state, + ccl_global float *ccl_restrict render_buffer, + const int aov_id, + const float3 color) +{ + ccl_global float *buffer = film_pass_pixel_render_buffer(kg, state, render_buffer); + film_write_pass_float4(buffer + kernel_data.film.pass_aov_color + aov_id, + make_float4(color.x, color.y, color.z, 1.0f)); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/film/id_passes.h b/intern/cycles/kernel/film/cryptomatte_passes.h index c8317512bb2..4765777e7e2 100644 --- a/intern/cycles/kernel/film/id_passes.h +++ b/intern/cycles/kernel/film/cryptomatte_passes.h @@ -8,15 +8,15 @@ CCL_NAMESPACE_BEGIN /* Element of ID pass stored in the render buffers. * It is `float2` semantically, but it must be unaligned since the offset of ID passes in the * render buffers might not meet expected by compiler alignment. */ -typedef struct IDPassBufferElement { +typedef struct CryptoPassBufferElement { float x; float y; -} IDPassBufferElement; +} CryptoPassBufferElement; -ccl_device_inline void kernel_write_id_slots(ccl_global float *buffer, - int num_slots, - float id, - float weight) +ccl_device_inline void film_write_cryptomatte_slots(ccl_global float *buffer, + int num_slots, + float id, + float weight) { kernel_assert(id != ID_NONE); if (weight == 0.0f) { @@ -24,7 +24,7 @@ ccl_device_inline void kernel_write_id_slots(ccl_global float *buffer, } for (int slot = 0; slot < num_slots; slot++) { - ccl_global IDPassBufferElement *id_buffer = (ccl_global IDPassBufferElement *)buffer; + ccl_global CryptoPassBufferElement *id_buffer = (ccl_global CryptoPassBufferElement *)buffer; #ifdef __ATOMIC_PASS_WRITE__ /* If the loop reaches an empty slot, the ID isn't in any slot yet - so add it! */ if (id_buffer[slot].x == ID_NONE) { @@ -60,9 +60,9 @@ ccl_device_inline void kernel_write_id_slots(ccl_global float *buffer, } } -ccl_device_inline void kernel_sort_id_slots(ccl_global float *buffer, int num_slots) +ccl_device_inline void film_sort_cryptomatte_slots(ccl_global float *buffer, int num_slots) { - ccl_global IDPassBufferElement *id_buffer = (ccl_global IDPassBufferElement *)buffer; + ccl_global CryptoPassBufferElement *id_buffer = (ccl_global CryptoPassBufferElement *)buffer; for (int slot = 1; slot < num_slots; ++slot) { if (id_buffer[slot].x == ID_NONE) { return; @@ -70,7 +70,7 @@ ccl_device_inline void kernel_sort_id_slots(ccl_global float *buffer, int num_sl /* Since we're dealing with a tiny number of elements, insertion sort should be fine. */ int i = slot; while (i > 0 && id_buffer[i].y > id_buffer[i - 1].y) { - const IDPassBufferElement swap = id_buffer[i]; + const CryptoPassBufferElement swap = id_buffer[i]; id_buffer[i] = id_buffer[i - 1]; id_buffer[i - 1] = swap; --i; @@ -79,15 +79,15 @@ ccl_device_inline void kernel_sort_id_slots(ccl_global float *buffer, int num_sl } /* post-sorting for Cryptomatte */ -ccl_device_inline void kernel_cryptomatte_post(KernelGlobals kg, - ccl_global float *render_buffer, - int pixel_index) +ccl_device_inline void film_cryptomatte_post(KernelGlobals kg, + ccl_global float *render_buffer, + int pixel_index) { const int pass_stride = kernel_data.film.pass_stride; const uint64_t render_buffer_offset = (uint64_t)pixel_index * pass_stride; ccl_global float *cryptomatte_buffer = render_buffer + render_buffer_offset + kernel_data.film.pass_cryptomatte; - kernel_sort_id_slots(cryptomatte_buffer, 2 * kernel_data.film.cryptomatte_depth); + film_sort_cryptomatte_slots(cryptomatte_buffer, 2 * kernel_data.film.cryptomatte_depth); } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/film/data_passes.h b/intern/cycles/kernel/film/data_passes.h new file mode 100644 index 00000000000..d14b3cea989 --- /dev/null +++ b/intern/cycles/kernel/film/data_passes.h @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#pragma once + +#include "kernel/geom/geom.h" + +#include "kernel/film/cryptomatte_passes.h" +#include "kernel/film/write.h" + +CCL_NAMESPACE_BEGIN + +ccl_device_inline size_t film_write_cryptomatte_pass(ccl_global float *ccl_restrict buffer, + size_t depth, + float id, + float matte_weight) +{ + film_write_cryptomatte_slots(buffer, depth * 2, id, matte_weight); + return depth * 4; +} + +ccl_device_inline void film_write_data_passes(KernelGlobals kg, + IntegratorState state, + ccl_private const ShaderData *sd, + ccl_global float *ccl_restrict render_buffer) +{ +#ifdef __PASSES__ + const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); + + if (!(path_flag & PATH_RAY_TRANSPARENT_BACKGROUND)) { + return; + } + + const int flag = kernel_data.film.pass_flag; + + if (!(flag & PASS_ANY)) { + return; + } + + ccl_global float *buffer = film_pass_pixel_render_buffer(kg, state, render_buffer); + + if (!(path_flag & PATH_RAY_SINGLE_PASS_DONE)) { + if (!(sd->flag & SD_TRANSPARENT) || kernel_data.film.pass_alpha_threshold == 0.0f || + average(surface_shader_alpha(kg, sd)) >= kernel_data.film.pass_alpha_threshold) { + if (INTEGRATOR_STATE(state, path, sample) == 0) { + if (flag & PASSMASK(DEPTH)) { + const float depth = camera_z_depth(kg, sd->P); + film_write_pass_float(buffer + kernel_data.film.pass_depth, depth); + } + if (flag & PASSMASK(OBJECT_ID)) { + const float id = object_pass_id(kg, sd->object); + film_write_pass_float(buffer + kernel_data.film.pass_object_id, id); + } + if (flag & PASSMASK(MATERIAL_ID)) { + const float id = shader_pass_id(kg, sd); + film_write_pass_float(buffer + kernel_data.film.pass_material_id, id); + } + if (flag & PASSMASK(POSITION)) { + const float3 position = sd->P; + film_write_pass_float3(buffer + kernel_data.film.pass_position, position); + } + } + + if (flag & PASSMASK(NORMAL)) { + const float3 normal = surface_shader_average_normal(kg, sd); + film_write_pass_float3(buffer + kernel_data.film.pass_normal, normal); + } + if (flag & PASSMASK(ROUGHNESS)) { + const float roughness = surface_shader_average_roughness(sd); + film_write_pass_float(buffer + kernel_data.film.pass_roughness, roughness); + } + if (flag & PASSMASK(UV)) { + const float3 uv = primitive_uv(kg, sd); + film_write_pass_float3(buffer + kernel_data.film.pass_uv, uv); + } + if (flag & PASSMASK(MOTION)) { + const float4 speed = primitive_motion_vector(kg, sd); + film_write_pass_float4(buffer + kernel_data.film.pass_motion, speed); + film_write_pass_float(buffer + kernel_data.film.pass_motion_weight, 1.0f); + } + + INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SINGLE_PASS_DONE; + } + } + + if (kernel_data.film.cryptomatte_passes) { + const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput); + const float matte_weight = average(throughput) * + (1.0f - average(surface_shader_transparency(kg, sd))); + if (matte_weight > 0.0f) { + ccl_global float *cryptomatte_buffer = buffer + kernel_data.film.pass_cryptomatte; + if (kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) { + const float id = object_cryptomatte_id(kg, sd->object); + cryptomatte_buffer += film_write_cryptomatte_pass( + cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight); + } + if (kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) { + const float id = kernel_data_fetch(shaders, (sd->shader & SHADER_MASK)).cryptomatte_id; + cryptomatte_buffer += film_write_cryptomatte_pass( + cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight); + } + if (kernel_data.film.cryptomatte_passes & CRYPT_ASSET) { + const float id = object_cryptomatte_asset_id(kg, sd->object); + cryptomatte_buffer += film_write_cryptomatte_pass( + cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight); + } + } + } + + if (flag & PASSMASK(DIFFUSE_COLOR)) { + const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput); + film_write_pass_spectrum(buffer + kernel_data.film.pass_diffuse_color, + surface_shader_diffuse(kg, sd) * throughput); + } + if (flag & PASSMASK(GLOSSY_COLOR)) { + const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput); + film_write_pass_spectrum(buffer + kernel_data.film.pass_glossy_color, + surface_shader_glossy(kg, sd) * throughput); + } + if (flag & PASSMASK(TRANSMISSION_COLOR)) { + const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput); + film_write_pass_spectrum(buffer + kernel_data.film.pass_transmission_color, + surface_shader_transmission(kg, sd) * throughput); + } + if (flag & PASSMASK(MIST)) { + /* Bring depth into 0..1 range. */ + const float mist_start = kernel_data.film.mist_start; + const float mist_inv_depth = kernel_data.film.mist_inv_depth; + + const float depth = camera_distance(kg, sd->P); + float mist = saturatef((depth - mist_start) * mist_inv_depth); + + /* Falloff */ + const float mist_falloff = kernel_data.film.mist_falloff; + + if (mist_falloff == 1.0f) + ; + else if (mist_falloff == 2.0f) + mist = mist * mist; + else if (mist_falloff == 0.5f) + mist = sqrtf(mist); + else + mist = powf(mist, mist_falloff); + + /* Modulate by transparency */ + const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput); + const Spectrum alpha = surface_shader_alpha(kg, sd); + const float mist_output = (1.0f - mist) * average(throughput * alpha); + + /* Note that the final value in the render buffer we want is 1 - mist_output, + * to avoid having to tracking this in the Integrator state we do the negation + * after rendering. */ + film_write_pass_float(buffer + kernel_data.film.pass_mist, mist_output); + } +#endif +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/film/denoising_passes.h b/intern/cycles/kernel/film/denoising_passes.h new file mode 100644 index 00000000000..1517e8bad56 --- /dev/null +++ b/intern/cycles/kernel/film/denoising_passes.h @@ -0,0 +1,146 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#pragma once + +#include "kernel/geom/geom.h" + +#include "kernel/film/write.h" + +CCL_NAMESPACE_BEGIN + +#ifdef __DENOISING_FEATURES__ +ccl_device_forceinline void film_write_denoising_features_surface(KernelGlobals kg, + IntegratorState state, + ccl_private const ShaderData *sd, + ccl_global float *ccl_restrict + render_buffer) +{ + if (!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_DENOISING_FEATURES)) { + return; + } + + /* Skip implicitly transparent surfaces. */ + if (sd->flag & SD_HAS_ONLY_VOLUME) { + return; + } + + ccl_global float *buffer = film_pass_pixel_render_buffer(kg, state, render_buffer); + + if (kernel_data.film.pass_denoising_depth != PASS_UNUSED) { + const Spectrum denoising_feature_throughput = INTEGRATOR_STATE( + state, path, denoising_feature_throughput); + const float denoising_depth = ensure_finite(average(denoising_feature_throughput) * + sd->ray_length); + film_write_pass_float(buffer + kernel_data.film.pass_denoising_depth, denoising_depth); + } + + float3 normal = zero_float3(); + Spectrum diffuse_albedo = zero_spectrum(); + Spectrum specular_albedo = zero_spectrum(); + float sum_weight = 0.0f, sum_nonspecular_weight = 0.0f; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (!CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + continue; + } + + /* All closures contribute to the normal feature, but only diffuse-like ones to the albedo. */ + normal += sc->N * sc->sample_weight; + sum_weight += sc->sample_weight; + + Spectrum closure_albedo = sc->weight; + /* Closures that include a Fresnel term typically have weights close to 1 even though their + * actual contribution is significantly lower. + * To account for this, we scale their weight by the average fresnel factor (the same is also + * done for the sample weight in the BSDF setup, so we don't need to scale that here). */ + if (CLOSURE_IS_BSDF_MICROFACET_FRESNEL(sc->type)) { + ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc; + closure_albedo *= bsdf->extra->fresnel_color; + } + else if (sc->type == CLOSURE_BSDF_PRINCIPLED_SHEEN_ID) { + ccl_private PrincipledSheenBsdf *bsdf = (ccl_private PrincipledSheenBsdf *)sc; + closure_albedo *= bsdf->avg_value; + } + else if (sc->type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) { + closure_albedo *= bsdf_principled_hair_albedo(sc); + } + else if (sc->type == CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID) { + /* BSSRDF already accounts for weight, retro-reflection would double up. */ + ccl_private const PrincipledDiffuseBsdf *bsdf = (ccl_private const PrincipledDiffuseBsdf *) + sc; + if (bsdf->components == PRINCIPLED_DIFFUSE_RETRO_REFLECTION) { + continue; + } + } + + if (bsdf_get_specular_roughness_squared(sc) > sqr(0.075f)) { + diffuse_albedo += closure_albedo; + sum_nonspecular_weight += sc->sample_weight; + } + else { + specular_albedo += closure_albedo; + } + } + + /* Wait for next bounce if 75% or more sample weight belongs to specular-like closures. */ + if ((sum_weight == 0.0f) || (sum_nonspecular_weight * 4.0f > sum_weight)) { + if (sum_weight != 0.0f) { + normal /= sum_weight; + } + + if (kernel_data.film.pass_denoising_normal != PASS_UNUSED) { + /* Transform normal into camera space. */ + const Transform worldtocamera = kernel_data.cam.worldtocamera; + normal = transform_direction(&worldtocamera, normal); + + const float3 denoising_normal = ensure_finite(normal); + film_write_pass_float3(buffer + kernel_data.film.pass_denoising_normal, denoising_normal); + } + + if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) { + const Spectrum denoising_feature_throughput = INTEGRATOR_STATE( + state, path, denoising_feature_throughput); + const Spectrum denoising_albedo = ensure_finite(denoising_feature_throughput * + diffuse_albedo); + film_write_pass_spectrum(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo); + } + + INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_DENOISING_FEATURES; + } + else { + INTEGRATOR_STATE_WRITE(state, path, denoising_feature_throughput) *= specular_albedo; + } +} + +ccl_device_forceinline void film_write_denoising_features_volume(KernelGlobals kg, + IntegratorState state, + const Spectrum albedo, + const bool scatter, + ccl_global float *ccl_restrict + render_buffer) +{ + ccl_global float *buffer = film_pass_pixel_render_buffer(kg, state, render_buffer); + const Spectrum denoising_feature_throughput = INTEGRATOR_STATE( + state, path, denoising_feature_throughput); + + if (scatter && kernel_data.film.pass_denoising_normal != PASS_UNUSED) { + /* Assume scatter is sufficiently diffuse to stop writing denoising features. */ + INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_DENOISING_FEATURES; + + /* Write view direction as normal. */ + const float3 denoising_normal = make_float3(0.0f, 0.0f, -1.0f); + film_write_pass_float3(buffer + kernel_data.film.pass_denoising_normal, denoising_normal); + } + + if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) { + /* Write albedo. */ + const Spectrum denoising_albedo = ensure_finite(denoising_feature_throughput * albedo); + film_write_pass_spectrum(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo); + } +} +#endif /* __DENOISING_FEATURES__ */ + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/film/accumulate.h b/intern/cycles/kernel/film/light_passes.h index 97ec915a8ad..b45b5305119 100644 --- a/intern/cycles/kernel/film/accumulate.h +++ b/intern/cycles/kernel/film/light_passes.h @@ -4,7 +4,7 @@ #pragma once #include "kernel/film/adaptive_sampling.h" -#include "kernel/film/write_passes.h" +#include "kernel/film/write.h" #include "kernel/integrator/shadow_catcher.h" @@ -95,9 +95,7 @@ ccl_device_inline Spectrum bsdf_eval_pass_glossy_weight(ccl_private const BsdfEv * to render buffers instead of using per-thread memory, and to avoid the * impact of clamping on other contributions. */ -ccl_device_forceinline void kernel_accum_clamp(KernelGlobals kg, - ccl_private Spectrum *L, - int bounce) +ccl_device_forceinline void film_clamp_light(KernelGlobals kg, ccl_private Spectrum *L, int bounce) { #ifdef __KERNEL_DEBUG_NAN__ if (!isfinite_safe(*L)) { @@ -123,59 +121,49 @@ ccl_device_forceinline void kernel_accum_clamp(KernelGlobals kg, * Pass accumulation utilities. */ -/* Get pointer to pixel in render buffer. */ -ccl_device_forceinline ccl_global float *kernel_accum_pixel_render_buffer( - KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer) -{ - const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index); - const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * - kernel_data.film.pass_stride; - return render_buffer + render_buffer_offset; -} - /* -------------------------------------------------------------------- * Adaptive sampling. */ -ccl_device_inline int kernel_accum_sample(KernelGlobals kg, - ConstIntegratorState state, - ccl_global float *ccl_restrict render_buffer, - int sample, - int sample_offset) +ccl_device_inline int film_write_sample(KernelGlobals kg, + ConstIntegratorState state, + ccl_global float *ccl_restrict render_buffer, + int sample, + int sample_offset) { if (kernel_data.film.pass_sample_count == PASS_UNUSED) { return sample; } - ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer); + ccl_global float *buffer = film_pass_pixel_render_buffer(kg, state, render_buffer); return atomic_fetch_and_add_uint32( (ccl_global uint *)(buffer) + kernel_data.film.pass_sample_count, 1) + sample_offset; } -ccl_device void kernel_accum_adaptive_buffer(KernelGlobals kg, - const int sample, - const Spectrum contribution, - ccl_global float *ccl_restrict buffer) +ccl_device void film_write_adaptive_buffer(KernelGlobals kg, + const int sample, + const Spectrum contribution, + ccl_global float *ccl_restrict buffer) { - /* Adaptive Sampling. Fill the additional buffer with the odd samples and calculate our stopping - * criteria. This is the heuristic from "A hierarchical automatic stopping condition for Monte - * Carlo global illumination" except that here it is applied per pixel and not in hierarchical - * tiles. */ + /* Adaptive Sampling. Fill the additional buffer with only one half of the samples and + * calculate our stopping criteria. This is the heuristic from "A hierarchical automatic + * stopping condition for Monte Carlo global illumination" except that here it is applied + * per pixel and not in hierarchical tiles. */ if (kernel_data.film.pass_adaptive_aux_buffer == PASS_UNUSED) { return; } - if (sample_is_even(kernel_data.integrator.sampling_pattern, sample)) { + if (sample_is_class_A(kernel_data.integrator.sampling_pattern, sample)) { const float3 contribution_rgb = spectrum_to_rgb(contribution); - kernel_write_pass_float4(buffer + kernel_data.film.pass_adaptive_aux_buffer, - make_float4(contribution_rgb.x * 2.0f, - contribution_rgb.y * 2.0f, - contribution_rgb.z * 2.0f, - 0.0f)); + film_write_pass_float4(buffer + kernel_data.film.pass_adaptive_aux_buffer, + make_float4(contribution_rgb.x * 2.0f, + contribution_rgb.y * 2.0f, + contribution_rgb.z * 2.0f, + 0.0f)); } } @@ -190,10 +178,10 @@ ccl_device void kernel_accum_adaptive_buffer(KernelGlobals kg, * Returns truth if the contribution is fully handled here and is not to be added to the other * passes (like combined, adaptive sampling). */ -ccl_device bool kernel_accum_shadow_catcher(KernelGlobals kg, - const uint32_t path_flag, - const Spectrum contribution, - ccl_global float *ccl_restrict buffer) +ccl_device bool film_write_shadow_catcher(KernelGlobals kg, + const uint32_t path_flag, + const Spectrum contribution, + ccl_global float *ccl_restrict buffer) { if (!kernel_data.integrator.has_shadow_catcher) { return false; @@ -204,7 +192,7 @@ ccl_device bool kernel_accum_shadow_catcher(KernelGlobals kg, /* Matte pass. */ if (kernel_shadow_catcher_is_matte_path(path_flag)) { - kernel_write_pass_spectrum(buffer + kernel_data.film.pass_shadow_catcher_matte, contribution); + film_write_pass_spectrum(buffer + kernel_data.film.pass_shadow_catcher_matte, contribution); /* NOTE: Accumulate the combined pass and to the samples count pass, so that the adaptive * sampling is based on how noisy the combined pass is as if there were no catchers in the * scene. */ @@ -212,18 +200,18 @@ ccl_device bool kernel_accum_shadow_catcher(KernelGlobals kg, /* Shadow catcher pass. */ if (kernel_shadow_catcher_is_object_pass(path_flag)) { - kernel_write_pass_spectrum(buffer + kernel_data.film.pass_shadow_catcher, contribution); + film_write_pass_spectrum(buffer + kernel_data.film.pass_shadow_catcher, contribution); return true; } return false; } -ccl_device bool kernel_accum_shadow_catcher_transparent(KernelGlobals kg, - const uint32_t path_flag, - const Spectrum contribution, - const float transparent, - ccl_global float *ccl_restrict buffer) +ccl_device bool film_write_shadow_catcher_transparent(KernelGlobals kg, + const uint32_t path_flag, + const Spectrum contribution, + const float transparent, + ccl_global float *ccl_restrict buffer) { if (!kernel_data.integrator.has_shadow_catcher) { return false; @@ -240,7 +228,7 @@ ccl_device bool kernel_accum_shadow_catcher_transparent(KernelGlobals kg, if (kernel_shadow_catcher_is_matte_path(path_flag)) { const float3 contribution_rgb = spectrum_to_rgb(contribution); - kernel_write_pass_float4( + film_write_pass_float4( buffer + kernel_data.film.pass_shadow_catcher_matte, make_float4(contribution_rgb.x, contribution_rgb.y, contribution_rgb.z, transparent)); /* NOTE: Accumulate the combined pass and to the samples count pass, so that the adaptive @@ -253,17 +241,17 @@ ccl_device bool kernel_accum_shadow_catcher_transparent(KernelGlobals kg, /* NOTE: The transparency of the shadow catcher pass is ignored. It is not needed for the * calculation and the alpha channel of the pass contains numbers of samples contributed to a * pixel of the pass. */ - kernel_write_pass_spectrum(buffer + kernel_data.film.pass_shadow_catcher, contribution); + film_write_pass_spectrum(buffer + kernel_data.film.pass_shadow_catcher, contribution); return true; } return false; } -ccl_device void kernel_accum_shadow_catcher_transparent_only(KernelGlobals kg, - const uint32_t path_flag, - const float transparent, - ccl_global float *ccl_restrict buffer) +ccl_device void film_write_shadow_catcher_transparent_only(KernelGlobals kg, + const uint32_t path_flag, + const float transparent, + ccl_global float *ccl_restrict buffer) { if (!kernel_data.integrator.has_shadow_catcher) { return; @@ -273,10 +261,29 @@ ccl_device void kernel_accum_shadow_catcher_transparent_only(KernelGlobals kg, /* Matte pass. */ if (kernel_shadow_catcher_is_matte_path(path_flag)) { - kernel_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_matte + 3, transparent); + film_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_matte + 3, transparent); } } +/* Write shadow catcher passes on a bounce from the shadow catcher object. */ +ccl_device_forceinline void film_write_shadow_catcher_bounce_data( + KernelGlobals kg, IntegratorState state, ccl_global float *ccl_restrict render_buffer) +{ + kernel_assert(kernel_data.film.pass_shadow_catcher_sample_count != PASS_UNUSED); + kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED); + + ccl_global float *buffer = film_pass_pixel_render_buffer(kg, state, render_buffer); + + /* Count sample for the shadow catcher object. */ + film_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_sample_count, 1.0f); + + /* Since the split is done, the sample does not contribute to the matte, so accumulate it as + * transparency to the matte. */ + const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput); + film_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_matte + 3, + average(throughput)); +} + #endif /* __SHADOW_CATCHER__ */ /* -------------------------------------------------------------------- @@ -284,36 +291,35 @@ ccl_device void kernel_accum_shadow_catcher_transparent_only(KernelGlobals kg, */ /* Write combined pass. */ -ccl_device_inline void kernel_accum_combined_pass(KernelGlobals kg, - const uint32_t path_flag, - const int sample, - const Spectrum contribution, - ccl_global float *ccl_restrict buffer) +ccl_device_inline void film_write_combined_pass(KernelGlobals kg, + const uint32_t path_flag, + const int sample, + const Spectrum contribution, + ccl_global float *ccl_restrict buffer) { #ifdef __SHADOW_CATCHER__ - if (kernel_accum_shadow_catcher(kg, path_flag, contribution, buffer)) { + if (film_write_shadow_catcher(kg, path_flag, contribution, buffer)) { return; } #endif if (kernel_data.film.light_pass_flag & PASSMASK(COMBINED)) { - kernel_write_pass_spectrum(buffer + kernel_data.film.pass_combined, contribution); + film_write_pass_spectrum(buffer + kernel_data.film.pass_combined, contribution); } - kernel_accum_adaptive_buffer(kg, sample, contribution, buffer); + film_write_adaptive_buffer(kg, sample, contribution, buffer); } /* Write combined pass with transparency. */ -ccl_device_inline void kernel_accum_combined_transparent_pass(KernelGlobals kg, - const uint32_t path_flag, - const int sample, - const Spectrum contribution, - const float transparent, - ccl_global float *ccl_restrict - buffer) +ccl_device_inline void film_write_combined_transparent_pass(KernelGlobals kg, + const uint32_t path_flag, + const int sample, + const Spectrum contribution, + const float transparent, + ccl_global float *ccl_restrict buffer) { #ifdef __SHADOW_CATCHER__ - if (kernel_accum_shadow_catcher_transparent(kg, path_flag, contribution, transparent, buffer)) { + if (film_write_shadow_catcher_transparent(kg, path_flag, contribution, transparent, buffer)) { return; } #endif @@ -321,16 +327,16 @@ ccl_device_inline void kernel_accum_combined_transparent_pass(KernelGlobals kg, if (kernel_data.film.light_pass_flag & PASSMASK(COMBINED)) { const float3 contribution_rgb = spectrum_to_rgb(contribution); - kernel_write_pass_float4( + film_write_pass_float4( buffer + kernel_data.film.pass_combined, make_float4(contribution_rgb.x, contribution_rgb.y, contribution_rgb.z, transparent)); } - kernel_accum_adaptive_buffer(kg, sample, contribution, buffer); + film_write_adaptive_buffer(kg, sample, contribution, buffer); } /* Write background or emission to appropriate pass. */ -ccl_device_inline void kernel_accum_emission_or_background_pass( +ccl_device_inline void film_write_emission_or_background_pass( KernelGlobals kg, ConstIntegratorState state, Spectrum contribution, @@ -353,15 +359,14 @@ ccl_device_inline void kernel_accum_emission_or_background_pass( const Spectrum denoising_feature_throughput = INTEGRATOR_STATE( state, path, denoising_feature_throughput); const Spectrum denoising_albedo = denoising_feature_throughput * contribution; - kernel_write_pass_spectrum(buffer + kernel_data.film.pass_denoising_albedo, - denoising_albedo); + film_write_pass_spectrum(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo); } } # endif /* __DENOISING_FEATURES__ */ if (lightgroup != LIGHTGROUP_NONE && kernel_data.film.pass_lightgroup != PASS_UNUSED) { - kernel_write_pass_spectrum(buffer + kernel_data.film.pass_lightgroup + 3 * lightgroup, - contribution); + film_write_pass_spectrum(buffer + kernel_data.film.pass_lightgroup + 3 * lightgroup, + contribution); } if (!(path_flag & PATH_RAY_ANY_PASS)) { @@ -385,7 +390,7 @@ ccl_device_inline void kernel_accum_emission_or_background_pass( kernel_data.film.pass_glossy_direct : kernel_data.film.pass_glossy_indirect); if (glossy_pass_offset != PASS_UNUSED) { - kernel_write_pass_spectrum(buffer + glossy_pass_offset, glossy_weight * contribution); + film_write_pass_spectrum(buffer + glossy_pass_offset, glossy_weight * contribution); } /* Transmission */ @@ -397,8 +402,8 @@ ccl_device_inline void kernel_accum_emission_or_background_pass( /* Transmission is what remains if not diffuse and glossy, not stored explicitly to save * GPU memory. */ const Spectrum transmission_weight = one_spectrum() - diffuse_weight - glossy_weight; - kernel_write_pass_spectrum(buffer + transmission_pass_offset, - transmission_weight * contribution); + film_write_pass_spectrum(buffer + transmission_pass_offset, + transmission_weight * contribution); } /* Reconstruct diffuse subset of throughput. */ @@ -419,19 +424,19 @@ ccl_device_inline void kernel_accum_emission_or_background_pass( /* Single write call for GPU coherence. */ if (pass_offset != PASS_UNUSED) { - kernel_write_pass_spectrum(buffer + pass_offset, contribution); + film_write_pass_spectrum(buffer + pass_offset, contribution); } #endif /* __PASSES__ */ } /* Write light contribution to render buffer. */ -ccl_device_inline void kernel_accum_light(KernelGlobals kg, - ConstIntegratorShadowState state, - ccl_global float *ccl_restrict render_buffer) +ccl_device_inline void film_write_direct_light(KernelGlobals kg, + ConstIntegratorShadowState state, + ccl_global float *ccl_restrict render_buffer) { /* The throughput for shadow paths already contains the light shader evaluation. */ Spectrum contribution = INTEGRATOR_STATE(state, shadow_path, throughput); - kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, shadow_path, bounce)); + film_clamp_light(kg, &contribution, INTEGRATOR_STATE(state, shadow_path, bounce)); const uint32_t render_pixel_index = INTEGRATOR_STATE(state, shadow_path, render_pixel_index); const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * @@ -444,17 +449,17 @@ ccl_device_inline void kernel_accum_light(KernelGlobals kg, /* Ambient occlusion. */ if (path_flag & PATH_RAY_SHADOW_FOR_AO) { if ((kernel_data.kernel_features & KERNEL_FEATURE_AO_PASS) && (path_flag & PATH_RAY_CAMERA)) { - kernel_write_pass_spectrum(buffer + kernel_data.film.pass_ao, contribution); + film_write_pass_spectrum(buffer + kernel_data.film.pass_ao, contribution); } if (kernel_data.kernel_features & KERNEL_FEATURE_AO_ADDITIVE) { const Spectrum ao_weight = INTEGRATOR_STATE(state, shadow_path, unshadowed_throughput); - kernel_accum_combined_pass(kg, path_flag, sample, contribution * ao_weight, buffer); + film_write_combined_pass(kg, path_flag, sample, contribution * ao_weight, buffer); } return; } /* Direct light shadow. */ - kernel_accum_combined_pass(kg, path_flag, sample, contribution, buffer); + film_write_combined_pass(kg, path_flag, sample, contribution, buffer); #ifdef __PASSES__ if (kernel_data.film.light_pass_flag & PASS_ANY) { @@ -469,8 +474,8 @@ ccl_device_inline void kernel_accum_light(KernelGlobals kg, /* Write lightgroup pass. LIGHTGROUP_NONE is ~0 so decode from unsigned to signed */ const int lightgroup = (int)(INTEGRATOR_STATE(state, shadow_path, lightgroup)) - 1; if (lightgroup != LIGHTGROUP_NONE && kernel_data.film.pass_lightgroup != PASS_UNUSED) { - kernel_write_pass_spectrum(buffer + kernel_data.film.pass_lightgroup + 3 * lightgroup, - contribution); + film_write_pass_spectrum(buffer + kernel_data.film.pass_lightgroup + 3 * lightgroup, + contribution); } if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) { @@ -486,7 +491,7 @@ ccl_device_inline void kernel_accum_light(KernelGlobals kg, kernel_data.film.pass_glossy_direct : kernel_data.film.pass_glossy_indirect); if (glossy_pass_offset != PASS_UNUSED) { - kernel_write_pass_spectrum(buffer + glossy_pass_offset, glossy_weight * contribution); + film_write_pass_spectrum(buffer + glossy_pass_offset, glossy_weight * contribution); } /* Transmission */ @@ -498,8 +503,8 @@ ccl_device_inline void kernel_accum_light(KernelGlobals kg, /* Transmission is what remains if not diffuse and glossy, not stored explicitly to save * GPU memory. */ const Spectrum transmission_weight = one_spectrum() - diffuse_weight - glossy_weight; - kernel_write_pass_spectrum(buffer + transmission_pass_offset, - transmission_weight * contribution); + film_write_pass_spectrum(buffer + transmission_pass_offset, + transmission_weight * contribution); } /* Reconstruct diffuse subset of throughput. */ @@ -519,7 +524,7 @@ ccl_device_inline void kernel_accum_light(KernelGlobals kg, /* Single write call for GPU coherence. */ if (pass_offset != PASS_UNUSED) { - kernel_write_pass_spectrum(buffer + pass_offset, contribution); + film_write_pass_spectrum(buffer + pass_offset, contribution); } } @@ -531,7 +536,7 @@ ccl_device_inline void kernel_accum_light(KernelGlobals kg, const Spectrum shadowed_throughput = INTEGRATOR_STATE(state, shadow_path, throughput); const Spectrum shadow = safe_divide(shadowed_throughput, unshadowed_throughput) * kernel_data.film.pass_shadow_scale; - kernel_write_pass_spectrum(buffer + kernel_data.film.pass_shadow, shadow); + film_write_pass_spectrum(buffer + kernel_data.film.pass_shadow, shadow); } } #endif @@ -542,78 +547,96 @@ ccl_device_inline void kernel_accum_light(KernelGlobals kg, * Note that we accumulate transparency = 1 - alpha in the render buffer. * Otherwise we'd have to write alpha on path termination, which happens * in many places. */ -ccl_device_inline void kernel_accum_transparent(KernelGlobals kg, - ConstIntegratorState state, - const uint32_t path_flag, - const float transparent, - ccl_global float *ccl_restrict buffer) +ccl_device_inline void film_write_transparent(KernelGlobals kg, + ConstIntegratorState state, + const uint32_t path_flag, + const float transparent, + ccl_global float *ccl_restrict buffer) { if (kernel_data.film.light_pass_flag & PASSMASK(COMBINED)) { - kernel_write_pass_float(buffer + kernel_data.film.pass_combined + 3, transparent); + film_write_pass_float(buffer + kernel_data.film.pass_combined + 3, transparent); } - kernel_accum_shadow_catcher_transparent_only(kg, path_flag, transparent, buffer); + film_write_shadow_catcher_transparent_only(kg, path_flag, transparent, buffer); } /* Write holdout to render buffer. */ -ccl_device_inline void kernel_accum_holdout(KernelGlobals kg, - ConstIntegratorState state, - const uint32_t path_flag, - const float transparent, - ccl_global float *ccl_restrict render_buffer) +ccl_device_inline void film_write_holdout(KernelGlobals kg, + ConstIntegratorState state, + const uint32_t path_flag, + const float transparent, + ccl_global float *ccl_restrict render_buffer) { - ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer); - kernel_accum_transparent(kg, state, path_flag, transparent, buffer); + ccl_global float *buffer = film_pass_pixel_render_buffer(kg, state, render_buffer); + film_write_transparent(kg, state, path_flag, transparent, buffer); } /* Write background contribution to render buffer. * - * Includes transparency, matching kernel_accum_transparent. */ -ccl_device_inline void kernel_accum_background(KernelGlobals kg, - ConstIntegratorState state, - const Spectrum L, - const float transparent, - const bool is_transparent_background_ray, - ccl_global float *ccl_restrict render_buffer) + * Includes transparency, matching film_write_transparent. */ +ccl_device_inline void film_write_background(KernelGlobals kg, + ConstIntegratorState state, + const Spectrum L, + const float transparent, + const bool is_transparent_background_ray, + ccl_global float *ccl_restrict render_buffer) { Spectrum contribution = INTEGRATOR_STATE(state, path, throughput) * L; - kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, path, bounce) - 1); + film_clamp_light(kg, &contribution, INTEGRATOR_STATE(state, path, bounce) - 1); - ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer); + ccl_global float *buffer = film_pass_pixel_render_buffer(kg, state, render_buffer); const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); if (is_transparent_background_ray) { - kernel_accum_transparent(kg, state, path_flag, transparent, buffer); + film_write_transparent(kg, state, path_flag, transparent, buffer); } else { const int sample = INTEGRATOR_STATE(state, path, sample); - kernel_accum_combined_transparent_pass( - kg, path_flag, sample, contribution, transparent, buffer); - } - kernel_accum_emission_or_background_pass(kg, - state, - contribution, - buffer, - kernel_data.film.pass_background, - kernel_data.background.lightgroup); + film_write_combined_transparent_pass(kg, path_flag, sample, contribution, transparent, buffer); + } + film_write_emission_or_background_pass(kg, + state, + contribution, + buffer, + kernel_data.film.pass_background, + kernel_data.background.lightgroup); } /* Write emission to render buffer. */ -ccl_device_inline void kernel_accum_emission(KernelGlobals kg, - ConstIntegratorState state, - const Spectrum L, - ccl_global float *ccl_restrict render_buffer, - const int lightgroup = LIGHTGROUP_NONE) +ccl_device_inline void film_write_volume_emission(KernelGlobals kg, + ConstIntegratorState state, + const Spectrum L, + ccl_global float *ccl_restrict render_buffer, + const int lightgroup = LIGHTGROUP_NONE) { Spectrum contribution = L; - kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, path, bounce) - 1); + film_clamp_light(kg, &contribution, INTEGRATOR_STATE(state, path, bounce) - 1); + + ccl_global float *buffer = film_pass_pixel_render_buffer(kg, state, render_buffer); + const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); + const int sample = INTEGRATOR_STATE(state, path, sample); + + film_write_combined_pass(kg, path_flag, sample, contribution, buffer); + film_write_emission_or_background_pass( + kg, state, contribution, buffer, kernel_data.film.pass_emission, lightgroup); +} + +ccl_device_inline void film_write_surface_emission(KernelGlobals kg, + ConstIntegratorState state, + const Spectrum L, + const float mis_weight, + ccl_global float *ccl_restrict render_buffer, + const int lightgroup = LIGHTGROUP_NONE) +{ + Spectrum contribution = INTEGRATOR_STATE(state, path, throughput) * L * mis_weight; + film_clamp_light(kg, &contribution, INTEGRATOR_STATE(state, path, bounce) - 1); - ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer); + ccl_global float *buffer = film_pass_pixel_render_buffer(kg, state, render_buffer); const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); const int sample = INTEGRATOR_STATE(state, path, sample); - kernel_accum_combined_pass(kg, path_flag, sample, contribution, buffer); - kernel_accum_emission_or_background_pass( + film_write_combined_pass(kg, path_flag, sample, contribution, buffer); + film_write_emission_or_background_pass( kg, state, contribution, buffer, kernel_data.film.pass_emission, lightgroup); } diff --git a/intern/cycles/kernel/film/passes.h b/intern/cycles/kernel/film/passes.h deleted file mode 100644 index bea23411000..00000000000 --- a/intern/cycles/kernel/film/passes.h +++ /dev/null @@ -1,304 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 - * Copyright 2011-2022 Blender Foundation */ - -#pragma once - -#include "kernel/geom/geom.h" - -#include "kernel/film/id_passes.h" -#include "kernel/film/write_passes.h" - -CCL_NAMESPACE_BEGIN - -/* Get pointer to pixel in render buffer. */ -ccl_device_forceinline ccl_global float *kernel_pass_pixel_render_buffer( - KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer) -{ - const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index); - const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * - kernel_data.film.pass_stride; - return render_buffer + render_buffer_offset; -} - -#ifdef __DENOISING_FEATURES__ - -ccl_device_forceinline void kernel_write_denoising_features_surface( - KernelGlobals kg, - IntegratorState state, - ccl_private const ShaderData *sd, - ccl_global float *ccl_restrict render_buffer) -{ - if (!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_DENOISING_FEATURES)) { - return; - } - - /* Skip implicitly transparent surfaces. */ - if (sd->flag & SD_HAS_ONLY_VOLUME) { - return; - } - - ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer); - - if (kernel_data.film.pass_denoising_depth != PASS_UNUSED) { - const Spectrum denoising_feature_throughput = INTEGRATOR_STATE( - state, path, denoising_feature_throughput); - const float denoising_depth = ensure_finite(average(denoising_feature_throughput) * - sd->ray_length); - kernel_write_pass_float(buffer + kernel_data.film.pass_denoising_depth, denoising_depth); - } - - float3 normal = zero_float3(); - Spectrum diffuse_albedo = zero_spectrum(); - Spectrum specular_albedo = zero_spectrum(); - float sum_weight = 0.0f, sum_nonspecular_weight = 0.0f; - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (!CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { - continue; - } - - /* All closures contribute to the normal feature, but only diffuse-like ones to the albedo. */ - normal += sc->N * sc->sample_weight; - sum_weight += sc->sample_weight; - - Spectrum closure_albedo = sc->weight; - /* Closures that include a Fresnel term typically have weights close to 1 even though their - * actual contribution is significantly lower. - * To account for this, we scale their weight by the average fresnel factor (the same is also - * done for the sample weight in the BSDF setup, so we don't need to scale that here). */ - if (CLOSURE_IS_BSDF_MICROFACET_FRESNEL(sc->type)) { - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc; - closure_albedo *= bsdf->extra->fresnel_color; - } - else if (sc->type == CLOSURE_BSDF_PRINCIPLED_SHEEN_ID) { - ccl_private PrincipledSheenBsdf *bsdf = (ccl_private PrincipledSheenBsdf *)sc; - closure_albedo *= bsdf->avg_value; - } - else if (sc->type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) { - closure_albedo *= bsdf_principled_hair_albedo(sc); - } - else if (sc->type == CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID) { - /* BSSRDF already accounts for weight, retro-reflection would double up. */ - ccl_private const PrincipledDiffuseBsdf *bsdf = (ccl_private const PrincipledDiffuseBsdf *) - sc; - if (bsdf->components == PRINCIPLED_DIFFUSE_RETRO_REFLECTION) { - continue; - } - } - - if (bsdf_get_specular_roughness_squared(sc) > sqr(0.075f)) { - diffuse_albedo += closure_albedo; - sum_nonspecular_weight += sc->sample_weight; - } - else { - specular_albedo += closure_albedo; - } - } - - /* Wait for next bounce if 75% or more sample weight belongs to specular-like closures. */ - if ((sum_weight == 0.0f) || (sum_nonspecular_weight * 4.0f > sum_weight)) { - if (sum_weight != 0.0f) { - normal /= sum_weight; - } - - if (kernel_data.film.pass_denoising_normal != PASS_UNUSED) { - /* Transform normal into camera space. */ - const Transform worldtocamera = kernel_data.cam.worldtocamera; - normal = transform_direction(&worldtocamera, normal); - - const float3 denoising_normal = ensure_finite(normal); - kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_normal, denoising_normal); - } - - if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) { - const Spectrum denoising_feature_throughput = INTEGRATOR_STATE( - state, path, denoising_feature_throughput); - const Spectrum denoising_albedo = ensure_finite(denoising_feature_throughput * - diffuse_albedo); - kernel_write_pass_spectrum(buffer + kernel_data.film.pass_denoising_albedo, - denoising_albedo); - } - - INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_DENOISING_FEATURES; - } - else { - INTEGRATOR_STATE_WRITE(state, path, denoising_feature_throughput) *= specular_albedo; - } -} - -ccl_device_forceinline void kernel_write_denoising_features_volume(KernelGlobals kg, - IntegratorState state, - const Spectrum albedo, - const bool scatter, - ccl_global float *ccl_restrict - render_buffer) -{ - ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer); - const Spectrum denoising_feature_throughput = INTEGRATOR_STATE( - state, path, denoising_feature_throughput); - - if (scatter && kernel_data.film.pass_denoising_normal != PASS_UNUSED) { - /* Assume scatter is sufficiently diffuse to stop writing denoising features. */ - INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_DENOISING_FEATURES; - - /* Write view direction as normal. */ - const float3 denoising_normal = make_float3(0.0f, 0.0f, -1.0f); - kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_normal, denoising_normal); - } - - if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) { - /* Write albedo. */ - const Spectrum denoising_albedo = ensure_finite(denoising_feature_throughput * albedo); - kernel_write_pass_spectrum(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo); - } -} -#endif /* __DENOISING_FEATURES__ */ - -ccl_device_inline size_t kernel_write_id_pass(ccl_global float *ccl_restrict buffer, - size_t depth, - float id, - float matte_weight) -{ - kernel_write_id_slots(buffer, depth * 2, id, matte_weight); - return depth * 4; -} - -ccl_device_inline void kernel_write_data_passes(KernelGlobals kg, - IntegratorState state, - ccl_private const ShaderData *sd, - ccl_global float *ccl_restrict render_buffer) -{ -#ifdef __PASSES__ - const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); - - if (!(path_flag & PATH_RAY_TRANSPARENT_BACKGROUND)) { - return; - } - - const int flag = kernel_data.film.pass_flag; - - if (!(flag & PASS_ANY)) { - return; - } - - ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer); - - if (!(path_flag & PATH_RAY_SINGLE_PASS_DONE)) { - if (!(sd->flag & SD_TRANSPARENT) || kernel_data.film.pass_alpha_threshold == 0.0f || - average(shader_bsdf_alpha(kg, sd)) >= kernel_data.film.pass_alpha_threshold) { - if (INTEGRATOR_STATE(state, path, sample) == 0) { - if (flag & PASSMASK(DEPTH)) { - const float depth = camera_z_depth(kg, sd->P); - kernel_write_pass_float(buffer + kernel_data.film.pass_depth, depth); - } - if (flag & PASSMASK(OBJECT_ID)) { - const float id = object_pass_id(kg, sd->object); - kernel_write_pass_float(buffer + kernel_data.film.pass_object_id, id); - } - if (flag & PASSMASK(MATERIAL_ID)) { - const float id = shader_pass_id(kg, sd); - kernel_write_pass_float(buffer + kernel_data.film.pass_material_id, id); - } - if (flag & PASSMASK(POSITION)) { - const float3 position = sd->P; - kernel_write_pass_float3(buffer + kernel_data.film.pass_position, position); - } - } - - if (flag & PASSMASK(NORMAL)) { - const float3 normal = shader_bsdf_average_normal(kg, sd); - kernel_write_pass_float3(buffer + kernel_data.film.pass_normal, normal); - } - if (flag & PASSMASK(ROUGHNESS)) { - const float roughness = shader_bsdf_average_roughness(sd); - kernel_write_pass_float(buffer + kernel_data.film.pass_roughness, roughness); - } - if (flag & PASSMASK(UV)) { - const float3 uv = primitive_uv(kg, sd); - kernel_write_pass_float3(buffer + kernel_data.film.pass_uv, uv); - } - if (flag & PASSMASK(MOTION)) { - const float4 speed = primitive_motion_vector(kg, sd); - kernel_write_pass_float4(buffer + kernel_data.film.pass_motion, speed); - kernel_write_pass_float(buffer + kernel_data.film.pass_motion_weight, 1.0f); - } - - INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SINGLE_PASS_DONE; - } - } - - if (kernel_data.film.cryptomatte_passes) { - const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput); - const float matte_weight = average(throughput) * - (1.0f - average(shader_bsdf_transparency(kg, sd))); - if (matte_weight > 0.0f) { - ccl_global float *cryptomatte_buffer = buffer + kernel_data.film.pass_cryptomatte; - if (kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) { - const float id = object_cryptomatte_id(kg, sd->object); - cryptomatte_buffer += kernel_write_id_pass( - cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight); - } - if (kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) { - const float id = shader_cryptomatte_id(kg, sd->shader); - cryptomatte_buffer += kernel_write_id_pass( - cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight); - } - if (kernel_data.film.cryptomatte_passes & CRYPT_ASSET) { - const float id = object_cryptomatte_asset_id(kg, sd->object); - cryptomatte_buffer += kernel_write_id_pass( - cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight); - } - } - } - - if (flag & PASSMASK(DIFFUSE_COLOR)) { - const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput); - kernel_write_pass_spectrum(buffer + kernel_data.film.pass_diffuse_color, - shader_bsdf_diffuse(kg, sd) * throughput); - } - if (flag & PASSMASK(GLOSSY_COLOR)) { - const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput); - kernel_write_pass_spectrum(buffer + kernel_data.film.pass_glossy_color, - shader_bsdf_glossy(kg, sd) * throughput); - } - if (flag & PASSMASK(TRANSMISSION_COLOR)) { - const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput); - kernel_write_pass_spectrum(buffer + kernel_data.film.pass_transmission_color, - shader_bsdf_transmission(kg, sd) * throughput); - } - if (flag & PASSMASK(MIST)) { - /* Bring depth into 0..1 range. */ - const float mist_start = kernel_data.film.mist_start; - const float mist_inv_depth = kernel_data.film.mist_inv_depth; - - const float depth = camera_distance(kg, sd->P); - float mist = saturatef((depth - mist_start) * mist_inv_depth); - - /* Falloff */ - const float mist_falloff = kernel_data.film.mist_falloff; - - if (mist_falloff == 1.0f) - ; - else if (mist_falloff == 2.0f) - mist = mist * mist; - else if (mist_falloff == 0.5f) - mist = sqrtf(mist); - else - mist = powf(mist, mist_falloff); - - /* Modulate by transparency */ - const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput); - const Spectrum alpha = shader_bsdf_alpha(kg, sd); - const float mist_output = (1.0f - mist) * average(throughput * alpha); - - /* Note that the final value in the render buffer we want is 1 - mist_output, - * to avoid having to tracking this in the Integrator state we do the negation - * after rendering. */ - kernel_write_pass_float(buffer + kernel_data.film.pass_mist, mist_output); - } -#endif -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/film/read.h b/intern/cycles/kernel/film/read.h index 995c20a0053..108f992e29d 100644 --- a/intern/cycles/kernel/film/read.h +++ b/intern/cycles/kernel/film/read.h @@ -1,6 +1,10 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ +/* Functions to retrieving render passes for display or output. Reading from + * the raw render buffer and normalizing based on the number of samples, + * computing alpha, compositing shadow catchers, etc. */ + #pragma once CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/film/write_passes.h b/intern/cycles/kernel/film/write.h index c78116cedc6..c630a522ee3 100644 --- a/intern/cycles/kernel/film/write_passes.h +++ b/intern/cycles/kernel/film/write.h @@ -11,7 +11,18 @@ CCL_NAMESPACE_BEGIN -ccl_device_inline void kernel_write_pass_float(ccl_global float *ccl_restrict buffer, float value) +/* Get pointer to pixel in render buffer. */ +ccl_device_forceinline ccl_global float *film_pass_pixel_render_buffer( + KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer) +{ + const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index); + const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * + kernel_data.film.pass_stride; + return render_buffer + render_buffer_offset; +} + +/* Write to pixel. */ +ccl_device_inline void film_write_pass_float(ccl_global float *ccl_restrict buffer, float value) { #ifdef __ATOMIC_PASS_WRITE__ atomic_add_and_fetch_float(buffer, value); @@ -20,8 +31,7 @@ ccl_device_inline void kernel_write_pass_float(ccl_global float *ccl_restrict bu #endif } -ccl_device_inline void kernel_write_pass_float3(ccl_global float *ccl_restrict buffer, - float3 value) +ccl_device_inline void film_write_pass_float3(ccl_global float *ccl_restrict buffer, float3 value) { #ifdef __ATOMIC_PASS_WRITE__ ccl_global float *buf_x = buffer + 0; @@ -38,14 +48,13 @@ ccl_device_inline void kernel_write_pass_float3(ccl_global float *ccl_restrict b #endif } -ccl_device_inline void kernel_write_pass_spectrum(ccl_global float *ccl_restrict buffer, - Spectrum value) +ccl_device_inline void film_write_pass_spectrum(ccl_global float *ccl_restrict buffer, + Spectrum value) { - kernel_write_pass_float3(buffer, spectrum_to_rgb(value)); + film_write_pass_float3(buffer, spectrum_to_rgb(value)); } -ccl_device_inline void kernel_write_pass_float4(ccl_global float *ccl_restrict buffer, - float4 value) +ccl_device_inline void film_write_pass_float4(ccl_global float *ccl_restrict buffer, float4 value) { #ifdef __ATOMIC_PASS_WRITE__ ccl_global float *buf_x = buffer + 0; diff --git a/intern/cycles/kernel/integrator/displacement_shader.h b/intern/cycles/kernel/integrator/displacement_shader.h new file mode 100644 index 00000000000..71a0f56fb3e --- /dev/null +++ b/intern/cycles/kernel/integrator/displacement_shader.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +/* Functions to evaluate displacement shader. */ + +#pragma once + +#include "kernel/svm/svm.h" + +#ifdef __OSL__ +# include "kernel/osl/shader.h" +#endif + +CCL_NAMESPACE_BEGIN + +template<typename ConstIntegratorGenericState> +ccl_device void displacement_shader_eval(KernelGlobals kg, + ConstIntegratorGenericState state, + ccl_private ShaderData *sd) +{ + sd->num_closure = 0; + sd->num_closure_left = 0; + + /* this will modify sd->P */ +#ifdef __SVM__ +# ifdef __OSL__ + if (kg->osl) + OSLShader::eval_displacement(kg, state, sd); + else +# endif + { + svm_eval_nodes<KERNEL_FEATURE_NODE_MASK_DISPLACEMENT, SHADER_TYPE_DISPLACEMENT>( + kg, state, sd, NULL, 0); + } +#endif +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/integrator/init_from_bake.h b/intern/cycles/kernel/integrator/init_from_bake.h index 9897bc3d65c..eca2c0b9ffb 100644 --- a/intern/cycles/kernel/integrator/init_from_bake.h +++ b/intern/cycles/kernel/integrator/init_from_bake.h @@ -5,8 +5,8 @@ #include "kernel/camera/camera.h" -#include "kernel/film/accumulate.h" #include "kernel/film/adaptive_sampling.h" +#include "kernel/film/light_passes.h" #include "kernel/integrator/path_state.h" @@ -92,12 +92,12 @@ ccl_device bool integrator_init_from_bake(KernelGlobals kg, path_state_init(state, tile, x, y); /* Check whether the pixel has converged and should not be sampled anymore. */ - if (!kernel_need_sample_pixel(kg, state, render_buffer)) { + if (!film_need_sample_pixel(kg, state, render_buffer)) { return false; } /* Always count the sample, even if the camera sample will reject the ray. */ - const int sample = kernel_accum_sample( + const int sample = film_write_sample( kg, state, render_buffer, scheduled_sample, tile->sample_offset); /* Setup render buffers. */ @@ -112,7 +112,7 @@ ccl_device bool integrator_init_from_bake(KernelGlobals kg, int prim = __float_as_uint(primitive[1]); if (prim == -1) { /* Accumulate transparency for empty pixels. */ - kernel_accum_transparent(kg, state, 0, 1.0f, buffer); + film_write_transparent(kg, state, 0, 1.0f, buffer); return true; } @@ -200,11 +200,11 @@ ccl_device bool integrator_init_from_bake(KernelGlobals kg, /* Fast path for position and normal passes not affected by shaders. */ if (kernel_data.film.pass_position != PASS_UNUSED) { - kernel_write_pass_float3(buffer + kernel_data.film.pass_position, P); + film_write_pass_float3(buffer + kernel_data.film.pass_position, P); return true; } else if (kernel_data.film.pass_normal != PASS_UNUSED && !(shader_flags & SD_HAS_BUMP)) { - kernel_write_pass_float3(buffer + kernel_data.film.pass_normal, N); + film_write_pass_float3(buffer + kernel_data.film.pass_normal, N); return true; } diff --git a/intern/cycles/kernel/integrator/init_from_camera.h b/intern/cycles/kernel/integrator/init_from_camera.h index 67ac3603d4c..8df3e1b9fb3 100644 --- a/intern/cycles/kernel/integrator/init_from_camera.h +++ b/intern/cycles/kernel/integrator/init_from_camera.h @@ -5,8 +5,8 @@ #include "kernel/camera/camera.h" -#include "kernel/film/accumulate.h" #include "kernel/film/adaptive_sampling.h" +#include "kernel/film/light_passes.h" #include "kernel/integrator/path_state.h" #include "kernel/integrator/shadow_catcher.h" @@ -57,7 +57,7 @@ ccl_device bool integrator_init_from_camera(KernelGlobals kg, path_state_init(state, tile, x, y); /* Check whether the pixel has converged and should not be sampled anymore. */ - if (!kernel_need_sample_pixel(kg, state, render_buffer)) { + if (!film_need_sample_pixel(kg, state, render_buffer)) { return false; } @@ -66,7 +66,7 @@ ccl_device bool integrator_init_from_camera(KernelGlobals kg, * This logic allows to both count actual number of samples per pixel, and to add samples to this * pixel after it was converged and samples were added somewhere else (in which case the * `scheduled_sample` will be different from actual number of samples in this pixel). */ - const int sample = kernel_accum_sample( + const int sample = film_write_sample( kg, state, render_buffer, scheduled_sample, tile->sample_offset); /* Initialize random number seed for path. */ diff --git a/intern/cycles/kernel/integrator/intersect_closest.h b/intern/cycles/kernel/integrator/intersect_closest.h index 60299f2cb2f..4ecff56a3fd 100644 --- a/intern/cycles/kernel/integrator/intersect_closest.h +++ b/intern/cycles/kernel/integrator/intersect_closest.h @@ -5,6 +5,8 @@ #include "kernel/camera/projection.h" +#include "kernel/film/light_passes.h" + #include "kernel/integrator/path_state.h" #include "kernel/integrator/shadow_catcher.h" @@ -87,7 +89,7 @@ ccl_device_forceinline void integrator_split_shadow_catcher( return; } - kernel_write_shadow_catcher_bounce_data(kg, state, render_buffer); + film_write_shadow_catcher_bounce_data(kg, state, render_buffer); /* Mark state as having done a shadow catcher split so that it stops contributing to * the shadow catcher matte pass, but keeps contributing to the combined pass. */ diff --git a/intern/cycles/kernel/integrator/intersect_volume_stack.h b/intern/cycles/kernel/integrator/intersect_volume_stack.h index b53bee11312..c2490581e4d 100644 --- a/intern/cycles/kernel/integrator/intersect_volume_stack.h +++ b/intern/cycles/kernel/integrator/intersect_volume_stack.h @@ -5,7 +5,6 @@ #include "kernel/bvh/bvh.h" #include "kernel/geom/geom.h" -#include "kernel/integrator/shader_eval.h" #include "kernel/integrator/volume_stack.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/integrator/mnee.h b/intern/cycles/kernel/integrator/mnee.h index 84d527bc8b1..a0ad7afe591 100644 --- a/intern/cycles/kernel/integrator/mnee.h +++ b/intern/cycles/kernel/integrator/mnee.h @@ -807,7 +807,7 @@ ccl_device_forceinline bool mnee_path_contribution(KernelGlobals kg, float3 wo = normalize_len(vertices[0].p - sd->P, &wo_len); /* Initialize throughput and evaluate receiver bsdf * |n.wo|. */ - shader_bsdf_eval(kg, sd, wo, false, throughput, ls->shader); + surface_shader_bsdf_eval(kg, sd, wo, false, throughput, ls->shader); /* Update light sample with new position / direct.ion * and keep pdf in vertex area measure */ @@ -913,7 +913,7 @@ ccl_device_forceinline bool mnee_path_contribution(KernelGlobals kg, INTEGRATOR_STATE_WRITE(state, path, bounce) = bounce + 1 + vi; /* Evaluate shader nodes at solution vi. */ - shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW>( + surface_shader_eval<KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW>( kg, state, sd_mnee, NULL, PATH_RAY_DIFFUSE, true); /* Set light looking dir. */ @@ -1006,7 +1006,7 @@ ccl_device_forceinline int kernel_path_mnee_sample(KernelGlobals kg, return 0; /* Last bool argument is the MNEE flag (for TINY_MAX_CLOSURE cap in kernel_shader.h). */ - shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW>( + surface_shader_eval<KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW>( kg, state, sd_mnee, NULL, PATH_RAY_DIFFUSE, true); /* Get and sample refraction bsdf */ diff --git a/intern/cycles/kernel/integrator/shade_background.h b/intern/cycles/kernel/integrator/shade_background.h index 57d060d58df..30ce0999258 100644 --- a/intern/cycles/kernel/integrator/shade_background.h +++ b/intern/cycles/kernel/integrator/shade_background.h @@ -3,8 +3,10 @@ #pragma once -#include "kernel/film/accumulate.h" -#include "kernel/integrator/shader_eval.h" +#include "kernel/film/light_passes.h" + +#include "kernel/integrator/surface_shader.h" + #include "kernel/light/light.h" #include "kernel/light/sample.h" @@ -14,7 +16,6 @@ ccl_device Spectrum integrator_eval_background_shader(KernelGlobals kg, IntegratorState state, ccl_global float *ccl_restrict render_buffer) { -#ifdef __BACKGROUND__ const int shader = kernel_data.background.surface_shader; const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); @@ -31,50 +32,30 @@ ccl_device Spectrum integrator_eval_background_shader(KernelGlobals kg, /* Use fast constant background color if available. */ Spectrum L = zero_spectrum(); - if (!shader_constant_emission_eval(kg, shader, &L)) { - /* Evaluate background shader. */ - - /* TODO: does aliasing like this break automatic SoA in CUDA? - * Should we instead store closures separate from ShaderData? */ - ShaderDataTinyStorage emission_sd_storage; - ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage); - - PROFILING_INIT_FOR_SHADER(kg, PROFILING_SHADE_LIGHT_SETUP); - shader_setup_from_background(kg, - emission_sd, - INTEGRATOR_STATE(state, ray, P), - INTEGRATOR_STATE(state, ray, D), - INTEGRATOR_STATE(state, ray, time)); - - PROFILING_SHADER(emission_sd->object, emission_sd->shader); - PROFILING_EVENT(PROFILING_SHADE_LIGHT_EVAL); - shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_BACKGROUND>( - kg, state, emission_sd, render_buffer, path_flag | PATH_RAY_EMISSION); - - L = shader_background_eval(emission_sd); + if (surface_shader_constant_emission(kg, shader, &L)) { + return L; } - /* Background MIS weights. */ -# ifdef __BACKGROUND_MIS__ - /* Check if background light exists or if we should skip pdf. */ - if (!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_MIS_SKIP) && - kernel_data.background.use_mis) { - const float3 ray_P = INTEGRATOR_STATE(state, ray, P); - const float3 ray_D = INTEGRATOR_STATE(state, ray, D); - const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf); - - /* multiple importance sampling, get background light pdf for ray - * direction, and compute weight with respect to BSDF pdf */ - const float pdf = background_light_pdf(kg, ray_P, ray_D); - const float mis_weight = light_sample_mis_weight_forward(kg, mis_ray_pdf, pdf); - L *= mis_weight; - } -# endif + /* Evaluate background shader. */ - return L; -#else - return make_spectrum(0.8f); -#endif + /* TODO: does aliasing like this break automatic SoA in CUDA? + * Should we instead store closures separate from ShaderData? */ + ShaderDataTinyStorage emission_sd_storage; + ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage); + + PROFILING_INIT_FOR_SHADER(kg, PROFILING_SHADE_LIGHT_SETUP); + shader_setup_from_background(kg, + emission_sd, + INTEGRATOR_STATE(state, ray, P), + INTEGRATOR_STATE(state, ray, D), + INTEGRATOR_STATE(state, ray, time)); + + PROFILING_SHADER(emission_sd->object, emission_sd->shader); + PROFILING_EVENT(PROFILING_SHADE_LIGHT_EVAL); + surface_shader_eval<KERNEL_FEATURE_NODE_MASK_SURFACE_BACKGROUND>( + kg, state, emission_sd, render_buffer, path_flag | PATH_RAY_EMISSION); + + return surface_shader_background(emission_sd); } ccl_device_inline void integrate_background(KernelGlobals kg, @@ -117,17 +98,37 @@ ccl_device_inline void integrate_background(KernelGlobals kg, #endif /* __MNEE__ */ /* Evaluate background shader. */ - Spectrum L = (eval_background) ? integrator_eval_background_shader(kg, state, render_buffer) : - zero_spectrum(); + Spectrum L = zero_spectrum(); + + if (eval_background) { + L = integrator_eval_background_shader(kg, state, render_buffer); + + /* When using the ao bounces approximation, adjust background + * shader intensity with ao factor. */ + if (path_state_ao_bounce(kg, state)) { + L *= kernel_data.integrator.ao_bounces_factor; + } + + /* Background MIS weights. */ + float mis_weight = 1.0f; + /* Check if background light exists or if we should skip pdf. */ + if (!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_MIS_SKIP) && + kernel_data.background.use_mis) { + const float3 ray_P = INTEGRATOR_STATE(state, ray, P); + const float3 ray_D = INTEGRATOR_STATE(state, ray, D); + const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf); + + /* multiple importance sampling, get background light pdf for ray + * direction, and compute weight with respect to BSDF pdf */ + const float pdf = background_light_pdf(kg, ray_P, ray_D); + mis_weight = light_sample_mis_weight_forward(kg, mis_ray_pdf, pdf); + } - /* When using the ao bounces approximation, adjust background - * shader intensity with ao factor. */ - if (path_state_ao_bounce(kg, state)) { - L *= kernel_data.integrator.ao_bounces_factor; + L *= mis_weight; } /* Write to render buffer. */ - kernel_accum_background(kg, state, L, transparent, is_transparent_background_ray, render_buffer); + film_write_background(kg, state, L, transparent, is_transparent_background_ray, render_buffer); } ccl_device_inline void integrate_distant_lights(KernelGlobals kg, @@ -175,18 +176,17 @@ ccl_device_inline void integrate_distant_lights(KernelGlobals kg, } /* MIS weighting. */ + float mis_weight = 1.0f; if (!(path_flag & PATH_RAY_MIS_SKIP)) { /* multiple importance sampling, get regular light pdf, * and compute weight with respect to BSDF pdf */ const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf); - const float mis_weight = light_sample_mis_weight_forward(kg, mis_ray_pdf, ls.pdf); - light_eval *= mis_weight; + mis_weight = light_sample_mis_weight_forward(kg, mis_ray_pdf, ls.pdf); } /* Write to render buffer. */ - const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput); - kernel_accum_emission( - kg, state, throughput * light_eval, render_buffer, kernel_data.background.lightgroup); + film_write_surface_emission( + kg, state, light_eval, mis_weight, render_buffer, kernel_data.background.lightgroup); } } } diff --git a/intern/cycles/kernel/integrator/shade_light.h b/intern/cycles/kernel/integrator/shade_light.h index ac9d1415abb..a4246f99bbf 100644 --- a/intern/cycles/kernel/integrator/shade_light.h +++ b/intern/cycles/kernel/integrator/shade_light.h @@ -3,8 +3,8 @@ #pragma once -#include "kernel/film/accumulate.h" -#include "kernel/integrator/shader_eval.h" +#include "kernel/film/light_passes.h" +#include "kernel/integrator/surface_shader.h" #include "kernel/light/light.h" #include "kernel/light/sample.h" @@ -57,6 +57,7 @@ ccl_device_inline void integrate_light(KernelGlobals kg, } /* MIS weighting. */ + float mis_weight = 1.0f; if (!(path_flag & PATH_RAY_MIS_SKIP)) { /* multiple importance sampling, get regular light pdf, * and compute weight with respect to BSDF pdf */ @@ -66,8 +67,7 @@ ccl_device_inline void integrate_light(KernelGlobals kg, } /* Write to render buffer. */ - const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput); - kernel_accum_emission(kg, state, throughput * light_eval, render_buffer, ls.group); + film_write_surface_emission(kg, state, light_eval, mis_weight, render_buffer, ls.group); } ccl_device void integrator_shade_light(KernelGlobals kg, diff --git a/intern/cycles/kernel/integrator/shade_shadow.h b/intern/cycles/kernel/integrator/shade_shadow.h index a52706a77f1..ba18aed6ff0 100644 --- a/intern/cycles/kernel/integrator/shade_shadow.h +++ b/intern/cycles/kernel/integrator/shade_shadow.h @@ -4,7 +4,7 @@ #pragma once #include "kernel/integrator/shade_volume.h" -#include "kernel/integrator/shader_eval.h" +#include "kernel/integrator/surface_shader.h" #include "kernel/integrator/volume_stack.h" CCL_NAMESPACE_BEGIN @@ -40,7 +40,7 @@ ccl_device_inline Spectrum integrate_transparent_surface_shadow(KernelGlobals kg /* Evaluate shader. */ if (!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) { - shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW>( + surface_shader_eval<KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW>( kg, state, shadow_sd, NULL, PATH_RAY_SHADOW); } @@ -50,7 +50,7 @@ ccl_device_inline Spectrum integrate_transparent_surface_shadow(KernelGlobals kg # endif /* Compute transparency from closures. */ - return shader_bsdf_transparency(kg, shadow_sd); + return surface_shader_transparency(kg, shadow_sd); } # ifdef __VOLUME__ @@ -165,7 +165,7 @@ ccl_device void integrator_shade_shadow(KernelGlobals kg, return; } else { - kernel_accum_light(kg, state, render_buffer); + film_write_direct_light(kg, state, render_buffer); integrator_shadow_path_terminate(kg, state, DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW); return; } diff --git a/intern/cycles/kernel/integrator/shade_surface.h b/intern/cycles/kernel/integrator/shade_surface.h index f3f8ed67713..c19f56a9b70 100644 --- a/intern/cycles/kernel/integrator/shade_surface.h +++ b/intern/cycles/kernel/integrator/shade_surface.h @@ -3,14 +3,15 @@ #pragma once -#include "kernel/film/accumulate.h" -#include "kernel/film/passes.h" +#include "kernel/film/data_passes.h" +#include "kernel/film/denoising_passes.h" +#include "kernel/film/light_passes.h" #include "kernel/integrator/mnee.h" #include "kernel/integrator/path_state.h" -#include "kernel/integrator/shader_eval.h" #include "kernel/integrator/subsurface.h" +#include "kernel/integrator/surface_shader.h" #include "kernel/integrator/volume_stack.h" #include "kernel/light/light.h" @@ -77,7 +78,6 @@ ccl_device_forceinline float3 integrate_surface_ray_offset(KernelGlobals kg, } } -#ifdef __HOLDOUT__ ccl_device_forceinline bool integrate_surface_holdout(KernelGlobals kg, ConstIntegratorState state, ccl_private ShaderData *sd, @@ -88,10 +88,10 @@ ccl_device_forceinline bool integrate_surface_holdout(KernelGlobals kg, if (((sd->flag & SD_HOLDOUT) || (sd->object_flag & SD_OBJECT_HOLDOUT_MASK)) && (path_flag & PATH_RAY_TRANSPARENT_BACKGROUND)) { - const Spectrum holdout_weight = shader_holdout_apply(kg, sd); + const Spectrum holdout_weight = surface_shader_apply_holdout(kg, sd); const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput); const float transparent = average(holdout_weight * throughput); - kernel_accum_holdout(kg, state, path_flag, transparent, render_buffer); + film_write_holdout(kg, state, path_flag, transparent, render_buffer); if (isequal(holdout_weight, one_spectrum())) { return false; } @@ -99,9 +99,7 @@ ccl_device_forceinline bool integrate_surface_holdout(KernelGlobals kg, return true; } -#endif /* __HOLDOUT__ */ -#ifdef __EMISSION__ ccl_device_forceinline void integrate_surface_emission(KernelGlobals kg, ConstIntegratorState state, ccl_private const ShaderData *sd, @@ -111,14 +109,15 @@ ccl_device_forceinline void integrate_surface_emission(KernelGlobals kg, const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); /* Evaluate emissive closure. */ - Spectrum L = shader_emissive_eval(sd); + Spectrum L = surface_shader_emission(sd); + float mis_weight = 1.0f; -# ifdef __HAIR__ +#ifdef __HAIR__ if (!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS) && (sd->type & PRIMITIVE_TRIANGLE)) -# else +#else if (!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS)) -# endif +#endif { const float bsdf_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf); const float t = sd->ray_length; @@ -126,17 +125,13 @@ ccl_device_forceinline void integrate_surface_emission(KernelGlobals kg, /* Multiple importance sampling, get triangle light pdf, * and compute weight with respect to BSDF pdf. */ float pdf = triangle_light_pdf(kg, sd, t); - float mis_weight = light_sample_mis_weight_forward(kg, bsdf_pdf, pdf); - L *= mis_weight; + mis_weight = light_sample_mis_weight_forward(kg, bsdf_pdf, pdf); } - const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput); - kernel_accum_emission( - kg, state, throughput * L, render_buffer, object_lightgroup(kg, sd->object)); + film_write_surface_emission( + kg, state, L, mis_weight, render_buffer, object_lightgroup(kg, sd->object)); } -#endif /* __EMISSION__ */ -#ifdef __EMISSION__ /* Path tracing: sample point on light and evaluate light shader, then * queue shadow ray to be traced. */ template<uint node_feature_mask> @@ -176,9 +171,9 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg, Ray ray ccl_optional_struct_init; BsdfEval bsdf_eval ccl_optional_struct_init; - const bool is_transmission = shader_bsdf_is_transmission(sd, ls.D); + const bool is_transmission = surface_shader_is_transmission(sd, ls.D); -# ifdef __MNEE__ +#ifdef __MNEE__ int mnee_vertex_count = 0; IF_KERNEL_FEATURE(MNEE) { @@ -204,7 +199,7 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg, light_sample_to_surface_shadow_ray(kg, emission_sd, &ls, &ray); } else -# endif /* __MNEE__ */ +#endif /* __MNEE__ */ { const Spectrum light_eval = light_sample_shader_eval(kg, state, emission_sd, &ls, sd->time); if (is_zero(light_eval)) { @@ -212,7 +207,8 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg, } /* Evaluate BSDF. */ - const float bsdf_pdf = shader_bsdf_eval(kg, sd, ls.D, is_transmission, &bsdf_eval, ls.shader); + const float bsdf_pdf = surface_shader_bsdf_eval( + kg, sd, ls.D, is_transmission, &bsdf_eval, ls.shader); bsdf_eval_mul(&bsdf_eval, light_eval / ls.pdf); if (ls.shader & SHADER_USE_MIS) { @@ -240,9 +236,9 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg, integrator_state_copy_volume_stack_to_shadow(kg, shadow_state, state); if (is_transmission) { -# ifdef __VOLUME__ +#ifdef __VOLUME__ shadow_volume_stack_enter_exit(kg, shadow_state, sd); -# endif +#endif } if (ray.self.object != OBJECT_NONE) { @@ -298,7 +294,7 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg, INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, glossy_bounce) = INTEGRATOR_STATE( state, path, glossy_bounce); -# ifdef __MNEE__ +#ifdef __MNEE__ if (mnee_vertex_count > 0) { INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, transmission_bounce) = INTEGRATOR_STATE(state, path, transmission_bounce) + mnee_vertex_count - 1; @@ -310,7 +306,7 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg, bounce) = INTEGRATOR_STATE(state, path, bounce) + mnee_vertex_count; } else -# endif +#endif { INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, transmission_bounce) = INTEGRATOR_STATE( state, path, transmission_bounce); @@ -332,7 +328,6 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg, ls.group + 1 : kernel_data.background.lightgroup + 1; } -#endif /* Path tracing: bounce off or through surface with new direction. */ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce( @@ -347,7 +342,7 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce( } float2 rand_bsdf = path_state_rng_2D(kg, rng_state, PRNG_SURFACE_BSDF); - ccl_private const ShaderClosure *sc = shader_bsdf_bssrdf_pick(sd, &rand_bsdf); + ccl_private const ShaderClosure *sc = surface_shader_bsdf_bssrdf_pick(sd, &rand_bsdf); #ifdef __SUBSURFACE__ /* BSSRDF closure, we schedule subsurface intersection kernel. */ @@ -362,7 +357,8 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce( float3 bsdf_omega_in ccl_optional_struct_init; int label; - label = shader_bsdf_sample_closure(kg, sd, sc, rand_bsdf, &bsdf_eval, &bsdf_omega_in, &bsdf_pdf); + label = surface_shader_bsdf_sample_closure( + kg, sd, sc, rand_bsdf, &bsdf_eval, &bsdf_omega_in, &bsdf_pdf); if (bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval)) { return LABEL_NONE; @@ -456,7 +452,7 @@ ccl_device_forceinline void integrate_surface_ao(KernelGlobals kg, const float2 rand_bsdf = path_state_rng_2D(kg, rng_state, PRNG_SURFACE_BSDF); float3 ao_N; - const Spectrum ao_weight = shader_bsdf_ao( + const Spectrum ao_weight = surface_shader_ao( kg, sd, kernel_data.integrator.ao_additive_factor, &ao_N); float3 ao_D; @@ -500,7 +496,7 @@ ccl_device_forceinline void integrate_surface_ao(KernelGlobals kg, const uint16_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce); uint32_t shadow_flag = INTEGRATOR_STATE(state, path, flag) | PATH_RAY_SHADOW_FOR_AO; const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput) * - shader_bsdf_alpha(kg, sd); + surface_shader_alpha(kg, sd); INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, render_pixel_index) = INTEGRATOR_STATE( state, path, render_pixel_index); @@ -549,7 +545,7 @@ ccl_device bool integrate_surface(KernelGlobals kg, { /* Evaluate shader. */ PROFILING_EVENT(PROFILING_SHADE_SURFACE_EVAL); - shader_eval_surface<node_feature_mask>(kg, state, &sd, render_buffer, path_flag); + surface_shader_eval<node_feature_mask>(kg, state, &sd, render_buffer, path_flag); /* Initialize additional RNG for BSDFs. */ if (sd.flag & SD_BSDF_NEEDS_LCG) { @@ -571,21 +567,17 @@ ccl_device bool integrate_surface(KernelGlobals kg, #endif { /* Filter closures. */ - shader_prepare_surface_closures(kg, state, &sd, path_flag); + surface_shader_prepare_closures(kg, state, &sd, path_flag); -#ifdef __HOLDOUT__ /* Evaluate holdout. */ if (!integrate_surface_holdout(kg, state, &sd, render_buffer)) { return false; } -#endif -#ifdef __EMISSION__ /* Write emission. */ if (sd.flag & SD_EMISSION) { integrate_surface_emission(kg, state, &sd, render_buffer); } -#endif /* Perform path termination. Most paths have already been terminated in * the intersect_closest kernel, this is just for emission and for dividing @@ -599,11 +591,11 @@ ccl_device bool integrate_surface(KernelGlobals kg, /* Write render passes. */ #ifdef __PASSES__ PROFILING_EVENT(PROFILING_SHADE_SURFACE_PASSES); - kernel_write_data_passes(kg, state, &sd, render_buffer); + film_write_data_passes(kg, state, &sd, render_buffer); #endif #ifdef __DENOISING_FEATURES__ - kernel_write_denoising_features_surface(kg, state, &sd, render_buffer); + film_write_denoising_features_surface(kg, state, &sd, render_buffer); #endif } diff --git a/intern/cycles/kernel/integrator/shade_volume.h b/intern/cycles/kernel/integrator/shade_volume.h index 5e0584d4f98..aaef92729d6 100644 --- a/intern/cycles/kernel/integrator/shade_volume.h +++ b/intern/cycles/kernel/integrator/shade_volume.h @@ -3,12 +3,13 @@ #pragma once -#include "kernel/film/accumulate.h" -#include "kernel/film/passes.h" +#include "kernel/film/data_passes.h" +#include "kernel/film/denoising_passes.h" +#include "kernel/film/light_passes.h" #include "kernel/integrator/intersect_closest.h" #include "kernel/integrator/path_state.h" -#include "kernel/integrator/shader_eval.h" +#include "kernel/integrator/volume_shader.h" #include "kernel/integrator/volume_stack.h" #include "kernel/light/light.h" @@ -64,7 +65,7 @@ ccl_device_inline bool shadow_volume_shader_sample(KernelGlobals kg, ccl_private Spectrum *ccl_restrict extinction) { VOLUME_READ_LAMBDA(integrator_state_read_shadow_volume_stack(state, i)) - shader_eval_volume<true>(kg, state, sd, PATH_RAY_SHADOW, volume_read_lambda_pass); + volume_shader_eval<true>(kg, state, sd, PATH_RAY_SHADOW, volume_read_lambda_pass); if (!(sd->flag & SD_EXTINCTION)) { return false; @@ -83,7 +84,7 @@ ccl_device_inline bool volume_shader_sample(KernelGlobals kg, { const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); VOLUME_READ_LAMBDA(integrator_state_read_volume_stack(state, i)) - shader_eval_volume<false>(kg, state, sd, path_flag, volume_read_lambda_pass); + volume_shader_eval<false>(kg, state, sd, path_flag, volume_read_lambda_pass); if (!(sd->flag & (SD_EXTINCTION | SD_SCATTER | SD_EMISSION))) { return false; @@ -442,7 +443,7 @@ ccl_device_forceinline void volume_integrate_step_scattering( result.direct_scatter = true; result.direct_throughput *= coeff.sigma_s * new_transmittance / vstate.equiangular_pdf; - shader_copy_volume_phases(&result.direct_phases, sd); + volume_shader_copy_phases(&result.direct_phases, sd); /* Multiple importance sampling. */ if (vstate.use_mis) { @@ -478,7 +479,7 @@ ccl_device_forceinline void volume_integrate_step_scattering( result.indirect_scatter = true; result.indirect_t = new_t; result.indirect_throughput *= coeff.sigma_s * new_transmittance / distance_pdf; - shader_copy_volume_phases(&result.indirect_phases, sd); + volume_shader_copy_phases(&result.indirect_phases, sd); if (vstate.direct_sample_method != VOLUME_SAMPLE_EQUIANGULAR) { /* If using distance sampling for direct light, just copy parameters @@ -486,7 +487,7 @@ ccl_device_forceinline void volume_integrate_step_scattering( result.direct_scatter = true; result.direct_t = result.indirect_t; result.direct_throughput = result.indirect_throughput; - shader_copy_volume_phases(&result.direct_phases, sd); + volume_shader_copy_phases(&result.direct_phases, sd); /* Multiple importance sampling. */ if (vstate.use_mis) { @@ -663,20 +664,19 @@ ccl_device_forceinline void volume_integrate_heterogeneous( /* Write accumulated emission. */ if (!is_zero(accum_emission)) { - kernel_accum_emission( + film_write_volume_emission( kg, state, accum_emission, render_buffer, object_lightgroup(kg, sd->object)); } # ifdef __DENOISING_FEATURES__ /* Write denoising features. */ if (write_denoising_features) { - kernel_write_denoising_features_volume( + film_write_denoising_features_volume( kg, state, accum_albedo, result.indirect_scatter, render_buffer); } # endif /* __DENOISING_FEATURES__ */ } -# ifdef __EMISSION__ /* Path tracing: sample point on light and evaluate light shader, then * queue shadow ray to be traced. */ ccl_device_forceinline bool integrate_volume_sample_light( @@ -761,7 +761,7 @@ ccl_device_forceinline void integrate_volume_direct_light( /* Evaluate BSDF. */ BsdfEval phase_eval ccl_optional_struct_init; - const float phase_pdf = shader_volume_phase_eval(kg, sd, phases, ls->D, &phase_eval); + const float phase_pdf = volume_shader_phase_eval(kg, sd, phases, ls->D, &phase_eval); if (ls->shader & SHADER_USE_MIS) { float mis_weight = light_sample_mis_weight_nee(kg, ls->pdf, phase_pdf); @@ -850,7 +850,6 @@ ccl_device_forceinline void integrate_volume_direct_light( integrator_state_copy_volume_stack_to_shadow(kg, shadow_state, state); } -# endif /* Path tracing: scatter in new direction using phase function */ ccl_device_forceinline bool integrate_volume_phase_scatter( @@ -869,7 +868,7 @@ ccl_device_forceinline bool integrate_volume_phase_scatter( BsdfEval phase_eval ccl_optional_struct_init; float3 phase_omega_in ccl_optional_struct_init; - const int label = shader_volume_phase_sample( + const int label = volume_shader_phase_sample( kg, sd, phases, rand_phase, &phase_eval, &phase_omega_in, &phase_pdf); if (phase_pdf == 0.0f || bsdf_eval_is_zero(&phase_eval)) { diff --git a/intern/cycles/kernel/integrator/shader_eval.h b/intern/cycles/kernel/integrator/shader_eval.h deleted file mode 100644 index b1316bda9bb..00000000000 --- a/intern/cycles/kernel/integrator/shader_eval.h +++ /dev/null @@ -1,947 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 - * Copyright 2011-2022 Blender Foundation */ - -/* Functions to evaluate shaders and use the resulting shader closures. */ - -#pragma once - -#include "kernel/closure/alloc.h" -#include "kernel/closure/bsdf.h" -#include "kernel/closure/bsdf_util.h" -#include "kernel/closure/emissive.h" - -#include "kernel/film/accumulate.h" - -#include "kernel/svm/svm.h" - -#ifdef __OSL__ -# include "kernel/osl/shader.h" -#endif - -CCL_NAMESPACE_BEGIN - -/* Merging */ - -#if defined(__VOLUME__) -ccl_device_inline void shader_merge_volume_closures(ccl_private ShaderData *sd) -{ - /* Merge identical closures to save closure space with stacked volumes. */ - for (int i = 0; i < sd->num_closure; i++) { - ccl_private ShaderClosure *sci = &sd->closure[i]; - - if (sci->type != CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) { - continue; - } - - for (int j = i + 1; j < sd->num_closure; j++) { - ccl_private ShaderClosure *scj = &sd->closure[j]; - if (sci->type != scj->type) { - continue; - } - - ccl_private const HenyeyGreensteinVolume *hgi = (ccl_private const HenyeyGreensteinVolume *) - sci; - ccl_private const HenyeyGreensteinVolume *hgj = (ccl_private const HenyeyGreensteinVolume *) - scj; - if (!(hgi->g == hgj->g)) { - continue; - } - - sci->weight += scj->weight; - sci->sample_weight += scj->sample_weight; - - int size = sd->num_closure - (j + 1); - if (size > 0) { - for (int k = 0; k < size; k++) { - scj[k] = scj[k + 1]; - } - } - - sd->num_closure--; - kernel_assert(sd->num_closure >= 0); - j--; - } - } -} - -ccl_device_inline void shader_copy_volume_phases(ccl_private ShaderVolumePhases *ccl_restrict - phases, - ccl_private const ShaderData *ccl_restrict sd) -{ - phases->num_closure = 0; - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *from_sc = &sd->closure[i]; - ccl_private const HenyeyGreensteinVolume *from_hg = - (ccl_private const HenyeyGreensteinVolume *)from_sc; - - if (from_sc->type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) { - ccl_private ShaderVolumeClosure *to_sc = &phases->closure[phases->num_closure]; - - to_sc->weight = from_sc->weight; - to_sc->sample_weight = from_sc->sample_weight; - to_sc->g = from_hg->g; - phases->num_closure++; - if (phases->num_closure >= MAX_VOLUME_CLOSURE) { - break; - } - } - } -} -#endif /* __VOLUME__ */ - -ccl_device_inline void shader_prepare_surface_closures(KernelGlobals kg, - ConstIntegratorState state, - ccl_private ShaderData *sd, - const uint32_t path_flag) -{ - /* Filter out closures. */ - if (kernel_data.integrator.filter_closures) { - if (kernel_data.integrator.filter_closures & FILTER_CLOSURE_EMISSION) { - sd->closure_emission_background = zero_spectrum(); - } - - if (kernel_data.integrator.filter_closures & FILTER_CLOSURE_DIRECT_LIGHT) { - sd->flag &= ~SD_BSDF_HAS_EVAL; - } - - if (path_flag & PATH_RAY_CAMERA) { - for (int i = 0; i < sd->num_closure; i++) { - ccl_private ShaderClosure *sc = &sd->closure[i]; - - if ((CLOSURE_IS_BSDF_DIFFUSE(sc->type) && - (kernel_data.integrator.filter_closures & FILTER_CLOSURE_DIFFUSE)) || - (CLOSURE_IS_BSDF_GLOSSY(sc->type) && - (kernel_data.integrator.filter_closures & FILTER_CLOSURE_GLOSSY)) || - (CLOSURE_IS_BSDF_TRANSMISSION(sc->type) && - (kernel_data.integrator.filter_closures & FILTER_CLOSURE_TRANSMISSION))) { - sc->type = CLOSURE_NONE_ID; - sc->sample_weight = 0.0f; - } - else if ((CLOSURE_IS_BSDF_TRANSPARENT(sc->type) && - (kernel_data.integrator.filter_closures & FILTER_CLOSURE_TRANSPARENT))) { - sc->type = CLOSURE_HOLDOUT_ID; - sc->sample_weight = 0.0f; - sd->flag |= SD_HOLDOUT; - } - } - } - } - - /* Defensive sampling. - * - * We can likely also do defensive sampling at deeper bounces, particularly - * for cases like a perfect mirror but possibly also others. This will need - * a good heuristic. */ - if (INTEGRATOR_STATE(state, path, bounce) + INTEGRATOR_STATE(state, path, transparent_bounce) == - 0 && - sd->num_closure > 1) { - float sum = 0.0f; - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private ShaderClosure *sc = &sd->closure[i]; - if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { - sum += sc->sample_weight; - } - } - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private ShaderClosure *sc = &sd->closure[i]; - if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { - sc->sample_weight = max(sc->sample_weight, 0.125f * sum); - } - } - } - - /* Filter glossy. - * - * Blurring of bsdf after bounces, for rays that have a small likelihood - * of following this particular path (diffuse, rough glossy) */ - if (kernel_data.integrator.filter_glossy != FLT_MAX -#ifdef __MNEE__ - && !(INTEGRATOR_STATE(state, path, mnee) & PATH_MNEE_VALID) -#endif - ) { - float blur_pdf = kernel_data.integrator.filter_glossy * - INTEGRATOR_STATE(state, path, min_ray_pdf); - - if (blur_pdf < 1.0f) { - float blur_roughness = sqrtf(1.0f - blur_pdf) * 0.5f; - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private ShaderClosure *sc = &sd->closure[i]; - if (CLOSURE_IS_BSDF(sc->type)) { - bsdf_blur(kg, sc, blur_roughness); - } - } - } - } -} - -/* BSDF */ - -ccl_device_inline bool shader_bsdf_is_transmission(ccl_private const ShaderData *sd, - const float3 omega_in) -{ - return dot(sd->N, omega_in) < 0.0f; -} - -ccl_device_forceinline bool _shader_bsdf_exclude(ClosureType type, uint light_shader_flags) -{ - if (!(light_shader_flags & SHADER_EXCLUDE_ANY)) { - return false; - } - if (light_shader_flags & SHADER_EXCLUDE_DIFFUSE) { - if (CLOSURE_IS_BSDF_DIFFUSE(type)) { - return true; - } - } - if (light_shader_flags & SHADER_EXCLUDE_GLOSSY) { - if (CLOSURE_IS_BSDF_GLOSSY(type)) { - return true; - } - } - if (light_shader_flags & SHADER_EXCLUDE_TRANSMIT) { - if (CLOSURE_IS_BSDF_TRANSMISSION(type)) { - return true; - } - } - return false; -} - -ccl_device_inline float _shader_bsdf_multi_eval(KernelGlobals kg, - ccl_private ShaderData *sd, - const float3 omega_in, - const bool is_transmission, - ccl_private const ShaderClosure *skip_sc, - ccl_private BsdfEval *result_eval, - float sum_pdf, - float sum_sample_weight, - const uint light_shader_flags) -{ - /* This is the veach one-sample model with balance heuristic, - * some PDF factors drop out when using balance heuristic weighting. */ - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (sc == skip_sc) { - continue; - } - - if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { - if (CLOSURE_IS_BSDF(sc->type) && !_shader_bsdf_exclude(sc->type, light_shader_flags)) { - float bsdf_pdf = 0.0f; - Spectrum eval = bsdf_eval(kg, sd, sc, omega_in, is_transmission, &bsdf_pdf); - - if (bsdf_pdf != 0.0f) { - bsdf_eval_accum(result_eval, sc->type, eval * sc->weight); - sum_pdf += bsdf_pdf * sc->sample_weight; - } - } - - sum_sample_weight += sc->sample_weight; - } - } - - return (sum_sample_weight > 0.0f) ? sum_pdf / sum_sample_weight : 0.0f; -} - -#ifndef __KERNEL_CUDA__ -ccl_device -#else -ccl_device_inline -#endif - float - shader_bsdf_eval(KernelGlobals kg, - ccl_private ShaderData *sd, - const float3 omega_in, - const bool is_transmission, - ccl_private BsdfEval *bsdf_eval, - const uint light_shader_flags) -{ - bsdf_eval_init(bsdf_eval, CLOSURE_NONE_ID, zero_spectrum()); - - return _shader_bsdf_multi_eval( - kg, sd, omega_in, is_transmission, NULL, bsdf_eval, 0.0f, 0.0f, light_shader_flags); -} - -/* Randomly sample a BSSRDF or BSDF proportional to ShaderClosure.sample_weight. */ -ccl_device_inline ccl_private const ShaderClosure *shader_bsdf_bssrdf_pick( - ccl_private const ShaderData *ccl_restrict sd, ccl_private float2 *rand_bsdf) -{ - int sampled = 0; - - if (sd->num_closure > 1) { - /* Pick a BSDF or based on sample weights. */ - float sum = 0.0f; - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { - sum += sc->sample_weight; - } - } - - float r = (*rand_bsdf).x * sum; - float partial_sum = 0.0f; - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { - float next_sum = partial_sum + sc->sample_weight; - - if (r < next_sum) { - sampled = i; - - /* Rescale to reuse for direction sample, to better preserve stratification. */ - (*rand_bsdf).x = (r - partial_sum) / sc->sample_weight; - break; - } - - partial_sum = next_sum; - } - } - } - - return &sd->closure[sampled]; -} - -/* Return weight for picked BSSRDF. */ -ccl_device_inline Spectrum -shader_bssrdf_sample_weight(ccl_private const ShaderData *ccl_restrict sd, - ccl_private const ShaderClosure *ccl_restrict bssrdf_sc) -{ - Spectrum weight = bssrdf_sc->weight; - - if (sd->num_closure > 1) { - float sum = 0.0f; - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { - sum += sc->sample_weight; - } - } - weight *= sum / bssrdf_sc->sample_weight; - } - - return weight; -} - -/* Sample direction for picked BSDF, and return evaluation and pdf for all - * BSDFs combined using MIS. */ -ccl_device int shader_bsdf_sample_closure(KernelGlobals kg, - ccl_private ShaderData *sd, - ccl_private const ShaderClosure *sc, - const float2 rand_bsdf, - ccl_private BsdfEval *bsdf_eval, - ccl_private float3 *omega_in, - ccl_private float *pdf) -{ - /* BSSRDF should already have been handled elsewhere. */ - kernel_assert(CLOSURE_IS_BSDF(sc->type)); - - int label; - Spectrum eval = zero_spectrum(); - - *pdf = 0.0f; - label = bsdf_sample(kg, sd, sc, rand_bsdf.x, rand_bsdf.y, &eval, omega_in, pdf); - - if (*pdf != 0.0f) { - bsdf_eval_init(bsdf_eval, sc->type, eval * sc->weight); - - if (sd->num_closure > 1) { - const bool is_transmission = shader_bsdf_is_transmission(sd, *omega_in); - float sweight = sc->sample_weight; - *pdf = _shader_bsdf_multi_eval( - kg, sd, *omega_in, is_transmission, sc, bsdf_eval, *pdf * sweight, sweight, 0); - } - } - - return label; -} - -ccl_device float shader_bsdf_average_roughness(ccl_private const ShaderData *sd) -{ - float roughness = 0.0f; - float sum_weight = 0.0f; - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSDF(sc->type)) { - /* sqrt once to undo the squaring from multiplying roughness on the - * two axes, and once for the squared roughness convention. */ - float weight = fabsf(average(sc->weight)); - roughness += weight * sqrtf(safe_sqrtf(bsdf_get_roughness_squared(sc))); - sum_weight += weight; - } - } - - return (sum_weight > 0.0f) ? roughness / sum_weight : 0.0f; -} - -ccl_device Spectrum shader_bsdf_transparency(KernelGlobals kg, ccl_private const ShaderData *sd) -{ - if (sd->flag & SD_HAS_ONLY_VOLUME) { - return one_spectrum(); - } - else if (sd->flag & SD_TRANSPARENT) { - return sd->closure_transparent_extinction; - } - else { - return zero_spectrum(); - } -} - -ccl_device void shader_bsdf_disable_transparency(KernelGlobals kg, ccl_private ShaderData *sd) -{ - if (sd->flag & SD_TRANSPARENT) { - for (int i = 0; i < sd->num_closure; i++) { - ccl_private ShaderClosure *sc = &sd->closure[i]; - - if (sc->type == CLOSURE_BSDF_TRANSPARENT_ID) { - sc->sample_weight = 0.0f; - sc->weight = zero_spectrum(); - } - } - - sd->flag &= ~SD_TRANSPARENT; - } -} - -ccl_device Spectrum shader_bsdf_alpha(KernelGlobals kg, ccl_private const ShaderData *sd) -{ - Spectrum alpha = one_spectrum() - shader_bsdf_transparency(kg, sd); - - alpha = saturate(alpha); - - return alpha; -} - -ccl_device Spectrum shader_bsdf_diffuse(KernelGlobals kg, ccl_private const ShaderData *sd) -{ - Spectrum eval = zero_spectrum(); - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSDF_DIFFUSE(sc->type) || CLOSURE_IS_BSSRDF(sc->type)) - eval += sc->weight; - } - - return eval; -} - -ccl_device Spectrum shader_bsdf_glossy(KernelGlobals kg, ccl_private const ShaderData *sd) -{ - Spectrum eval = zero_spectrum(); - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSDF_GLOSSY(sc->type)) - eval += sc->weight; - } - - return eval; -} - -ccl_device Spectrum shader_bsdf_transmission(KernelGlobals kg, ccl_private const ShaderData *sd) -{ - Spectrum eval = zero_spectrum(); - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSDF_TRANSMISSION(sc->type)) - eval += sc->weight; - } - - return eval; -} - -ccl_device float3 shader_bsdf_average_normal(KernelGlobals kg, ccl_private const ShaderData *sd) -{ - float3 N = zero_float3(); - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) - N += sc->N * fabsf(average(sc->weight)); - } - - return (is_zero(N)) ? sd->N : normalize(N); -} - -ccl_device Spectrum shader_bsdf_ao(KernelGlobals kg, - ccl_private const ShaderData *sd, - const float ao_factor, - ccl_private float3 *N_) -{ - Spectrum eval = zero_spectrum(); - float3 N = zero_float3(); - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) { - ccl_private const DiffuseBsdf *bsdf = (ccl_private const DiffuseBsdf *)sc; - eval += sc->weight * ao_factor; - N += bsdf->N * fabsf(average(sc->weight)); - } - } - - *N_ = (is_zero(N)) ? sd->N : normalize(N); - return eval; -} - -#ifdef __SUBSURFACE__ -ccl_device float3 shader_bssrdf_normal(ccl_private const ShaderData *sd) -{ - float3 N = zero_float3(); - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSSRDF(sc->type)) { - ccl_private const Bssrdf *bssrdf = (ccl_private const Bssrdf *)sc; - float avg_weight = fabsf(average(sc->weight)); - - N += bssrdf->N * avg_weight; - } - } - - return (is_zero(N)) ? sd->N : normalize(N); -} -#endif /* __SUBSURFACE__ */ - -/* Constant emission optimization */ - -ccl_device bool shader_constant_emission_eval(KernelGlobals kg, - int shader, - ccl_private Spectrum *eval) -{ - int shader_index = shader & SHADER_MASK; - int shader_flag = kernel_data_fetch(shaders, shader_index).flags; - - if (shader_flag & SD_HAS_CONSTANT_EMISSION) { - const float3 emission_rgb = make_float3( - kernel_data_fetch(shaders, shader_index).constant_emission[0], - kernel_data_fetch(shaders, shader_index).constant_emission[1], - kernel_data_fetch(shaders, shader_index).constant_emission[2]); - *eval = rgb_to_spectrum(emission_rgb); - - return true; - } - - return false; -} - -/* Background */ - -ccl_device Spectrum shader_background_eval(ccl_private const ShaderData *sd) -{ - if (sd->flag & SD_EMISSION) { - return sd->closure_emission_background; - } - else { - return zero_spectrum(); - } -} - -/* Emission */ - -ccl_device Spectrum shader_emissive_eval(ccl_private const ShaderData *sd) -{ - if (sd->flag & SD_EMISSION) { - return emissive_simple_eval(sd->Ng, sd->I) * sd->closure_emission_background; - } - else { - return zero_spectrum(); - } -} - -/* Holdout */ - -ccl_device Spectrum shader_holdout_apply(KernelGlobals kg, ccl_private ShaderData *sd) -{ - Spectrum weight = zero_spectrum(); - - /* For objects marked as holdout, preserve transparency and remove all other - * closures, replacing them with a holdout weight. */ - if (sd->object_flag & SD_OBJECT_HOLDOUT_MASK) { - if ((sd->flag & SD_TRANSPARENT) && !(sd->flag & SD_HAS_ONLY_VOLUME)) { - weight = one_spectrum() - sd->closure_transparent_extinction; - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private ShaderClosure *sc = &sd->closure[i]; - if (!CLOSURE_IS_BSDF_TRANSPARENT(sc->type)) { - sc->type = NBUILTIN_CLOSURES; - } - } - - sd->flag &= ~(SD_CLOSURE_FLAGS - (SD_TRANSPARENT | SD_BSDF)); - } - else { - weight = one_spectrum(); - } - } - else { - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - if (CLOSURE_IS_HOLDOUT(sc->type)) { - weight += sc->weight; - } - } - } - - return weight; -} - -/* Surface Evaluation */ - -template<uint node_feature_mask, typename ConstIntegratorGenericState> -ccl_device void shader_eval_surface(KernelGlobals kg, - ConstIntegratorGenericState state, - ccl_private ShaderData *ccl_restrict sd, - ccl_global float *ccl_restrict buffer, - uint32_t path_flag, - bool use_caustics_storage = false) -{ - /* If path is being terminated, we are tracing a shadow ray or evaluating - * emission, then we don't need to store closures. The emission and shadow - * shader data also do not have a closure array to save GPU memory. */ - int max_closures; - if (path_flag & (PATH_RAY_TERMINATE | PATH_RAY_SHADOW | PATH_RAY_EMISSION)) { - max_closures = 0; - } - else { - max_closures = use_caustics_storage ? CAUSTICS_MAX_CLOSURE : kernel_data.max_closures; - } - - sd->num_closure = 0; - sd->num_closure_left = max_closures; - -#ifdef __OSL__ - if (kg->osl) { - if (sd->object == OBJECT_NONE && sd->lamp == LAMP_NONE) { - OSLShader::eval_background(kg, state, sd, path_flag); - } - else { - OSLShader::eval_surface(kg, state, sd, path_flag); - } - } - else -#endif - { -#ifdef __SVM__ - svm_eval_nodes<node_feature_mask, SHADER_TYPE_SURFACE>(kg, state, sd, buffer, path_flag); -#else - if (sd->object == OBJECT_NONE) { - sd->closure_emission_background = make_spectrum(0.8f); - sd->flag |= SD_EMISSION; - } - else { - ccl_private DiffuseBsdf *bsdf = (ccl_private DiffuseBsdf *)bsdf_alloc( - sd, sizeof(DiffuseBsdf), make_spectrum(0.8f)); - if (bsdf != NULL) { - bsdf->N = sd->N; - sd->flag |= bsdf_diffuse_setup(bsdf); - } - } -#endif - } -} - -/* Volume */ - -#ifdef __VOLUME__ - -ccl_device_inline float _shader_volume_phase_multi_eval( - ccl_private const ShaderData *sd, - ccl_private const ShaderVolumePhases *phases, - const float3 omega_in, - int skip_phase, - ccl_private BsdfEval *result_eval, - float sum_pdf, - float sum_sample_weight) -{ - for (int i = 0; i < phases->num_closure; i++) { - if (i == skip_phase) - continue; - - ccl_private const ShaderVolumeClosure *svc = &phases->closure[i]; - float phase_pdf = 0.0f; - Spectrum eval = volume_phase_eval(sd, svc, omega_in, &phase_pdf); - - if (phase_pdf != 0.0f) { - bsdf_eval_accum(result_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval); - sum_pdf += phase_pdf * svc->sample_weight; - } - - sum_sample_weight += svc->sample_weight; - } - - return (sum_sample_weight > 0.0f) ? sum_pdf / sum_sample_weight : 0.0f; -} - -ccl_device float shader_volume_phase_eval(KernelGlobals kg, - ccl_private const ShaderData *sd, - ccl_private const ShaderVolumePhases *phases, - const float3 omega_in, - ccl_private BsdfEval *phase_eval) -{ - bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, zero_spectrum()); - - return _shader_volume_phase_multi_eval(sd, phases, omega_in, -1, phase_eval, 0.0f, 0.0f); -} - -ccl_device int shader_volume_phase_sample(KernelGlobals kg, - ccl_private const ShaderData *sd, - ccl_private const ShaderVolumePhases *phases, - float2 rand_phase, - ccl_private BsdfEval *phase_eval, - ccl_private float3 *omega_in, - ccl_private float *pdf) -{ - int sampled = 0; - - if (phases->num_closure > 1) { - /* pick a phase closure based on sample weights */ - float sum = 0.0f; - - for (sampled = 0; sampled < phases->num_closure; sampled++) { - ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled]; - sum += svc->sample_weight; - } - - float r = rand_phase.x * sum; - float partial_sum = 0.0f; - - for (sampled = 0; sampled < phases->num_closure; sampled++) { - ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled]; - float next_sum = partial_sum + svc->sample_weight; - - if (r <= next_sum) { - /* Rescale to reuse for BSDF direction sample. */ - rand_phase.x = (r - partial_sum) / svc->sample_weight; - break; - } - - partial_sum = next_sum; - } - - if (sampled == phases->num_closure) { - *pdf = 0.0f; - return LABEL_NONE; - } - } - - /* todo: this isn't quite correct, we don't weight anisotropy properly - * depending on color channels, even if this is perhaps not a common case */ - ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled]; - int label; - Spectrum eval = zero_spectrum(); - - *pdf = 0.0f; - label = volume_phase_sample(sd, svc, rand_phase.x, rand_phase.y, &eval, omega_in, pdf); - - if (*pdf != 0.0f) { - bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval); - } - - return label; -} - -ccl_device int shader_phase_sample_closure(KernelGlobals kg, - ccl_private const ShaderData *sd, - ccl_private const ShaderVolumeClosure *sc, - const float2 rand_phase, - ccl_private BsdfEval *phase_eval, - ccl_private float3 *omega_in, - ccl_private float *pdf) -{ - int label; - Spectrum eval = zero_spectrum(); - - *pdf = 0.0f; - label = volume_phase_sample(sd, sc, rand_phase.x, rand_phase.y, &eval, omega_in, pdf); - - if (*pdf != 0.0f) - bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval); - - return label; -} - -/* Volume Evaluation */ - -template<const bool shadow, typename StackReadOp, typename ConstIntegratorGenericState> -ccl_device_inline void shader_eval_volume(KernelGlobals kg, - ConstIntegratorGenericState state, - ccl_private ShaderData *ccl_restrict sd, - const uint32_t path_flag, - StackReadOp stack_read) -{ - /* If path is being terminated, we are tracing a shadow ray or evaluating - * emission, then we don't need to store closures. The emission and shadow - * shader data also do not have a closure array to save GPU memory. */ - int max_closures; - if (path_flag & (PATH_RAY_TERMINATE | PATH_RAY_SHADOW | PATH_RAY_EMISSION)) { - max_closures = 0; - } - else { - max_closures = kernel_data.max_closures; - } - - /* reset closures once at the start, we will be accumulating the closures - * for all volumes in the stack into a single array of closures */ - sd->num_closure = 0; - sd->num_closure_left = max_closures; - sd->flag = 0; - sd->object_flag = 0; - - for (int i = 0;; i++) { - const VolumeStack entry = stack_read(i); - if (entry.shader == SHADER_NONE) { - break; - } - - /* Setup shader-data from stack. it's mostly setup already in - * shader_setup_from_volume, this switching should be quick. */ - sd->object = entry.object; - sd->lamp = LAMP_NONE; - sd->shader = entry.shader; - - sd->flag &= ~SD_SHADER_FLAGS; - sd->flag |= kernel_data_fetch(shaders, (sd->shader & SHADER_MASK)).flags; - sd->object_flag &= ~SD_OBJECT_FLAGS; - - if (sd->object != OBJECT_NONE) { - sd->object_flag |= kernel_data_fetch(object_flag, sd->object); - -# ifdef __OBJECT_MOTION__ - /* todo: this is inefficient for motion blur, we should be - * caching matrices instead of recomputing them each step */ - shader_setup_object_transforms(kg, sd, sd->time); - - if ((sd->object_flag & SD_OBJECT_HAS_VOLUME_MOTION) != 0) { - AttributeDescriptor v_desc = find_attribute(kg, sd, ATTR_STD_VOLUME_VELOCITY); - kernel_assert(v_desc.offset != ATTR_STD_NOT_FOUND); - - const float3 P = sd->P; - const float velocity_scale = kernel_data_fetch(objects, sd->object).velocity_scale; - const float time_offset = kernel_data.cam.motion_position == MOTION_POSITION_CENTER ? - 0.5f : - 0.0f; - const float time = kernel_data.cam.motion_position == MOTION_POSITION_END ? - (1.0f - kernel_data.cam.shuttertime) + sd->time : - sd->time; - - /* Use a 1st order semi-lagrangian advection scheme to estimate what volume quantity - * existed, or will exist, at the given time: - * - * `phi(x, T) = phi(x - (T - t) * u(x, T), t)` - * - * where - * - * x : position - * T : super-sampled time (or ray time) - * t : current time of the simulation (in rendering we assume this is center frame with - * relative time = 0) - * phi : the volume quantity - * u : the velocity field - * - * But first we need to determine the velocity field `u(x, T)`, which we can estimate also - * using semi-lagrangian advection. - * - * `u(x, T) = u(x - (T - t) * u(x, T), t)` - * - * This is the typical way to model self-advection in fluid dynamics, however, we do not - * account for other forces affecting the velocity during simulation (pressure, buoyancy, - * etc.): this gives a linear interpolation when fluid are mostly "curvy". For better - * results, a higher order interpolation scheme can be used (at the cost of more lookups), - * or an interpolation of the velocity fields for the previous and next frames could also - * be used to estimate `u(x, T)` (which will cost more memory and lookups). - * - * References: - * "Eulerian Motion Blur", Kim and Ko, 2007 - * "Production Volume Rendering", Wreninge et al., 2012 - */ - - /* Find velocity. */ - float3 velocity = primitive_volume_attribute_float3(kg, sd, v_desc); - object_dir_transform(kg, sd, &velocity); - - /* Find advected P. */ - sd->P = P - (time - time_offset) * velocity_scale * velocity; - - /* Find advected velocity. */ - velocity = primitive_volume_attribute_float3(kg, sd, v_desc); - object_dir_transform(kg, sd, &velocity); - - /* Find advected P. */ - sd->P = P - (time - time_offset) * velocity_scale * velocity; - } -# endif - } - - /* evaluate shader */ -# ifdef __SVM__ -# ifdef __OSL__ - if (kg->osl) { - OSLShader::eval_volume(kg, state, sd, path_flag); - } - else -# endif - { - svm_eval_nodes<KERNEL_FEATURE_NODE_MASK_VOLUME, SHADER_TYPE_VOLUME>( - kg, state, sd, NULL, path_flag); - } -# endif - - /* Merge closures to avoid exceeding number of closures limit. */ - if (!shadow) { - if (i > 0) { - shader_merge_volume_closures(sd); - } - } - } -} - -#endif /* __VOLUME__ */ - -/* Displacement Evaluation */ - -template<typename ConstIntegratorGenericState> -ccl_device void shader_eval_displacement(KernelGlobals kg, - ConstIntegratorGenericState state, - ccl_private ShaderData *sd) -{ - sd->num_closure = 0; - sd->num_closure_left = 0; - - /* this will modify sd->P */ -#ifdef __SVM__ -# ifdef __OSL__ - if (kg->osl) - OSLShader::eval_displacement(kg, state, sd); - else -# endif - { - svm_eval_nodes<KERNEL_FEATURE_NODE_MASK_DISPLACEMENT, SHADER_TYPE_DISPLACEMENT>( - kg, state, sd, NULL, 0); - } -#endif -} - -/* Cryptomatte */ - -ccl_device float shader_cryptomatte_id(KernelGlobals kg, int shader) -{ - return kernel_data_fetch(shaders, (shader & SHADER_MASK)).cryptomatte_id; -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/integrator/shadow_catcher.h b/intern/cycles/kernel/integrator/shadow_catcher.h index 7103b6032ac..a620853faea 100644 --- a/intern/cycles/kernel/integrator/shadow_catcher.h +++ b/intern/cycles/kernel/integrator/shadow_catcher.h @@ -3,7 +3,6 @@ #pragma once -#include "kernel/film/write_passes.h" #include "kernel/integrator/path_state.h" #include "kernel/integrator/state_util.h" @@ -76,28 +75,6 @@ ccl_device_forceinline bool kernel_shadow_catcher_is_object_pass(const uint32_t return path_flag & PATH_RAY_SHADOW_CATCHER_PASS; } -/* Write shadow catcher passes on a bounce from the shadow catcher object. */ -ccl_device_forceinline void kernel_write_shadow_catcher_bounce_data( - KernelGlobals kg, IntegratorState state, ccl_global float *ccl_restrict render_buffer) -{ - kernel_assert(kernel_data.film.pass_shadow_catcher_sample_count != PASS_UNUSED); - kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED); - - const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index); - const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * - kernel_data.film.pass_stride; - ccl_global float *buffer = render_buffer + render_buffer_offset; - - /* Count sample for the shadow catcher object. */ - kernel_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_sample_count, 1.0f); - - /* Since the split is done, the sample does not contribute to the matte, so accumulate it as - * transparency to the matte. */ - const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput); - kernel_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_matte + 3, - average(throughput)); -} - #endif /* __SHADOW_CATCHER__ */ CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/integrator/subsurface.h b/intern/cycles/kernel/integrator/subsurface.h index ee3a619f968..15c2cb1c708 100644 --- a/intern/cycles/kernel/integrator/subsurface.h +++ b/intern/cycles/kernel/integrator/subsurface.h @@ -15,9 +15,9 @@ #include "kernel/integrator/intersect_volume_stack.h" #include "kernel/integrator/path_state.h" -#include "kernel/integrator/shader_eval.h" #include "kernel/integrator/subsurface_disk.h" #include "kernel/integrator/subsurface_random_walk.h" +#include "kernel/integrator/surface_shader.h" CCL_NAMESPACE_BEGIN @@ -51,12 +51,10 @@ ccl_device int subsurface_bounce(KernelGlobals kg, PATH_RAY_SUBSURFACE_RANDOM_WALK); /* Compute weight, optionally including Fresnel from entry point. */ - Spectrum weight = shader_bssrdf_sample_weight(sd, sc); -# ifdef __PRINCIPLED__ + Spectrum weight = surface_shader_bssrdf_sample_weight(sd, sc); if (bssrdf->roughness != FLT_MAX) { path_flag |= PATH_RAY_SUBSURFACE_USE_FRESNEL; } -# endif if (sd->flag & SD_BACKFACING) { path_flag |= PATH_RAY_SUBSURFACE_BACKFACING; @@ -91,7 +89,7 @@ ccl_device void subsurface_shader_data_setup(KernelGlobals kg, /* Get bump mapped normal from shader evaluation at exit point. */ float3 N = sd->N; if (sd->flag & SD_HAS_BSSRDF_BUMP) { - N = shader_bssrdf_normal(sd); + N = surface_shader_bssrdf_normal(sd); } /* Setup diffuse BSDF at the exit point. This replaces shader_eval_surface. */ @@ -101,7 +99,6 @@ ccl_device void subsurface_shader_data_setup(KernelGlobals kg, const Spectrum weight = one_spectrum(); -# ifdef __PRINCIPLED__ if (path_flag & PATH_RAY_SUBSURFACE_USE_FRESNEL) { ccl_private PrincipledDiffuseBsdf *bsdf = (ccl_private PrincipledDiffuseBsdf *)bsdf_alloc( sd, sizeof(PrincipledDiffuseBsdf), weight); @@ -112,9 +109,7 @@ ccl_device void subsurface_shader_data_setup(KernelGlobals kg, sd->flag |= bsdf_principled_diffuse_setup(bsdf, PRINCIPLED_DIFFUSE_LAMBERT_EXIT); } } - else -# endif /* __PRINCIPLED__ */ - { + else { ccl_private DiffuseBsdf *bsdf = (ccl_private DiffuseBsdf *)bsdf_alloc( sd, sizeof(DiffuseBsdf), weight); diff --git a/intern/cycles/kernel/integrator/surface_shader.h b/intern/cycles/kernel/integrator/surface_shader.h new file mode 100644 index 00000000000..f40ff3c33ee --- /dev/null +++ b/intern/cycles/kernel/integrator/surface_shader.h @@ -0,0 +1,587 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +/* Functions to evaluate shaders. */ + +#pragma once + +#include "kernel/closure/alloc.h" +#include "kernel/closure/bsdf.h" +#include "kernel/closure/bsdf_util.h" +#include "kernel/closure/emissive.h" + +#include "kernel/svm/svm.h" + +#ifdef __OSL__ +# include "kernel/osl/shader.h" +#endif + +CCL_NAMESPACE_BEGIN + +ccl_device_inline void surface_shader_prepare_closures(KernelGlobals kg, + ConstIntegratorState state, + ccl_private ShaderData *sd, + const uint32_t path_flag) +{ + /* Filter out closures. */ + if (kernel_data.integrator.filter_closures) { + if (kernel_data.integrator.filter_closures & FILTER_CLOSURE_EMISSION) { + sd->closure_emission_background = zero_spectrum(); + } + + if (kernel_data.integrator.filter_closures & FILTER_CLOSURE_DIRECT_LIGHT) { + sd->flag &= ~SD_BSDF_HAS_EVAL; + } + + if (path_flag & PATH_RAY_CAMERA) { + for (int i = 0; i < sd->num_closure; i++) { + ccl_private ShaderClosure *sc = &sd->closure[i]; + + if ((CLOSURE_IS_BSDF_DIFFUSE(sc->type) && + (kernel_data.integrator.filter_closures & FILTER_CLOSURE_DIFFUSE)) || + (CLOSURE_IS_BSDF_GLOSSY(sc->type) && + (kernel_data.integrator.filter_closures & FILTER_CLOSURE_GLOSSY)) || + (CLOSURE_IS_BSDF_TRANSMISSION(sc->type) && + (kernel_data.integrator.filter_closures & FILTER_CLOSURE_TRANSMISSION))) { + sc->type = CLOSURE_NONE_ID; + sc->sample_weight = 0.0f; + } + else if ((CLOSURE_IS_BSDF_TRANSPARENT(sc->type) && + (kernel_data.integrator.filter_closures & FILTER_CLOSURE_TRANSPARENT))) { + sc->type = CLOSURE_HOLDOUT_ID; + sc->sample_weight = 0.0f; + sd->flag |= SD_HOLDOUT; + } + } + } + } + + /* Defensive sampling. + * + * We can likely also do defensive sampling at deeper bounces, particularly + * for cases like a perfect mirror but possibly also others. This will need + * a good heuristic. */ + if (INTEGRATOR_STATE(state, path, bounce) + INTEGRATOR_STATE(state, path, transparent_bounce) == + 0 && + sd->num_closure > 1) { + float sum = 0.0f; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private ShaderClosure *sc = &sd->closure[i]; + if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + sum += sc->sample_weight; + } + } + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private ShaderClosure *sc = &sd->closure[i]; + if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + sc->sample_weight = max(sc->sample_weight, 0.125f * sum); + } + } + } + + /* Filter glossy. + * + * Blurring of bsdf after bounces, for rays that have a small likelihood + * of following this particular path (diffuse, rough glossy) */ + if (kernel_data.integrator.filter_glossy != FLT_MAX +#ifdef __MNEE__ + && !(INTEGRATOR_STATE(state, path, mnee) & PATH_MNEE_VALID) +#endif + ) { + float blur_pdf = kernel_data.integrator.filter_glossy * + INTEGRATOR_STATE(state, path, min_ray_pdf); + + if (blur_pdf < 1.0f) { + float blur_roughness = sqrtf(1.0f - blur_pdf) * 0.5f; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private ShaderClosure *sc = &sd->closure[i]; + if (CLOSURE_IS_BSDF(sc->type)) { + bsdf_blur(kg, sc, blur_roughness); + } + } + } + } +} + +/* BSDF */ + +ccl_device_inline bool surface_shader_is_transmission(ccl_private const ShaderData *sd, + const float3 omega_in) +{ + return dot(sd->N, omega_in) < 0.0f; +} + +ccl_device_forceinline bool _surface_shader_exclude(ClosureType type, uint light_shader_flags) +{ + if (!(light_shader_flags & SHADER_EXCLUDE_ANY)) { + return false; + } + if (light_shader_flags & SHADER_EXCLUDE_DIFFUSE) { + if (CLOSURE_IS_BSDF_DIFFUSE(type)) { + return true; + } + } + if (light_shader_flags & SHADER_EXCLUDE_GLOSSY) { + if (CLOSURE_IS_BSDF_GLOSSY(type)) { + return true; + } + } + if (light_shader_flags & SHADER_EXCLUDE_TRANSMIT) { + if (CLOSURE_IS_BSDF_TRANSMISSION(type)) { + return true; + } + } + return false; +} + +ccl_device_inline float _surface_shader_bsdf_eval_mis(KernelGlobals kg, + ccl_private ShaderData *sd, + const float3 omega_in, + const bool is_transmission, + ccl_private const ShaderClosure *skip_sc, + ccl_private BsdfEval *result_eval, + float sum_pdf, + float sum_sample_weight, + const uint light_shader_flags) +{ + /* This is the veach one-sample model with balance heuristic, + * some PDF factors drop out when using balance heuristic weighting. */ + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (sc == skip_sc) { + continue; + } + + if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + if (CLOSURE_IS_BSDF(sc->type) && !_surface_shader_exclude(sc->type, light_shader_flags)) { + float bsdf_pdf = 0.0f; + Spectrum eval = bsdf_eval(kg, sd, sc, omega_in, is_transmission, &bsdf_pdf); + + if (bsdf_pdf != 0.0f) { + bsdf_eval_accum(result_eval, sc->type, eval * sc->weight); + sum_pdf += bsdf_pdf * sc->sample_weight; + } + } + + sum_sample_weight += sc->sample_weight; + } + } + + return (sum_sample_weight > 0.0f) ? sum_pdf / sum_sample_weight : 0.0f; +} + +#ifndef __KERNEL_CUDA__ +ccl_device +#else +ccl_device_inline +#endif + float + surface_shader_bsdf_eval(KernelGlobals kg, + ccl_private ShaderData *sd, + const float3 omega_in, + const bool is_transmission, + ccl_private BsdfEval *bsdf_eval, + const uint light_shader_flags) +{ + bsdf_eval_init(bsdf_eval, CLOSURE_NONE_ID, zero_spectrum()); + + return _surface_shader_bsdf_eval_mis( + kg, sd, omega_in, is_transmission, NULL, bsdf_eval, 0.0f, 0.0f, light_shader_flags); +} + +/* Randomly sample a BSSRDF or BSDF proportional to ShaderClosure.sample_weight. */ +ccl_device_inline ccl_private const ShaderClosure *surface_shader_bsdf_bssrdf_pick( + ccl_private const ShaderData *ccl_restrict sd, ccl_private float2 *rand_bsdf) +{ + int sampled = 0; + + if (sd->num_closure > 1) { + /* Pick a BSDF or based on sample weights. */ + float sum = 0.0f; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + sum += sc->sample_weight; + } + } + + float r = (*rand_bsdf).x * sum; + float partial_sum = 0.0f; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + float next_sum = partial_sum + sc->sample_weight; + + if (r < next_sum) { + sampled = i; + + /* Rescale to reuse for direction sample, to better preserve stratification. */ + (*rand_bsdf).x = (r - partial_sum) / sc->sample_weight; + break; + } + + partial_sum = next_sum; + } + } + } + + return &sd->closure[sampled]; +} + +/* Return weight for picked BSSRDF. */ +ccl_device_inline Spectrum +surface_shader_bssrdf_sample_weight(ccl_private const ShaderData *ccl_restrict sd, + ccl_private const ShaderClosure *ccl_restrict bssrdf_sc) +{ + Spectrum weight = bssrdf_sc->weight; + + if (sd->num_closure > 1) { + float sum = 0.0f; + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + sum += sc->sample_weight; + } + } + weight *= sum / bssrdf_sc->sample_weight; + } + + return weight; +} + +/* Sample direction for picked BSDF, and return evaluation and pdf for all + * BSDFs combined using MIS. */ +ccl_device int surface_shader_bsdf_sample_closure(KernelGlobals kg, + ccl_private ShaderData *sd, + ccl_private const ShaderClosure *sc, + const float2 rand_bsdf, + ccl_private BsdfEval *bsdf_eval, + ccl_private float3 *omega_in, + ccl_private float *pdf) +{ + /* BSSRDF should already have been handled elsewhere. */ + kernel_assert(CLOSURE_IS_BSDF(sc->type)); + + int label; + Spectrum eval = zero_spectrum(); + + *pdf = 0.0f; + label = bsdf_sample(kg, sd, sc, rand_bsdf.x, rand_bsdf.y, &eval, omega_in, pdf); + + if (*pdf != 0.0f) { + bsdf_eval_init(bsdf_eval, sc->type, eval * sc->weight); + + if (sd->num_closure > 1) { + const bool is_transmission = surface_shader_is_transmission(sd, *omega_in); + float sweight = sc->sample_weight; + *pdf = _surface_shader_bsdf_eval_mis( + kg, sd, *omega_in, is_transmission, sc, bsdf_eval, *pdf * sweight, sweight, 0); + } + } + + return label; +} + +ccl_device float surface_shader_average_roughness(ccl_private const ShaderData *sd) +{ + float roughness = 0.0f; + float sum_weight = 0.0f; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSDF(sc->type)) { + /* sqrt once to undo the squaring from multiplying roughness on the + * two axes, and once for the squared roughness convention. */ + float weight = fabsf(average(sc->weight)); + roughness += weight * sqrtf(safe_sqrtf(bsdf_get_roughness_squared(sc))); + sum_weight += weight; + } + } + + return (sum_weight > 0.0f) ? roughness / sum_weight : 0.0f; +} + +ccl_device Spectrum surface_shader_transparency(KernelGlobals kg, ccl_private const ShaderData *sd) +{ + if (sd->flag & SD_HAS_ONLY_VOLUME) { + return one_spectrum(); + } + else if (sd->flag & SD_TRANSPARENT) { + return sd->closure_transparent_extinction; + } + else { + return zero_spectrum(); + } +} + +ccl_device void surface_shader_disable_transparency(KernelGlobals kg, ccl_private ShaderData *sd) +{ + if (sd->flag & SD_TRANSPARENT) { + for (int i = 0; i < sd->num_closure; i++) { + ccl_private ShaderClosure *sc = &sd->closure[i]; + + if (sc->type == CLOSURE_BSDF_TRANSPARENT_ID) { + sc->sample_weight = 0.0f; + sc->weight = zero_spectrum(); + } + } + + sd->flag &= ~SD_TRANSPARENT; + } +} + +ccl_device Spectrum surface_shader_alpha(KernelGlobals kg, ccl_private const ShaderData *sd) +{ + Spectrum alpha = one_spectrum() - surface_shader_transparency(kg, sd); + + alpha = saturate(alpha); + + return alpha; +} + +ccl_device Spectrum surface_shader_diffuse(KernelGlobals kg, ccl_private const ShaderData *sd) +{ + Spectrum eval = zero_spectrum(); + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSDF_DIFFUSE(sc->type) || CLOSURE_IS_BSSRDF(sc->type)) + eval += sc->weight; + } + + return eval; +} + +ccl_device Spectrum surface_shader_glossy(KernelGlobals kg, ccl_private const ShaderData *sd) +{ + Spectrum eval = zero_spectrum(); + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSDF_GLOSSY(sc->type)) + eval += sc->weight; + } + + return eval; +} + +ccl_device Spectrum surface_shader_transmission(KernelGlobals kg, ccl_private const ShaderData *sd) +{ + Spectrum eval = zero_spectrum(); + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSDF_TRANSMISSION(sc->type)) + eval += sc->weight; + } + + return eval; +} + +ccl_device float3 surface_shader_average_normal(KernelGlobals kg, ccl_private const ShaderData *sd) +{ + float3 N = zero_float3(); + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) + N += sc->N * fabsf(average(sc->weight)); + } + + return (is_zero(N)) ? sd->N : normalize(N); +} + +ccl_device Spectrum surface_shader_ao(KernelGlobals kg, + ccl_private const ShaderData *sd, + const float ao_factor, + ccl_private float3 *N_) +{ + Spectrum eval = zero_spectrum(); + float3 N = zero_float3(); + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) { + ccl_private const DiffuseBsdf *bsdf = (ccl_private const DiffuseBsdf *)sc; + eval += sc->weight * ao_factor; + N += bsdf->N * fabsf(average(sc->weight)); + } + } + + *N_ = (is_zero(N)) ? sd->N : normalize(N); + return eval; +} + +#ifdef __SUBSURFACE__ +ccl_device float3 surface_shader_bssrdf_normal(ccl_private const ShaderData *sd) +{ + float3 N = zero_float3(); + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSSRDF(sc->type)) { + ccl_private const Bssrdf *bssrdf = (ccl_private const Bssrdf *)sc; + float avg_weight = fabsf(average(sc->weight)); + + N += bssrdf->N * avg_weight; + } + } + + return (is_zero(N)) ? sd->N : normalize(N); +} +#endif /* __SUBSURFACE__ */ + +/* Constant emission optimization */ + +ccl_device bool surface_shader_constant_emission(KernelGlobals kg, + int shader, + ccl_private Spectrum *eval) +{ + int shader_index = shader & SHADER_MASK; + int shader_flag = kernel_data_fetch(shaders, shader_index).flags; + + if (shader_flag & SD_HAS_CONSTANT_EMISSION) { + const float3 emission_rgb = make_float3( + kernel_data_fetch(shaders, shader_index).constant_emission[0], + kernel_data_fetch(shaders, shader_index).constant_emission[1], + kernel_data_fetch(shaders, shader_index).constant_emission[2]); + *eval = rgb_to_spectrum(emission_rgb); + + return true; + } + + return false; +} + +/* Background */ + +ccl_device Spectrum surface_shader_background(ccl_private const ShaderData *sd) +{ + if (sd->flag & SD_EMISSION) { + return sd->closure_emission_background; + } + else { + return zero_spectrum(); + } +} + +/* Emission */ + +ccl_device Spectrum surface_shader_emission(ccl_private const ShaderData *sd) +{ + if (sd->flag & SD_EMISSION) { + return emissive_simple_eval(sd->Ng, sd->I) * sd->closure_emission_background; + } + else { + return zero_spectrum(); + } +} + +/* Holdout */ + +ccl_device Spectrum surface_shader_apply_holdout(KernelGlobals kg, ccl_private ShaderData *sd) +{ + Spectrum weight = zero_spectrum(); + + /* For objects marked as holdout, preserve transparency and remove all other + * closures, replacing them with a holdout weight. */ + if (sd->object_flag & SD_OBJECT_HOLDOUT_MASK) { + if ((sd->flag & SD_TRANSPARENT) && !(sd->flag & SD_HAS_ONLY_VOLUME)) { + weight = one_spectrum() - sd->closure_transparent_extinction; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private ShaderClosure *sc = &sd->closure[i]; + if (!CLOSURE_IS_BSDF_TRANSPARENT(sc->type)) { + sc->type = NBUILTIN_CLOSURES; + } + } + + sd->flag &= ~(SD_CLOSURE_FLAGS - (SD_TRANSPARENT | SD_BSDF)); + } + else { + weight = one_spectrum(); + } + } + else { + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + if (CLOSURE_IS_HOLDOUT(sc->type)) { + weight += sc->weight; + } + } + } + + return weight; +} + +/* Surface Evaluation */ + +template<uint node_feature_mask, typename ConstIntegratorGenericState> +ccl_device void surface_shader_eval(KernelGlobals kg, + ConstIntegratorGenericState state, + ccl_private ShaderData *ccl_restrict sd, + ccl_global float *ccl_restrict buffer, + uint32_t path_flag, + bool use_caustics_storage = false) +{ + /* If path is being terminated, we are tracing a shadow ray or evaluating + * emission, then we don't need to store closures. The emission and shadow + * shader data also do not have a closure array to save GPU memory. */ + int max_closures; + if (path_flag & (PATH_RAY_TERMINATE | PATH_RAY_SHADOW | PATH_RAY_EMISSION)) { + max_closures = 0; + } + else { + max_closures = use_caustics_storage ? CAUSTICS_MAX_CLOSURE : kernel_data.max_closures; + } + + sd->num_closure = 0; + sd->num_closure_left = max_closures; + +#ifdef __OSL__ + if (kg->osl) { + if (sd->object == OBJECT_NONE && sd->lamp == LAMP_NONE) { + OSLShader::eval_background(kg, state, sd, path_flag); + } + else { + OSLShader::eval_surface(kg, state, sd, path_flag); + } + } + else +#endif + { +#ifdef __SVM__ + svm_eval_nodes<node_feature_mask, SHADER_TYPE_SURFACE>(kg, state, sd, buffer, path_flag); +#else + if (sd->object == OBJECT_NONE) { + sd->closure_emission_background = make_spectrum(0.8f); + sd->flag |= SD_EMISSION; + } + else { + ccl_private DiffuseBsdf *bsdf = (ccl_private DiffuseBsdf *)bsdf_alloc( + sd, sizeof(DiffuseBsdf), make_spectrum(0.8f)); + if (bsdf != NULL) { + bsdf->N = sd->N; + sd->flag |= bsdf_diffuse_setup(bsdf); + } + } +#endif + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/integrator/volume_shader.h b/intern/cycles/kernel/integrator/volume_shader.h new file mode 100644 index 00000000000..a1d191e2d32 --- /dev/null +++ b/intern/cycles/kernel/integrator/volume_shader.h @@ -0,0 +1,353 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +/* Volume shader evaluation and sampling. */ + +#pragma once + +#include "kernel/closure/alloc.h" +#include "kernel/closure/bsdf.h" +#include "kernel/closure/bsdf_util.h" +#include "kernel/closure/emissive.h" + +#include "kernel/svm/svm.h" + +#ifdef __OSL__ +# include "kernel/osl/shader.h" +#endif + +CCL_NAMESPACE_BEGIN + +#ifdef __VOLUME__ + +/* Merging */ +ccl_device_inline void volume_shader_merge_closures(ccl_private ShaderData *sd) +{ + /* Merge identical closures to save closure space with stacked volumes. */ + for (int i = 0; i < sd->num_closure; i++) { + ccl_private ShaderClosure *sci = &sd->closure[i]; + + if (sci->type != CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) { + continue; + } + + for (int j = i + 1; j < sd->num_closure; j++) { + ccl_private ShaderClosure *scj = &sd->closure[j]; + if (sci->type != scj->type) { + continue; + } + + ccl_private const HenyeyGreensteinVolume *hgi = (ccl_private const HenyeyGreensteinVolume *) + sci; + ccl_private const HenyeyGreensteinVolume *hgj = (ccl_private const HenyeyGreensteinVolume *) + scj; + if (!(hgi->g == hgj->g)) { + continue; + } + + sci->weight += scj->weight; + sci->sample_weight += scj->sample_weight; + + int size = sd->num_closure - (j + 1); + if (size > 0) { + for (int k = 0; k < size; k++) { + scj[k] = scj[k + 1]; + } + } + + sd->num_closure--; + kernel_assert(sd->num_closure >= 0); + j--; + } + } +} + +ccl_device_inline void volume_shader_copy_phases(ccl_private ShaderVolumePhases *ccl_restrict + phases, + ccl_private const ShaderData *ccl_restrict sd) +{ + phases->num_closure = 0; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *from_sc = &sd->closure[i]; + ccl_private const HenyeyGreensteinVolume *from_hg = + (ccl_private const HenyeyGreensteinVolume *)from_sc; + + if (from_sc->type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) { + ccl_private ShaderVolumeClosure *to_sc = &phases->closure[phases->num_closure]; + + to_sc->weight = from_sc->weight; + to_sc->sample_weight = from_sc->sample_weight; + to_sc->g = from_hg->g; + phases->num_closure++; + if (phases->num_closure >= MAX_VOLUME_CLOSURE) { + break; + } + } + } +} + +ccl_device_inline float _volume_shader_phase_eval_mis(ccl_private const ShaderData *sd, + ccl_private const ShaderVolumePhases *phases, + const float3 omega_in, + int skip_phase, + ccl_private BsdfEval *result_eval, + float sum_pdf, + float sum_sample_weight) +{ + for (int i = 0; i < phases->num_closure; i++) { + if (i == skip_phase) + continue; + + ccl_private const ShaderVolumeClosure *svc = &phases->closure[i]; + float phase_pdf = 0.0f; + Spectrum eval = volume_phase_eval(sd, svc, omega_in, &phase_pdf); + + if (phase_pdf != 0.0f) { + bsdf_eval_accum(result_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval); + sum_pdf += phase_pdf * svc->sample_weight; + } + + sum_sample_weight += svc->sample_weight; + } + + return (sum_sample_weight > 0.0f) ? sum_pdf / sum_sample_weight : 0.0f; +} + +ccl_device float volume_shader_phase_eval(KernelGlobals kg, + ccl_private const ShaderData *sd, + ccl_private const ShaderVolumePhases *phases, + const float3 omega_in, + ccl_private BsdfEval *phase_eval) +{ + bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, zero_spectrum()); + + return _volume_shader_phase_eval_mis(sd, phases, omega_in, -1, phase_eval, 0.0f, 0.0f); +} + +ccl_device int volume_shader_phase_sample(KernelGlobals kg, + ccl_private const ShaderData *sd, + ccl_private const ShaderVolumePhases *phases, + float2 rand_phase, + ccl_private BsdfEval *phase_eval, + ccl_private float3 *omega_in, + ccl_private float *pdf) +{ + int sampled = 0; + + if (phases->num_closure > 1) { + /* pick a phase closure based on sample weights */ + float sum = 0.0f; + + for (sampled = 0; sampled < phases->num_closure; sampled++) { + ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled]; + sum += svc->sample_weight; + } + + float r = rand_phase.x * sum; + float partial_sum = 0.0f; + + for (sampled = 0; sampled < phases->num_closure; sampled++) { + ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled]; + float next_sum = partial_sum + svc->sample_weight; + + if (r <= next_sum) { + /* Rescale to reuse for BSDF direction sample. */ + rand_phase.x = (r - partial_sum) / svc->sample_weight; + break; + } + + partial_sum = next_sum; + } + + if (sampled == phases->num_closure) { + *pdf = 0.0f; + return LABEL_NONE; + } + } + + /* todo: this isn't quite correct, we don't weight anisotropy properly + * depending on color channels, even if this is perhaps not a common case */ + ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled]; + int label; + Spectrum eval = zero_spectrum(); + + *pdf = 0.0f; + label = volume_phase_sample(sd, svc, rand_phase.x, rand_phase.y, &eval, omega_in, pdf); + + if (*pdf != 0.0f) { + bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval); + } + + return label; +} + +ccl_device int volume_shader_phase_sample_closure(KernelGlobals kg, + ccl_private const ShaderData *sd, + ccl_private const ShaderVolumeClosure *sc, + const float2 rand_phase, + ccl_private BsdfEval *phase_eval, + ccl_private float3 *omega_in, + ccl_private float *pdf) +{ + int label; + Spectrum eval = zero_spectrum(); + + *pdf = 0.0f; + label = volume_phase_sample(sd, sc, rand_phase.x, rand_phase.y, &eval, omega_in, pdf); + + if (*pdf != 0.0f) + bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval); + + return label; +} + +/* Motion Blur */ + +# ifdef __OBJECT_MOTION__ +ccl_device_inline void volume_shader_motion_blur(KernelGlobals kg, + ccl_private ShaderData *ccl_restrict sd) +{ + if ((sd->object_flag & SD_OBJECT_HAS_VOLUME_MOTION) == 0) { + return; + } + + AttributeDescriptor v_desc = find_attribute(kg, sd, ATTR_STD_VOLUME_VELOCITY); + kernel_assert(v_desc.offset != ATTR_STD_NOT_FOUND); + + const float3 P = sd->P; + const float velocity_scale = kernel_data_fetch(objects, sd->object).velocity_scale; + const float time_offset = kernel_data.cam.motion_position == MOTION_POSITION_CENTER ? 0.5f : + 0.0f; + const float time = kernel_data.cam.motion_position == MOTION_POSITION_END ? + (1.0f - kernel_data.cam.shuttertime) + sd->time : + sd->time; + + /* Use a 1st order semi-lagrangian advection scheme to estimate what volume quantity + * existed, or will exist, at the given time: + * + * `phi(x, T) = phi(x - (T - t) * u(x, T), t)` + * + * where + * + * x : position + * T : super-sampled time (or ray time) + * t : current time of the simulation (in rendering we assume this is center frame with + * relative time = 0) + * phi : the volume quantity + * u : the velocity field + * + * But first we need to determine the velocity field `u(x, T)`, which we can estimate also + * using semi-lagrangian advection. + * + * `u(x, T) = u(x - (T - t) * u(x, T), t)` + * + * This is the typical way to model self-advection in fluid dynamics, however, we do not + * account for other forces affecting the velocity during simulation (pressure, buoyancy, + * etc.): this gives a linear interpolation when fluid are mostly "curvy". For better + * results, a higher order interpolation scheme can be used (at the cost of more lookups), + * or an interpolation of the velocity fields for the previous and next frames could also + * be used to estimate `u(x, T)` (which will cost more memory and lookups). + * + * References: + * "Eulerian Motion Blur", Kim and Ko, 2007 + * "Production Volume Rendering", Wreninge et al., 2012 + */ + + /* Find velocity. */ + float3 velocity = primitive_volume_attribute_float3(kg, sd, v_desc); + object_dir_transform(kg, sd, &velocity); + + /* Find advected P. */ + sd->P = P - (time - time_offset) * velocity_scale * velocity; + + /* Find advected velocity. */ + velocity = primitive_volume_attribute_float3(kg, sd, v_desc); + object_dir_transform(kg, sd, &velocity); + + /* Find advected P. */ + sd->P = P - (time - time_offset) * velocity_scale * velocity; +} +# endif + +/* Volume Evaluation */ + +template<const bool shadow, typename StackReadOp, typename ConstIntegratorGenericState> +ccl_device_inline void volume_shader_eval(KernelGlobals kg, + ConstIntegratorGenericState state, + ccl_private ShaderData *ccl_restrict sd, + const uint32_t path_flag, + StackReadOp stack_read) +{ + /* If path is being terminated, we are tracing a shadow ray or evaluating + * emission, then we don't need to store closures. The emission and shadow + * shader data also do not have a closure array to save GPU memory. */ + int max_closures; + if (path_flag & (PATH_RAY_TERMINATE | PATH_RAY_SHADOW | PATH_RAY_EMISSION)) { + max_closures = 0; + } + else { + max_closures = kernel_data.max_closures; + } + + /* reset closures once at the start, we will be accumulating the closures + * for all volumes in the stack into a single array of closures */ + sd->num_closure = 0; + sd->num_closure_left = max_closures; + sd->flag = 0; + sd->object_flag = 0; + + for (int i = 0;; i++) { + const VolumeStack entry = stack_read(i); + if (entry.shader == SHADER_NONE) { + break; + } + + /* Setup shader-data from stack. it's mostly setup already in + * shader_setup_from_volume, this switching should be quick. */ + sd->object = entry.object; + sd->lamp = LAMP_NONE; + sd->shader = entry.shader; + + sd->flag &= ~SD_SHADER_FLAGS; + sd->flag |= kernel_data_fetch(shaders, (sd->shader & SHADER_MASK)).flags; + sd->object_flag &= ~SD_OBJECT_FLAGS; + + if (sd->object != OBJECT_NONE) { + sd->object_flag |= kernel_data_fetch(object_flag, sd->object); + +# ifdef __OBJECT_MOTION__ + /* todo: this is inefficient for motion blur, we should be + * caching matrices instead of recomputing them each step */ + shader_setup_object_transforms(kg, sd, sd->time); + + volume_shader_motion_blur(kg, sd); +# endif + } + + /* evaluate shader */ +# ifdef __SVM__ +# ifdef __OSL__ + if (kg->osl) { + OSLShader::eval_volume(kg, state, sd, path_flag); + } + else +# endif + { + svm_eval_nodes<KERNEL_FEATURE_NODE_MASK_VOLUME, SHADER_TYPE_VOLUME>( + kg, state, sd, NULL, path_flag); + } +# endif + + /* Merge closures to avoid exceeding number of closures limit. */ + if (!shadow) { + if (i > 0) { + volume_shader_merge_closures(sd); + } + } + } +} + +#endif /* __VOLUME__ */ + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/light/background.h b/intern/cycles/kernel/light/background.h index 2a97d43c9ce..951620ff1cb 100644 --- a/intern/cycles/kernel/light/background.h +++ b/intern/cycles/kernel/light/background.h @@ -9,8 +9,6 @@ CCL_NAMESPACE_BEGIN /* Background Light */ -#ifdef __BACKGROUND_MIS__ - ccl_device float3 background_map_sample(KernelGlobals kg, float randu, float randv, @@ -435,6 +433,4 @@ ccl_device float background_light_pdf(KernelGlobals kg, float3 P, float3 directi return pdf * kernel_data.integrator.pdf_lights; } -#endif - CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/light/light.h b/intern/cycles/kernel/light/light.h index b939489bb18..85478cd09c5 100644 --- a/intern/cycles/kernel/light/light.h +++ b/intern/cycles/kernel/light/light.h @@ -86,7 +86,6 @@ ccl_device_inline bool light_sample(KernelGlobals kg, ls->pdf = invarea / (costheta * costheta * costheta); ls->eval_fac = ls->pdf; } -#ifdef __BACKGROUND_MIS__ else if (type == LIGHT_BACKGROUND) { /* infinite area light (e.g. light dome or env light) */ float3 D = -background_light_sample(kg, P, randu, randv, &ls->pdf); @@ -97,7 +96,6 @@ ccl_device_inline bool light_sample(KernelGlobals kg, ls->t = FLT_MAX; ls->eval_fac = 1.0f; } -#endif else { ls->P = make_float3(klight->co[0], klight->co[1], klight->co[2]); diff --git a/intern/cycles/kernel/light/sample.h b/intern/cycles/kernel/light/sample.h index 4195675dd13..e0d4f221bef 100644 --- a/intern/cycles/kernel/light/sample.h +++ b/intern/cycles/kernel/light/sample.h @@ -4,7 +4,7 @@ #pragma once #include "kernel/integrator/path_state.h" -#include "kernel/integrator/shader_eval.h" +#include "kernel/integrator/surface_shader.h" #include "kernel/light/light.h" @@ -24,22 +24,19 @@ light_sample_shader_eval(KernelGlobals kg, /* setup shading at emitter */ Spectrum eval = zero_spectrum(); - if (shader_constant_emission_eval(kg, ls->shader, &eval)) { + if (surface_shader_constant_emission(kg, ls->shader, &eval)) { if ((ls->prim != PRIM_NONE) && dot(ls->Ng, ls->D) > 0.0f) { ls->Ng = -ls->Ng; } } else { - /* Setup shader data and call shader_eval_surface once, better + /* Setup shader data and call surface_shader_eval once, better * for GPU coherence and compile times. */ PROFILING_INIT_FOR_SHADER(kg, PROFILING_SHADE_LIGHT_SETUP); -#ifdef __BACKGROUND_MIS__ if (ls->type == LIGHT_BACKGROUND) { shader_setup_from_background(kg, emission_sd, ls->P, ls->D, time); } - else -#endif - { + else { shader_setup_from_sample(kg, emission_sd, ls->P, @@ -63,18 +60,15 @@ light_sample_shader_eval(KernelGlobals kg, /* No proper path flag, we're evaluating this for all closures. that's * weak but we'd have to do multiple evaluations otherwise. */ - shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT>( + surface_shader_eval<KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT>( kg, state, emission_sd, NULL, PATH_RAY_EMISSION); /* Evaluate closures. */ -#ifdef __BACKGROUND_MIS__ if (ls->type == LIGHT_BACKGROUND) { - eval = shader_background_eval(emission_sd); + eval = surface_shader_background(emission_sd); } - else -#endif - { - eval = shader_emissive_eval(emission_sd); + else { + eval = surface_shader_emission(emission_sd); } } diff --git a/intern/cycles/kernel/osl/services.cpp b/intern/cycles/kernel/osl/services.cpp index 6766fe2ce89..faa027f4e1e 100644 --- a/intern/cycles/kernel/osl/services.cpp +++ b/intern/cycles/kernel/osl/services.cpp @@ -27,7 +27,6 @@ #include "util/log.h" #include "util/string.h" -// clang-format off #include "kernel/device/cpu/compat.h" #include "kernel/device/cpu/globals.h" #include "kernel/device/cpu/image.h" @@ -45,10 +44,10 @@ #include "kernel/camera/projection.h" #include "kernel/integrator/path_state.h" -#include "kernel/integrator/shader_eval.h" + +#include "kernel/svm/svm.h" #include "kernel/util/color.h" -// clang-format on CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/sample/pattern.h b/intern/cycles/kernel/sample/pattern.h index 6477e29fa40..ebdecc1bff9 100644 --- a/intern/cycles/kernel/sample/pattern.h +++ b/intern/cycles/kernel/sample/pattern.h @@ -90,18 +90,33 @@ ccl_device_inline uint path_rng_hash_init(KernelGlobals kg, return rng_hash; } -ccl_device_inline bool sample_is_even(int pattern, int sample) +/** + * Splits samples into two different classes, A and B, which can be + * compared for variance estimation. + */ +ccl_device_inline bool sample_is_class_A(int pattern, int sample) { - if (pattern == SAMPLING_PATTERN_PMJ) { - /* See Section 10.2.1, "Progressive Multi-Jittered Sample Sequences", Christensen et al. - * We can use this to get divide sample sequence into two classes for easier variance - * estimation. */ - return popcount(uint(sample) & 0xaaaaaaaa) & 1; - } - else { - /* TODO(Stefan): Are there reliable ways of dividing Sobol-Burley into two classes? */ - return sample & 0x1; +#if 0 + if (!(pattern == SAMPLING_PATTERN_PMJ || pattern == SAMPLING_PATTERN_SOBOL_BURLEY)) { + /* Fallback: assign samples randomly. + * This is guaranteed to work "okay" for any sampler, but isn't good. + * (Note: the seed constant is just a random number to guard against + * possible interactions with other uses of the hash. There's nothing + * special about it.) + */ + return hash_hp_seeded_uint(sample, 0xa771f873) & 1; } -} +#else + (void)pattern; +#endif + /* This follows the approach from section 10.2.1 of "Progressive + * Multi-Jittered Sample Sequences" by Christensen et al., but + * implemented with efficient bit-fiddling. + * + * This approach also turns out to work equally well with Sobol-Burley + * (see https://developer.blender.org/D15746#429471). + */ + return popcount(uint(sample) & 0xaaaaaaaa) & 1; +} CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/aov.h b/intern/cycles/kernel/svm/aov.h index 9b818f0e6f8..c574b28c078 100644 --- a/intern/cycles/kernel/svm/aov.h +++ b/intern/cycles/kernel/svm/aov.h @@ -3,7 +3,7 @@ #pragma once -#include "kernel/film/write_passes.h" +#include "kernel/film/aov_passes.h" CCL_NAMESPACE_BEGIN @@ -27,12 +27,7 @@ ccl_device void svm_node_aov_color(KernelGlobals kg, IF_KERNEL_NODES_FEATURE(AOV) { const float3 val = stack_load_float3(stack, node.y); - const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index); - const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * - kernel_data.film.pass_stride; - ccl_global float *buffer = render_buffer + render_buffer_offset + - (kernel_data.film.pass_aov_color + node.z); - kernel_write_pass_float4(buffer, make_float4(val.x, val.y, val.z, 1.0f)); + film_write_aov_pass_color(kg, state, render_buffer, node.z, val); } } @@ -47,12 +42,7 @@ ccl_device void svm_node_aov_value(KernelGlobals kg, IF_KERNEL_NODES_FEATURE(AOV) { const float val = stack_load_float(stack, node.y); - const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index); - const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * - kernel_data.film.pass_stride; - ccl_global float *buffer = render_buffer + render_buffer_offset + - (kernel_data.film.pass_aov_value + node.z); - kernel_write_pass_float(buffer, val); + film_write_aov_pass_value(kg, state, render_buffer, node.z, val); } } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/closure.h b/intern/cycles/kernel/svm/closure.h index 5e8ef69fd15..2d91b014f60 100644 --- a/intern/cycles/kernel/svm/closure.h +++ b/intern/cycles/kernel/svm/closure.h @@ -3,6 +3,11 @@ #pragma once +#include "kernel/closure/alloc.h" +#include "kernel/closure/bsdf.h" +#include "kernel/closure/bsdf_util.h" +#include "kernel/closure/emissive.h" + #include "kernel/util/color.h" CCL_NAMESPACE_BEGIN @@ -106,7 +111,6 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, __uint_as_float(node.w); switch (type) { -#ifdef __PRINCIPLED__ case CLOSURE_BSDF_PRINCIPLED_ID: { uint specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset, sheen_offset, sheen_tint_offset, clearcoat_offset, clearcoat_roughness_offset, @@ -202,7 +206,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, Spectrum weight = sd->svm_closure_weight * mix_weight; -# ifdef __SUBSURFACE__ +#ifdef __SUBSURFACE__ float3 mixed_ss_base_color = subsurface_color * subsurface + base_color * (1.0f - subsurface); Spectrum subsurf_weight = weight * rgb_to_spectrum(mixed_ss_base_color) * diffuse_weight; @@ -253,7 +257,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, } } } -# else +#else /* diffuse */ if (diffuse_weight > CLOSURE_WEIGHT_CUTOFF) { Spectrum diff_weight = weight * rgb_to_spectrum(base_color) * diffuse_weight; @@ -269,7 +273,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, sd->flag |= bsdf_principled_diffuse_setup(bsdf, PRINCIPLED_DIFFUSE_FULL); } } -# endif +#endif /* sheen */ if (diffuse_weight > CLOSURE_WEIGHT_CUTOFF && sheen > CLOSURE_WEIGHT_CUTOFF) { @@ -294,9 +298,9 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, } /* specular reflection */ -# ifdef __CAUSTICS_TRICKS__ +#ifdef __CAUSTICS_TRICKS__ if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) { -# endif +#endif if (specular_weight > CLOSURE_WEIGHT_CUTOFF && (specular > CLOSURE_WEIGHT_CUTOFF || metallic > CLOSURE_WEIGHT_CUTOFF)) { Spectrum spec_weight = weight * specular_weight; @@ -339,15 +343,15 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(bsdf, sd); } } -# ifdef __CAUSTICS_TRICKS__ +#ifdef __CAUSTICS_TRICKS__ } -# endif +#endif /* BSDF */ -# ifdef __CAUSTICS_TRICKS__ +#ifdef __CAUSTICS_TRICKS__ if (kernel_data.integrator.caustics_reflective || kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0) { -# endif +#endif if (final_transmission > CLOSURE_WEIGHT_CUTOFF) { Spectrum glass_weight = weight * final_transmission; float3 cspec0 = base_color * specular_tint + make_float3(1.0f - specular_tint); @@ -357,9 +361,9 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, float refl_roughness = roughness; /* reflection */ -# ifdef __CAUSTICS_TRICKS__ +#ifdef __CAUSTICS_TRICKS__ if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) -# endif +#endif { ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( sd, sizeof(MicrofacetBsdf), glass_weight * fresnel); @@ -387,9 +391,9 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, } /* refraction */ -# ifdef __CAUSTICS_TRICKS__ +#ifdef __CAUSTICS_TRICKS__ if (kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0) -# endif +#endif { /* This is to prevent MNEE from receiving a null BSDF. */ float refraction_fresnel = fmaxf(0.0001f, 1.0f - fresnel); @@ -443,14 +447,14 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, } } } -# ifdef __CAUSTICS_TRICKS__ +#ifdef __CAUSTICS_TRICKS__ } -# endif +#endif /* clearcoat */ -# ifdef __CAUSTICS_TRICKS__ +#ifdef __CAUSTICS_TRICKS__ if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) { -# endif +#endif if (clearcoat > CLOSURE_WEIGHT_CUTOFF) { ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( sd, sizeof(MicrofacetBsdf), weight); @@ -476,13 +480,12 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, sd->flag |= bsdf_microfacet_ggx_clearcoat_setup(bsdf, sd); } } -# ifdef __CAUSTICS_TRICKS__ +#ifdef __CAUSTICS_TRICKS__ } -# endif +#endif break; } -#endif /* __PRINCIPLED__ */ case CLOSURE_BSDF_DIFFUSE_ID: { Spectrum weight = sd->svm_closure_weight * mix_weight; ccl_private OrenNayarBsdf *bsdf = (ccl_private OrenNayarBsdf *)bsdf_alloc( diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 16c37beeb5a..33a27ad3677 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -54,36 +54,25 @@ CCL_NAMESPACE_BEGIN #endif /* Kernel features */ -#define __DPDU__ -#define __BACKGROUND__ +#define __AO__ #define __CAUSTICS_TRICKS__ -#define __VISIBILITY_FLAG__ -#define __RAY_DIFFERENTIALS__ -#define __CAMERA_CLIPPING__ -#define __INTERSECTION_REFINE__ #define __CLAMP_SAMPLE__ -#define __PATCH_EVAL__ -#define __SHADOW_CATCHER__ #define __DENOISING_FEATURES__ -#define __SHADER_RAYTRACE__ -#define __AO__ -#define __PASSES__ +#define __DPDU__ #define __HAIR__ +#define __OBJECT_MOTION__ +#define __PASSES__ +#define __PATCH_EVAL__ #define __POINTCLOUD__ +#define __RAY_DIFFERENTIALS__ +#define __SHADER_RAYTRACE__ +#define __SHADOW_CATCHER__ +#define __SHADOW_RECORD_ALL__ +#define __SUBSURFACE__ #define __SVM__ -#define __EMISSION__ -#define __HOLDOUT__ #define __TRANSPARENT_SHADOWS__ -#define __BACKGROUND_MIS__ -#define __LAMP_MIS__ -#define __CAMERA_MOTION__ -#define __OBJECT_MOTION__ -#define __PRINCIPLED__ -#define __SUBSURFACE__ +#define __VISIBILITY_FLAG__ #define __VOLUME__ -#define __CMJ__ -#define __SHADOW_RECORD_ALL__ -#define __BRANCHED_PATH__ /* Device specific features */ #ifndef __KERNEL_GPU__ @@ -101,9 +90,6 @@ CCL_NAMESPACE_BEGIN /* Scene-based selective features compilation. */ #ifdef __KERNEL_FEATURES__ -# if !(__KERNEL_FEATURES & KERNEL_FEATURE_CAMERA_MOTION) -# undef __CAMERA_MOTION__ -# endif # if !(__KERNEL_FEATURES & KERNEL_FEATURE_OBJECT_MOTION) # undef __OBJECT_MOTION__ # endif @@ -128,9 +114,6 @@ CCL_NAMESPACE_BEGIN # if !(__KERNEL_FEATURES & KERNEL_FEATURE_SHADOW_CATCHER) # undef __SHADOW_CATCHER__ # endif -# if !(__KERNEL_FEATURES & KERNEL_FEATURE_PRINCIPLED) -# undef __PRINCIPLED__ -# endif # if !(__KERNEL_FEATURES & KERNEL_FEATURE_DENOISING) # undef __DENOISING_FEATURES__ # endif @@ -1488,42 +1471,38 @@ enum KernelFeatureFlag : uint32_t { KERNEL_FEATURE_HAIR = (1U << 12U), KERNEL_FEATURE_HAIR_THICK = (1U << 13U), KERNEL_FEATURE_OBJECT_MOTION = (1U << 14U), - KERNEL_FEATURE_CAMERA_MOTION = (1U << 15U), /* Denotes whether baking functionality is needed. */ - KERNEL_FEATURE_BAKING = (1U << 16U), + KERNEL_FEATURE_BAKING = (1U << 15U), /* Use subsurface scattering materials. */ - KERNEL_FEATURE_SUBSURFACE = (1U << 17U), + KERNEL_FEATURE_SUBSURFACE = (1U << 16U), /* Use volume materials. */ - KERNEL_FEATURE_VOLUME = (1U << 18U), + KERNEL_FEATURE_VOLUME = (1U << 17U), /* Use OpenSubdiv patch evaluation */ - KERNEL_FEATURE_PATCH_EVALUATION = (1U << 19U), + KERNEL_FEATURE_PATCH_EVALUATION = (1U << 18U), /* Use Transparent shadows */ - KERNEL_FEATURE_TRANSPARENT = (1U << 20U), + KERNEL_FEATURE_TRANSPARENT = (1U << 19U), /* Use shadow catcher. */ - KERNEL_FEATURE_SHADOW_CATCHER = (1U << 21U), - - /* Per-uber shader usage flags. */ - KERNEL_FEATURE_PRINCIPLED = (1U << 22U), + KERNEL_FEATURE_SHADOW_CATCHER = (1U << 29U), /* Light render passes. */ - KERNEL_FEATURE_LIGHT_PASSES = (1U << 23U), + KERNEL_FEATURE_LIGHT_PASSES = (1U << 21U), /* Shadow render pass. */ - KERNEL_FEATURE_SHADOW_PASS = (1U << 24U), + KERNEL_FEATURE_SHADOW_PASS = (1U << 22U), /* AO. */ - KERNEL_FEATURE_AO_PASS = (1U << 25U), - KERNEL_FEATURE_AO_ADDITIVE = (1U << 26U), + KERNEL_FEATURE_AO_PASS = (1U << 23U), + KERNEL_FEATURE_AO_ADDITIVE = (1U << 24U), KERNEL_FEATURE_AO = (KERNEL_FEATURE_AO_PASS | KERNEL_FEATURE_AO_ADDITIVE), /* MNEE. */ - KERNEL_FEATURE_MNEE = (1U << 27U), + KERNEL_FEATURE_MNEE = (1U << 25U), }; /* Shader node feature mask, to specialize shader evaluation for kernels. */ diff --git a/intern/cycles/scene/camera.cpp b/intern/cycles/scene/camera.cpp index d9e574873bd..240e5d9c128 100644 --- a/intern/cycles/scene/camera.cpp +++ b/intern/cycles/scene/camera.cpp @@ -761,9 +761,7 @@ float Camera::world_to_raster_size(float3 P) } #else camera_sample_panorama(&kernel_camera, -# ifdef __CAMERA_MOTION__ kernel_camera_motion.data(), -# endif 0.5f * full_width, 0.5f * full_height, 0.0f, diff --git a/intern/cycles/scene/integrator.cpp b/intern/cycles/scene/integrator.cpp index 86a2c9571c6..e9cd753854f 100644 --- a/intern/cycles/scene/integrator.cpp +++ b/intern/cycles/scene/integrator.cpp @@ -217,9 +217,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene FLT_MAX : sample_clamp_indirect * 3.0f; - /* Adaptive sampling requires PMJ, see sample_is_even. */ - kintegrator->sampling_pattern = (use_adaptive_sampling) ? SAMPLING_PATTERN_PMJ : - sampling_pattern; + kintegrator->sampling_pattern = sampling_pattern; kintegrator->scrambling_distance = scrambling_distance; if (light_sampling_threshold > 0.0f) { diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene.cpp index 18cd665ac74..478396ea98e 100644 --- a/intern/cycles/scene/scene.cpp +++ b/intern/cycles/scene/scene.cpp @@ -497,9 +497,6 @@ void Scene::update_kernel_features() if (params.hair_shape == CURVE_THICK) { kernel_features |= KERNEL_FEATURE_HAIR_THICK; } - if (use_motion && camera->use_motion()) { - kernel_features |= KERNEL_FEATURE_CAMERA_MOTION; - } /* Figure out whether the scene will use shader ray-trace we need at least * one caustic light, one caustic caster and one caustic receiver to use @@ -520,9 +517,6 @@ void Scene::update_kernel_features() if (object->use_motion() || geom->get_use_motion_blur()) { kernel_features |= KERNEL_FEATURE_OBJECT_MOTION; } - if (geom->get_use_motion_blur()) { - kernel_features |= KERNEL_FEATURE_CAMERA_MOTION; - } } if (object->get_is_shadow_catcher()) { kernel_features |= KERNEL_FEATURE_SHADOW_CATCHER; @@ -590,8 +584,6 @@ static void log_kernel_features(const uint features) { VLOG_INFO << "Requested features:\n"; VLOG_INFO << "Use BSDF " << string_from_bool(features & KERNEL_FEATURE_NODE_BSDF) << "\n"; - VLOG_INFO << "Use Principled BSDF " << string_from_bool(features & KERNEL_FEATURE_PRINCIPLED) - << "\n"; VLOG_INFO << "Use Emission " << string_from_bool(features & KERNEL_FEATURE_NODE_EMISSION) << "\n"; VLOG_INFO << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_NODE_VOLUME) << "\n"; @@ -611,8 +603,6 @@ static void log_kernel_features(const uint features) << "\n"; VLOG_INFO << "Use Object Motion " << string_from_bool(features & KERNEL_FEATURE_OBJECT_MOTION) << "\n"; - VLOG_INFO << "Use Camera Motion " << string_from_bool(features & KERNEL_FEATURE_CAMERA_MOTION) - << "\n"; VLOG_INFO << "Use Baking " << string_from_bool(features & KERNEL_FEATURE_BAKING) << "\n"; VLOG_INFO << "Use Subsurface " << string_from_bool(features & KERNEL_FEATURE_SUBSURFACE) << "\n"; VLOG_INFO << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_VOLUME) << "\n"; diff --git a/intern/cycles/scene/shader.cpp b/intern/cycles/scene/shader.cpp index e1af92ea8cf..bd647ab55e7 100644 --- a/intern/cycles/scene/shader.cpp +++ b/intern/cycles/scene/shader.cpp @@ -685,9 +685,6 @@ uint ShaderManager::get_graph_kernel_features(ShaderGraph *graph) if (CLOSURE_IS_VOLUME(bsdf_node->get_closure_type())) { kernel_features |= KERNEL_FEATURE_NODE_VOLUME; } - else if (CLOSURE_IS_PRINCIPLED(bsdf_node->get_closure_type())) { - kernel_features |= KERNEL_FEATURE_PRINCIPLED; - } } if (node->has_surface_bssrdf()) { kernel_features |= KERNEL_FEATURE_SUBSURFACE; |