Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/integrator/shade_volume.h
| Show First 20 Lines • Show All 679 Lines • ▼ Show 20 Lines | # ifdef __DENOISING_FEATURES__ | ||||
| /* Write denoising features. */ | /* Write denoising features. */ | ||||
| if (write_denoising_features) { | if (write_denoising_features) { | ||||
| film_write_denoising_features_volume( | film_write_denoising_features_volume( | ||||
| kg, state, accum_albedo, result.indirect_scatter, render_buffer); | kg, state, accum_albedo, result.indirect_scatter, render_buffer); | ||||
| } | } | ||||
| # endif /* __DENOISING_FEATURES__ */ | # endif /* __DENOISING_FEATURES__ */ | ||||
| } | } | ||||
| /* Path tracing: sample point on light and evaluate light shader, then | /* Path tracing: sample point on light for equiangular sampling. */ | ||||
| * queue shadow ray to be traced. */ | ccl_device_forceinline bool integrate_volume_equiangular_sample_light( | ||||
| ccl_device_forceinline bool integrate_volume_sample_light( | |||||
| KernelGlobals kg, | KernelGlobals kg, | ||||
| IntegratorState state, | IntegratorState state, | ||||
| ccl_private const Ray *ccl_restrict ray, | ccl_private const Ray *ccl_restrict ray, | ||||
| ccl_private const ShaderData *ccl_restrict sd, | ccl_private const ShaderData *ccl_restrict sd, | ||||
| ccl_private const RNGState *ccl_restrict rng_state, | ccl_private const RNGState *ccl_restrict rng_state, | ||||
| ccl_private LightSample *ccl_restrict ls) | ccl_private float3 *ccl_restrict P) | ||||
| { | { | ||||
| /* Test if there is a light or BSDF that needs direct light. */ | /* Test if there is a light or BSDF that needs direct light. */ | ||||
| if (!kernel_data.integrator.use_direct_light) { | if (!kernel_data.integrator.use_direct_light) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Sample position on a light. */ | /* Sample position on a light. */ | ||||
| const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); | const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); | ||||
| const uint bounce = INTEGRATOR_STATE(state, path, bounce); | const uint bounce = INTEGRATOR_STATE(state, path, bounce); | ||||
| const float2 rand_light = path_state_rng_2D(kg, rng_state, PRNG_LIGHT); | const float2 rand_light = path_state_rng_2D(kg, rng_state, PRNG_LIGHT); | ||||
| LightSample ls; | |||||
| if (!light_sample_from_volume_segment(kg, | if (!light_sample_from_volume_segment(kg, | ||||
| rand_light.x, | rand_light.x, | ||||
| rand_light.y, | rand_light.y, | ||||
| sd->time, | sd->time, | ||||
| sd->P, | sd->P, | ||||
| ray->D, | ray->D, | ||||
| ray->tmax - ray->tmin, | ray->tmax - ray->tmin, | ||||
| bounce, | bounce, | ||||
| path_flag, | path_flag, | ||||
| ls)) { | &ls)) { | ||||
| return false; | |||||
| } | |||||
| if (ls.shader & SHADER_EXCLUDE_SCATTER) { | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (ls->shader & SHADER_EXCLUDE_SCATTER) { | if (ls.t == FLT_MAX) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| *P = ls.P; | |||||
| return true; | return true; | ||||
| } | } | ||||
| /* Path tracing: sample point on light and evaluate light shader, then | /* Path tracing: sample point on light and evaluate light shader, then | ||||
| * queue shadow ray to be traced. */ | * queue shadow ray to be traced. */ | ||||
| ccl_device_forceinline void integrate_volume_direct_light( | ccl_device_forceinline void integrate_volume_direct_light( | ||||
| KernelGlobals kg, | KernelGlobals kg, | ||||
| IntegratorState state, | IntegratorState state, | ||||
| ccl_private const ShaderData *ccl_restrict sd, | ccl_private const ShaderData *ccl_restrict sd, | ||||
| ccl_private const RNGState *ccl_restrict rng_state, | ccl_private const RNGState *ccl_restrict rng_state, | ||||
| const float3 P, | const float3 P, | ||||
| ccl_private const ShaderVolumePhases *ccl_restrict phases, | ccl_private const ShaderVolumePhases *ccl_restrict phases, | ||||
| # ifdef __PATH_GUIDING__ | # ifdef __PATH_GUIDING__ | ||||
| ccl_private const Spectrum unlit_throughput, | ccl_private const Spectrum unlit_throughput, | ||||
| # endif | # endif | ||||
| ccl_private const Spectrum throughput, | ccl_private const Spectrum throughput) | ||||
| ccl_private LightSample *ccl_restrict ls) | |||||
| { | { | ||||
| PROFILING_INIT(kg, PROFILING_SHADE_VOLUME_DIRECT_LIGHT); | PROFILING_INIT(kg, PROFILING_SHADE_VOLUME_DIRECT_LIGHT); | ||||
| if (!kernel_data.integrator.use_direct_light) { | if (!kernel_data.integrator.use_direct_light) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Sample position on the same light again, now from the shading point where we scattered. | /* Sample position on the same light again, now from the shading point where we scattered. | ||||
| * | * | ||||
| * Note that this means we sample the light tree twice when equiangular sampling is used. | * Note that this means we sample the light tree twice when equiangular sampling is used. | ||||
| * We could consider sampling the light tree just once and use the same light position again. | * We could consider sampling the light tree just once and use the same light position again. | ||||
| * | * | ||||
| * This would make the PDFs for MIS weights more complicated due to having to account for | * This would make the PDFs for MIS weights more complicated due to having to account for | ||||
| * both distance/equiangular and direct/indirect light sampling, but could be more accurate. | * both distance/equiangular and direct/indirect light sampling, but could be more accurate. | ||||
| * Additionally we could end up behind the light or outside a spot light cone, which might | * Additionally we could end up behind the light or outside a spot light cone, which might | ||||
| * waste a sample. Though on the other hand it would be possible to prevent that with | * waste a sample. Though on the other hand it would be possible to prevent that with | ||||
| * equiangular sampling restricted to a smaller sub-segment where the light has influence. */ | * equiangular sampling restricted to a smaller sub-segment where the light has influence. */ | ||||
| LightSample ls; | |||||
| { | { | ||||
| const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); | const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); | ||||
| const uint bounce = INTEGRATOR_STATE(state, path, bounce); | const uint bounce = INTEGRATOR_STATE(state, path, bounce); | ||||
| const float2 rand_light = path_state_rng_2D(kg, rng_state, PRNG_LIGHT); | const float2 rand_light = path_state_rng_2D(kg, rng_state, PRNG_LIGHT); | ||||
| if (!light_sample_from_position(kg, | if (!light_sample_from_position(kg, | ||||
| rng_state, | rng_state, | ||||
| rand_light.x, | rand_light.x, | ||||
| rand_light.y, | rand_light.y, | ||||
| sd->time, | sd->time, | ||||
| P, | P, | ||||
| zero_float3(), | zero_float3(), | ||||
| SD_BSDF_HAS_TRANSMISSION, | SD_BSDF_HAS_TRANSMISSION, | ||||
| bounce, | bounce, | ||||
| path_flag, | path_flag, | ||||
| ls)) { | &ls)) { | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| if (ls->shader & SHADER_EXCLUDE_SCATTER) { | if (ls.shader & SHADER_EXCLUDE_SCATTER) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Evaluate light shader. | /* Evaluate light shader. | ||||
| * | * | ||||
| * TODO: can we reuse sd memory? In theory we can move this after | * TODO: can we reuse sd memory? In theory we can move this after | ||||
| * integrate_surface_bounce, evaluate the BSDF, and only then evaluate | * integrate_surface_bounce, evaluate the BSDF, and only then evaluate | ||||
| * the light shader. This could also move to its own kernel, for | * the light shader. This could also move to its own kernel, for | ||||
| * non-constant light sources. */ | * non-constant light sources. */ | ||||
| ShaderDataTinyStorage emission_sd_storage; | ShaderDataTinyStorage emission_sd_storage; | ||||
| ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage); | ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage); | ||||
| const Spectrum light_eval = light_sample_shader_eval(kg, state, emission_sd, ls, sd->time); | const Spectrum light_eval = light_sample_shader_eval(kg, state, emission_sd, &ls, sd->time); | ||||
| if (is_zero(light_eval)) { | if (is_zero(light_eval)) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Evaluate BSDF. */ | /* Evaluate BSDF. */ | ||||
| BsdfEval phase_eval ccl_optional_struct_init; | BsdfEval phase_eval ccl_optional_struct_init; | ||||
| float phase_pdf = volume_shader_phase_eval(kg, state, sd, phases, ls->D, &phase_eval); | float phase_pdf = volume_shader_phase_eval(kg, state, sd, phases, ls.D, &phase_eval); | ||||
| if (ls->shader & SHADER_USE_MIS) { | if (ls.shader & SHADER_USE_MIS) { | ||||
| float mis_weight = light_sample_mis_weight_nee(kg, ls->pdf, phase_pdf); | float mis_weight = light_sample_mis_weight_nee(kg, ls.pdf, phase_pdf); | ||||
| bsdf_eval_mul(&phase_eval, mis_weight); | bsdf_eval_mul(&phase_eval, mis_weight); | ||||
| } | } | ||||
| bsdf_eval_mul(&phase_eval, light_eval / ls->pdf); | bsdf_eval_mul(&phase_eval, light_eval / ls.pdf); | ||||
| /* Path termination. */ | /* Path termination. */ | ||||
| const float terminate = path_state_rng_light_termination(kg, rng_state); | const float terminate = path_state_rng_light_termination(kg, rng_state); | ||||
| if (light_sample_terminate(kg, ls, &phase_eval, terminate)) { | if (light_sample_terminate(kg, &ls, &phase_eval, terminate)) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Create shadow ray. */ | /* Create shadow ray. */ | ||||
| Ray ray ccl_optional_struct_init; | Ray ray ccl_optional_struct_init; | ||||
| light_sample_to_volume_shadow_ray(kg, sd, ls, P, &ray); | light_sample_to_volume_shadow_ray(kg, sd, &ls, P, &ray); | ||||
| const bool is_light = light_sample_is_light(ls); | const bool is_light = light_sample_is_light(&ls); | ||||
| /* Branch off shadow kernel. */ | /* Branch off shadow kernel. */ | ||||
| IntegratorShadowState shadow_state = integrator_shadow_path_init( | IntegratorShadowState shadow_state = integrator_shadow_path_init( | ||||
| kg, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW, false); | kg, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW, false); | ||||
| /* Write shadow ray and associated state to global memory. */ | /* Write shadow ray and associated state to global memory. */ | ||||
| integrator_state_write_shadow_ray(kg, shadow_state, &ray); | integrator_state_write_shadow_ray(kg, shadow_state, &ray); | ||||
| INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, object) = ray.self.object; | INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, object) = ray.self.object; | ||||
| ▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | # endif | ||||
| INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, throughput) = throughput_phase; | INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, throughput) = throughput_phase; | ||||
| if (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_PASS) { | if (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_PASS) { | ||||
| INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unshadowed_throughput) = throughput; | INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unshadowed_throughput) = throughput; | ||||
| } | } | ||||
| /* Write Lightgroup, +1 as lightgroup is int but we need to encode into a uint8_t. */ | /* Write Lightgroup, +1 as lightgroup is int but we need to encode into a uint8_t. */ | ||||
| INTEGRATOR_STATE_WRITE( | INTEGRATOR_STATE_WRITE( | ||||
| shadow_state, shadow_path, lightgroup) = (ls->type != LIGHT_BACKGROUND) ? | shadow_state, shadow_path, lightgroup) = (ls.type != LIGHT_BACKGROUND) ? | ||||
| ls->group + 1 : | ls.group + 1 : | ||||
| kernel_data.background.lightgroup + 1; | kernel_data.background.lightgroup + 1; | ||||
| # ifdef __PATH_GUIDING__ | # ifdef __PATH_GUIDING__ | ||||
| INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unlit_throughput) = unlit_throughput; | INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unlit_throughput) = unlit_throughput; | ||||
| INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, path_segment) = INTEGRATOR_STATE( | INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, path_segment) = INTEGRATOR_STATE( | ||||
| state, guiding, path_segment); | state, guiding, path_segment); | ||||
| # endif | # endif | ||||
| ▲ Show 20 Lines • Show All 113 Lines • ▼ Show 20 Lines | ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg, | ||||
| /* Load random number state. */ | /* Load random number state. */ | ||||
| RNGState rng_state; | RNGState rng_state; | ||||
| path_state_rng_load(state, &rng_state); | path_state_rng_load(state, &rng_state); | ||||
| /* Sample light ahead of volume stepping, for equiangular sampling. */ | /* Sample light ahead of volume stepping, for equiangular sampling. */ | ||||
| /* TODO: distant lights are ignored now, but could instead use even distribution. */ | /* TODO: distant lights are ignored now, but could instead use even distribution. */ | ||||
| LightSample ls ccl_optional_struct_init; | LightSample ls ccl_optional_struct_init; | ||||
| const bool need_light_sample = !(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_TERMINATE); | const bool need_light_sample = !(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_TERMINATE); | ||||
| float3 equiangular_P = zero_float3(); | |||||
| const bool have_equiangular_sample = need_light_sample && | const bool have_equiangular_sample = need_light_sample && | ||||
| integrate_volume_sample_light( | integrate_volume_equiangular_sample_light( | ||||
| kg, state, ray, &sd, &rng_state, &ls) && | kg, state, ray, &sd, &rng_state, &equiangular_P); | ||||
| (ls.t != FLT_MAX); | |||||
| VolumeSampleMethod direct_sample_method = (have_equiangular_sample) ? | VolumeSampleMethod direct_sample_method = (have_equiangular_sample) ? | ||||
| volume_stack_sample_method(kg, state) : | volume_stack_sample_method(kg, state) : | ||||
| VOLUME_SAMPLE_DISTANCE; | VOLUME_SAMPLE_DISTANCE; | ||||
| /* Step through volume. */ | /* Step through volume. */ | ||||
| VOLUME_READ_LAMBDA(integrator_state_read_volume_stack(state, i)) | VOLUME_READ_LAMBDA(integrator_state_read_volume_stack(state, i)) | ||||
| const float step_size = volume_stack_step_size(kg, volume_read_lambda_pass); | const float step_size = volume_stack_step_size(kg, volume_read_lambda_pass); | ||||
| Show All 13 Lines | # endif | ||||
| volume_integrate_heterogeneous(kg, | volume_integrate_heterogeneous(kg, | ||||
| state, | state, | ||||
| ray, | ray, | ||||
| &sd, | &sd, | ||||
| &rng_state, | &rng_state, | ||||
| render_buffer, | render_buffer, | ||||
| step_size, | step_size, | ||||
| direct_sample_method, | direct_sample_method, | ||||
| ls.P, | equiangular_P, | ||||
| result); | result); | ||||
| /* Perform path termination. The intersect_closest will have already marked this path | /* Perform path termination. The intersect_closest will have already marked this path | ||||
| * to be terminated. That will shading evaluating to leave out any scattering closures, | * to be terminated. That will shading evaluating to leave out any scattering closures, | ||||
| * but emission and absorption are still handled for multiple importance sampling. */ | * but emission and absorption are still handled for multiple importance sampling. */ | ||||
| const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); | const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); | ||||
| const float continuation_probability = (path_flag & PATH_RAY_TERMINATE_IN_NEXT_VOLUME) ? | const float continuation_probability = (path_flag & PATH_RAY_TERMINATE_IN_NEXT_VOLUME) ? | ||||
| 0.0f : | 0.0f : | ||||
| ▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | integrate_volume_direct_light(kg, | ||||
| state, | state, | ||||
| &sd, | &sd, | ||||
| &rng_state, | &rng_state, | ||||
| direct_P, | direct_P, | ||||
| &result.direct_phases, | &result.direct_phases, | ||||
| # ifdef __PATH_GUIDING__ | # ifdef __PATH_GUIDING__ | ||||
| unlit_throughput, | unlit_throughput, | ||||
| # endif | # endif | ||||
| result.direct_throughput, | result.direct_throughput); | ||||
| &ls); | |||||
| } | } | ||||
| /* Indirect light. | /* Indirect light. | ||||
| * | * | ||||
| * Only divide throughput by continuation_probability if we scatter. For the attenuation | * Only divide throughput by continuation_probability if we scatter. For the attenuation | ||||
| * case the next surface will already do this division. */ | * case the next surface will already do this division. */ | ||||
| if (result.indirect_scatter) { | if (result.indirect_scatter) { | ||||
| # if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1 | # if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1 | ||||
| ▲ Show 20 Lines • Show All 95 Lines • Show Last 20 Lines | |||||