32enum VolumeIntegrateEvent {
33 VOLUME_PATH_SCATTERED = 0,
34 VOLUME_PATH_ATTENUATED = 1,
35 VOLUME_PATH_MISSED = 2
38struct VolumeIntegrateResult {
43 ShaderVolumePhases direct_phases;
44# if defined(__PATH_GUIDING__)
45 VolumeSampleMethod direct_sample_method;
49 bool indirect_scatter;
52 ShaderVolumePhases indirect_phases;
59# define OVERLAP_EXP 5e-4f
61# define VOLUME_MAX_STEPS 1024
63# define MANTISSA_BITS 23
70struct VolumeShaderCoefficients {
76struct EquiangularCoefficients {
78 Interval<float> t_range;
82template<const
bool shadow,
typename IntegratorGenericState>
84 const IntegratorGenericState
state,
93 volume_shader_eval<shadow>(kg,
state, sd, path_flag);
105 volume_shader_eval<false>(kg,
state, sd, path_flag);
112 coeff->sigma_t = (sd->flag &
SD_EXTINCTION) ? sd->closure_transparent_extinction :
117 for (
int i = 0;
i < sd->num_closure;
i++) {
121 coeff->sigma_s += sc->weight;
146struct OctreeTracing {
148 ccl_global const KernelOctreeNode *node =
nullptr;
174 bool no_overlap =
false;
177 Extrema<float> sigma = 0.0f;
185 enum Dimension { DIM_X = 1U << 0
U, DIM_Y = 1U << 1U, DIM_Z = 1U << 2U };
201 float3 local_P = (
P +
D * t.
min) * scale + translation;
206 const auto positive = ray_D > 0.0f;
207 octant_mask = (!!positive.x * DIM_X) | (!!positive.y * DIM_Y) | (!!positive.z * DIM_Z);
208 local_P =
select(positive, 3.0f - local_P, local_P);
214 ray_D = -
fabs(ray_D);
217 ray_P = local_P - ray_D * t.
min;
220 return all(local_P > 1.0f);
242 select(t == tmax, bbox_min - half_size, ray_D * tmax + ray_P));
245 const uint diff = (current_P.
x ^ next_P.
x) | (current_P.
y ^ next_P.
y) |
246 (current_P.
z ^ next_P.
z);
256 const float3 bbox_min = floor_pos();
259 float3 intersect_t = (bbox_min - ray_P) / ray_D;
267 find_next_pos(bbox_min, intersect_t, tmax);
269 return fminf(tmax, ray_tmax);
278 return (
x |
y |
z) ^ octant_mask;
285 return knode->first_child == -1;
291 while (!volume_node_is_leaf(octree.node)) {
293 const int child_index = octree.node->first_child + octree.get_octant();
300template<const
bool shadow,
typename IntegratorGenericState>
304 const IntegratorGenericState
state,
306 const uint32_t path_flag,
316# ifdef __KERNEL_HIP__
320 const bool homogeneous = volume_is_homogeneous(kg, entry);
321 const int samples = homogeneous ? 1 : 4;
322 const float shade_offset = homogeneous ?
325 const float step_size = t.length() /
float(samples);
328 sd->num_closure_left = 0;
331 for (
int i = 0;
i < samples;
i++) {
332 const float shade_t = t.min + (shade_offset +
i) * step_size;
333 sd->P = ray->P + ray->D * shade_t;
335 sd->closure_transparent_extinction =
zero_float3();
338 volume_shader_eval_entry<shadow, KERNEL_FEATURE_NODE_MASK_VOLUME>(
339 kg,
state, sd, entry, path_flag);
341 const float sigma =
reduce_max(sd->closure_transparent_extinction);
342 const float emission =
reduce_max(sd->closure_emission_background);
344 extrema =
merge(extrema,
fmaxf(sigma, emission));
358template<const
bool shadow,
typename IntegratorGenericState>
362 const IntegratorGenericState
state,
365 const uint32_t path_flag)
373# ifdef __KERNEL_HIP__
374 return volume_estimate_extrema<shadow>(kg, ray, sd,
state, rng_state, path_flag, octree);
376 return volume_estimate_extrema<shadow>(
377 kg, ray, sd,
state, rng_state, path_flag, octree.t, octree.entry);
399template<const
bool shadow,
typename IntegratorGenericState>
403 const IntegratorGenericState
state,
405 const uint32_t path_flag,
408 if (global.no_overlap) {
410 return !global.t.is_empty();
430 OctreeTracing local(global.t.min);
435 float3 local_P = ray->P, local_D = ray->D;
443 if (local.to_octree_space(local_P, local_D, kroot->scale, kroot->translation)) {
444 volume_voxel_get(kg, local);
445 local.t.max = local.ray_voxel_intersect(ray->tmax);
450 local.t.max = ray->tmax;
453 global.sigma += volume_object_get_extrema<shadow>(
454 kg, ray, sd,
state, local, rng_state, path_flag);
455 if (local.t.max <= global.t.max) {
457 local.sigma = global.sigma;
463 global.no_overlap =
true;
466 return global.node && !global.t.is_empty();
470template<const
bool shadow,
typename IntegratorGenericState>
474 const IntegratorGenericState
state,
476 const uint32_t path_flag,
479 if (octree.t.max >= ray->tmax) {
484 if (octree.next_scale > MANTISSA_BITS) {
485 if (
fabsf(octree.t.max - ray->tmax) <= OVERLAP_EXP) {
492 octree.t = {octree.t.max, ray->tmax};
494 volume_find_octree_root(kg, octree.entry)->id);
500 for (; octree.scale < octree.next_scale; octree.scale++) {
506 volume_voxel_get(kg, octree);
509 octree.t.min = octree.t.max;
510 octree.t.max = octree.ray_voxel_intersect(ray->tmax);
513 octree.sigma = volume_object_get_extrema<shadow>(
514 kg, ray, sd,
state, octree, rng_state, path_flag);
515 return volume_octree_setup<shadow>(kg, ray, sd,
state, rng_state, path_flag, octree);
533 const uint32_t path_flag,
540 const float tmin = octree.t.
min;
542 while (octree.t.is_empty() || sigma.
range() * octree.t.length() < 1.0f) {
543 if (!volume_octree_advance<true>(kg, ray, sd,
state, rng_state, path_flag, octree)) {
544 return !octree.t.is_empty();
547 octree.sigma = sigma =
merge(sigma, octree.sigma);
569template<const
bool shadow,
typename IntegratorGenericState>
571 IntegratorGenericState
state,
577 const uint32_t path_flag)
579 constexpr float r = 0.9f;
580 const float ray_length = t.
length();
583 const float expected_steps = sigma_c * ray_length;
585 const int k =
clamp(
int(
roundf(expected_steps)), 1, VOLUME_MAX_STEPS);
594 constexpr int cut_off = 4;
597 const int N = (sigma_c == 0.0f) ?
602 const int samples =
N * k;
605 const float step_size = ray_length /
float(samples);
610 for (
int i = 0;
i < k;
i++) {
611 const float shade_t =
min(t.
max, t.
min + (shade_offset +
i) * step_size);
612 sd->P = ray->P + ray->D * shade_t;
613 tau_k += volume_shader_eval_extinction<shadow>(kg,
state, sd, path_flag);
626 for (
int n = 0; n <
N; n++) {
628 for (
int i = 0;
i < k;
i++) {
629 const int step =
i *
N + n;
630 const float shade_t =
min(t.
max, t.
min + (shade_offset +
step) * step_size);
631 sd->P = ray->P + ray->D * shade_t;
634 volume_shader_eval_extinction<shadow>(kg,
state, sd, path_flag);
637 tau_j[
step % 2] += tau * 2.0f;
650 return T_k + (T_j_1 - T_j) / pmf;
671 OctreeTracing octree(ray->tmin);
673 if (!volume_octree_setup<true>(kg, ray, sd,
state, &rng_state, path_flag, octree)) {
677 while (volume_octree_advance_shadow(kg, ray, sd,
state, &rng_state, path_flag, octree)) {
678 const float sigma = octree.sigma.
range();
679 *throughput *= volume_transmittance<true>(
680 kg,
state, ray, sd, sigma, octree.t, &rng_state, path_flag);
685 octree.t.min = octree.t.max;
696# define VOLUME_SAMPLE_PDF_CUTOFF 1e-8f
703 const float delta =
dot((coeffs.P - ray->P), ray->D);
704 const float D =
len(coeffs.P - ray->P - ray->D * delta);
709 const float tmin = coeffs.t_range.min;
710 const float tmax = coeffs.t_range.max;
712 const float theta_a =
atan2f(tmin - delta,
D);
713 const float theta_b =
atan2f(tmax - delta,
D);
714 const float theta_d = theta_b - theta_a;
718 return mix(tmin, tmax, xi);
721 const float t_ =
D *
tanf((xi * theta_b) + (1 - xi) * theta_a);
722 *pdf =
D / (theta_d * (
D *
D + t_ * t_));
724 return clamp(delta + t_, tmin, tmax);
729 const float sample_t)
731 const float delta =
dot((coeffs.P - ray->P), ray->D);
732 const float D =
len(coeffs.P - ray->P - ray->D * delta);
737 const float tmin = coeffs.t_range.min;
738 const float tmax = coeffs.t_range.max;
740 const float theta_a =
atan2f(tmin - delta,
D);
741 const float theta_b =
atan2f(tmax - delta,
D);
742 const float theta_d = theta_b - theta_a;
747 const float t_ = sample_t - delta;
748 const float pdf =
D / (theta_d * (
D *
D + t_ * t_));
774 return !t_range->is_empty();
780 const int closure_flag,
785 Spectrum emission = coeff->emission;
788 const Spectrum optical_depth = coeff->sigma_t * t;
789 emission *=
select(optical_depth > 1e-5f,
790 (1.0f -
exp(-optical_depth)) / coeff->sigma_t,
792 t * (1.0f - 0.5f * optical_depth));
803struct VolumeIntegrateState {
808 VolumeSampleMethod direct_sample_method;
812 float equiangular_pdf;
832 float majorant_scale;
834 float direct_rr_scale;
838# ifdef __DENOISING_FEATURES__
861 if (vstate.direct_sample_method != VOLUME_SAMPLE_EQUIANGULAR || vstate.use_mis ||
868 if (interval.contains(
result.direct_t)) {
870 t = {interval.min,
result.direct_t};
871 result.direct_scatter =
true;
879 result.direct_throughput *= volume_transmittance<false>(
880 kg,
state, ray, sd, sigma.range(), t, rng_state, path_flag);
887 const bool equiangular,
892 const float sigma_max = octree.sigma.max * vstate.majorant_scale;
893 residual_optical_depth = (octree.t.max - vstate.t) * sigma_max;
894 if (sigma_max == 0.0f) {
899 vstate.t += vstate.dt;
901 const bool segment_has_equiangular = equiangular && octree.t.contains(
result.direct_t);
902 if (segment_has_equiangular && vstate.t >
result.direct_t && !
result.direct_scatter) {
904 result.direct_scatter =
true;
905 result.direct_throughput =
result.indirect_throughput * vstate.transmittance *
906 vstate.direct_rr_scale;
907 vstate.sample_dt =
result.direct_t - vstate.t + vstate.dt;
908 vstate.distance_pdf = vstate.transmittance * sigma_max;
909 vstate.sigma_max = sigma_max;
913 return vstate.t > octree.t.max;
922 const uint32_t path_flag,
927 if (vstate.step++ > VOLUME_MAX_STEPS) {
932 float residual_optical_depth;
934 const bool equiangular = (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR) &&
938 volume_indirect_scatter_advance(octree, equiangular, residual_optical_depth, vstate,
result))
941 if (!volume_octree_advance<false>(kg, ray, sd,
state, rng_state, path_flag, octree)) {
945 vstate.optical_depth += octree.sigma.max * octree.t.length();
946 vstate.t = octree.t.min;
947 volume_equiangular_transmittance(
948 kg,
state, ray, octree.sigma, octree.t, sd, rng_state, vstate,
result);
951 vstate.rscatter =
saturatef(1.0f - (1.0f - vstate.rscatter) *
expf(residual_optical_depth));
973struct VolumeSampleCandidate {
978# ifdef __DENOISING_FEATURES__
986struct VolumeSampleReservoir {
987 float total_weight = 0.0f;
989 VolumeSampleCandidate candidate;
995 const VolumeSampleCandidate new_candidate)
997 if (!(weight > 0.0f)) {
1001 total_weight += weight;
1002 const float thresh = weight / total_weight;
1004 if ((rand <= thresh) || (total_weight == weight)) {
1006 candidate = new_candidate;
1010 rand = (rand - thresh) / (1.0f - thresh);
1020 return total_weight == 0.0f;
1032 const ccl_global float *accumulated_optical_depth = buffer +
1062 const float L_volume = L_transmitted + L_scattered;
1065 if (L_volume == 0.0f) {
1067 vstate.scatter_prob = 0.5f;
1072 vstate.scatter_prob =
fminf(L_scattered / L_volume, 0.9999f);
1075 const float optical_depth = volume_majorant_optical_depth(kg, buffer);
1080 vstate.majorant_scale = (optical_depth == 0.0f) ?
1082 -
fast_logf(1.0f - vstate.scatter_prob) / optical_depth;
1083 if (vstate.majorant_scale < 1.0f) {
1084 vstate.majorant_scale = 1.0f;
1085 vstate.scatter_prob = safe_divide(vstate.scatter_prob, 1.0f - fast_expf(-optical_depth));
1088 vstate.scatter_prob = 1.0f;
1102 if (reservoir.is_empty()) {
1107 (vstate.direct_sample_method == VOLUME_SAMPLE_DISTANCE);
1110 result.indirect_throughput = reservoir.candidate.throughput;
1111 vstate.emission = reservoir.candidate.emission;
1112# ifdef __DENOISING_FEATURES__
1113 vstate.albedo = reservoir.candidate.albedo;
1115 result.indirect_t = reservoir.candidate.t;
1117 if (sample_distance) {
1120 result.direct_scatter =
true;
1123 if (vstate.use_mis) {
1124 vstate.distance_pdf = reservoir.candidate.distance_pdf;
1130 const uint lcg_state = reservoir.candidate.lcg_state;
1132 if (sample_distance) {
1134 result.direct_throughput = reservoir.candidate.throughput * reservoir.total_weight;
1135 vstate.distance_pdf = reservoir.candidate.distance_pdf;
1139 vstate.emission =
mix(vstate.emission, reservoir.candidate.emission, reservoir.total_weight);
1140# ifdef __DENOISING_FEATURES__
1141 vstate.albedo =
mix(vstate.albedo, reservoir.candidate.albedo, reservoir.total_weight);
1144 const float unguided_scatter_prob = reservoir.total_weight;
1145 float guided_scatter_prob;
1148 guided_scatter_prob = 1.0f;
1152 const float alpha = 0.75f;
1153 reservoir.total_weight =
mix(reservoir.total_weight, vstate.scatter_prob, alpha);
1154 guided_scatter_prob = reservoir.total_weight;
1157 reservoir.add_sample(
1158 1.0f - guided_scatter_prob,
1160 { vstate.emission, reservoir.candidate.t,
result.indirect_throughput, 0.0f, vstate.albedo }
1162 {vstate.emission, reservoir.candidate.t,
result.indirect_throughput, 0.0f}
1167 const bool scatter = (reservoir.candidate.distance_pdf > 0.0f);
1168 const float scale =
scatter ? unguided_scatter_prob / guided_scatter_prob :
1169 (1.0f - unguided_scatter_prob) / (1.0f - guided_scatter_prob);
1170 result.indirect_throughput = reservoir.candidate.throughput *
scale;
1172 if (!
scatter && !sample_distance) {
1178 sd->P = ray->P + ray->D * reservoir.candidate.t;
1179 sd->lcg_state = lcg_state;
1181 if (!volume_shader_sample(kg,
state, sd, &coeff)) {
1187 if (sample_distance) {
1189 result.direct_scatter =
true;
1190 result.direct_t = reservoir.candidate.t;
1191 volume_shader_copy_phases(&
result.direct_phases, sd);
1196 result.indirect_scatter =
true;
1197 result.indirect_t = reservoir.candidate.t;
1198 volume_shader_copy_phases(&
result.indirect_phases, sd);
1212 return (
result.direct_scatter &&
result.indirect_scatter);
1224 if (
result.direct_scatter &&
result.indirect_scatter) {
1229 if (thresh > 0.05f) {
1235 const bool equiangular = (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR) &&
1236 vstate.use_mis && !
result.direct_scatter;
1238 const bool has_scatter_samples = !reservoir.is_empty() && !equiangular;
1243 if (absorption_only || has_scatter_samples) {
1244 if (reservoir.rand > thresh) {
1246 if (equiangular || (vstate.direct_sample_method == VOLUME_SAMPLE_DISTANCE)) {
1253 reservoir.rand =
saturatef(reservoir.rand / thresh);
1254 result.indirect_throughput /= thresh;
1259 if (reservoir.rand > thresh) {
1260 result.direct_scatter =
true;
1262 reservoir.rand = (reservoir.rand - thresh) / (1.0f - thresh);
1265 reservoir.rand /= thresh;
1266 vstate.direct_rr_scale /= thresh;
1268 reservoir.rand =
saturatef(reservoir.rand);
1282 const float sigma_max,
1291 const ccl_private VolumeShaderCoefficients &coeff,
1297 const Spectrum sigma_c = coeff.sigma_s + sigma_n;
1310 return dot(coeff.sigma_s / sigma_c, channel_pdf);
1315 const float sigma_max,
1321 const uint lcg_state,
1324 const float weight = vstate.transmittance * prob_s;
1325 const Spectrum throughput =
result.indirect_throughput * sigma_s / prob_s;
1329 reservoir.add_sample(
1332 {vstate.emission, vstate.t, throughput, weight * sigma_max, vstate.albedo, lcg_state}
1334 weight, {vstate.emission, vstate.t, throughput, weight * sigma_max, lcg_state}
1338 else if (!
result.indirect_scatter) {
1341 if (reservoir.rand <= prob_s) {
1343 reservoir.rand /= prob_s;
1346 result.indirect_scatter =
true;
1347 volume_shader_copy_phases(&
result.indirect_phases, sd);
1348 reservoir.add_sample(
1351 {vstate.emission, vstate.t, throughput, weight * sigma_max, vstate.albedo, lcg_state}
1353 weight, {vstate.emission, vstate.t, throughput, weight * sigma_max, lcg_state}
1357 if (vstate.direct_sample_method == VOLUME_SAMPLE_DISTANCE) {
1358 result.direct_scatter =
true;
1359 volume_shader_copy_phases(&
result.direct_phases, sd);
1364 reservoir.rand = (reservoir.rand - prob_s) / (1.0f - prob_s);
1366 reservoir.rand =
saturatef(reservoir.rand);
1386ccl_device void volume_integrate_step_scattering(
1390 const float sigma_max,
1396 if (volume_russian_roulette_termination(
state, reservoir,
result, vstate)) {
1400 sd->P = ray->P + ray->D * vstate.t;
1402 const uint lcg_state = sd->lcg_state;
1403 if (!volume_shader_sample(kg,
state, sd, &coeff)) {
1411 const Spectrum sigma_n = volume_null_event_coefficients(coeff.sigma_t, sigma_max, majorant);
1412 if (majorant != sigma_max) {
1424 result.indirect_throughput *=
expf((sigma_max - majorant) * vstate.dt) / sigma_max;
1427 result.indirect_throughput /= majorant;
1433 vstate.emission +=
result.indirect_throughput * coeff.emission;
1434 if (!
result.indirect_scatter) {
1443 result.indirect_throughput *= sigma_n;
1447# ifdef __DENOISING_FEATURES__
1450 vstate.albedo +=
result.indirect_throughput * coeff.sigma_s;
1455 const float prob_s = volume_scatter_probability(coeff, sigma_n,
result.indirect_throughput);
1456 volume_sample_indirect_scatter(
1457 sigma_max, prob_s, coeff.sigma_s, sd, vstate,
result, lcg_state, reservoir);
1460 const float prob_n = 1.0f - prob_s;
1462 vstate.transmittance *= prob_n;
1474 if (vstate.direct_sample_method != VOLUME_SAMPLE_EQUIANGULAR || !
result.direct_scatter) {
1478 sd->P = ray->P + ray->D *
result.direct_t;
1480 if (volume_shader_sample(kg,
state, sd, &coeff) && (sd->flag &
SD_SCATTER)) {
1481 volume_shader_copy_phases(&
result.direct_phases, sd);
1483 if (vstate.use_mis) {
1486 const Spectrum sigma_n = volume_null_event_coefficients(
1487 coeff.sigma_t, vstate.sigma_max, majorant);
1488 if ((vstate.sample_dt !=
FLT_MAX) && (majorant != vstate.sigma_max)) {
1489 result.direct_throughput *=
expf((vstate.sigma_max - majorant) * vstate.sample_dt);
1491 vstate.distance_pdf *= volume_scatter_probability(coeff, sigma_n,
result.direct_throughput);
1494 result.direct_throughput *= coeff.sigma_s / vstate.equiangular_pdf;
1498 result.direct_scatter =
false;
1537 const ccl_private EquiangularCoefficients &equiangular_coeffs,
1540 if (!vstate.use_mis || !
result.direct_scatter) {
1545 if (vstate.direct_sample_method == VOLUME_SAMPLE_DISTANCE) {
1546 const float equiangular_pdf = volume_equiangular_pdf(ray, equiangular_coeffs,
result.direct_t);
1550 kernel_assert(vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR);
1551 mis_weight =
power_heuristic(vstate.equiangular_pdf, vstate.distance_pdf);
1554 result.direct_throughput *= 2.0f * mis_weight;
1561 const VolumeSampleMethod direct_sample_method,
1569 vstate.direct_sample_method = direct_sample_method;
1570 vstate.use_mis = (direct_sample_method == VOLUME_SAMPLE_MIS);
1571 if (vstate.use_mis) {
1572 if (vstate.rscatter < 0.5f) {
1573 vstate.direct_sample_method = VOLUME_SAMPLE_DISTANCE;
1574 vstate.rscatter *= 2.0f;
1578 vstate.rscatter = (vstate.rscatter - 0.5f) * 2.0f;
1579 vstate.direct_sample_method = VOLUME_SAMPLE_EQUIANGULAR;
1583 vstate.distance_pdf = 0.0f;
1584 vstate.equiangular_pdf = 0.0f;
1585 vstate.sigma_max = 0.0f;
1586 vstate.transmittance = 1.0f;
1588 vstate.optical_depth = 0.0f;
1592 vstate.scatter_prob = 1.0f;
1593 vstate.majorant_scale = 1.0f;
1594 vstate.direct_rr_scale = 1.0f;
1596# ifdef __DENOISING_FEATURES__
1605 const ccl_private EquiangularCoefficients &equiangular_coeffs,
1609 result.direct_throughput = (vstate.direct_sample_method == VOLUME_SAMPLE_NONE) ?
1612 result.indirect_throughput = throughput;
1615 if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR) {
1616 result.direct_t = volume_equiangular_sample(
1617 ray, equiangular_coeffs, vstate.rscatter, &vstate.equiangular_pdf);
1620# if defined(__PATH_GUIDING__)
1621 result.direct_sample_method = vstate.direct_sample_method;
1631 const float ray_length,
1632 const ccl_private VolumeShaderCoefficients &coeff,
1637 if (attenuation_only) {
1653 buffer +
kernel_data.film.pass_volume_scatter_denoised);
1655 buffer +
kernel_data.film.pass_volume_transmit_denoised);
1656 const Spectrum L_volume = L_transmitted + L_scattered;
1667 const float optical_depth = volume_majorant_optical_depth(kg, buffer);
1670 guided_scatter_prob =
clamp(
1675 return mix(attenuation, guided_scatter_prob, 0.75f);
1694 sd->P = ray->P + ray->D * ray->tmin;
1696 if (!volume_shader_sample(kg,
state, sd, &coeff)) {
1700 const float ray_length = ray->tmax - ray->tmin;
1701 vstate.optical_depth =
reduce_max(coeff.sigma_t) * ray_length;
1706 const Spectrum emission = volume_emission_integrate(&coeff, sd->flag, ray_length);
1707 vstate.emission = throughput * emission;
1715 result.indirect_throughput *= transmittance;
1723 vstate.albedo = albedo * (1.0f - transmittance) * throughput;
1731 vstate.albedo + transmittance, throughput, &rchannel, &channel_pdf);
1733 const Spectrum scatter_prob = volume_scatter_probability_homogeneous(
1737 if (vstate.rscatter < scatter_pdf_channel) {
1739 vstate.rscatter /= scatter_pdf_channel;
1744 result.indirect_t = ray->tmin + dt;
1746 const float indirect_distance_pdf =
dot(distance_pdf * scatter_prob, channel_pdf);
1748 result.indirect_throughput *= coeff.sigma_s * transmittance / indirect_distance_pdf;
1749 volume_shader_copy_phases(&
result.indirect_phases, sd);
1753 const float indirect_distance_pdf =
dot((1.0f - scatter_prob), channel_pdf);
1754 result.indirect_throughput *= transmittance / indirect_distance_pdf;
1755 vstate.rscatter = (vstate.rscatter - scatter_pdf_channel) / (1.0f - scatter_pdf_channel);
1760 if (vstate.direct_sample_method == VOLUME_SAMPLE_NONE) {
1767 volume_shader_copy_phases(&
result.direct_phases, sd);
1772 if (vstate.direct_sample_method == VOLUME_SAMPLE_DISTANCE) {
1775 result.direct_t = ray->tmin + dt;
1777 vstate.distance_pdf =
dot(distance_pdf, channel_pdf);
1779 result.direct_throughput *= coeff.sigma_s * transmittance / vstate.distance_pdf;
1782 kernel_assert(vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR);
1783 const float dt =
result.direct_t - ray->tmin;
1785 result.direct_throughput *= coeff.sigma_s * transmittance / vstate.equiangular_pdf;
1786 if (vstate.use_mis) {
1807 OctreeTracing octree(ray->tmin);
1809 if (!volume_octree_setup<false>(kg, ray, sd,
state, &rng_state, path_flag, octree)) {
1814 vstate.optical_depth = octree.sigma.max * octree.t.length();
1823 volume_equiangular_transmittance(
1824 kg,
state, ray, octree.sigma, octree.t, sd, &rng_state, vstate,
result);
1827 volume_integrate_advance(kg, ray, sd,
state, &rng_state, path_flag, octree, vstate,
result))
1829 const float sigma_max = octree.sigma.max * vstate.majorant_scale;
1830 volume_integrate_step_scattering(kg,
state, ray, sigma_max, sd, vstate,
result, reservoir);
1832 if (volume_integrate_should_stop(
result)) {
1837 volume_distance_sampling_finalize(kg,
state, ray, sd, vstate,
result, reservoir);
1838 volume_equiangular_direct_scatter(kg,
state, ray, sd, vstate,
result);
1866 ray->tmax - ray->tmin,
1881 equiangular_coeffs->P = ls->P;
1883 return volume_valid_direct_ray_segment(kg, ray->P, ray->D, &equiangular_coeffs->t_range, ls);
1897 return VOLUME_SAMPLE_NONE;
1900 if (!integrate_volume_sample_direct_light(kg,
state, ray, sd, rng_state, coeffs, ls)) {
1901 return VOLUME_SAMPLE_NONE;
1905 const bool has_equiangular_sample = (ls->t !=
FLT_MAX);
1906 return has_equiangular_sample ? volume_stack_sample_method(kg,
state) : VOLUME_SAMPLE_DISTANCE;
1921 EquiangularCoefficients equiangular_coeffs = {
zero_float3(), {ray->tmin, ray->tmax}};
1922 const VolumeSampleMethod direct_sample_method = volume_direct_sample_method(
1923 kg,
state, ray, sd, rng_state, &equiangular_coeffs, ls);
1927 volume_integrate_state_init(kg,
state, direct_sample_method, rng_state, ray->tmin, vstate);
1930 volume_integrate_result_init(
state, ray, vstate, equiangular_coeffs,
result);
1932 if (volume_is_homogeneous<false>(kg,
state)) {
1933 volume_integrate_homogeneous(
1940 volume_direct_scatter_mis(ray, vstate, equiangular_coeffs,
result);
1943 if (!
is_zero(vstate.emission)) {
1950# ifdef __DENOISING_FEATURES__
1953 film_write_denoising_features_volume(
1986template<const
bool shadow>
1989 const float object_step_size,
1994 vstep->t.min = vstep->t.max = tmin;
1996 if (object_step_size ==
FLT_MAX) {
1998 vstep->size = tmax - tmin;
1999 vstep->shade_offset = 0.0f;
2000 vstep->offset = 1.0f;
2001 vstep->max_steps = 1;
2005 vstep->max_steps =
kernel_data.integrator.volume_max_steps;
2006 const float t = tmax - tmin;
2007 float step_size =
min(object_step_size, t);
2009 if (t > vstep->max_steps * step_size) {
2011 step_size = t / (
float)vstep->max_steps;
2014 vstep->size = step_size;
2021 vstep->offset = 1.0f;
2034 if (vstep.t.max == ray->tmax) {
2040 vstep.t.min = vstep.t.max;
2041 vstep.t.max =
min(ray->tmax, ray->tmin + (
step + vstep.offset) * vstep.size);
2042 const float shade_t =
mix(vstep.t.min, vstep.t.max, vstep.shade_offset);
2043 *shade_P = ray->P + ray->D * shade_t;
2045 return step < vstep.max_steps;
2053 const float object_step_size)
2067 volume_step_init<true>(kg, &rng_state, object_step_size, ray->tmin, ray->tmax, &vstep);
2071 for (
int step = 0; volume_ray_marching_advance(
step, ray, &sd->P, vstep);
step++) {
2077 sum += (-sigma_t * vstep.t.length());
2078 if ((
step & 0x07) == 0) {
2079 tp = *throughput *
exp(
sum);
2088 if (vstep.t.max == ray->tmax) {
2090 tp = *throughput *
exp(
sum);
2096struct VolumeRayMarchingState {
2102 VolumeSampleMethod direct_sample_method;
2105 float equiangular_pdf;
2111 const VolumeSampleMethod direct_sample_method,
2118 vstate.direct_sample_method = direct_sample_method;
2119 vstate.use_mis = (direct_sample_method == VOLUME_SAMPLE_MIS);
2120 if (vstate.use_mis) {
2121 if (vstate.rscatter < 0.5f) {
2122 vstate.rscatter *= 2.0f;
2123 vstate.direct_sample_method = VOLUME_SAMPLE_DISTANCE;
2126 vstate.rscatter = (vstate.rscatter - 0.5f) * 2.0f;
2127 vstate.direct_sample_method = VOLUME_SAMPLE_EQUIANGULAR;
2130 vstate.equiangular_pdf = 0.0f;
2131 vstate.distance_pdf = 1.0f;
2135ccl_device bool volume_sample_indirect_scatter_ray_marching(
2145 if (
result.indirect_scatter) {
2153 if (1.0f - vstate.rscatter >= sample_transmittance) {
2159 const float new_dt = -
logf(1.0f - vstate.rscatter) / sample_sigma_t;
2160 const float new_t = t.min + new_dt;
2165 const float distance_pdf =
dot(channel_pdf, coeff.sigma_t * new_transmittance);
2167 if (vstate.distance_pdf * distance_pdf > VOLUME_SAMPLE_PDF_CUTOFF) {
2169 result.indirect_scatter =
true;
2170 result.indirect_t = new_t;
2171 result.indirect_throughput *= coeff.sigma_s * new_transmittance / distance_pdf;
2172 if (vstate.direct_sample_method == VOLUME_SAMPLE_DISTANCE) {
2173 vstate.distance_pdf *= distance_pdf;
2176 volume_shader_copy_phases(&
result.indirect_phases, sd);
2183 const float distance_pdf =
dot(channel_pdf, transmittance);
2184 result.indirect_throughput *= transmittance / distance_pdf;
2185 if (vstate.direct_sample_method == VOLUME_SAMPLE_DISTANCE) {
2186 vstate.distance_pdf *= distance_pdf;
2190 vstate.rscatter = 1.0f - (1.0f - vstate.rscatter) / sample_transmittance;
2200 const ccl_private EquiangularCoefficients &equiangular_coeffs,
2215 albedo,
result.indirect_throughput, &vstate.rchannel, &channel_pdf);
2218 if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR && !
result.direct_scatter) {
2219 if (t.contains(
result.direct_t) && vstate.equiangular_pdf > VOLUME_SAMPLE_PDF_CUTOFF) {
2220 const float new_dt =
result.direct_t - t.min;
2223 result.direct_scatter =
true;
2224 result.direct_throughput *= coeff.sigma_s * new_transmittance / vstate.equiangular_pdf;
2225 volume_shader_copy_phases(&
result.direct_phases, sd);
2228 if (vstate.use_mis) {
2229 const float distance_pdf = vstate.distance_pdf *
2230 dot(channel_pdf, coeff.sigma_t * new_transmittance);
2231 const float mis_weight = 2.0f *
power_heuristic(vstate.equiangular_pdf, distance_pdf);
2232 result.direct_throughput *= mis_weight;
2236 result.direct_throughput *= transmittance;
2237 vstate.distance_pdf *=
dot(channel_pdf, transmittance);
2242 if (volume_sample_indirect_scatter_ray_marching(
2243 transmittance, channel_pdf, channel, sd, coeff, t, vstate,
result))
2245 if (vstate.direct_sample_method == VOLUME_SAMPLE_DISTANCE) {
2248 result.direct_scatter =
true;
2251 volume_shader_copy_phases(&
result.direct_phases, sd);
2254 if (vstate.use_mis) {
2255 const float equiangular_pdf = volume_equiangular_pdf(
2256 ray, equiangular_coeffs,
result.indirect_t);
2257 const float mis_weight =
power_heuristic(vstate.distance_pdf, equiangular_pdf);
2258 result.direct_throughput *= 2.0f * mis_weight;
2275 const float object_step_size,
2281 EquiangularCoefficients equiangular_coeffs = {
zero_float3(), {ray->tmin, ray->tmax}};
2282 const VolumeSampleMethod direct_sample_method = volume_direct_sample_method(
2283 kg,
state, ray, sd, rng_state, &equiangular_coeffs, ls);
2287 volume_step_init<false>(kg, rng_state, object_step_size, ray->tmin, ray->tmax, &vstep);
2291 volume_ray_marching_state_init(kg, rng_state, direct_sample_method, vstate);
2295 result.direct_throughput = (vstate.direct_sample_method == VOLUME_SAMPLE_NONE) ?
2298 result.indirect_throughput = throughput;
2301 if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR) {
2302 result.direct_t = volume_equiangular_sample(
2303 ray, equiangular_coeffs, vstate.rscatter, &vstate.equiangular_pdf);
2305# if defined(__PATH_GUIDING__)
2306 result.direct_sample_method = vstate.direct_sample_method;
2309# ifdef __DENOISING_FEATURES__
2316 for (
int step = 0; volume_ray_marching_advance(
step, ray, &sd->P, vstep);
step++) {
2319 if (volume_shader_sample(kg,
state, sd, &coeff)) {
2320 const int closure_flag = sd->flag;
2323 const float dt = vstep.t.length();
2332 if (!
result.indirect_scatter) {
2333 const Spectrum emission = volume_emission_integrate(&coeff, closure_flag, dt);
2334 accum_emission +=
result.indirect_throughput * emission;
2340# ifdef __DENOISING_FEATURES__
2342 if (write_denoising_features && (closure_flag &
SD_SCATTER)) {
2344 accum_albedo +=
result.indirect_throughput * albedo * (
one_spectrum() - transmittance);
2349 volume_ray_marching_step_scattering(
2350 sd, ray, equiangular_coeffs, coeff, transmittance, vstep.t, vstate,
result);
2354 result.indirect_throughput *= transmittance;
2355 result.direct_throughput *= transmittance;
2358 if (volume_integrate_should_stop(
result)) {
2365 if (!
is_zero(accum_emission)) {
2372# ifdef __DENOISING_FEATURES__
2374 if (write_denoising_features) {
2375 film_write_denoising_features_volume(
2392#
if defined(__PATH_GUIDING__)
2414 kg, rand_light, sd->time,
P,
N, object_receiver, shader_flags, bounce, path_flag, &ls))
2439 const float phase_pdf = volume_shader_phase_eval(
2440 kg,
state, sd, phases, ls.D, &phase_eval, ls.shader);
2442 bsdf_eval_mul(&phase_eval, light_eval / ls.pdf * mis_weight);
2494 state, path, render_pixel_index);
2496 state, path, rng_offset);
2498 state, path, rng_pixel);
2505 state, path, diffuse_bounce);
2507 state, path, glossy_bounce);
2509 state, path, transmission_bounce);
2511 state, path, volume_bounds_bounce);
2517# if defined(__PATH_GUIDING__)
2521 state, guiding, path_segment);
2526 integrator_state_copy_volume_stack_to_shadow(kg, shadow_state,
state);
2545 float phase_pdf = 0.0f;
2546 float unguided_phase_pdf = 0.0f;
2549 float sampled_roughness = 1.0f;
2552# if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
2556 label = volume_shader_phase_guided_sample(kg,
2564 &unguided_phase_pdf,
2565 &sampled_roughness);
2576 label = volume_shader_phase_sample(
2577 sd, svc, rand_phase, &phase_eval, &phase_wo, &phase_pdf, &sampled_roughness);
2583 unguided_phase_pdf = phase_pdf;
2590# ifdef __LIGHT_TREE__
2596# ifdef __RAY_DIFFERENTIALS__
2607 kg,
state, phase_weight, phase_pdf,
normalize(phase_wo), sampled_roughness);
2611 const Spectrum throughput_phase = throughput * phase_weight;
2623 const float3 previous_P = ray->P + ray->D * ray->tmin;
2628# ifdef __LIGHT_LINKING__
2647# if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
2651 float3 unlit_throughput = initial_throughput;
2653 bool guiding_generated_new_segment =
false;
2654 float rand_phase_guiding = 0.5f;
2664 state, path, continuation_probability);
2665 if (continuation_probability == 0.0f) {
2666 return VOLUME_PATH_MISSED;
2670 if (
result.direct_scatter) {
2671 const float3 direct_P = ray->P + result.direct_t * ray->D;
2673# if defined(__PATH_GUIDING__)
2674 if (kernel_data.integrator.use_guiding) {
2675# if PATH_GUIDING_LEVEL >= 1
2676 if (result.direct_sample_method == VOLUME_SAMPLE_DISTANCE) {
2680 const float3 transmittance_weight = spectrum_to_rgb(
2681 safe_divide_color(result.indirect_throughput, initial_throughput));
2682 guiding_record_volume_transmission(kg, state, transmittance_weight);
2683 guiding_record_volume_segment(kg, state, direct_P, sd->wi);
2684 guiding_generated_new_segment = true;
2685 unlit_throughput = result.indirect_throughput / continuation_probability;
2686 rand_phase_guiding = path_state_rng_1D(kg, rng_state, PRNG_VOLUME_PHASE_GUIDING_DISTANCE);
2688 else if (result.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR) {
2694 float3 scatterEval = one_float3();
2695 if (INTEGRATOR_STATE(state, guiding, path_segment)) {
2696 const pgl_vec3f scatteringWeight =
2697 INTEGRATOR_STATE(state, guiding, path_segment)->scatteringWeight;
2698 scatterEval = make_float3(scatteringWeight.x, scatteringWeight.y, scatteringWeight.z);
2700 unlit_throughput /= scatterEval;
2701 unlit_throughput *= continuation_probability;
2702 rand_phase_guiding = path_state_rng_1D(
2703 kg, rng_state, PRNG_VOLUME_PHASE_GUIDING_EQUIANGULAR);
2706# if PATH_GUIDING_LEVEL >= 4
2707 if ((kernel_data.kernel_features & KERNEL_FEATURE_PATH_GUIDING)) {
2708 volume_shader_prepare_guiding(
2709 kg, state, rand_phase_guiding, direct_P, ray->D, &result.direct_phases);
2715 result.direct_throughput /= continuation_probability;
2716 integrate_volume_direct_light(kg,
2722#
if defined(__PATH_GUIDING__)
2725 result.direct_throughput,
2733 if (
result.indirect_scatter) {
2734# if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
2735 if (!guiding_generated_new_segment) {
2736 const float3 transmittance_weight = spectrum_to_rgb(
2737 safe_divide_color(result.indirect_throughput, initial_throughput));
2738 guiding_record_volume_transmission(kg, state, transmittance_weight);
2741 result.indirect_throughput /= continuation_probability;
2745 if (
result.indirect_scatter) {
2746 sd->P = ray->P +
result.indirect_t * ray->D;
2748# if defined(__PATH_GUIDING__)
2750# if PATH_GUIDING_LEVEL >= 1
2751 if (!guiding_generated_new_segment) {
2755# if PATH_GUIDING_LEVEL >= 4
2758 if (
result.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR) {
2760 volume_shader_prepare_guiding(
2761 kg,
state, rand_phase_guiding, sd->P, ray->D, &
result.indirect_phases);
2767 if (integrate_volume_phase_scatter(kg,
state, sd, ray, rng_state, &
result.indirect_phases)) {
2768 return VOLUME_PATH_SCATTERED;
2770 return VOLUME_PATH_MISSED;
2772# if defined(__PATH_GUIDING__)
2778 return VOLUME_PATH_ATTENUATED;
2792 if (integrator_state_volume_stack_is_empty(kg,
state)) {
2793 return VOLUME_PATH_ATTENUATED;
2812 VolumeIntegrateResult
result = {};
2815 return volume_integrate_event(kg,
state, ray, &sd, &rng_state, ls,
result);
2826 if (integrator_state_volume_stack_is_empty(kg,
state)) {
2827 return VOLUME_PATH_ATTENUATED;
2846 VolumeIntegrateResult
result = {};
2848 const float step_size = volume_stack_step_size<false>(kg,
state);
2849 volume_integrate_ray_marching(
2852 return volume_integrate_event(kg,
state, ray, &sd, &rng_state, ls,
result);
2874 volume_stack_clean(kg,
state);
2884template<DeviceKernel volume_kernel>
2890 const VolumeIntegrateEvent event)
2892 if (event == VOLUME_PATH_MISSED) {
2898 if (event == VOLUME_PATH_ATTENUATED) {
2904#ifdef __SHADOW_LINKING__
2905 if (shadow_linking_schedule_intersection_kernel<volume_kernel>(kg,
state)) {
2923 integrator_shade_volume_setup(kg,
state, &ray, &isect);
2939 integrator_shade_volume_setup(kg,
state, &ray, &isect);
2941 const VolumeIntegrateEvent
event = volume_integrate_ray_marching(kg,
state, &ray,
render_buffer);
MINLINE float power_of_2(float f)
MINLINE float safe_divide(float a, float b)
blender::float3 packed_float3
ccl_device_inline bool area_light_valid_ray_segment(const ccl_global KernelAreaLight *light, float3 P, float3 D, ccl_private Interval< float > *t_range)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
static T sum(const btAlignedObjectArray< T > &items)
ccl_device_inline Spectrum safe_divide_color(Spectrum a, Spectrum b, const float fallback=0.0f)
reduce_max(value.rgb)") DEFINE_VALUE("REDUCE(lhs
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
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, const float time)
ccl_device_inline void light_sample_to_volume_shadow_ray(const ccl_private ShaderData *ccl_restrict sd, const ccl_private LightSample *ccl_restrict ls, const float3 P, ccl_private Ray *ray)
ccl_device_inline float light_sample_mis_weight_nee(KernelGlobals kg, const float nee_pdf, const float forward_pdf)
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)
#define CLOSURE_IS_VOLUME(type)
#define ccl_device_forceinline
#define KERNEL_FEATURE_PATH_GUIDING
#define ccl_optional_struct_init
#define kernel_data_fetch(name, index)
#define AS_SHADER_DATA(shader_data_tiny_storage)
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define KERNEL_FEATURE_LIGHT_PASSES
#define __DENOISING_FEATURES__
#define KERNEL_FEATURE_LIGHT_LINKING
#define VOLUME_OCTREE_MAX_DEPTH
#define ccl_device_noinline
#define ccl_device_inline_method
#define CCL_NAMESPACE_END
ccl_device_forceinline float differential_make_compact(const float dD)
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt)
VecBase< float, D > normalize(VecOp< float, D >) RET
bool all(VecOp< bool, D >) RET
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
constexpr T clamp(T, U, U) RET
VecBase< float, 3 > float3
ccl_device_forceinline void integrator_intersect_next_kernel_after_volume(KernelGlobals kg, IntegratorState state, const ccl_private Intersection *ccl_restrict isect, ccl_global float *ccl_restrict render_buffer)
#define VOLUME_THROUGHPUT_EPSILON
ccl_device Spectrum volume_color_transmittance(Spectrum sigma, const float t)
ccl_device int volume_sample_channel(Spectrum albedo, Spectrum throughput, ccl_private float *rand, ccl_private Spectrum *pdf)
ccl_device_inline Spectrum volume_sample_channel_pdf(Spectrum albedo, Spectrum throughput)
ccl_device float volume_channel_get(Spectrum value, const int channel)
ccl_gpu_kernel_postfix ccl_global KernelWorkTile const int ccl_global float * render_buffer
@ OBJECT_INVERSE_TRANSFORM
ccl_device_inline float object_volume_density(KernelGlobals kg, const int object)
ccl_device_inline int object_lightgroup(KernelGlobals kg, const int object)
ccl_device_inline Transform object_fetch_transform(KernelGlobals kg, const int object, enum ObjectTransform type)
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_emission(KernelGlobals kg, IntegratorState state, const Spectrum Le)
ccl_device_forceinline void guiding_record_volume_bounce(KernelGlobals kg, IntegratorState state, const Spectrum weight, const float pdf, const float3 wo, const float roughness)
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)
@ SD_BSDF_HAS_TRANSMISSION
ShaderData ShaderDataTinyStorage
@ PRNG_VOLUME_EXPANSION_ORDER
@ PRNG_VOLUME_SHADE_OFFSET
@ PRNG_VOLUME_PHASE_GUIDING_DISTANCE
@ PRNG_VOLUME_COLOR_CHANNEL
@ PRNG_VOLUME_SCATTER_DISTANCE
@ PATH_RAY_VOLUME_SCATTER
@ PATH_RAY_TERMINATE_IN_NEXT_VOLUME
@ PATH_RAY_DENOISING_FEATURES
@ PATH_RAY_VOLUME_PRIMARY_TRANSMIT
@ SD_OBJECT_TRANSFORM_APPLIED
@ DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW
@ DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST
ccl_device_inline uint lcg_state_init(const uint rng_hash, const uint rng_offset, const uint sample, const uint scramble)
ccl_device_inline bool triangle_light_valid_ray_segment(KernelGlobals kg, const float3 P, const float3 D, ccl_private Interval< float > *t_range, const ccl_private LightSample *ls)
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 void bsdf_eval_mul(ccl_private BsdfEval *eval, const float value)
ccl_device_inline Spectrum bsdf_eval_sum(const ccl_private BsdfEval *eval)
OrientationBounds merge(const OrientationBounds &cone_a, const OrientationBounds &cone_b)
ccl_device_inline uint count_leading_zeros(const uint x)
ccl_device_inline bool isfinite_safe(const float f)
ccl_device_inline dual1 reduce_add(const dual< T > a)
ccl_device_inline float fast_logf(const float x)
ccl_device_inline bool is_zero(const float2 a)
ccl_device_inline float reduce_min(const float2 a)
ccl_device_inline float2 fabs(const float2 a)
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
ccl_device_inline uint3 float3_as_uint3(const float3 f)
#define PROFILING_INIT(kg, event)
ccl_device float power_heuristic(const float a, const float b)
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
closure color scatter(string phase, float Anisotropy, float IOR, float Backscatter, float Alpha, float Diameter)
ccl_device_inline float path_state_rng_1D(KernelGlobals kg, const ccl_private 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_light_termination(KernelGlobals kg, const ccl_private RNGState *state)
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_device_inline void path_state_rng_scramble(ccl_private RNGState *rng_state, const int seed)
ccl_device_inline float2 path_state_rng_2D(KernelGlobals kg, const ccl_private RNGState *rng_state, const int dimension)
ccl_device_inline float3 path_state_rng_3D(KernelGlobals kg, const ccl_private RNGState *rng_state, const int dimension)
ccl_device_forceinline float path_rng_1D(KernelGlobals kg, const uint rng_pixel, const uint sample, const int dimension)
@ PROFILING_SHADE_VOLUME_INTEGRATE
@ PROFILING_SHADE_VOLUME_SETUP
@ PROFILING_SHADE_VOLUME_DIRECT_LIGHT
@ PROFILING_SHADE_VOLUME_INDIRECT_LIGHT
ccl_device_inline float sample_exponential_distribution(const float rand, const float lambda)
ccl_device_inline int sample_geometric_distribution(const float rand, const float r, ccl_private float &pmf, const int cut_off=INT_MAX)
ccl_device_inline Spectrum pdf_exponential_distribution(const float x, const Spectrum lambda, const Interval< float > t)
ccl_device void integrator_shade_volume_ray_marching(KernelGlobals kg, IntegratorState state, ccl_global float *ccl_restrict render_buffer)
ccl_device void integrator_shade_volume(KernelGlobals kg, IntegratorState state, ccl_global float *ccl_restrict render_buffer)
CCL_NAMESPACE_BEGIN ccl_device_inline void integrator_next_kernel_after_shade_volume(KernelGlobals kg, const IntegratorState state, ccl_global float *ccl_restrict render_buffer, const ccl_private Intersection *ccl_restrict isect, const VolumeIntegrateEvent event)
ccl_device_inline bool spot_light_valid_ray_segment(KernelGlobals kg, const ccl_global KernelLight *klight, const float3 P, const float3 D, ccl_private Interval< float > *t_range)
IntegratorShadowStateCPU * IntegratorShadowState
#define INTEGRATOR_STATE_WRITE(state, nested_struct, member)
#define INTEGRATOR_STATE(state, nested_struct, member)
#define INTEGRATOR_STATE_ARRAY(state, nested_struct, array_index, member)
IntegratorStateCPU * IntegratorState
const IntegratorStateCPU * ConstIntegratorState
ccl_device_forceinline void integrator_path_next(IntegratorState state, const DeviceKernel current_kernel, const DeviceKernel next_kernel)
ccl_device_forceinline void integrator_path_terminate(KernelGlobals kg, IntegratorState state, ccl_global float *ccl_restrict render_buffer, const DeviceKernel current_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_write_shadow_ray_self(IntegratorShadowState state, const ccl_private Ray *ccl_restrict ray)
ccl_device_forceinline void integrator_state_read_ray(ConstIntegratorState state, ccl_private Ray *ccl_restrict ray)
ccl_device_forceinline void integrator_state_write_shadow_ray(IntegratorShadowState state, const ccl_private Ray *ccl_restrict ray)
ccl_device_forceinline void integrator_state_read_isect(ConstIntegratorState state, ccl_private Intersection *ccl_restrict isect)
ccl_device_inline_method T range() const
ccl_device_inline_method T length() const
ccl_device_inline_method bool is_empty() const
packed_float3 PackedSpectrum
CCL_NAMESPACE_BEGIN ccl_device_forceinline ccl_global float * film_pass_pixel_render_buffer(KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer)
ccl_device_inline float3 kernel_read_pass_rgbe(const ccl_global float *ccl_restrict buffer)