Blender V5.0
kernel/closure/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
7#include "kernel/types.h"
8
13
15
16/* VOLUME EXTINCTION */
17
19{
20 if (sd->flag & SD_EXTINCTION) {
21 sd->closure_transparent_extinction += weight;
22 }
23 else {
24 sd->flag |= SD_EXTINCTION;
25 sd->closure_transparent_extinction = weight;
26 }
27}
28
29/* VOLUME SCATTERING */
30
33 const float3 wo,
34 ccl_private float *pdf)
35{
36 switch (svc->type) {
38 return volume_fournier_forand_eval(sd, svc, wo, pdf);
40 return volume_rayleigh_eval(sd, wo, pdf);
42 return volume_draine_eval(sd, svc, wo, pdf);
44 return volume_henyey_greenstein_eval(sd, svc, wo, pdf);
45 default:
46 kernel_assert(false);
47 *pdf = 0.0f;
48 return zero_spectrum();
49 }
50}
51
54 const float2 rand,
57 ccl_private float *pdf)
58{
59 switch (svc->type) {
61 return volume_fournier_forand_sample(sd, svc, rand, eval, wo, pdf);
63 return volume_rayleigh_sample(sd, rand, eval, wo, pdf);
65 return volume_draine_sample(sd, svc, rand, eval, wo, pdf);
67 return volume_henyey_greenstein_sample(sd, svc, rand, eval, wo, pdf);
68 default:
69 kernel_assert(false);
70 *pdf = 0.0f;
71 return 0;
72 }
73}
74
75ccl_device bool volume_phase_equal(const ccl_private ShaderClosure *c1,
76 const ccl_private ShaderClosure *c2)
77{
78 if (c1->type != c2->type) {
79 return false;
80 }
81 switch (c1->type) {
85 return v1->c1 == v2->c1 && v1->c2 == v2->c2 && v1->c3 == v2->c3;
86 }
88 return true;
92 return v1->g == v2->g && v1->alpha == v2->alpha;
93 }
97 return v1->g == v2->g;
98 }
99 default:
100 return false;
101 }
102 return false;
103}
104
105/* Approximate phase functions as Henyey-Greenstein for volume guiding.
106 * TODO: This is not ideal, we should use RIS guiding for non-HG phase functions. */
108{
109 switch (svc->type) {
111 /* TODO */
112 return 1.0f;
114 /* Approximate as isotropic */
115 return 0.0f;
117 /* Approximate as HG, TODO */
118 return ((ccl_private DraineVolume *)svc)->g;
120 return ((ccl_private HenyeyGreensteinVolume *)svc)->g;
121 default:
122 return 0.0f;
123 }
124}
125
126/* Volume sampling utilities. */
127
128/* Ignore paths that have volume throughput below this value, to avoid unnecessary work
129 * and precision issues.
130 * TODO: this value could be tweaked or turned into a probability to avoid unnecessary work in
131 * volumes and subsurface scattering. */
132#define VOLUME_THROUGHPUT_EPSILON 1e-6f
133
135{
136 return exp(-sigma * t);
137}
138
139ccl_device float volume_channel_get(Spectrum value, const int channel)
140{
141 return GET_SPECTRUM_CHANNEL(value, channel);
142}
143
144/* Sample color channel proportional to throughput and single scattering albedo, to significantly
145 * reduce noise with many bounce, following:
146 *
147 * "Practical and Controllable Subsurface Scattering for Production Path Tracing".
148 * Matt Jen-Yuan Chiang, Peter Kutz, Brent Burley. SIGGRAPH 2016. */
150{
151 const Spectrum weights = fabs(throughput * albedo);
152 const float sum_weights = reduce_add(weights);
153
154 if ((1.0f - sum_weights) < 1.0f) {
155 /* The same as `sum_weights > 0.0f`, but avoids the case where `sum_weight` is denormal, which
156 * could produce `nan` after division. */
157 return weights / sum_weights;
158 }
159
160 return make_spectrum(1.0f / SPECTRUM_CHANNELS);
161}
162
164 Spectrum throughput,
165 ccl_private float *rand,
167{
168 *pdf = volume_sample_channel_pdf(albedo, throughput);
169
170 float pdf_sum = 0.0f;
172 const float channel_pdf = GET_SPECTRUM_CHANNEL(*pdf, i);
173 if (*rand < pdf_sum + channel_pdf) {
174 /* Rescale to reuse. */
175 *rand = (*rand - pdf_sum) / channel_pdf;
176 return i;
177 }
178 pdf_sum += channel_pdf;
179 }
180 return SPECTRUM_CHANNELS - 1;
181}
182
ATTR_WARN_UNUSED_RESULT const BMVert * v2
#define kernel_assert(cond)
#define SPECTRUM_CHANNELS
#define zero_spectrum
#define make_spectrum(f)
#define ccl_private
#define ccl_device_inline
#define FOREACH_SPECTRUM_CHANNEL(counter)
#define GET_SPECTRUM_CHANNEL(v, i)
#define CCL_NAMESPACE_END
#define exp
CCL_NAMESPACE_BEGIN ccl_device void volume_extinction_setup(ccl_private ShaderData *sd, Spectrum weight)
ccl_device bool volume_phase_equal(const ccl_private ShaderClosure *c1, const ccl_private ShaderClosure *c2)
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 Spectrum volume_phase_eval(const ccl_private ShaderData *sd, const ccl_private ShaderVolumeClosure *svc, const float3 wo, ccl_private float *pdf)
ccl_device_inline Spectrum volume_sample_channel_pdf(Spectrum albedo, Spectrum throughput)
ccl_device float volume_phase_get_g(const ccl_private ShaderVolumeClosure *svc)
ccl_device float volume_channel_get(Spectrum value, const int channel)
ccl_device int volume_phase_sample(const ccl_private ShaderData *sd, const ccl_private ShaderVolumeClosure *svc, const float2 rand, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf)
@ CLOSURE_VOLUME_RAYLEIGH_ID
@ CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID
@ CLOSURE_VOLUME_DRAINE_ID
@ CLOSURE_VOLUME_FOURNIER_FORAND_ID
@ SD_EXTINCTION
ccl_device_inline dual1 reduce_add(const dual< T > a)
Definition math_dual.h:49
ccl_device_inline float2 fabs(const float2 a)
#define ccl_device
i
Definition text_draw.cc:230
float3 Spectrum
ccl_device int volume_draine_sample(const ccl_private ShaderData *sd, const ccl_private ShaderVolumeClosure *svc, const float2 rand, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf)
ccl_device Spectrum volume_draine_eval(const ccl_private ShaderData *sd, const ccl_private ShaderVolumeClosure *svc, const float3 wo, ccl_private float *pdf)
ccl_device Spectrum volume_fournier_forand_eval(const ccl_private ShaderData *sd, const ccl_private ShaderVolumeClosure *svc, const float3 wo, ccl_private float *pdf)
ccl_device int volume_fournier_forand_sample(const ccl_private ShaderData *sd, const ccl_private ShaderVolumeClosure *svc, const float2 rand, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf)
ccl_device Spectrum volume_henyey_greenstein_eval(const ccl_private ShaderData *sd, const ccl_private ShaderVolumeClosure *svc, const float3 wo, ccl_private float *pdf)
ccl_device int volume_henyey_greenstein_sample(const ccl_private ShaderData *sd, const ccl_private ShaderVolumeClosure *svc, const float2 rand, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf)
ccl_device Spectrum volume_rayleigh_eval(const ccl_private ShaderData *sd, const float3 wo, ccl_private float *pdf)
ccl_device int volume_rayleigh_sample(const ccl_private ShaderData *sd, const float2 rand, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf)