Blender V5.0
volume_util.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2024 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
7#include "util/math_fast.h"
8#include "util/projection.h"
9
11
12/* Given a random number, sample a direction that makes an angle of theta with direction D. */
13ccl_device float3 phase_sample_direction(const float3 D, const float cos_theta, const float rand)
14{
15 const float phi = M_2PI_F * rand;
17
18 float3 T;
19 float3 B;
21 return to_global(dir, T, B, D);
22}
23
24/* Given cosine between rays, return probability density that a photon bounces
25 * to that direction. The g parameter controls how different it is from the
26 * uniform sphere. g=0 uniform diffuse-like, g=1 close to sharp single ray. */
27ccl_device float phase_henyey_greenstein(const float cos_theta, const float g)
28{
29 if (fabsf(g) < 1e-3f) {
30 return M_1_4PI_F;
31 }
32 const float fac = 1 + g * (g - 2 * cos_theta);
33 return (1 - sqr(g)) / (M_4PI_F * fac * safe_sqrtf(fac));
34}
35
37 const float g,
38 const float2 rand,
39 ccl_private float *pdf)
40{
41 float cos_theta = 1 - 2 * rand.x;
42 if (fabsf(g) >= 1e-3f) {
43 const float k = (1 - sqr(g)) / (1 - g * cos_theta);
44 cos_theta = (1 + sqr(g) - sqr(k)) / (2 * g);
45 }
46
48
49 return phase_sample_direction(D, cos_theta, rand.y);
50}
51
52/* Given cosine between rays, return probability density that a photon bounces to that direction
53 * according to the constant Rayleigh phase function.
54 * See https://doi.org/10.1364/JOSAA.28.002436 for details. */
56{
57 return (0.1875f * M_1_PI_F) * (1.0f + sqr(cos_theta));
58}
59
61{
62 const float a = 2 - 4 * rand.x;
63 /* Metal doesn't have cbrtf, but since we compute u - 1/u anyways, we can just as well
64 * use the inverse cube root for which there is a simple Quake-style fast implementation. */
65 const float inv_u = -fast_inv_cbrtf(sqrtf(1 + sqr(a)) + a);
66 const float cos_theta = 1 / inv_u - inv_u;
68
69 return phase_sample_direction(D, cos_theta, rand.y);
70}
71
72/* Given cosine between rays, return probability density that a photon bounces to that direction
73 * according to the Draine phase function. This is a generalization of the Henyey-Greenstein
74 * function which bridges the cases of HG and Rayleigh scattering. The parameter g mainly controls
75 * the first moment <cos theta>, and alpha the second moment <cos2 theta> of the exact phase
76 * function. alpha=0 reduces to HG function, g=0, alpha=1 reduces to Rayleigh function, alpha=1
77 * reduces to Cornette-Shanks function.
78 * See https://doi.org/10.1086/379118 for details. */
79ccl_device float phase_draine(const float cos_theta, const float g, float alpha)
80{
81 /* Check special cases. */
82 if (fabsf(g) < 1e-3f && alpha > 0.999f) {
84 }
85 if (fabsf(alpha) < 1e-3f) {
87 }
88
89 const float g2 = sqr(g);
90 const float fac = 1 + g2 - 2 * g * cos_theta;
91 return ((1 - g2) * (1 + alpha * sqr(cos_theta))) /
92 ((1 + (alpha * (1 + 2 * g2)) * (1 / 3.0f)) * M_4PI_F * fac * sqrtf(fac));
93}
94
95/* Adapted from the HLSL code provided in https://research.nvidia.com/labs/rtr/approximate-mie/ */
96ccl_device float phase_draine_sample_cos(const float g, const float alpha, const float rand)
97{
98 if (fabsf(g) < 1e-2f) {
99 /* Special case to prevent division by zero.
100 * The sample technique is similar as in https://doi.org/10.1364/JOSAA.28.002436. */
101 const float inv_alpha = 1.0f / alpha;
102 const float b_2 = (3 + alpha) * inv_alpha * (0.5f - rand);
103 const float inv_u = -fast_inv_cbrtf(b_2 + sqrtf(sqr(b_2) + sqr(inv_alpha) * inv_alpha));
104 return 1 / inv_u - inv_u / alpha;
105 }
106 const float g2 = sqr(g);
107 const float g3 = g * g2;
108 const float g4 = sqr(g2);
109 const float g6 = g2 * g4;
110 const float pgp1_2 = sqr(1 + g2);
111 const float T1a = alpha * (g4 - 1);
112 const float T1a3 = sqr(T1a) * T1a;
113 const float T2 = -1296 * (g2 - 1) * (alpha - alpha * g2) * T1a * (4 * g2 + alpha * pgp1_2);
114 const float T9 = 2 + g2 + g3 * (1 + 2 * g2) * (2 * rand - 1);
115 const float T3 = 3 * g2 * (1 + g * (2 * rand - 1)) + alpha * T9;
116 const float T4a = 432 * T1a3 + T2 + 432 * (alpha * (1 - g2)) * sqr(T3);
117 const float T10 = alpha * (2 * g4 - g2 - g6);
118 const float T4b = 144 * T10;
119 const float T4b3 = sqr(T4b) * T4b;
120 const float T4 = T4a + sqrtf(-4 * T4b3 + sqr(T4a));
121 const float inv_T4p3 = fast_inv_cbrtf(T4);
122 const float T8 = 48 * M_CBRT2_F * T10;
123 const float T6 = (2 * T1a + T8 * inv_T4p3 + 1 / (3 * M_CBRT2_F * inv_T4p3)) / (alpha * (1 - g2));
124 const float T5 = 6 * (1 + g2) + T6;
125 const float T7 = 6 * (1 + g2) - (8 * T3) / (alpha * (g2 - 1) * sqrtf(T5)) - T6;
126 return (1 + g2 - 0.25f * sqr(sqrtf(T7) - sqrtf(T5))) / (2 * g);
127}
128
130 const float3 D, const float g, float alpha, const float2 rand, ccl_private float *pdf)
131{
132 /* Check special cases. */
133 if (fabsf(g) < 1e-3f && alpha > 0.999f) {
134 return phase_rayleigh_sample(D, rand, pdf);
135 }
136 if (fabsf(alpha) < 1e-3f) {
137 return phase_henyey_greenstein_sample(D, g, rand, pdf);
138 }
139
140 const float cos_theta = phase_draine_sample_cos(g, alpha, rand.x);
141 *pdf = phase_draine(cos_theta, g, alpha);
142
143 return phase_sample_direction(D, cos_theta, rand.y);
144}
145
146ccl_device float phase_fournier_forand_delta(const float n, const float sin_htheta_sqr)
147{
148 const float u = 4 * sin_htheta_sqr;
149 return u / (3 * sqr(n - 1));
150}
151
153{
154 const float d90 = phase_fournier_forand_delta(IOR, 0.5f);
155 const float d180 = phase_fournier_forand_delta(IOR, 1.0f);
156 const float v = -logf(2 * B * (d90 - 1) + 1) / logf(d90);
157 return make_float3(IOR, v, (powf(d180, -v) - 1) / (d180 - 1));
158}
159
160/* Given cosine between rays, return probability density that a photon bounces to that direction
161 * according to the Fournier-Forand phase function. The n parameter is the particle index of
162 * refraction and controls how much of the light is refracted. B is the particle backscatter
163 * fraction, B = b_b / b.
164 * See https://doi.org/10.1117/12.366488 for details. */
166 const float delta,
167 const float pow_delta_v,
168 const float v,
169 float sin_htheta_sqr,
170 const float pf_coeff)
171{
172 const float m_delta = 1 - delta;
173 const float m_pow_delta_v = 1 - pow_delta_v;
174
175 float pf;
176 if (fabsf(m_delta) < 1e-3f) {
177 /* Special case (first-order Taylor expansion) to avoid singularity at delta near 1.0 */
178 pf = v * ((v - 1) - (v + 1) / sin_htheta_sqr) * (1 / (8 * M_PI_F));
179 pf += v * (v + 1) * m_delta * (2 * (v - 1) - (2 * v + 1) / sin_htheta_sqr) *
180 (1 / (24 * M_PI_F));
181 }
182 else {
183 pf = (v * m_delta - m_pow_delta_v + (delta * m_pow_delta_v - v * m_delta) / sin_htheta_sqr) /
184 (M_4PI_F * sqr(m_delta) * pow_delta_v);
185 }
186 pf += pf_coeff * (3 * sqr(cos_theta) - 1);
187 return pf;
188}
189
190ccl_device float phase_fournier_forand(const float cos_theta, const float3 coeffs)
191{
192 if (fabsf(cos_theta) >= 1.0f) {
193 return 0.0f;
194 }
195
196 const float n = coeffs.x;
197 const float v = coeffs.y;
198 const float pf_coeff = coeffs.z * (1.0f / (16.0f * M_PI_F));
199 const float sin_htheta_sqr = 0.5f * (1 - cos_theta); /* sin^2(theta / 2)*/
200 const float delta = phase_fournier_forand_delta(n, sin_htheta_sqr);
201
202 return phase_fournier_forand_impl(cos_theta, delta, powf(delta, v), v, sin_htheta_sqr, pf_coeff);
203}
204
205ccl_device float phase_fournier_forand_newton(const float rand, const float3 coeffs)
206{
207 const float n = coeffs.x;
208 const float v = coeffs.y;
209 const float cdf_coeff = coeffs.z * (1.0f / 8.0f);
210 const float pf_coeff = coeffs.z * (1.0f / (16.0f * M_PI_F));
211
212 float cos_theta = 0.64278760968f; /* Initial guess: 50 degrees */
213 for (int it = 0; it < 20; it++) {
214 const float sin_htheta_sqr = 0.5f * (1 - cos_theta); /* sin^2(theta / 2)*/
215 const float delta = phase_fournier_forand_delta(n, sin_htheta_sqr);
216 const float pow_delta_v = powf(delta, v);
217 const float m_delta = 1 - delta;
218 const float m_pow_delta_v = 1 - pow_delta_v;
219
220 /* Evaluate CDF and phase functions */
221 float cdf;
222 if (fabsf(m_delta) < 1e-3f) {
223 /* Special case (first-order Taylor expansion) to avoid singularity at delta near 1.0 */
224 cdf = 1 + v * (1 - sin_htheta_sqr) * (1 - 0.5f * (v + 1) * m_delta);
225 }
226 else {
227 cdf = (1 - pow_delta_v * delta - m_pow_delta_v * sin_htheta_sqr) / (m_delta * pow_delta_v);
228 }
229 cdf += cdf_coeff * cos_theta * (1 - sqr(cos_theta));
230 const float pf = phase_fournier_forand_impl(
231 cos_theta, delta, pow_delta_v, v, sin_htheta_sqr, pf_coeff);
232
233 /* Perform Newton iteration step */
234 float new_cos_theta = cos_theta + M_1_2PI_F * (cdf - rand) / pf;
235
236 /* Don't step off past 1.0, approach the peak slowly */
237 if (new_cos_theta >= 1.0f) {
238 new_cos_theta = max(mix(cos_theta, 1.0f, 0.5f), 0.99f);
239 }
240 if (fabsf(cos_theta - new_cos_theta) < 1e-6f || new_cos_theta == 1.0f) {
241 return new_cos_theta;
242 }
243 cos_theta = new_cos_theta;
244 }
245 /* Reached iteration limit, so give up and use what we have. */
246 return cos_theta;
247}
248
250 const float3 coeffs,
251 const float2 rand,
252 ccl_private float *pdf)
253{
254 const float cos_theta = phase_fournier_forand_newton(rand.x, coeffs);
255 *pdf = phase_fournier_forand(cos_theta, coeffs);
256
257 return phase_sample_direction(D, cos_theta, rand.y);
258}
259
260/* We approximate the Mie phase function for water droplets with diameters 0 < d < 50 um using a
261 * mixture of Draine and Henyey-Greenstein, following
262 * "An Approximate Mie Scattering Function for Fog and Cloud Rendering (Supplemental)"
263 * https://research.nvidia.com/labs/rtr/approximate-mie/publications/approximate-mie-supplemental.pdf
264 * For d > 1, the phase function is strong forward-scattering. For d very close to 0, the phase
265 * function is a mixture of Henyey-Greenstein and Rayleigh.
266 */
268 ccl_private float *g_HG,
269 ccl_private float *g_D,
270 ccl_private float *alpha,
271 ccl_private float *w)
272{
273 d = fmaxf(d, 0.0f);
274 if (d <= 0.1f) {
275 /* Eq (11 - 14). */
276 *g_HG = 13.8f * sqr(d);
277 *g_D = 1.1456f * d * fast_sinf(9.29044f * d);
278 *alpha = 250.0f;
279 *w = 0.252977f - 312.983f * powf(d, 4.3f);
280 }
281 else if (d < 1.5f) {
282 /* Eq (15 - 18). */
283 const float log_d = fast_logf(d);
284 *g_HG = 0.862f - 0.143f * sqr(log_d);
285 const float a = (log_d - 0.238604f) * (log_d + 1.00667f);
286 const float b = 0.507522f - 0.15677f * log_d;
287 const float c = 1.19692f * fast_cosf(a / b) + 1.37932f * log_d + 0.0625835f;
288 *g_D = 0.379685f * fast_cosf(c) + 0.344213f;
289 *alpha = 250.0f;
290 *w = 0.146209f * fast_cosf(3.38707f * log_d + 2.11193f) + 0.316072f + 0.0778917f * log_d;
291 }
292 else if (d < 5.0f) {
293 /* Eq (19 - 22). */
294 const float log_d = fast_logf(d);
295 *g_HG = 0.0604931f * fast_logf(log_d) + 0.940256f;
296 *g_D = 0.500411f - (0.081287f / (-2.0f * log_d + fast_tanf(log_d) + 1.27551f));
297 *alpha = 7.30354f * log_d + 6.31675f;
298 const float temp = fast_cosf(5.68947f * (fast_logf(log_d) - 0.0292149f));
299 *w = 0.026914f * (log_d - temp) + 0.3764f;
300 }
301 else {
302 /* Eq (7 - 10). */
303 *g_HG = fast_expf(-0.0990567f / (d - 1.67154f));
304 *g_D = fast_expf(-2.20679f / (d + 3.91029f) - 0.428934f);
305 *alpha = fast_expf(3.62489f - 8.29288f / (d + 5.52825f));
306 *w = fast_expf(-0.599085f / (d - 0.641583f) - 0.665888f);
307 }
308}
309
#define D
MINLINE float safe_sqrtf(float a)
ATTR_WARN_UNUSED_RESULT const BMVert * v
ccl_device_inline float cos_theta(const float3 w)
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
btVector3 m_delta
ccl_device float3 spherical_cos_to_direction(const float cos_theta, const float phi)
ccl_device_inline T to_global(const float2 p, const T X, const T Y)
#define M_CBRT2_F
#define ccl_private
#define M_1_4PI_F
#define ccl_device_inline
#define M_1_PI_F
#define M_1_2PI_F
#define M_4PI_F
#define logf(x)
#define powf(x, y)
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define pf(_x, _i)
Prefetch 64.
Definition gim_memory.h:48
ccl_device float fast_tanf(float x)
Definition math_fast.h:183
ccl_device_inline float fast_expf(const float x)
Definition math_fast.h:431
ccl_device float fast_sinf(float x)
Definition math_fast.h:83
ccl_device float fast_cosf(float x)
Definition math_fast.h:118
ccl_device_inline float fast_inv_cbrtf(const float x)
Definition math_fast.h:638
ccl_device_inline float fast_logf(const float x)
Definition math_fast.h:379
ccl_device_inline void make_orthonormals(const float3 N, ccl_private float3 *a, ccl_private float3 *b)
#define T
#define B
#define T9
Definition md5.cpp:28
#define T2
Definition md5.cpp:21
#define T7
Definition md5.cpp:26
#define T10
Definition md5.cpp:29
#define T6
Definition md5.cpp:25
#define T3
Definition md5.cpp:22
#define T5
Definition md5.cpp:24
#define T4
Definition md5.cpp:23
#define T8
Definition md5.cpp:27
#define mix
#define sqr
#define fabsf
#define sqrtf
#define ccl_device
#define M_2PI_F
#define fmaxf
#define M_PI_F
float x
float y
float z
Definition sky_math.h:136
float y
Definition sky_math.h:136
float x
Definition sky_math.h:136
max
Definition text_draw.cc:251
ccl_device_inline float phase_fournier_forand_impl(float cos_theta, const float delta, const float pow_delta_v, const float v, float sin_htheta_sqr, const float pf_coeff)
ccl_device float phase_draine(const float cos_theta, const float g, float alpha)
Definition volume_util.h:79
ccl_device float3 phase_draine_sample(const float3 D, const float g, float alpha, const float2 rand, ccl_private float *pdf)
ccl_device float3 phase_henyey_greenstein_sample(const float3 D, const float g, const float2 rand, ccl_private float *pdf)
Definition volume_util.h:36
ccl_device_inline float3 phase_fournier_forand_coeffs(const float B, const float IOR)
ccl_device float phase_fournier_forand_newton(const float rand, const float3 coeffs)
ccl_device float3 phase_rayleigh_sample(const float3 D, const float2 rand, ccl_private float *pdf)
Definition volume_util.h:60
ccl_device float phase_henyey_greenstein(const float cos_theta, const float g)
Definition volume_util.h:27
ccl_device void phase_mie_fitted_parameters(float d, ccl_private float *g_HG, ccl_private float *g_D, ccl_private float *alpha, ccl_private float *w)
ccl_device float phase_draine_sample_cos(const float g, const float alpha, const float rand)
Definition volume_util.h:96
ccl_device float phase_fournier_forand_delta(const float n, const float sin_htheta_sqr)
CCL_NAMESPACE_BEGIN ccl_device float3 phase_sample_direction(const float3 D, const float cos_theta, const float rand)
Definition volume_util.h:13
ccl_device float3 phase_fournier_forand_sample(const float3 D, const float3 coeffs, const float2 rand, ccl_private float *pdf)
ccl_device float phase_rayleigh(const float cos_theta)
Definition volume_util.h:55
ccl_device float phase_fournier_forand(const float cos_theta, const float3 coeffs)