Blender V4.5
shade_volume.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
8
11
18
19#include "kernel/light/light.h"
20#include "kernel/light/sample.h"
21
23
25
26#ifdef __VOLUME__
27
28/* Events for probabilistic scattering. */
29
30enum VolumeIntegrateEvent {
31 VOLUME_PATH_SCATTERED = 0,
32 VOLUME_PATH_ATTENUATED = 1,
33 VOLUME_PATH_MISSED = 2
34};
35
36struct VolumeIntegrateResult {
37 /* Throughput and offset for direct light scattering. */
38 bool direct_scatter;
39 Spectrum direct_throughput;
40 float direct_t;
41 ShaderVolumePhases direct_phases;
42# ifdef __PATH_GUIDING__
43 VolumeSampleMethod direct_sample_method;
44# endif
45
46 /* Throughput and offset for indirect light scattering. */
47 bool indirect_scatter;
48 Spectrum indirect_throughput;
49 float indirect_t;
50 ShaderVolumePhases indirect_phases;
51};
52
53/* Ignore paths that have volume throughput below this value, to avoid unnecessary work
54 * and precision issues.
55 * todo: this value could be tweaked or turned into a probability to avoid unnecessary
56 * work in volumes and subsurface scattering. */
57# define VOLUME_THROUGHPUT_EPSILON 1e-6f
58
59/* Volume shader properties
60 *
61 * extinction coefficient = absorption coefficient + scattering coefficient
62 * sigma_t = sigma_a + sigma_s */
63
64struct VolumeShaderCoefficients {
65 Spectrum sigma_t;
66 Spectrum sigma_s;
67 Spectrum emission;
68};
69
70struct EquiangularCoefficients {
71 float3 P;
72 Interval<float> t_range;
73};
74
75/* Evaluate shader to get extinction coefficient at P. */
76ccl_device_inline bool shadow_volume_shader_sample(KernelGlobals kg,
78 ccl_private ShaderData *ccl_restrict sd,
80{
81 VOLUME_READ_LAMBDA(integrator_state_read_shadow_volume_stack(state, i))
82 volume_shader_eval<true>(kg, state, sd, PATH_RAY_SHADOW, volume_read_lambda_pass);
83
84 if (!(sd->flag & SD_EXTINCTION)) {
85 return false;
86 }
87
88 *extinction = sd->closure_transparent_extinction;
89 return true;
90}
91
92/* Evaluate shader to get absorption, scattering and emission at P. */
93ccl_device_inline bool volume_shader_sample(KernelGlobals kg,
95 ccl_private ShaderData *ccl_restrict sd,
96 ccl_private VolumeShaderCoefficients *coeff)
97{
98 const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
99 VOLUME_READ_LAMBDA(integrator_state_read_volume_stack(state, i))
100 volume_shader_eval<false>(kg, state, sd, path_flag, volume_read_lambda_pass);
101
102 if (!(sd->flag & (SD_EXTINCTION | SD_SCATTER | SD_EMISSION))) {
103 return false;
104 }
105
106 coeff->sigma_s = zero_spectrum();
107 coeff->sigma_t = (sd->flag & SD_EXTINCTION) ? sd->closure_transparent_extinction :
109 coeff->emission = (sd->flag & SD_EMISSION) ? sd->closure_emission_background : zero_spectrum();
110
111 if (sd->flag & SD_SCATTER) {
112 for (int i = 0; i < sd->num_closure; i++) {
113 const ccl_private ShaderClosure *sc = &sd->closure[i];
114
115 if (CLOSURE_IS_VOLUME(sc->type)) {
116 coeff->sigma_s += sc->weight;
117 }
118 }
119 }
120
121 return true;
122}
123
124/* Determines the next shading position. */
125struct VolumeStep {
126 /* Shift starting point of all segments by a random amount to avoid banding artifacts due to
127 * biased ray marching with insufficient step size. */
128 float offset;
129
130 /* Step size taken at each marching step. */
131 float size;
132
133 /* Perform shading at this offset within a step, to integrate over the entire step segment. */
134 float shade_offset;
135
136 /* Maximal steps allowed between `ray->tmin` and `ray->tmax`. */
137 int max_steps;
138
139 /* Current active segment. */
140 Interval<float> t;
141};
142
143template<const bool shadow>
144ccl_device_forceinline void volume_step_init(KernelGlobals kg,
145 const ccl_private RNGState *rng_state,
146 const float object_step_size,
147 const float tmin,
148 const float tmax,
149 ccl_private VolumeStep *vstep)
150{
151 vstep->t.min = vstep->t.max = tmin;
152
153 if (object_step_size == FLT_MAX) {
154 /* Homogeneous volume. */
155 vstep->size = tmax - tmin;
156 vstep->shade_offset = 0.0f;
157 vstep->offset = 1.0f;
158 vstep->max_steps = 1;
159 }
160 else {
161 /* Heterogeneous volume. */
162 vstep->max_steps = kernel_data.integrator.volume_max_steps;
163 const float t = tmax - tmin;
164 float step_size = min(object_step_size, t);
165
166 if (t > vstep->max_steps * step_size) {
167 /* Increase step size to cover the whole ray segment. */
168 step_size = t / (float)vstep->max_steps;
169 }
170
171 vstep->size = step_size;
172 vstep->shade_offset = path_state_rng_1D(kg, rng_state, PRNG_VOLUME_SHADE_OFFSET);
173
174 if (shadow) {
175 /* For shadows we do not offset all segments, since the starting point is already a random
176 * distance inside the volume. It also appears to create banding artifacts for unknown
177 * reasons. */
178 vstep->offset = 1.0f;
179 }
180 else {
181 vstep->offset = path_state_rng_1D(kg, rng_state, PRNG_VOLUME_OFFSET);
182 }
183 }
184}
185
186ccl_device_inline bool volume_integrate_advance(const int step,
187 const ccl_private Ray *ccl_restrict ray,
188 ccl_private float3 *shade_P,
189 ccl_private VolumeStep &vstep)
190{
191 if (vstep.t.max == ray->tmax) {
192 /* Reached the last segment. */
193 return false;
194 }
195
196 /* Advance to new position. */
197 vstep.t.min = vstep.t.max;
198 vstep.t.max = min(ray->tmax, ray->tmin + (step + vstep.offset) * vstep.size);
199 const float shade_t = mix(vstep.t.min, vstep.t.max, vstep.shade_offset);
200 *shade_P = ray->P + ray->D * shade_t;
201
202 return step < vstep.max_steps;
203}
204
205/* Volume Shadows
206 *
207 * These functions are used to attenuate shadow rays to lights. Both absorption
208 * and scattering will block light, represented by the extinction coefficient. */
209
210/* heterogeneous volume: integrate stepping through the volume until we
211 * reach the end, get absorbed entirely, or run out of iterations */
212ccl_device void volume_shadow_heterogeneous(KernelGlobals kg,
215 ccl_private ShaderData *ccl_restrict sd,
217 const float object_step_size)
218{
219 /* Load random number state. */
220 RNGState rng_state;
222
223 Spectrum tp = *throughput;
224
225 /* Prepare for stepping. */
226 VolumeStep vstep;
227 volume_step_init<true>(kg, &rng_state, object_step_size, ray->tmin, ray->tmax, &vstep);
228
229 /* compute extinction at the start */
231 for (int step = 0; volume_integrate_advance(step, ray, &sd->P, vstep); step++) {
232 /* compute attenuation over segment */
233 Spectrum sigma_t = zero_spectrum();
234 if (shadow_volume_shader_sample(kg, state, sd, &sigma_t)) {
235 /* Compute `expf()` only for every Nth step, to save some calculations
236 * because `exp(a)*exp(b) = exp(a+b)`, also do a quick #VOLUME_THROUGHPUT_EPSILON
237 * check then. */
238 sum += (-sigma_t * vstep.t.length());
239 if ((step & 0x07) == 0) { /* TODO: Other interval? */
240 tp = *throughput * exp(sum);
241
242 /* stop if nearly all light is blocked */
244 break;
245 }
246 }
247 }
248 }
249
250 if (vstep.t.max == ray->tmax) {
251 /* Update throughput in case we haven't done it above. */
252 tp = *throughput * exp(sum);
253 }
254
255 *throughput = tp;
256}
257
258/* Equi-angular sampling as in:
259 * "Importance Sampling Techniques for Path Tracing in Participating Media" */
260
261/* Below this pdf we ignore samples, as they tend to lead to very long distances.
262 * This can cause performance issues with BVH traversal in OptiX, leading it to
263 * traverse many nodes. Since these contribute very little to the image, just ignore
264 * those samples. */
265# define VOLUME_SAMPLE_PDF_CUTOFF 1e-8f
266
267ccl_device float volume_equiangular_sample(const ccl_private Ray *ccl_restrict ray,
268 const ccl_private EquiangularCoefficients &coeffs,
269 const float xi,
270 ccl_private float *pdf)
271{
272 const float delta = dot((coeffs.P - ray->P), ray->D);
273 const float D = safe_sqrtf(len_squared(coeffs.P - ray->P) - delta * delta);
274 if (UNLIKELY(D == 0.0f)) {
275 *pdf = 0.0f;
276 return 0.0f;
277 }
278 const float tmin = coeffs.t_range.min;
279 const float tmax = coeffs.t_range.max;
280 const float theta_a = atan2f(tmin - delta, D);
281 const float theta_b = atan2f(tmax - delta, D);
282 const float t_ = D * tanf((xi * theta_b) + (1 - xi) * theta_a);
283 if (UNLIKELY(theta_b == theta_a)) {
284 *pdf = 0.0f;
285 return 0.0f;
286 }
287 *pdf = D / ((theta_b - theta_a) * (D * D + t_ * t_));
288
289 return clamp(delta + t_, tmin, tmax); /* clamp is only for float precision errors */
290}
291
292ccl_device float volume_equiangular_pdf(const ccl_private Ray *ccl_restrict ray,
293 const ccl_private EquiangularCoefficients &coeffs,
294 const float sample_t)
295{
296 const float delta = dot((coeffs.P - ray->P), ray->D);
297 const float D = safe_sqrtf(len_squared(coeffs.P - ray->P) - delta * delta);
298 if (UNLIKELY(D == 0.0f)) {
299 return 0.0f;
300 }
301
302 const float tmin = coeffs.t_range.min;
303 const float tmax = coeffs.t_range.max;
304 const float t_ = sample_t - delta;
305
306 const float theta_a = atan2f(tmin - delta, D);
307 const float theta_b = atan2f(tmax - delta, D);
308 if (UNLIKELY(theta_b == theta_a)) {
309 return 0.0f;
310 }
311
312 const float pdf = D / ((theta_b - theta_a) * (D * D + t_ * t_));
313
314 return pdf;
315}
316
317ccl_device_inline bool volume_equiangular_valid_ray_segment(KernelGlobals kg,
318 const float3 ray_P,
319 const float3 ray_D,
321 const ccl_private LightSample *ls)
322{
323 if (ls->type == LIGHT_SPOT) {
324 const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->prim);
325 return spot_light_valid_ray_segment(kg, klight, ray_P, ray_D, t_range);
326 }
327 if (ls->type == LIGHT_AREA) {
328 const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->prim);
329 return area_light_valid_ray_segment(&klight->area, ray_P - klight->co, ray_D, t_range);
330 }
331 if (ls->type == LIGHT_TRIANGLE) {
332 return triangle_light_valid_ray_segment(kg, ray_P - ls->P, ray_D, t_range, ls);
333 }
334
335 /* Point light, the whole range of the ray is visible. */
336 kernel_assert(ls->type == LIGHT_POINT);
337 return true;
338}
339
340/* Emission */
341
342ccl_device Spectrum volume_emission_integrate(ccl_private VolumeShaderCoefficients *coeff,
343 const int closure_flag,
344 Spectrum transmittance,
345 const float t)
346{
347 /* integral E * exp(-sigma_t * t) from 0 to t = E * (1 - exp(-sigma_t * t))/sigma_t
348 * this goes to E * t as sigma_t goes to zero
349 *
350 * todo: we should use an epsilon to avoid precision issues near zero sigma_t */
351 Spectrum emission = coeff->emission;
352
353 if (closure_flag & SD_EXTINCTION) {
354 Spectrum sigma_t = coeff->sigma_t;
355
357 GET_SPECTRUM_CHANNEL(emission, i) *= (GET_SPECTRUM_CHANNEL(sigma_t, i) > 0.0f) ?
358 (1.0f - GET_SPECTRUM_CHANNEL(transmittance, i)) /
359 GET_SPECTRUM_CHANNEL(sigma_t, i) :
360 t;
361 }
362 }
363 else {
364 emission *= t;
365 }
366
367 return emission;
368}
369
370/* Volume Integration */
371
372struct VolumeIntegrateState {
373 /* Random numbers for scattering. */
374 float rscatter;
375 float rchannel;
376
377 /* Multiple importance sampling. */
378 VolumeSampleMethod direct_sample_method;
379 bool use_mis;
380 float distance_pdf;
381 float equiangular_pdf;
382};
383
384ccl_device bool volume_integrate_should_stop(ccl_private VolumeIntegrateResult &result)
385{
386 /* Stop if nearly all light blocked. */
387 if (!result.indirect_scatter) {
388 if (reduce_max(result.indirect_throughput) < VOLUME_THROUGHPUT_EPSILON) {
389 result.indirect_throughput = zero_spectrum();
390 return true;
391 }
392 }
393 else if (!result.direct_scatter) {
394 if (reduce_max(result.direct_throughput) < VOLUME_THROUGHPUT_EPSILON) {
395 return true;
396 }
397 }
398
399 /* If we have scattering data for both direct and indirect, we're done. */
400 return (result.direct_scatter && result.indirect_scatter);
401}
402
403/* Returns true if we found the indirect scatter position within the current active ray segment. */
404ccl_device bool volume_sample_indirect_scatter(
405 const Spectrum transmittance,
406 const Spectrum channel_pdf,
407 const int channel,
408 const ccl_private ShaderData *ccl_restrict sd,
409 const ccl_private VolumeShaderCoefficients &ccl_restrict coeff,
411 ccl_private VolumeIntegrateState &ccl_restrict vstate,
412 ccl_private VolumeIntegrateResult &ccl_restrict result)
413{
414 if (result.indirect_scatter) {
415 /* Already sampled indirect scatter position. */
416 return false;
417 }
418
419 /* If sampled distance does not go beyond the current segment, we have found the scatter
420 * position. Otherwise continue searching and accumulate the transmittance along the ray. */
421 const float sample_transmittance = volume_channel_get(transmittance, channel);
422 if (1.0f - vstate.rscatter >= sample_transmittance) {
423 /* Pick `sigma_t` from a random channel. */
424 const float sample_sigma_t = volume_channel_get(coeff.sigma_t, channel);
425
426 /* Generate the next distance using random walk, following exponential distribution
427 * p(dt) = sigma_t * exp(-sigma_t * dt). */
428 const float new_dt = -logf(1.0f - vstate.rscatter) / sample_sigma_t;
429 const float new_t = t.min + new_dt;
430
431 const Spectrum new_transmittance = volume_color_transmittance(coeff.sigma_t, new_dt);
432 /* PDF for density-based distance sampling is handled implicitly via
433 * transmittance / pdf = exp(-sigma_t * dt) / (sigma_t * exp(-sigma_t * dt)) = 1 / sigma_t. */
434 const float distance_pdf = dot(channel_pdf, coeff.sigma_t * new_transmittance);
435
436 if (vstate.distance_pdf * distance_pdf > VOLUME_SAMPLE_PDF_CUTOFF) {
437 /* Update throughput. */
438 result.indirect_scatter = true;
439 result.indirect_t = new_t;
440 result.indirect_throughput *= coeff.sigma_s * new_transmittance / distance_pdf;
441 if (vstate.direct_sample_method != VOLUME_SAMPLE_EQUIANGULAR) {
442 vstate.distance_pdf *= distance_pdf;
443 }
444
445 volume_shader_copy_phases(&result.indirect_phases, sd);
446
447 return true;
448 }
449 }
450 else {
451 /* Update throughput. */
452 const float distance_pdf = dot(channel_pdf, transmittance);
453 result.indirect_throughput *= transmittance / distance_pdf;
454 if (vstate.direct_sample_method != VOLUME_SAMPLE_EQUIANGULAR) {
455 vstate.distance_pdf *= distance_pdf;
456 }
457
458 /* Remap rscatter so we can reuse it and keep thing stratified. */
459 vstate.rscatter = 1.0f - (1.0f - vstate.rscatter) / sample_transmittance;
460 }
461
462 return false;
463}
464
465/* Find direct and indirect scatter positions. */
466ccl_device_forceinline void volume_integrate_step_scattering(
467 const ccl_private ShaderData *sd,
468 const ccl_private Ray *ray,
469 const ccl_private EquiangularCoefficients &equiangular_coeffs,
470 const ccl_private VolumeShaderCoefficients &ccl_restrict coeff,
471 const Spectrum transmittance,
473 ccl_private VolumeIntegrateState &ccl_restrict vstate,
474 ccl_private VolumeIntegrateResult &ccl_restrict result)
475{
476 /* Pick random color channel for sampling the scatter distance. We use the Veach one-sample model
477 * with balance heuristic for the channels.
478 * Set `albedo` to 1 for the channel where extinction coefficient `sigma_t` is zero, to make sure
479 * that we sample a distance outside the current segment when that channel is picked, meaning
480 * light passes through without attenuation. */
481 const Spectrum albedo = safe_divide_color(coeff.sigma_s, coeff.sigma_t, 1.0f);
482 Spectrum channel_pdf;
483 const int channel = volume_sample_channel(
484 albedo, result.indirect_throughput, &vstate.rchannel, &channel_pdf);
485
486 /* Equiangular sampling for direct lighting. */
487 if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR && !result.direct_scatter) {
488 if (t.contains(result.direct_t) && vstate.equiangular_pdf > VOLUME_SAMPLE_PDF_CUTOFF) {
489 const float new_dt = result.direct_t - t.min;
490 const Spectrum new_transmittance = volume_color_transmittance(coeff.sigma_t, new_dt);
491
492 result.direct_scatter = true;
493 result.direct_throughput *= coeff.sigma_s * new_transmittance / vstate.equiangular_pdf;
494 volume_shader_copy_phases(&result.direct_phases, sd);
495
496 /* Multiple importance sampling. */
497 if (vstate.use_mis) {
498 const float distance_pdf = vstate.distance_pdf *
499 dot(channel_pdf, coeff.sigma_t * new_transmittance);
500 const float mis_weight = 2.0f * power_heuristic(vstate.equiangular_pdf, distance_pdf);
501 result.direct_throughput *= mis_weight;
502 }
503 }
504 else {
505 result.direct_throughput *= transmittance;
506 vstate.distance_pdf *= dot(channel_pdf, transmittance);
507 }
508 }
509
510 /* Distance sampling for indirect and optional direct lighting. */
511 if (volume_sample_indirect_scatter(
512 transmittance, channel_pdf, channel, sd, coeff, t, vstate, result))
513 {
514 if (vstate.direct_sample_method != VOLUME_SAMPLE_EQUIANGULAR) {
515 /* If using distance sampling for direct light, just copy parameters of indirect light
516 * since we scatter at the same point. */
517 result.direct_scatter = true;
518 result.direct_t = result.indirect_t;
519 result.direct_throughput = result.indirect_throughput;
520 volume_shader_copy_phases(&result.direct_phases, sd);
521
522 /* Multiple importance sampling. */
523 if (vstate.use_mis) {
524 const float equiangular_pdf = volume_equiangular_pdf(
525 ray, equiangular_coeffs, result.indirect_t);
526 const float mis_weight = power_heuristic(vstate.distance_pdf, equiangular_pdf);
527 result.direct_throughput *= 2.0f * mis_weight;
528 }
529 }
530 }
531}
532
533ccl_device_inline void volume_integrate_state_init(KernelGlobals kg,
534 const ccl_private RNGState *rng_state,
535 const VolumeSampleMethod direct_sample_method,
536 ccl_private VolumeIntegrateState &vstate)
537{
538 vstate.rscatter = path_state_rng_1D(kg, rng_state, PRNG_VOLUME_SCATTER_DISTANCE);
539 vstate.rchannel = path_state_rng_1D(kg, rng_state, PRNG_VOLUME_COLOR_CHANNEL);
540
541 /* Multiple importance sampling: pick between equiangular and distance sampling strategy. */
542 vstate.direct_sample_method = direct_sample_method;
543 vstate.use_mis = (direct_sample_method == VOLUME_SAMPLE_MIS);
544 if (vstate.use_mis) {
545 if (vstate.rscatter < 0.5f) {
546 vstate.rscatter *= 2.0f;
547 vstate.direct_sample_method = VOLUME_SAMPLE_DISTANCE;
548 }
549 else {
550 vstate.rscatter = (vstate.rscatter - 0.5f) * 2.0f;
551 vstate.direct_sample_method = VOLUME_SAMPLE_EQUIANGULAR;
552 }
553 }
554 vstate.equiangular_pdf = 0.0f;
555 vstate.distance_pdf = 1.0f;
556}
557
558/* heterogeneous volume distance sampling: integrate stepping through the
559 * volume until we reach the end, get absorbed entirely, or run out of
560 * iterations. this does probabilistically scatter or get transmitted through
561 * for path tracing where we don't want to branch. */
562ccl_device_forceinline void volume_integrate_heterogeneous(
563 KernelGlobals kg,
566 ccl_private ShaderData *ccl_restrict sd,
567 const ccl_private RNGState *rng_state,
569 const float object_step_size,
570 const VolumeSampleMethod direct_sample_method,
571 const ccl_private EquiangularCoefficients &equiangular_coeffs,
572 ccl_private VolumeIntegrateResult &result)
573{
575
576 /* Prepare for stepping. */
577 VolumeStep vstep;
578 volume_step_init<false>(kg, rng_state, object_step_size, ray->tmin, ray->tmax, &vstep);
579
580 /* Initialize volume integration state. */
581 VolumeIntegrateState vstate ccl_optional_struct_init;
582 volume_integrate_state_init(kg, rng_state, direct_sample_method, vstate);
583
584 /* Initialize volume integration result. */
585 const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput);
586 result.direct_throughput = throughput;
587 result.indirect_throughput = throughput;
588
589 /* Equiangular sampling: compute distance and PDF in advance. */
590 if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR) {
591 result.direct_t = volume_equiangular_sample(
592 ray, equiangular_coeffs, vstate.rscatter, &vstate.equiangular_pdf);
593 }
594# ifdef __PATH_GUIDING__
595 result.direct_sample_method = vstate.direct_sample_method;
596# endif
597
598# ifdef __DENOISING_FEATURES__
599 const bool write_denoising_features = (INTEGRATOR_STATE(state, path, flag) &
601 Spectrum accum_albedo = zero_spectrum();
602# endif
603 Spectrum accum_emission = zero_spectrum();
604
605 for (int step = 0; volume_integrate_advance(step, ray, &sd->P, vstep); step++) {
606 /* compute segment */
607 VolumeShaderCoefficients coeff ccl_optional_struct_init;
608 if (volume_shader_sample(kg, state, sd, &coeff)) {
609 const int closure_flag = sd->flag;
610
611 /* Evaluate transmittance over segment. */
612 const float dt = vstep.t.length();
613 const Spectrum transmittance = (closure_flag & SD_EXTINCTION) ?
614 volume_color_transmittance(coeff.sigma_t, dt) :
615 one_spectrum();
616
617 /* Emission. */
618 if (closure_flag & SD_EMISSION) {
619 /* Only write emission before indirect light scatter position, since we terminate
620 * stepping at that point if we have already found a direct light scatter position. */
621 if (!result.indirect_scatter) {
622 const Spectrum emission = volume_emission_integrate(
623 &coeff, closure_flag, transmittance, dt);
624 accum_emission += result.indirect_throughput * emission;
626 }
627 }
628
629 if (closure_flag & SD_SCATTER) {
630# ifdef __DENOISING_FEATURES__
631 /* Accumulate albedo for denoising features. */
632 if (write_denoising_features && (closure_flag & SD_SCATTER)) {
633 const Spectrum albedo = safe_divide_color(coeff.sigma_s, coeff.sigma_t);
634 accum_albedo += result.indirect_throughput * albedo * (one_spectrum() - transmittance);
635 }
636# endif
637
638 /* Scattering and absorption. */
639 volume_integrate_step_scattering(
640 sd, ray, equiangular_coeffs, coeff, transmittance, vstep.t, vstate, result);
641 }
642 else if (closure_flag & SD_EXTINCTION) {
643 /* Absorption only. */
644 result.indirect_throughput *= transmittance;
645 result.direct_throughput *= transmittance;
646 }
647
648 if (volume_integrate_should_stop(result)) {
649 break;
650 }
651 }
652 }
653
654 /* Write accumulated emission. */
655 if (!is_zero(accum_emission)) {
658 kg, state, accum_emission, render_buffer, object_lightgroup(kg, sd->object));
659 }
660 }
661
662# ifdef __DENOISING_FEATURES__
663 /* Write denoising features. */
664 if (write_denoising_features) {
665 film_write_denoising_features_volume(
666 kg, state, accum_albedo, result.indirect_scatter, render_buffer);
667 }
668# endif /* __DENOISING_FEATURES__ */
669}
670
671/* Path tracing: sample point on light for equiangular sampling. */
672ccl_device_forceinline bool integrate_volume_equiangular_sample_light(
673 KernelGlobals kg,
675 const ccl_private Ray *ccl_restrict ray,
676 const ccl_private ShaderData *ccl_restrict sd,
677 const ccl_private RNGState *ccl_restrict rng_state,
678 ccl_private EquiangularCoefficients *ccl_restrict equiangular_coeffs,
680{
681 /* Test if there is a light or BSDF that needs direct light. */
682 if (!kernel_data.integrator.use_direct_light) {
683 return false;
684 }
685
686 /* Sample position on a light. */
687 const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
688 const uint bounce = INTEGRATOR_STATE(state, path, bounce);
689 const float3 rand_light = path_state_rng_3D(kg, rng_state, PRNG_LIGHT);
690
692 rand_light,
693 sd->time,
694 sd->P,
695 ray->D,
696 ray->tmax - ray->tmin,
698 bounce,
699 path_flag,
700 &ls))
701 {
702 ls.emitter_id = EMITTER_NONE;
703 return false;
704 }
705
706 if (ls.shader & SHADER_EXCLUDE_SCATTER) {
707 ls.emitter_id = EMITTER_NONE;
708 return false;
709 }
710
711 if (ls.t == FLT_MAX) {
712 /* Sampled distant/background light is valid in volume segment, but we are going to sample the
713 * light position with distance sampling instead of equiangular. */
714 return false;
715 }
716
717 equiangular_coeffs->P = ls.P;
718
719 return volume_equiangular_valid_ray_segment(
720 kg, ray->P, ray->D, &equiangular_coeffs->t_range, &ls);
721}
722
723/* Path tracing: sample point on light and evaluate light shader, then
724 * queue shadow ray to be traced. */
725ccl_device_forceinline void integrate_volume_direct_light(
726 KernelGlobals kg,
728 const ccl_private ShaderData *ccl_restrict sd,
729 const ccl_private RNGState *ccl_restrict rng_state,
730 const float3 P,
732# ifdef __PATH_GUIDING__
733 const ccl_private Spectrum unlit_throughput,
734# endif
735 const ccl_private Spectrum throughput,
737{
739
740 if (!kernel_data.integrator.use_direct_light || ls.emitter_id == EMITTER_NONE) {
741 return;
742 }
743
744 /* Sample position on the same light again, now from the shading point where we scattered. */
745 {
746 const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
747 const uint bounce = INTEGRATOR_STATE(state, path, bounce);
748 const float3 rand_light = path_state_rng_3D(kg, rng_state, PRNG_LIGHT);
749 const float3 N = zero_float3();
750 const int object_receiver = light_link_receiver_nee(kg, sd);
751 const int shader_flags = SD_BSDF_HAS_TRANSMISSION;
752
754 kg, rand_light, sd->time, P, N, object_receiver, shader_flags, bounce, path_flag, &ls))
755 {
756 return;
757 }
758 }
759
760 if (ls.shader & SHADER_EXCLUDE_SCATTER) {
761 return;
762 }
763
764 /* Evaluate light shader.
765 *
766 * TODO: can we reuse sd memory? In theory we can move this after
767 * integrate_surface_bounce, evaluate the BSDF, and only then evaluate
768 * the light shader. This could also move to its own kernel, for
769 * non-constant light sources. */
770 ShaderDataTinyStorage emission_sd_storage;
771 ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
772 const Spectrum light_eval = light_sample_shader_eval(kg, state, emission_sd, &ls, sd->time);
773 if (is_zero(light_eval)) {
774 return;
775 }
776
777 /* Evaluate BSDF. */
779 const float phase_pdf = volume_shader_phase_eval(
780 kg, state, sd, phases, ls.D, &phase_eval, ls.shader);
781 const float mis_weight = light_sample_mis_weight_nee(kg, ls.pdf, phase_pdf);
782 bsdf_eval_mul(&phase_eval, light_eval / ls.pdf * mis_weight);
783
784 /* Path termination. */
785 const float terminate = path_state_rng_light_termination(kg, rng_state);
786 if (light_sample_terminate(kg, &phase_eval, terminate)) {
787 return;
788 }
789
790 /* Create shadow ray. */
792 light_sample_to_volume_shadow_ray(kg, sd, &ls, P, &ray);
793
794 /* Branch off shadow kernel. */
797
798 /* Write shadow ray and associated state to global memory. */
799 integrator_state_write_shadow_ray(shadow_state, &ray);
800 integrator_state_write_shadow_ray_self(kg, shadow_state, &ray);
801
802 /* Copy state from main path to shadow path. */
803 const uint16_t bounce = INTEGRATOR_STATE(state, path, bounce);
804 const uint16_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce);
805 uint32_t shadow_flag = INTEGRATOR_STATE(state, path, flag);
806 const Spectrum throughput_phase = throughput * bsdf_eval_sum(&phase_eval);
807
808 if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
809 PackedSpectrum pass_diffuse_weight;
810 PackedSpectrum pass_glossy_weight;
811
812 if (shadow_flag & PATH_RAY_ANY_PASS) {
813 /* Indirect bounce, use weights from earlier surface or volume bounce. */
814 pass_diffuse_weight = INTEGRATOR_STATE(state, path, pass_diffuse_weight);
815 pass_glossy_weight = INTEGRATOR_STATE(state, path, pass_glossy_weight);
816 }
817 else {
818 /* Direct light, no diffuse/glossy distinction needed for volumes. */
819 shadow_flag |= PATH_RAY_VOLUME_PASS;
820 pass_diffuse_weight = one_spectrum();
821 pass_glossy_weight = zero_spectrum();
822 }
823
824 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, pass_diffuse_weight) = pass_diffuse_weight;
825 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, pass_glossy_weight) = pass_glossy_weight;
826 }
827
828 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, render_pixel_index) = INTEGRATOR_STATE(
829 state, path, render_pixel_index);
830 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, rng_offset) = INTEGRATOR_STATE(
831 state, path, rng_offset);
832 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, rng_pixel) = INTEGRATOR_STATE(
833 state, path, rng_pixel);
834 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, sample) = INTEGRATOR_STATE(
835 state, path, sample);
836 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, flag) = shadow_flag;
837 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, bounce) = bounce;
838 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, transparent_bounce) = transparent_bounce;
839 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, diffuse_bounce) = INTEGRATOR_STATE(
840 state, path, diffuse_bounce);
841 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, glossy_bounce) = INTEGRATOR_STATE(
842 state, path, glossy_bounce);
843 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, transmission_bounce) = INTEGRATOR_STATE(
844 state, path, transmission_bounce);
845 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, throughput) = throughput_phase;
846
847 /* Write Light-group, +1 as light-group is int but we need to encode into a uint8_t. */
848 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, lightgroup) = ls.group + 1;
849
850# ifdef __PATH_GUIDING__
851 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unlit_throughput) = unlit_throughput;
852 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, path_segment) = INTEGRATOR_STATE(
853 state, guiding, path_segment);
854 INTEGRATOR_STATE(shadow_state, shadow_path, guiding_mis_weight) = 0.0f;
855# endif
856
857 integrator_state_copy_volume_stack_to_shadow(kg, shadow_state, state);
858}
859
860/* Path tracing: scatter in new direction using phase function */
861ccl_device_forceinline bool integrate_volume_phase_scatter(
862 KernelGlobals kg,
864 ccl_private ShaderData *sd,
865 const ccl_private Ray *ray,
866 const ccl_private RNGState *rng_state,
867 const ccl_private ShaderVolumePhases *phases)
868{
870
871 float2 rand_phase = path_state_rng_2D(kg, rng_state, PRNG_VOLUME_PHASE);
872
873 const ccl_private ShaderVolumeClosure *svc = volume_shader_phase_pick(phases, &rand_phase);
874
875 /* Phase closure, sample direction. */
876 float phase_pdf = 0.0f;
877 float unguided_phase_pdf = 0.0f;
880 float sampled_roughness = 1.0f;
881 int label;
882
883# if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
884 if (kernel_data.integrator.use_guiding) {
885 label = volume_shader_phase_guided_sample(kg,
886 state,
887 sd,
888 svc,
889 rand_phase,
890 &phase_eval,
891 &phase_wo,
892 &phase_pdf,
893 &unguided_phase_pdf,
894 &sampled_roughness);
895
896 if (phase_pdf == 0.0f || bsdf_eval_is_zero(&phase_eval)) {
897 return false;
898 }
899
900 INTEGRATOR_STATE_WRITE(state, path, unguided_throughput) *= phase_pdf / unguided_phase_pdf;
901 }
902 else
903# endif
904 {
905 label = volume_shader_phase_sample(
906 kg, sd, phases, svc, rand_phase, &phase_eval, &phase_wo, &phase_pdf, &sampled_roughness);
907
908 if (phase_pdf == 0.0f || bsdf_eval_is_zero(&phase_eval)) {
909 return false;
910 }
911
912 unguided_phase_pdf = phase_pdf;
913 }
914
915 /* Setup ray. */
916 INTEGRATOR_STATE_WRITE(state, ray, P) = sd->P;
917 INTEGRATOR_STATE_WRITE(state, ray, D) = normalize(phase_wo);
918 INTEGRATOR_STATE_WRITE(state, ray, tmin) = 0.0f;
919# ifdef __LIGHT_TREE__
920 if (kernel_data.integrator.use_light_tree) {
921 INTEGRATOR_STATE_WRITE(state, ray, previous_dt) = ray->tmax - ray->tmin;
922 }
923# endif
925# ifdef __RAY_DIFFERENTIALS__
927# endif
928 // Save memory by storing last hit prim and object in isect
929 INTEGRATOR_STATE_WRITE(state, isect, prim) = sd->prim;
930 INTEGRATOR_STATE_WRITE(state, isect, object) = sd->object;
931
932 const Spectrum phase_weight = bsdf_eval_sum(&phase_eval) / phase_pdf;
933
934 /* Add phase function sampling data to the path segment. */
936 kg, state, sd, phase_weight, phase_pdf, normalize(phase_wo), sampled_roughness);
937
938 /* Update throughput. */
939 const Spectrum throughput = INTEGRATOR_STATE(state, path, throughput);
940 const Spectrum throughput_phase = throughput * phase_weight;
941 INTEGRATOR_STATE_WRITE(state, path, throughput) = throughput_phase;
942
943 if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
944 if (INTEGRATOR_STATE(state, path, bounce) == 0) {
945 INTEGRATOR_STATE_WRITE(state, path, pass_diffuse_weight) = one_spectrum();
946 INTEGRATOR_STATE_WRITE(state, path, pass_glossy_weight) = zero_spectrum();
947 }
948 }
949
950 /* Update path state */
951 INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = phase_pdf;
952 const float3 previous_P = ray->P + ray->D * ray->tmin;
953 INTEGRATOR_STATE_WRITE(state, path, mis_origin_n) = sd->P - previous_P;
954 INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = fminf(
955 unguided_phase_pdf, INTEGRATOR_STATE(state, path, min_ray_pdf));
956
957# ifdef __LIGHT_LINKING__
958 if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_LINKING) {
959 INTEGRATOR_STATE_WRITE(state, path, mis_ray_object) = sd->object;
960 }
961# endif
962
963 path_state_next(kg, state, label, sd->flag);
964 return true;
965}
966
967/* get the volume attenuation and emission over line segment defined by
968 * ray, with the assumption that there are no surfaces blocking light
969 * between the endpoints. distance sampling is used to decide if we will
970 * scatter or not. */
971ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg,
975{
976 ShaderData sd;
977 /* FIXME: `object` is used for light linking. We read the bottom of the stack for simplicity, but
978 * this does not work for overlapping volumes. */
979 shader_setup_from_volume(kg, &sd, ray, INTEGRATOR_STATE_ARRAY(state, volume_stack, 0, object));
980
981 /* Load random number state. */
982 RNGState rng_state;
983 path_state_rng_load(state, &rng_state);
984
985 /* Sample light ahead of volume stepping, for equiangular sampling. */
986 /* TODO: distant lights are ignored now, but could instead use even distribution. */
988 const bool need_light_sample = !(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_TERMINATE);
989
990 EquiangularCoefficients equiangular_coeffs = {zero_float3(), {ray->tmin, ray->tmax}};
991
992 const bool have_equiangular_sample =
993 need_light_sample && integrate_volume_equiangular_sample_light(
994 kg, state, ray, &sd, &rng_state, &equiangular_coeffs, ls);
995
996 const VolumeSampleMethod direct_sample_method = (have_equiangular_sample) ?
997 volume_stack_sample_method(kg, state) :
998 VOLUME_SAMPLE_DISTANCE;
999
1000 /* Step through volume. */
1001 VOLUME_READ_LAMBDA(integrator_state_read_volume_stack(state, i))
1002 const float step_size = volume_stack_step_size(kg, volume_read_lambda_pass);
1003
1004# if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
1005 /* The current path throughput which is used later to calculate per-segment throughput. */
1006 const float3 initial_throughput = INTEGRATOR_STATE(state, path, throughput);
1007 /* The path throughput used to calculate the throughput for direct light. */
1008 float3 unlit_throughput = initial_throughput;
1009 /* If a new path segment is generated at the direct scatter position. */
1010 bool guiding_generated_new_segment = false;
1011 float rand_phase_guiding = 0.5f;
1012# endif
1013
1014 /* TODO: expensive to zero closures? */
1015 VolumeIntegrateResult result = {};
1016 volume_integrate_heterogeneous(kg,
1017 state,
1018 ray,
1019 &sd,
1020 &rng_state,
1022 step_size,
1023 direct_sample_method,
1024 equiangular_coeffs,
1025 result);
1026
1027 /* Perform path termination. The intersect_closest will have already marked this path
1028 * to be terminated. That will shading evaluating to leave out any scattering closures,
1029 * but emission and absorption are still handled for multiple importance sampling. */
1030 const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
1031 const float continuation_probability = (path_flag & PATH_RAY_TERMINATE_IN_NEXT_VOLUME) ?
1032 0.0f :
1034 state, path, continuation_probability);
1035 if (continuation_probability == 0.0f) {
1036 return VOLUME_PATH_MISSED;
1037 }
1038
1039 /* Direct light. */
1040 if (result.direct_scatter) {
1041 const float3 direct_P = ray->P + result.direct_t * ray->D;
1042
1043# ifdef __PATH_GUIDING__
1044 if (kernel_data.integrator.use_guiding) {
1045# if PATH_GUIDING_LEVEL >= 1
1046 if (result.direct_sample_method == VOLUME_SAMPLE_DISTANCE) {
1047 /* If the direct scatter event is generated using VOLUME_SAMPLE_DISTANCE the direct event
1048 * will happen at the same position as the indirect event and the direct light contribution
1049 * will contribute to the position of the next path segment. */
1050 const float3 transmittance_weight = spectrum_to_rgb(
1051 safe_divide_color(result.indirect_throughput, initial_throughput));
1052 guiding_record_volume_transmission(kg, state, transmittance_weight);
1053 guiding_record_volume_segment(kg, state, direct_P, sd.wi);
1054 guiding_generated_new_segment = true;
1055 unlit_throughput = result.indirect_throughput / continuation_probability;
1056 rand_phase_guiding = path_state_rng_1D(kg, &rng_state, PRNG_VOLUME_PHASE_GUIDING_DISTANCE);
1057 }
1058 else {
1059 /* If the direct scatter event is generated using VOLUME_SAMPLE_EQUIANGULAR the direct
1060 * event will happen at a separate position as the indirect event and the direct light
1061 * contribution will contribute to the position of the current/previous path segment. The
1062 * unlit_throughput has to be adjusted to include the scattering at the previous segment.
1063 */
1064 float3 scatterEval = one_float3();
1065 if (state->guiding.path_segment) {
1066 const pgl_vec3f scatteringWeight = state->guiding.path_segment->scatteringWeight;
1067 scatterEval = make_float3(scatteringWeight.x, scatteringWeight.y, scatteringWeight.z);
1068 }
1069 unlit_throughput /= scatterEval;
1070 unlit_throughput *= continuation_probability;
1071 rand_phase_guiding = path_state_rng_1D(
1072 kg, &rng_state, PRNG_VOLUME_PHASE_GUIDING_EQUIANGULAR);
1073 }
1074# endif
1075# if PATH_GUIDING_LEVEL >= 4
1076 volume_shader_prepare_guiding(
1077 kg, state, &sd, rand_phase_guiding, direct_P, ray->D, &result.direct_phases);
1078# endif
1079 }
1080# endif
1081
1082 result.direct_throughput /= continuation_probability;
1083 integrate_volume_direct_light(kg,
1084 state,
1085 &sd,
1086 &rng_state,
1087 direct_P,
1088 &result.direct_phases,
1089# ifdef __PATH_GUIDING__
1090 unlit_throughput,
1091# endif
1092 result.direct_throughput,
1093 ls);
1094 }
1095
1096 /* Indirect light.
1097 *
1098 * Only divide throughput by continuation_probability if we scatter. For the attenuation
1099 * case the next surface will already do this division. */
1100 if (result.indirect_scatter) {
1101# if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
1102 if (!guiding_generated_new_segment) {
1103 const float3 transmittance_weight = spectrum_to_rgb(
1104 safe_divide_color(result.indirect_throughput, initial_throughput));
1105 guiding_record_volume_transmission(kg, state, transmittance_weight);
1106 }
1107# endif
1108 result.indirect_throughput /= continuation_probability;
1109 }
1110 INTEGRATOR_STATE_WRITE(state, path, throughput) = result.indirect_throughput;
1111
1112 if (result.indirect_scatter) {
1113 sd.P = ray->P + result.indirect_t * ray->D;
1114
1115# if defined(__PATH_GUIDING__)
1116# if PATH_GUIDING_LEVEL >= 1
1117 if (!guiding_generated_new_segment) {
1118 guiding_record_volume_segment(kg, state, sd.P, sd.wi);
1119 }
1120# endif
1121# if PATH_GUIDING_LEVEL >= 4
1122 /* If the direct scatter event was generated using VOLUME_SAMPLE_EQUIANGULAR we need to
1123 * initialize the guiding distribution at the indirect scatter position. */
1124 if (result.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR) {
1125 rand_phase_guiding = path_state_rng_1D(kg, &rng_state, PRNG_VOLUME_PHASE_GUIDING_DISTANCE);
1126 volume_shader_prepare_guiding(
1127 kg, state, &sd, rand_phase_guiding, sd.P, ray->D, &result.indirect_phases);
1128 }
1129# endif
1130# endif
1131
1132 if (integrate_volume_phase_scatter(kg, state, &sd, ray, &rng_state, &result.indirect_phases)) {
1133 return VOLUME_PATH_SCATTERED;
1134 }
1135 return VOLUME_PATH_MISSED;
1136 }
1137# if defined(__PATH_GUIDING__)
1138 /* No guiding if we don't scatter. */
1139 state->guiding.use_volume_guiding = false;
1140# endif
1141 return VOLUME_PATH_ATTENUATED;
1142}
1143
1144#endif
1145
1149{
1151
1152#ifdef __VOLUME__
1153 /* Setup shader data. */
1156
1159
1160 /* Set ray length to current segment. */
1161 ray.tmax = (isect.prim != PRIM_NONE) ? isect.t : FLT_MAX;
1162
1163 /* Clean volume stack for background rays. */
1164 if (isect.prim == PRIM_NONE) {
1165 volume_stack_clean(kg, state);
1166 }
1167
1168 const VolumeIntegrateEvent event = volume_integrate(kg, state, &ray, render_buffer);
1169 if (event == VOLUME_PATH_MISSED) {
1170 /* End path. */
1172 return;
1173 }
1174
1175 if (event == VOLUME_PATH_ATTENUATED) {
1176 /* Continue to background, light or surface. */
1178 kg, state, &isect, render_buffer);
1179 return;
1180 }
1181
1182# ifdef __SHADOW_LINKING__
1183 if (shadow_linking_schedule_intersection_kernel<DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME>(kg,
1184 state))
1185 {
1186 return;
1187 }
1188# endif /* __SHADOW_LINKING__ */
1189
1190 /* Queue intersect_closest kernel. */
1192 state,
1195#endif /* __VOLUME__ */
1196}
1197
#define D
MINLINE float safe_sqrtf(float a)
unsigned int uint
#define UNLIKELY(x)
ccl_device_inline bool area_light_valid_ray_segment(const ccl_global KernelAreaLight *light, float3 P, float3 D, ccl_private Interval< float > *t_range)
Definition area.h:458
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static T sum(const btAlignedObjectArray< T > &items)
ccl_device_inline Spectrum safe_divide_color(Spectrum a, Spectrum b, const float fallback=0.0f)
Definition color.h:388
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 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, const ccl_private ShaderData *ccl_restrict sd, const ccl_private 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)
#define CLOSURE_IS_VOLUME(type)
#define kernel_data
#define ccl_restrict
#define ccl_device_forceinline
#define ccl_optional_struct_init
#define kernel_data_fetch(name, index)
#define AS_SHADER_DATA(shader_data_tiny_storage)
#define one_spectrum
#define PRIM_NONE
#define ccl_device
#define zero_spectrum
#define ccl_private
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define EMITTER_NONE
#define KERNEL_FEATURE_LIGHT_PASSES
#define FOREACH_SPECTRUM_CHANNEL(counter)
#define GET_SPECTRUM_CHANNEL(v, i)
#define KERNEL_FEATURE_LIGHT_LINKING
#define ccl_global
#define logf(x)
#define tanf(x)
#define CCL_NAMESPACE_END
#define atan2f(x, y)
#define fminf(x, y)
#define VOLUME_READ_LAMBDA(function_call)
ccl_device_forceinline float differential_make_compact(const float dD)
#define exp
VecBase< float, D > normalize(VecOp< float, D >) RET
VecBase< float, 3 > float3
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
constexpr T clamp(T, U, U) RET
#define mix(a, b, c)
Definition hash.h:35
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 float volume_channel_get(Spectrum value, const int channel)
ccl_gpu_kernel_postfix ccl_global KernelWorkTile const int ccl_global float * render_buffer
ccl_device_inline int object_lightgroup(KernelGlobals kg, const 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, const ccl_private 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_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_EXTINCTION
@ SD_BSDF_HAS_TRANSMISSION
@ SD_SCATTER
@ SD_EMISSION
ShaderData ShaderDataTinyStorage
@ PRNG_VOLUME_PHASE
@ PRNG_LIGHT
@ PRNG_VOLUME_OFFSET
@ PRNG_VOLUME_SHADE_OFFSET
@ PRNG_VOLUME_PHASE_GUIDING_DISTANCE
@ PRNG_VOLUME_COLOR_CHANNEL
@ PRNG_VOLUME_SCATTER_DISTANCE
@ PATH_RAY_SHADOW
@ PATH_RAY_VOLUME_PASS
@ PATH_RAY_TERMINATE
@ PATH_RAY_TERMINATE_IN_NEXT_VOLUME
@ PATH_RAY_DENOISING_FEATURES
@ PATH_RAY_ANY_PASS
@ SHADER_EXCLUDE_SCATTER
@ LIGHT_AREA
@ LIGHT_SPOT
@ LIGHT_TRIANGLE
@ LIGHT_POINT
@ DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME
@ DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW
@ DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST
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)
ccl_device_inline float len_squared(const float2 a)
ccl_device_inline bool is_zero(const float2 a)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
Definition math_float3.h:15
static ulong state[N]
#define N
ccl_device float power_heuristic(const float a, const float b)
Definition mis.h:26
ccl_device_inline float path_state_rng_1D(KernelGlobals kg, const ccl_private RNGState *rng_state, const int dimension)
Definition path_state.h:338
ccl_device_inline void shadow_path_state_rng_load(ConstIntegratorShadowState state, ccl_private RNGState *rng_state)
Definition path_state.h:322
ccl_device_inline float path_state_rng_light_termination(KernelGlobals kg, const ccl_private RNGState *state)
Definition path_state.h:401
ccl_device_inline void path_state_rng_load(ConstIntegratorState state, ccl_private RNGState *rng_state)
Definition path_state.h:314
ccl_device_inline void path_state_next(KernelGlobals kg, IntegratorState state, const int label, const int shader_flag)
Definition path_state.h:105
ccl_device_inline float2 path_state_rng_2D(KernelGlobals kg, const ccl_private RNGState *rng_state, const int dimension)
Definition path_state.h:346
ccl_device_inline float3 path_state_rng_3D(KernelGlobals kg, const ccl_private RNGState *rng_state, const int dimension)
Definition path_state.h:354
#define PROFILING_INIT(kg, event)
Definition profiler.h:14
@ PROFILING_SHADE_VOLUME_INTEGRATE
Definition profiling.h:34
@ PROFILING_SHADE_VOLUME_SETUP
Definition profiling.h:33
@ PROFILING_SHADE_VOLUME_DIRECT_LIGHT
Definition profiling.h:35
@ PROFILING_SHADE_VOLUME_INDIRECT_LIGHT
Definition profiling.h:36
CCL_NAMESPACE_BEGIN ccl_device void integrator_shade_volume(KernelGlobals kg, IntegratorState state, ccl_global float *ccl_restrict render_buffer)
#define min(a, b)
Definition sort.cc:36
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)
Definition spot.h:277
IntegratorShadowStateCPU * IntegratorShadowState
Definition state.h:230
#define INTEGRATOR_STATE_WRITE(state, nested_struct, member)
Definition state.h:236
#define INTEGRATOR_STATE(state, nested_struct, member)
Definition state.h:235
#define INTEGRATOR_STATE_ARRAY(state, nested_struct, array_index, member)
Definition state.h:238
IntegratorStateCPU * IntegratorState
Definition state.h:228
ccl_device_forceinline void integrator_path_terminate(KernelGlobals kg, IntegratorState state, const DeviceKernel current_kernel)
Definition state_flow.h:182
ccl_device_forceinline void integrator_path_next(KernelGlobals kg, IntegratorState state, const DeviceKernel current_kernel, const DeviceKernel next_kernel)
Definition state_flow.h:173
ccl_device_forceinline IntegratorShadowState integrator_shadow_path_init(KernelGlobals kg, IntegratorState state, const DeviceKernel next_kernel, const bool is_ao)
Definition state_flow.h:201
ccl_device_forceinline void integrator_state_write_shadow_ray_self(KernelGlobals kg, IntegratorShadowState state, const ccl_private Ray *ccl_restrict ray)
Definition state_util.h:98
ccl_device_forceinline void integrator_state_read_ray(ConstIntegratorState state, ccl_private Ray *ccl_restrict ray)
Definition state_util.h:55
ccl_device_forceinline void integrator_state_write_shadow_ray(IntegratorShadowState state, const ccl_private Ray *ccl_restrict ray)
Definition state_util.h:75
ccl_device_forceinline void integrator_state_read_isect(ConstIntegratorState state, ccl_private Intersection *ccl_restrict isect)
Definition state_util.h:179
#define FLT_MAX
Definition stdcycles.h:14
i
Definition text_draw.cc:230
float3 Spectrum
packed_float3 PackedSpectrum
uint8_t flag
Definition wm_window.cc:139