27typedef enum VolumeIntegrateEvent {
28 VOLUME_PATH_SCATTERED = 0,
29 VOLUME_PATH_ATTENUATED = 1,
30 VOLUME_PATH_MISSED = 2
31} VolumeIntegrateEvent;
33typedef struct VolumeIntegrateResult {
39# ifdef __PATH_GUIDING__
40 VolumeSampleMethod direct_sample_method;
44 bool indirect_scatter;
48} VolumeIntegrateResult;
54# define VOLUME_THROUGHPUT_EPSILON 1e-6f
61typedef struct VolumeShaderCoefficients {
65} VolumeShaderCoefficients;
67typedef struct EquiangularCoefficients {
70} EquiangularCoefficients;
85 *extinction = sd->closure_transparent_extinction;
97 volume_shader_eval<false>(kg,
state, sd, path_flag, volume_read_lambda_pass);
104 coeff->sigma_t = (sd->flag &
SD_EXTINCTION) ? sd->closure_transparent_extinction :
109 for (
int i = 0; i < sd->num_closure; i++) {
113 coeff->sigma_s += sc->weight;
123 const float object_step_size,
131 if (object_step_size ==
FLT_MAX) {
133 *step_size = tmax - tmin;
134 *step_shade_offset = 0.0f;
135 *steps_offset = 1.0f;
140 *max_steps =
kernel_data.integrator.volume_max_steps;
141 const float t = tmax - tmin;
142 float step =
min(object_step_size, t);
145 if (t > *max_steps * step) {
176 if (shadow_volume_shader_sample(kg,
state, sd, &sigma_t)) {
189 const float object_step_size)
202 float step_size, step_shade_offset, unused;
212 const float steps_offset = 1.0f;
219 for (
int i = 0; i < max_steps; i++) {
221 float new_t =
min(ray->tmax, ray->tmin + (i + steps_offset) * step_size);
222 float dt = new_t - t;
224 float3 new_P = ray->P + ray->D * (t + dt * step_shade_offset);
229 if (shadow_volume_shader_sample(kg,
state, sd, &sigma_t)) {
233 sum += (-sigma_t * dt);
234 if ((i & 0x07) == 0) {
235 tp = *throughput *
exp(
sum);
246 if (t == ray->tmax) {
248 tp = *throughput *
exp(
sum);
263# define VOLUME_SAMPLE_PDF_CUTOFF 1e-8f
270 const float delta =
dot((coeffs.P - ray->P), ray->D);
276 const float tmin = coeffs.t_range.x;
277 const float tmax = coeffs.t_range.y;
278 const float theta_a =
atan2f(tmin - delta, D);
279 const float theta_b =
atan2f(tmax - delta, D);
280 const float t_ = D *
tanf((xi * theta_b) + (1 - xi) * theta_a);
285 *pdf = D / ((theta_b - theta_a) * (D * D + t_ * t_));
287 return clamp(delta + t_, tmin, tmax);
292 const float sample_t)
294 const float delta =
dot((coeffs.P - ray->P), ray->D);
300 const float tmin = coeffs.t_range.x;
301 const float tmax = coeffs.t_range.y;
302 const float t_ = sample_t - delta;
304 const float theta_a =
atan2f(tmin - delta, D);
305 const float theta_b =
atan2f(tmax - delta, D);
310 const float pdf = D / ((theta_b - theta_a) * (D * D + t_ * t_));
340ccl_device float volume_distance_sample(
float max_t,
353 float sample_t =
min(max_t, -
logf(1.0f - xi * (1.0f - sample_transmittance)) / sample_sigma_t);
384 Spectrum emission = coeff->emission;
405typedef struct VolumeIntegrateState {
412 bool absorption_only;
419 VolumeSampleMethod direct_sample_method;
422 float equiangular_pdf;
423} VolumeIntegrateState;
428 ccl_private const EquiangularCoefficients &equiangular_coeffs,
439 albedo, result.indirect_throughput, &vstate.rchannel, &channel_pdf);
442 if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR && !result.direct_scatter) {
443 if (result.direct_t >= vstate.tmin && result.direct_t <= vstate.tmax &&
444 vstate.equiangular_pdf > VOLUME_SAMPLE_PDF_CUTOFF)
446 const float new_dt = result.direct_t - vstate.tmin;
449 result.direct_scatter =
true;
450 result.direct_throughput *= coeff.sigma_s * new_transmittance / vstate.equiangular_pdf;
451 volume_shader_copy_phases(&result.direct_phases, sd);
454 if (vstate.use_mis) {
455 const float distance_pdf = vstate.distance_pdf *
456 dot(channel_pdf, coeff.sigma_t * new_transmittance);
457 const float mis_weight = 2.0f *
power_heuristic(vstate.equiangular_pdf, distance_pdf);
458 result.direct_throughput *= mis_weight;
462 result.direct_throughput *= transmittance;
463 vstate.distance_pdf *=
dot(channel_pdf, transmittance);
468 if (!result.indirect_scatter) {
472 if (1.0f - vstate.rscatter >= sample_transmittance) {
475 const float new_dt = -
logf(1.0f - vstate.rscatter) / sample_sigma_t;
476 const float new_t = vstate.tmin + new_dt;
480 const float distance_pdf =
dot(channel_pdf, coeff.sigma_t * new_transmittance);
482 if (vstate.distance_pdf * distance_pdf > VOLUME_SAMPLE_PDF_CUTOFF) {
484 result.indirect_scatter =
true;
485 result.indirect_t = new_t;
486 result.indirect_throughput *= coeff.sigma_s * new_transmittance / distance_pdf;
487 volume_shader_copy_phases(&result.indirect_phases, sd);
489 if (vstate.direct_sample_method != VOLUME_SAMPLE_EQUIANGULAR) {
492 result.direct_scatter =
true;
493 result.direct_t = result.indirect_t;
494 result.direct_throughput = result.indirect_throughput;
495 volume_shader_copy_phases(&result.direct_phases, sd);
498 if (vstate.use_mis) {
499 const float equiangular_pdf = volume_equiangular_pdf(ray, equiangular_coeffs, new_t);
500 const float mis_weight =
power_heuristic(vstate.distance_pdf * distance_pdf,
502 result.direct_throughput *= 2.0f * mis_weight;
509 const float pdf =
dot(channel_pdf, transmittance);
510 result.indirect_throughput *= transmittance / pdf;
511 if (vstate.direct_sample_method != VOLUME_SAMPLE_EQUIANGULAR) {
512 vstate.distance_pdf *= pdf;
516 vstate.rscatter = 1.0f - (1.0f - vstate.rscatter) / sample_transmittance;
532 const float object_step_size,
533 const VolumeSampleMethod direct_sample_method,
534 ccl_private const EquiangularCoefficients &equiangular_coeffs,
542 float step_size, step_shade_offset, steps_offset;
555 vstate.tmin = ray->tmin;
556 vstate.tmax = ray->tmin;
557 vstate.absorption_only =
true;
562 vstate.direct_sample_method = direct_sample_method;
563 vstate.use_mis = (direct_sample_method == VOLUME_SAMPLE_MIS);
564 if (vstate.use_mis) {
565 if (vstate.rscatter < 0.5f) {
566 vstate.rscatter *= 2.0f;
567 vstate.direct_sample_method = VOLUME_SAMPLE_DISTANCE;
570 vstate.rscatter = (vstate.rscatter - 0.5f) * 2.0f;
571 vstate.direct_sample_method = VOLUME_SAMPLE_EQUIANGULAR;
574 vstate.equiangular_pdf = 0.0f;
575 vstate.distance_pdf = 1.0f;
579 result.direct_throughput = throughput;
580 result.indirect_throughput = throughput;
583 if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR) {
584 result.direct_t = volume_equiangular_sample(
585 ray, equiangular_coeffs, vstate.rscatter, &vstate.equiangular_pdf);
587# ifdef __PATH_GUIDING__
588 result.direct_sample_method = vstate.direct_sample_method;
591# ifdef __DENOISING_FEATURES__
598 for (
int i = 0; i < max_steps; i++) {
600 vstate.tmax =
min(ray->tmax, ray->tmin + (i + steps_offset) * step_size);
601 const float shade_t = vstate.tmin + (vstate.tmax - vstate.tmin) * step_shade_offset;
602 sd->P = ray->P + ray->D * shade_t;
606 if (volume_shader_sample(kg,
state, sd, &coeff)) {
607 const int closure_flag = sd->flag;
610 const float dt = (vstate.tmax - vstate.tmin);
619 if (!result.indirect_scatter) {
620 const Spectrum emission = volume_emission_integrate(
621 &coeff, closure_flag, transmittance, dt);
622 accum_emission += result.indirect_throughput * emission;
628 if ((closure_flag &
SD_SCATTER) || !vstate.absorption_only) {
629# ifdef __DENOISING_FEATURES__
631 if (write_denoising_features && (closure_flag &
SD_SCATTER)) {
633 accum_albedo += result.indirect_throughput * albedo * (
one_spectrum() - transmittance);
638 volume_integrate_step_scattering(
639 sd, ray, equiangular_coeffs, coeff, transmittance, vstate, result);
643 result.indirect_throughput *= transmittance;
644 result.direct_throughput *= transmittance;
648 if (!result.indirect_scatter) {
654 else if (!result.direct_scatter) {
662 if (result.direct_scatter && result.indirect_scatter) {
668 vstate.tmin = vstate.tmax;
669 if (vstate.tmin == ray->tmax) {
675 if (!
is_zero(accum_emission)) {
682# ifdef __DENOISING_FEATURES__
684 if (write_denoising_features) {
685 film_write_denoising_features_volume(
716 ray->tmax - ray->tmin,
737 equiangular_coeffs->P = ls.P;
739 return volume_equiangular_valid_ray_segment(
740 kg, ray->P, ray->D, &equiangular_coeffs->t_range, &ls);
752# ifdef __PATH_GUIDING__
774 kg, rand_light, sd->time,
P,
N, object_receiver, shader_flags, bounce, path_flag, &ls))
799 float phase_pdf = volume_shader_phase_eval(kg,
state, sd, phases, ls.D, &phase_eval, ls.shader);
801 bsdf_eval_mul(&phase_eval, light_eval / ls.pdf * mis_weight);
848 state, path, render_pixel_index);
850 state, path, rng_offset);
852 state, path, rng_pixel);
859 state, path, diffuse_bounce);
861 state, path, glossy_bounce);
863 state, path, transmission_bounce);
869# ifdef __PATH_GUIDING__
872 state, guiding, path_segment);
876 integrator_state_copy_volume_stack_to_shadow(kg, shadow_state,
state);
895 float phase_pdf = 0.0f, unguided_phase_pdf = 0.0f;
898 float sampled_roughness = 1.0f;
901# if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
903 label = volume_shader_phase_guided_sample(kg,
923 label = volume_shader_phase_sample(
924 kg, sd, phases, svc, rand_phase, &phase_eval, &phase_wo, &phase_pdf, &sampled_roughness);
930 unguided_phase_pdf = phase_pdf;
937# ifdef __LIGHT_TREE__
943# ifdef __RAY_DIFFERENTIALS__
954 kg,
state, sd, phase_weight, phase_pdf,
normalize(phase_wo), sampled_roughness);
958 const Spectrum throughput_phase = throughput * phase_weight;
970 const float3 previous_P = ray->P + ray->D * ray->tmin;
975# ifdef __LIGHT_LINKING__
1010 const bool have_equiangular_sample =
1011 need_light_sample && integrate_volume_equiangular_sample_light(
1012 kg,
state, ray, &sd, &rng_state, &equiangular_coeffs, ls);
1014 VolumeSampleMethod direct_sample_method = (have_equiangular_sample) ?
1015 volume_stack_sample_method(kg,
state) :
1016 VOLUME_SAMPLE_DISTANCE;
1020 const float step_size = volume_stack_step_size(kg, volume_read_lambda_pass);
1022# if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
1026 float3 unlit_throughput = initial_throughput;
1028 bool guiding_generated_new_segment =
false;
1029 float rand_phase_guiding = 0.5f;
1033 VolumeIntegrateResult result = {};
1034 volume_integrate_heterogeneous(kg,
1041 direct_sample_method,
1052 state, path, continuation_probability);
1053 if (continuation_probability == 0.0f) {
1054 return VOLUME_PATH_MISSED;
1058 if (result.direct_scatter) {
1059 const float3 direct_P = ray->P + result.direct_t * ray->D;
1061# ifdef __PATH_GUIDING__
1063# if PATH_GUIDING_LEVEL >= 1
1064 if (result.direct_sample_method == VOLUME_SAMPLE_DISTANCE) {
1072 guiding_generated_new_segment =
true;
1073 unlit_throughput = result.indirect_throughput / continuation_probability;
1083 if (
state->guiding.path_segment) {
1084 pgl_vec3f scatteringWeight =
state->guiding.path_segment->scatteringWeight;
1085 scatterEval =
make_float3(scatteringWeight.x, scatteringWeight.y, scatteringWeight.z);
1087 unlit_throughput /= scatterEval;
1088 unlit_throughput *= continuation_probability;
1093# if PATH_GUIDING_LEVEL >= 4
1094 volume_shader_prepare_guiding(
1095 kg,
state, &sd, rand_phase_guiding, direct_P, ray->D, &result.direct_phases);
1100 result.direct_throughput /= continuation_probability;
1101 integrate_volume_direct_light(kg,
1106 &result.direct_phases,
1107# ifdef __PATH_GUIDING__
1110 result.direct_throughput,
1118 if (result.indirect_scatter) {
1119# if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
1120 if (!guiding_generated_new_segment) {
1126 result.indirect_throughput /= continuation_probability;
1130 if (result.indirect_scatter) {
1131 sd.P = ray->P + result.indirect_t * ray->D;
1133# if defined(__PATH_GUIDING__)
1134# if PATH_GUIDING_LEVEL >= 1
1135 if (!guiding_generated_new_segment) {
1139# if PATH_GUIDING_LEVEL >= 4
1142 if (result.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR) {
1144 volume_shader_prepare_guiding(
1145 kg,
state, &sd, rand_phase_guiding, sd.P, ray->D, &result.indirect_phases);
1150 if (integrate_volume_phase_scatter(kg,
state, &sd, ray, &rng_state, &result.indirect_phases)) {
1151 return VOLUME_PATH_SCATTERED;
1154 return VOLUME_PATH_MISSED;
1158# if defined(__PATH_GUIDING__)
1160 state->guiding.use_volume_guiding =
false;
1162 return VOLUME_PATH_ATTENUATED;
1187 volume_stack_clean(kg,
state);
1191 if (event == VOLUME_PATH_MISSED) {
1197 if (event == VOLUME_PATH_ATTENUATED) {
1204# ifdef __SHADOW_LINKING__
1205 if (shadow_linking_schedule_intersection_kernel<DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME>(kg,
MINLINE float safe_sqrtf(float a)
ccl_device_inline bool area_light_valid_ray_segment(const ccl_global KernelAreaLight *light, float3 P, float3 D, ccl_private float2 *t_range)
static T sum(const btAlignedObjectArray< T > &items)
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
ccl_device_inline bool light_sample_terminate(KernelGlobals kg, ccl_private BsdfEval *ccl_restrict eval, const float rand_terminate)
CCL_NAMESPACE_BEGIN ccl_device_noinline_cpu Spectrum light_sample_shader_eval(KernelGlobals kg, IntegratorState state, ccl_private ShaderData *ccl_restrict emission_sd, ccl_private LightSample *ccl_restrict ls, float time)
ccl_device_inline float light_sample_mis_weight_nee(KernelGlobals kg, const float nee_pdf, const float forward_pdf)
ccl_device_inline void light_sample_to_volume_shadow_ray(KernelGlobals kg, ccl_private const ShaderData *ccl_restrict sd, ccl_private const LightSample *ccl_restrict ls, const float3 P, ccl_private Ray *ray)
ccl_device_inline bool light_sample_from_volume_segment(KernelGlobals kg, const float3 rand, const float time, const float3 P, const float3 D, const float t, const int object_receiver, const int bounce, const uint32_t path_flag, ccl_private LightSample *ls)
#define kernel_assert(cond)
const KernelGlobalsCPU *ccl_restrict KernelGlobals
#define kernel_data_fetch(name, index)
#define ccl_device_forceinline
#define ccl_optional_struct_init
#define ccl_device_inline
#define CCL_NAMESPACE_END
ccl_device_forceinline float differential_make_compact(const float dD)
draw_view in_light_buf[] float
ccl_device_forceinline void integrator_intersect_next_kernel_after_volume(KernelGlobals kg, IntegratorState state, ccl_private const Intersection *ccl_restrict isect, ccl_global float *ccl_restrict render_buffer)
#define VOLUME_THROUGHPUT_EPSILON
ccl_device int volume_sample_channel(Spectrum albedo, Spectrum throughput, ccl_private float *rand, ccl_private Spectrum *pdf)
ccl_device float volume_channel_get(Spectrum value, int channel)
ccl_device Spectrum volume_color_transmittance(Spectrum sigma, float t)
ccl_gpu_kernel_postfix ccl_global KernelWorkTile const int ccl_global float * render_buffer
ccl_device_inline int object_lightgroup(KernelGlobals kg, int object)
ccl_device_forceinline void guiding_record_volume_segment(KernelGlobals kg, IntegratorState state, const float3 P, const float3 I)
ccl_device_forceinline void guiding_record_volume_bounce(KernelGlobals kg, IntegratorState state, ccl_private const ShaderData *sd, const Spectrum weight, const float pdf, const float3 wo, const float roughness)
ccl_device_forceinline void guiding_record_volume_emission(KernelGlobals kg, IntegratorState state, const Spectrum Le)
ccl_device_forceinline void guiding_record_volume_transmission(KernelGlobals kg, IntegratorState state, const float3 transmittance_weight)
ccl_device_inline bool light_link_object_match(KernelGlobals kg, const int object_receiver, const int object_emitter)
ccl_device_inline bool light_sample(KernelGlobals kg, const int lamp, const float2 rand, const float3 P, const float3 N, const int shader_flags, const uint32_t path_flag, ccl_private LightSample *ls)
ccl_device_inline int light_link_receiver_nee(KernelGlobals kg, const ccl_private ShaderData *sd)
ccl_device_inline int light_link_receiver_forward(KernelGlobals kg, IntegratorState state)
#define CLOSURE_IS_VOLUME(type)
@ SD_BSDF_HAS_TRANSMISSION
#define AS_SHADER_DATA(shader_data_tiny_storage)
@ PRNG_VOLUME_SHADE_OFFSET
@ PRNG_VOLUME_PHASE_GUIDING_DISTANCE
@ PRNG_VOLUME_PHASE_GUIDING_EQUIANGULAR
@ PRNG_VOLUME_COLOR_CHANNEL
@ PRNG_VOLUME_SCATTER_DISTANCE
@ PATH_RAY_TERMINATE_IN_NEXT_VOLUME
@ PATH_RAY_DENOISING_FEATURES
#define KERNEL_FEATURE_LIGHT_PASSES
#define KERNEL_FEATURE_LIGHT_LINKING
@ DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME
@ DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW
@ DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST
ccl_device_inline float3 spectrum_to_rgb(Spectrum s)
#define PROFILING_INIT(kg, event)
ccl_device_inline bool triangle_light_valid_ray_segment(KernelGlobals kg, const float3 P, const float3 D, ccl_private float2 *t_range, const ccl_private LightSample *ls)
ccl_device_inline Spectrum bsdf_eval_sum(ccl_private const BsdfEval *eval)
ccl_device_inline void bsdf_eval_mul(ccl_private BsdfEval *eval, float value)
ccl_device_inline bool bsdf_eval_is_zero(ccl_private BsdfEval *eval)
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)
ccl_device_inline float len_squared(const float2 a)
ccl_device_inline bool is_zero(const float2 a)
ccl_device_inline float reduce_max(const float2 a)
ccl_device_inline float3 one_float3()
ccl_device_inline float3 exp(float3 v)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
ccl_device float power_heuristic(float a, float b)
T step(const T &edge, const T &value)
ccl_device_inline float3 path_state_rng_3D(KernelGlobals kg, ccl_private const RNGState *rng_state, const int dimension)
ccl_device_inline void shadow_path_state_rng_load(ConstIntegratorShadowState state, ccl_private RNGState *rng_state)
ccl_device_inline float path_state_rng_1D(KernelGlobals kg, ccl_private const RNGState *rng_state, const int dimension)
ccl_device_inline float path_state_rng_light_termination(KernelGlobals kg, ccl_private const RNGState *state)
ccl_device_inline float2 path_state_rng_2D(KernelGlobals kg, ccl_private const RNGState *rng_state, const int dimension)
ccl_device_inline void path_state_rng_load(ConstIntegratorState state, ccl_private RNGState *rng_state)
ccl_device_inline void path_state_next(KernelGlobals kg, IntegratorState state, const int label, const int shader_flag)
CCL_NAMESPACE_BEGIN ccl_device void integrator_shade_volume(KernelGlobals kg, IntegratorState state, ccl_global float *ccl_restrict render_buffer)
ccl_device_inline bool spot_light_valid_ray_segment(const ccl_global KernelLight *klight, const float3 P, const float3 D, ccl_private float2 *t_range)
IntegratorStateCPU *ccl_restrict IntegratorState
#define INTEGRATOR_STATE_WRITE(state, nested_struct, member)
#define INTEGRATOR_STATE(state, nested_struct, member)
IntegratorShadowStateCPU *ccl_restrict IntegratorShadowState
#define INTEGRATOR_STATE_ARRAY(state, nested_struct, array_index, member)
ccl_device_forceinline void integrator_path_terminate(KernelGlobals kg, IntegratorState state, const DeviceKernel current_kernel)
ccl_device_forceinline void integrator_path_next(KernelGlobals kg, IntegratorState state, const DeviceKernel current_kernel, const DeviceKernel next_kernel)
ccl_device_forceinline IntegratorShadowState integrator_shadow_path_init(KernelGlobals kg, IntegratorState state, const DeviceKernel next_kernel, const bool is_ao)
ccl_device_forceinline void integrator_state_read_ray(ConstIntegratorState state, ccl_private Ray *ccl_restrict ray)
ccl_device_forceinline void integrator_state_read_isect(ConstIntegratorState state, ccl_private Intersection *ccl_restrict isect)
ccl_device_forceinline void integrator_state_write_shadow_ray_self(KernelGlobals kg, IntegratorShadowState state, ccl_private const Ray *ccl_restrict ray)
ccl_device_forceinline void integrator_state_write_shadow_ray(IntegratorShadowState state, ccl_private const Ray *ccl_restrict ray)
PACKED_SPECTRUM_DATA_TYPE PackedSpectrum
#define FOREACH_SPECTRUM_CHANNEL(counter)
#define GET_SPECTRUM_CHANNEL(v, i)
SPECTRUM_DATA_TYPE Spectrum
ccl_device_inline Spectrum safe_divide_color(Spectrum a, Spectrum b)
ccl_device_inline int clamp(int a, int mn, int mx)
@ PROFILING_SHADE_VOLUME_INTEGRATE
@ PROFILING_SHADE_VOLUME_SETUP
@ PROFILING_SHADE_VOLUME_DIRECT_LIGHT
@ PROFILING_SHADE_VOLUME_INDIRECT_LIGHT