diff --git a/intern/cycles/kernel/integrator/shade_volume.h b/intern/cycles/kernel/integrator/shade_volume.h index a8324cda2dc..46d13f59c6a 100644 --- a/intern/cycles/kernel/integrator/shade_volume.h +++ b/intern/cycles/kernel/integrator/shade_volume.h @@ -34,6 +34,9 @@ typedef struct VolumeIntegrateResult { Spectrum direct_throughput; float direct_t; ShaderVolumePhases direct_phases; +# ifdef __PATH_GUIDING__ + VolumeSampleMethod direct_sample_method; +# endif /* Throughput and offset for indirect light scattering. */ bool indirect_scatter; @@ -580,6 +583,9 @@ ccl_device_forceinline void volume_integrate_heterogeneous( result.direct_t = volume_equiangular_sample( ray, equiangular_light_P, vstate.rscatter, &vstate.equiangular_pdf); } +# ifdef __PATH_GUIDING__ + result.direct_sample_method = vstate.direct_sample_method; +# endif # ifdef __DENOISING_FEATURES__ const bool write_denoising_features = (INTEGRATOR_STATE(state, path, flag) & @@ -719,6 +725,9 @@ ccl_device_forceinline void integrate_volume_direct_light( ccl_private const RNGState *ccl_restrict rng_state, const float3 P, ccl_private const ShaderVolumePhases *ccl_restrict phases, +# ifdef __PATH_GUIDING__ + ccl_private const Spectrum unlit_throughput, +# endif ccl_private const Spectrum throughput, ccl_private LightSample *ccl_restrict ls) { @@ -851,7 +860,7 @@ ccl_device_forceinline void integrate_volume_direct_light( kernel_data.background.lightgroup + 1; # ifdef __PATH_GUIDING__ - INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unlit_throughput) = throughput; + INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unlit_throughput) = unlit_throughput; INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, path_segment) = INTEGRATOR_STATE( state, guiding, path_segment); # endif @@ -990,7 +999,13 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg, const float step_size = volume_stack_step_size(kg, volume_read_lambda_pass); # if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1 + /* The current path throughput which is used later to calculate per-segment throughput.*/ const float3 initial_throughput = INTEGRATOR_STATE(state, path, throughput); + /* The path throughput used to calculate the throughput for direct light. */ + float3 unlit_throughput = initial_throughput; + /* If a new path segment is generated at the direct scatter position.*/ + bool guiding_generated_new_segment = false; + float rand_phase_guiding = 0.5f; # endif /* TODO: expensive to zero closures? */ @@ -1018,41 +1033,48 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg, return VOLUME_PATH_MISSED; } -# if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1 - bool guiding_generated_new_segment = false; - if (kernel_data.integrator.use_guiding) { - /* Record transmittance using change in throughput. */ - float3 transmittance_weight = spectrum_to_rgb( - safe_divide_color(result.indirect_throughput, initial_throughput)); - guiding_record_volume_transmission(kg, state, transmittance_weight); - - if (result.indirect_scatter) { - const float3 P = ray->P + result.indirect_t * ray->D; - - /* Record volume segment up to direct scatter position. - * TODO: volume segment is wrong when direct_t and indirect_t. */ - if (result.direct_scatter && (result.direct_t == result.indirect_t)) { - guiding_record_volume_segment(kg, state, P, sd.I); - guiding_generated_new_segment = true; - } - -# if PATH_GUIDING_LEVEL >= 4 - /* TODO: this position will be wrong for direct light pdf computation, - * since the direct light position may be different? */ - volume_shader_prepare_guiding( - kg, state, &sd, &rng_state, P, ray->D, &result.direct_phases, direct_sample_method); -# endif - } - else { - /* No guiding if we don't scatter. */ - state->guiding.use_volume_guiding = false; - } - } -# endif - /* Direct light. */ if (result.direct_scatter) { const float3 direct_P = ray->P + result.direct_t * ray->D; + +# ifdef __PATH_GUIDING__ + if (kernel_data.integrator.use_guiding) { +# if PATH_GUIDING_LEVEL >= 1 + if (result.direct_sample_method == VOLUME_SAMPLE_DISTANCE) { + /* If the direct scatter event is generated using VOLUME_SAMPLE_DISTANCE the direct event + * will happen at the same position as the indirect event and the direct light contribution + * will contribute to the position of the next path segment.*/ + float3 transmittance_weight = spectrum_to_rgb( + safe_divide_color(result.indirect_throughput, initial_throughput)); + guiding_record_volume_transmission(kg, state, transmittance_weight); + guiding_record_volume_segment(kg, state, direct_P, sd.I); + guiding_generated_new_segment = true; + unlit_throughput = result.indirect_throughput / continuation_probability; + rand_phase_guiding = path_state_rng_1D(kg, &rng_state, PRNG_VOLUME_PHASE_GUIDING_DISTANCE); + } + else { + /* If the direct scatter event is generated using VOLUME_SAMPLE_EQUIANGULAR the direct + * event will happen at a separate position as the indirect event and the direct light + * contribution will contribute to the position of the current/previous path segment. The + * unlit_throughput has to be adjusted to include the scattering at the previous segment.*/ + float3 scatterEval = one_float3(); + if (state->guiding.path_segment) { + pgl_vec3f scatteringWeight = state->guiding.path_segment->scatteringWeight; + scatterEval = make_float3(scatteringWeight.x, scatteringWeight.y, scatteringWeight.z); + } + unlit_throughput /= scatterEval; + unlit_throughput *= continuation_probability; + rand_phase_guiding = path_state_rng_1D( + kg, &rng_state, PRNG_VOLUME_PHASE_GUIDING_EQUIANGULAR); + } +# endif +# if PATH_GUIDING_LEVEL >= 4 + volume_shader_prepare_guiding( + kg, state, &sd, rand_phase_guiding, direct_P, ray->D, &result.direct_phases); +# endif + } +# endif + result.direct_throughput /= continuation_probability; integrate_volume_direct_light(kg, state, @@ -1060,6 +1082,9 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg, &rng_state, direct_P, &result.direct_phases, +# ifdef __PATH_GUIDING__ + unlit_throughput, +# endif result.direct_throughput, &ls); } @@ -1069,6 +1094,13 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg, * Only divide throughput by continuation_probability if we scatter. For the attenuation * case the next surface will already do this division. */ if (result.indirect_scatter) { +# if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1 + if (!guiding_generated_new_segment) { + float3 transmittance_weight = spectrum_to_rgb( + safe_divide_color(result.indirect_throughput, initial_throughput)); + guiding_record_volume_transmission(kg, state, transmittance_weight); + } +# endif result.indirect_throughput /= continuation_probability; } INTEGRATOR_STATE_WRITE(state, path, throughput) = result.indirect_throughput; @@ -1076,10 +1108,21 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg, if (result.indirect_scatter) { sd.P = ray->P + result.indirect_t * ray->D; -# if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1 +# if defined(__PATH_GUIDING__) +# if PATH_GUIDING_LEVEL >= 1 if (!guiding_generated_new_segment) { guiding_record_volume_segment(kg, state, sd.P, sd.I); } +# endif +# if PATH_GUIDING_LEVEL >= 4 + /* If the direct scatter event was generated using VOLUME_SAMPLE_EQUIANGULAR we need to + * initialize the guiding distribution at the indirect scatter position. */ + if (result.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR) { + rand_phase_guiding = path_state_rng_1D(kg, &rng_state, PRNG_VOLUME_PHASE_GUIDING_DISTANCE); + volume_shader_prepare_guiding( + kg, state, &sd, rand_phase_guiding, sd.P, ray->D, &result.indirect_phases); + } +# endif # endif if (integrate_volume_phase_scatter(kg, state, &sd, &rng_state, &result.indirect_phases)) { @@ -1090,6 +1133,10 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg, } } else { +# if defined(__PATH_GUIDING__) + /* No guiding if we don't scatter. */ + state->guiding.use_volume_guiding = false; +# endif return VOLUME_PATH_ATTENUATED; } } diff --git a/intern/cycles/kernel/integrator/volume_shader.h b/intern/cycles/kernel/integrator/volume_shader.h index f9050647c6d..625205e9931 100644 --- a/intern/cycles/kernel/integrator/volume_shader.h +++ b/intern/cycles/kernel/integrator/volume_shader.h @@ -95,11 +95,10 @@ ccl_device_inline void volume_shader_copy_phases(ccl_private ShaderVolumePhases ccl_device_inline void volume_shader_prepare_guiding(KernelGlobals kg, IntegratorState state, ccl_private ShaderData *sd, - ccl_private const RNGState *rng_state, + float rand_phase_guiding, const float3 P, const float3 D, - ccl_private ShaderVolumePhases *phases, - const VolumeSampleMethod direct_sample_method) + ccl_private ShaderVolumePhases *phases) { /* Have any phase functions to guide? */ const int num_phases = phases->num_closure; @@ -109,7 +108,6 @@ ccl_device_inline void volume_shader_prepare_guiding(KernelGlobals kg, } const float volume_guiding_probability = kernel_data.integrator.volume_guiding_probability; - float rand_phase_guiding = path_state_rng_1D(kg, rng_state, PRNG_VOLUME_PHASE_GUIDING); /* If we have more than one phase function we select one random based on its * sample weight to calculate the product distribution for guiding. */ diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 3746baafc90..c737e1f7f80 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -160,7 +160,8 @@ enum PathTraceDimension { PRNG_VOLUME_SCATTER_DISTANCE = 5, PRNG_VOLUME_OFFSET = 6, PRNG_VOLUME_SHADE_OFFSET = 7, - PRNG_VOLUME_PHASE_GUIDING = 8, + PRNG_VOLUME_PHASE_GUIDING_DISTANCE = 8, + PRNG_VOLUME_PHASE_GUIDING_EQUIANGULAR = 9, /* Subsurface random walk bounces */ PRNG_SUBSURFACE_BSDF = 0, diff --git a/intern/cycles/scene/osl.cpp b/intern/cycles/scene/osl.cpp index 17b916ad006..39693562d34 100644 --- a/intern/cycles/scene/osl.cpp +++ b/intern/cycles/scene/osl.cpp @@ -749,7 +749,7 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath) if (node_skip_input(node, input)) { continue; } - if (input->flags() & SocketType::LINK_OSL_INITIALIZER) { + if ((input->flags() & SocketType::LINK_OSL_INITIALIZER) && !(input->constant_folded_in)) { continue; } diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.cc b/source/blender/editors/sculpt_paint/sculpt_automasking.cc index f0b803ecfa1..211ff14c906 100644 --- a/source/blender/editors/sculpt_paint/sculpt_automasking.cc +++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc @@ -847,7 +847,10 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object use_stroke_id = true; if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_CAVITY_USE_CURVE)) { - BKE_curvemapping_init(brush->automasking_cavity_curve); + if (brush) { + BKE_curvemapping_init(brush->automasking_cavity_curve); + } + BKE_curvemapping_init(sd->automasking_cavity_curve); } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index ef068fbc3f4..b5bad2d3671 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -1357,6 +1357,7 @@ float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking, * brushes and filter. */ struct AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss); +/* Brush can be null. */ struct AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob); void SCULPT_automasking_cache_free(struct AutomaskingCache *automasking);