Blender V4.3
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
8
9/* Given a random number, sample a direction that makes an angle of theta with direction D. */
11{
13 float phi = M_2PI_F * rand;
15
16 float3 T, B;
17 make_orthonormals(D, &T, &B);
18 dir = dir.x * T + dir.y * B + dir.z * D;
19
20 return dir;
21}
22
23/* Given cosine between rays, return probability density that a photon bounces
24 * to that direction. The g parameter controls how different it is from the
25 * uniform sphere. g=0 uniform diffuse-like, g=1 close to sharp single ray. */
27{
28 if (fabsf(g) < 1e-3f) {
29 return M_1_4PI_F;
30 }
31 const float fac = 1 + g * (g - 2 * cos_theta);
32 return (1 - sqr(g)) / (M_4PI_F * fac * safe_sqrtf(fac));
33}
34
36 float g,
37 float2 rand,
38 ccl_private float *pdf)
39{
40 float cos_theta = 1 - 2 * rand.x;
41 if (fabsf(g) >= 1e-3f) {
42 const float k = (1 - sqr(g)) / (1 - g * cos_theta);
43 cos_theta = (1 + sqr(g) - sqr(k)) / (2 * g);
44 }
45
47
48 return phase_sample_direction(D, cos_theta, rand.y);
49}
50
51/* Given cosine between rays, return probability density that a photon bounces to that direction
52 * according to the constant Rayleigh phase function.
53 * See https://doi.org/10.1364/JOSAA.28.002436 for details. */
55{
56 return (0.1875f * M_1_PI_F) * (1.0f + sqr(cos_theta));
57}
58
60{
61 const float a = 2 - 4 * rand.x;
62 /* Metal doesn't have cbrtf, but since we compute u - 1/u anyways, we can just as well
63 * use the inverse cube root for which there is a simple Quake-style fast implementation.*/
64 const float inv_u = -fast_inv_cbrtf(sqrtf(1 + sqr(a)) + a);
65 const float cos_theta = 1 / inv_u - inv_u;
67
68 return phase_sample_direction(D, cos_theta, rand.y);
69}
70
71/* Given cosine between rays, return probability density that a photon bounces to that direction
72 * according to the Draine phase function. This is a generalization of the Henyey-Greenstein
73 * function which bridges the cases of HG and Rayleigh scattering. The parameter g mainly controls
74 * the first moment <cos theta>, and alpha the second moment <cos2 theta> of the exact phase
75 * function. alpha=0 reduces to HG function, g=0, alpha=1 reduces to Rayleigh function, alpha=1
76 * reduces to Cornette-Shanks function.
77 * See https://doi.org/10.1086/379118 for details. */
78ccl_device float phase_draine(float cos_theta, float g, float alpha)
79{
80 /* Check special cases. */
81 if (fabsf(g) < 1e-3f && alpha > 0.999f) {
83 }
84 else if (fabsf(alpha) < 1e-3f) {
86 }
87
88 const float g2 = sqr(g);
89 const float fac = 1 + g2 - 2 * g * cos_theta;
90 return ((1 - g2) * (1 + alpha * sqr(cos_theta))) /
91 ((1 + (alpha * (1 + 2 * g2)) * (1 / 3.0f)) * M_4PI_F * fac * sqrtf(fac));
92}
93
94/* Adapted from the HLSL code provided in https://research.nvidia.com/labs/rtr/approximate-mie/ */
95ccl_device float phase_draine_sample_cos(float g, float alpha, float rand)
96{
97 if (fabsf(g) < 1e-2f) {
98 /* Special case to prevent division by zero.
99 * The sample technique is similar as in https://doi.org/10.1364/JOSAA.28.002436. */
100 const float inv_alpha = 1.0f / alpha;
101 const float b_2 = (3 + alpha) * inv_alpha * (0.5f - rand);
102 const float inv_u = -fast_inv_cbrtf(b_2 + sqrtf(sqr(b_2) + sqr(inv_alpha) * inv_alpha));
103 return 1 / inv_u - inv_u / alpha;
104 }
105 const float g2 = sqr(g), g3 = g * g2, g4 = sqr(g2), g6 = g2 * g4;
106 const float pgp1_2 = sqr(1 + g2);
107 const float T1a = alpha * (g4 - 1), T1a3 = sqr(T1a) * T1a;
108 const float T2 = -1296 * (g2 - 1) * (alpha - alpha * g2) * T1a * (4 * g2 + alpha * pgp1_2);
109 const float T9 = 2 + g2 + g3 * (1 + 2 * g2) * (2 * rand - 1);
110 const float T3 = 3 * g2 * (1 + g * (2 * rand - 1)) + alpha * T9;
111 const float T4a = 432 * T1a3 + T2 + 432 * (alpha * (1 - g2)) * sqr(T3);
112 const float T10 = alpha * (2 * g4 - g2 - g6);
113 const float T4b = 144 * T10, T4b3 = sqr(T4b) * T4b;
114 const float T4 = T4a + sqrtf(-4 * T4b3 + sqr(T4a));
115 const float inv_T4p3 = fast_inv_cbrtf(T4);
116 const float T8 = 48 * M_CBRT2_F * T10;
117 const float T6 = (2 * T1a + T8 * inv_T4p3 + 1 / (3 * M_CBRT2_F * inv_T4p3)) / (alpha * (1 - g2));
118 const float T5 = 6 * (1 + g2) + T6;
119 const float T7 = 6 * (1 + g2) - (8 * T3) / (alpha * (g2 - 1) * sqrtf(T5)) - T6;
120 return (1 + g2 - 0.25f * sqr(sqrtf(T7) - sqrtf(T5))) / (2 * g);
121}
122
124phase_draine_sample(float3 D, float g, float alpha, float2 rand, ccl_private float *pdf)
125{
126 /* Check special cases. */
127 if (fabsf(g) < 1e-3f && alpha > 0.999f) {
128 return phase_rayleigh_sample(D, rand, pdf);
129 }
130 else if (fabsf(alpha) < 1e-3f) {
131 return phase_henyey_greenstein_sample(D, g, rand, pdf);
132 }
133
134 const float cos_theta = phase_draine_sample_cos(g, alpha, rand.x);
135 *pdf = phase_draine(cos_theta, g, alpha);
136
137 return phase_sample_direction(D, cos_theta, rand.y);
138}
139
140ccl_device float phase_fournier_forand_delta(float n, float sin_htheta_sqr)
141{
142 float u = 4 * sin_htheta_sqr;
143 return u / (3 * sqr(n - 1));
144}
145
147{
148 const float d90 = phase_fournier_forand_delta(IOR, 0.5f);
149 const float d180 = phase_fournier_forand_delta(IOR, 1.0f);
150 const float v = -logf(2 * B * (d90 - 1) + 1) / logf(d90);
151 return make_float3(IOR, v, (powf(d180, -v) - 1) / (d180 - 1));
152}
153
154/* Given cosine between rays, return probability density that a photon bounces to that direction
155 * according to the Fournier-Forand phase function. The n parameter is the particle index of
156 * refraction and controls how much of the light is refracted. B is the particle backscatter
157 * fraction, B = b_b / b.
158 * See https://doi.org/10.1117/12.366488 for details. */
160 float cos_theta, float delta, float pow_delta_v, float v, float sin_htheta_sqr, float pf_coeff)
161{
162 const float m_delta = 1 - delta, m_pow_delta_v = 1 - pow_delta_v;
163
164 float pf;
165 if (fabsf(m_delta) < 1e-3f) {
166 /* Special case (first-order Taylor expansion) to avoid singularity at delta near 1.0 */
167 pf = v * ((v - 1) - (v + 1) / sin_htheta_sqr) * (1 / (8 * M_PI_F));
168 pf += v * (v + 1) * m_delta * (2 * (v - 1) - (2 * v + 1) / sin_htheta_sqr) *
169 (1 / (24 * M_PI_F));
170 }
171 else {
172 pf = (v * m_delta - m_pow_delta_v + (delta * m_pow_delta_v - v * m_delta) / sin_htheta_sqr) /
173 (M_4PI_F * sqr(m_delta) * pow_delta_v);
174 }
175 pf += pf_coeff * (3 * sqr(cos_theta) - 1);
176 return pf;
177}
178
180{
181 if (fabsf(cos_theta) >= 1.0f) {
182 return 0.0f;
183 }
184
185 const float n = coeffs.x, v = coeffs.y;
186 const float pf_coeff = coeffs.z * (1.0f / (16.0f * M_PI_F));
187 const float sin_htheta_sqr = 0.5f * (1 - cos_theta); /* sin^2(theta / 2)*/
188 const float delta = phase_fournier_forand_delta(n, sin_htheta_sqr);
189
190 return phase_fournier_forand_impl(cos_theta, delta, powf(delta, v), v, sin_htheta_sqr, pf_coeff);
191}
192
194{
195 const float n = coeffs.x, v = coeffs.y;
196 const float cdf_coeff = coeffs.z * (1.0f / 8.0f);
197 const float pf_coeff = coeffs.z * (1.0f / (16.0f * M_PI_F));
198
199 float cos_theta = 0.64278760968f; /* Initial guess: 50 degrees */
200 for (int it = 0; it < 20; it++) {
201 const float sin_htheta_sqr = 0.5f * (1 - cos_theta); /* sin^2(theta / 2)*/
202 const float delta = phase_fournier_forand_delta(n, sin_htheta_sqr);
203 const float pow_delta_v = powf(delta, v);
204 const float m_delta = 1 - delta, m_pow_delta_v = 1 - pow_delta_v;
205
206 /* Evaluate CDF and phase functions */
207 float cdf;
208 if (fabsf(m_delta) < 1e-3f) {
209 /* Special case (first-order Taylor expansion) to avoid singularity at delta near 1.0 */
210 cdf = 1 + v * (1 - sin_htheta_sqr) * (1 - 0.5f * (v + 1) * m_delta);
211 }
212 else {
213 cdf = (1 - pow_delta_v * delta - m_pow_delta_v * sin_htheta_sqr) / (m_delta * pow_delta_v);
214 }
215 cdf += cdf_coeff * cos_theta * (1 - sqr(cos_theta));
216 const float pf = phase_fournier_forand_impl(
217 cos_theta, delta, pow_delta_v, v, sin_htheta_sqr, pf_coeff);
218
219 /* Perform Newton iteration step */
220 float new_cos_theta = cos_theta + M_1_2PI_F * (cdf - rand) / pf;
221
222 /* Don't step off past 1.0, approach the peak slowly */
223 if (new_cos_theta >= 1.0f) {
224 new_cos_theta = max(mix(cos_theta, 1.0f, 0.5f), 0.99f);
225 }
226 if (fabsf(cos_theta - new_cos_theta) < 1e-6f || new_cos_theta == 1.0f) {
227 return new_cos_theta;
228 }
229 cos_theta = new_cos_theta;
230 }
231 /* Reached iteration limit, so give up and use what we have. */
232 return cos_theta;
233}
234
236 float3 coeffs,
237 float2 rand,
238 ccl_private float *pdf)
239{
240 float cos_theta = phase_fournier_forand_newton(rand.x, coeffs);
241 *pdf = phase_fournier_forand(cos_theta, coeffs);
242
243 return phase_sample_direction(D, cos_theta, rand.y);
244}
245
#define D
MINLINE float safe_sqrtf(float a)
ATTR_WARN_UNUSED_RESULT const BMVert * v
ccl_device_inline float cos_theta(const float3 w)
ccl_device_inline float sin_theta(const float3 w)
btVector3 m_delta
#define logf(x)
#define sinf(x)
#define cosf(x)
#define ccl_device
#define ccl_private
#define ccl_device_inline
#define powf(x, y)
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define fabsf(x)
#define sqrtf(x)
#define pf(_x, _i)
Prefetch 64.
Definition gim_memory.h:48
#define mix(a, b, c)
Definition hash.h:36
ccl_device_inline float fast_inv_cbrtf(float x)
Definition math_fast.h:638
#define T
#define B
#define T9
Definition md5.cpp:26
#define T2
Definition md5.cpp:19
#define T7
Definition md5.cpp:24
#define T10
Definition md5.cpp:27
#define T6
Definition md5.cpp:23
#define T3
Definition md5.cpp:20
#define T5
Definition md5.cpp:22
#define T4
Definition md5.cpp:21
#define T8
Definition md5.cpp:25
#define M_PI_F
Definition mikk_util.hh:15
#define M_2PI_F
Definition sky_float3.h:23
float x
float y
float z
Definition sky_float3.h:27
float y
Definition sky_float3.h:27
float x
Definition sky_float3.h:27
float max
ccl_device_inline float sqr(float a)
Definition util/math.h:782
ccl_device_inline float sin_from_cos(const float c)
Definition util/math.h:787
ccl_device_inline void make_orthonormals(const float3 N, ccl_private float3 *a, ccl_private float3 *b)
Definition util/math.h:593
ccl_device float phase_henyey_greenstein(float cos_theta, float g)
Definition volume_util.h:26
ccl_device float3 phase_henyey_greenstein_sample(float3 D, float g, float2 rand, ccl_private float *pdf)
Definition volume_util.h:35
ccl_device float phase_fournier_forand_newton(float rand, float3 coeffs)
ccl_device float phase_rayleigh(float cos_theta)
Definition volume_util.h:54
ccl_device float phase_draine(float cos_theta, float g, float alpha)
Definition volume_util.h:78
ccl_device float3 phase_fournier_forand_sample(float3 D, float3 coeffs, float2 rand, ccl_private float *pdf)
ccl_device float3 phase_rayleigh_sample(float3 D, float2 rand, ccl_private float *pdf)
Definition volume_util.h:59
ccl_device float phase_fournier_forand_delta(float n, float sin_htheta_sqr)
ccl_device_inline float3 phase_fournier_forand_coeffs(float B, float IOR)
ccl_device float phase_fournier_forand(float cos_theta, float3 coeffs)
ccl_device float phase_draine_sample_cos(float g, float alpha, float rand)
Definition volume_util.h:95
ccl_device float3 phase_draine_sample(float3 D, float g, float alpha, float2 rand, ccl_private float *pdf)
CCL_NAMESPACE_BEGIN ccl_device float3 phase_sample_direction(float3 D, float cos_theta, float rand)
Definition volume_util.h:10
ccl_device_inline float phase_fournier_forand_impl(float cos_theta, float delta, float pow_delta_v, float v, float sin_htheta_sqr, float pf_coeff)