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