Blender V5.0
cycles_precompute.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include <map>
6
7#include "util/string.h"
8
9#include "util/array.h"
10#include "util/hash.h"
11#include "util/tbb.h"
12
15
16#include <iostream>
17
19
20static float precompute_ggx_E(const float rough, const float mu, const float3 rand)
21{
22 MicrofacetBsdf bsdf;
23 bsdf.weight = one_float3();
24 bsdf.sample_weight = 1.0f;
25 bsdf.N = make_float3(0.0f, 0.0f, 1.0f);
26 bsdf.alpha_x = bsdf.alpha_y = sqr(rough);
27 bsdf.ior = 1.0f;
28 bsdf.T = make_float3(1.0f, 0.0f, 0.0f);
29
31
32 float3 omega_in;
33 Spectrum eval;
34 float pdf = 0.0f;
35 float sampled_eta;
36 float2 sampled_roughness;
38 (ShaderClosure *)&bsdf,
39 make_float3(0.0f, 0.0f, 1.0f),
40 make_float3(sqrtf(1.0f - sqr(mu)), 0.0f, mu),
41 rand,
42 &eval,
43 &omega_in,
44 &pdf,
45 &sampled_roughness,
46 &sampled_eta);
47 if (pdf != 0.0f) {
48 return average(eval) / pdf;
49 }
50 return 0.0f;
51}
52
53static float precompute_ggx_glass_E(const float rough,
54 const float mu,
55 const float eta,
56 const float3 rand)
57{
58 MicrofacetBsdf bsdf;
59 bsdf.weight = one_float3();
60 bsdf.sample_weight = 1.0f;
61 bsdf.N = make_float3(0.0f, 0.0f, 1.0f);
62 bsdf.alpha_x = bsdf.alpha_y = sqr(rough);
63 bsdf.ior = eta;
64 bsdf.T = make_float3(1.0f, 0.0f, 0.0f);
65
67
68 float3 omega_in;
69 Spectrum eval;
70 float pdf = 0.0f;
71 float sampled_eta;
72 float2 sampled_roughness;
74 (ShaderClosure *)&bsdf,
75 make_float3(0.0f, 0.0f, 1.0f),
76 make_float3(sqrtf(1.0f - sqr(mu)), 0.0f, mu),
77 rand,
78 &eval,
79 &omega_in,
80 &pdf,
81 &sampled_roughness,
82 &sampled_eta);
83 if (pdf != 0.0f) {
84 return average(eval) / pdf;
85 }
86 return 0.0f;
87}
88
90 const float rough, const float mu, const float eta, const float exponent, const float3 rand)
91{
92 MicrofacetBsdf bsdf;
93 bsdf.weight = one_float3();
94 bsdf.sample_weight = 1.0f;
95 bsdf.N = make_float3(0.0f, 0.0f, 1.0f);
96 bsdf.alpha_x = bsdf.alpha_y = sqr(rough);
97 bsdf.ior = eta;
98 bsdf.T = make_float3(1.0f, 0.0f, 0.0f);
99
101
103 fresnel.reflection_tint = one_float3();
104 fresnel.transmission_tint = one_float3();
105 fresnel.f0 = make_float3(0.0f, 1.0f, 0.0f);
106 fresnel.f90 = make_float3(1.0f, 1.0f, 0.0f);
107 fresnel.exponent = exponent;
108
110 bsdf.fresnel = &fresnel;
111
112 float3 omega_in;
113 Spectrum eval;
114 float pdf = 0.0f;
115 float sampled_eta;
116 float2 sampled_roughness;
118 (ShaderClosure *)&bsdf,
119 make_float3(0.0f, 0.0f, 1.0f),
120 make_float3(sqrtf(1.0f - sqr(mu)), 0.0f, mu),
121 rand,
122 &eval,
123 &omega_in,
124 &pdf,
125 &sampled_roughness,
126 &sampled_eta);
127 if (pdf != 0.0f) {
128 /* The idea here is that the resulting Fresnel factor is always bounded by
129 * F0..F90, so it's enough to precompute and store the interpolation factor. */
130 return saturatef(eval.x / eval.y);
131 }
132 return 0.0f;
133}
134
135inline float ior_parametrization(const float z)
136{
137 /* This parametrization ensures that the entire [1..inf] range of IORs is covered
138 * and that most precision is allocated to the common areas (1-2). */
139 return ior_from_F0(sqr(sqr(z)));
140}
141
144 int nx, ny, nz;
145 std::function<float(float, float, float, float3)> evaluation;
146};
147
148static bool cycles_precompute(std::string name)
149{
150 std::map<string, PrecomputeTerm> precompute_terms;
151 /* Overall albedo of the GGX microfacet BRDF, depending on cosI and roughness. */
152 precompute_terms["ggx_E"] = {
153 1 << 23, 32, 32, 1, [](const float rough, const float mu, float, const float3 rand) {
154 return precompute_ggx_E(rough, mu, rand);
155 }};
156 /* Overall albedo of the GGX microfacet BRDF, averaged over cosI */
157 precompute_terms["ggx_Eavg"] = {
158 1 << 26, 32, 1, 1, [](const float rough, const float mu, float, const float3 rand) {
159 return 2.0f * mu * precompute_ggx_E(rough, mu, rand);
160 }};
161 /* Overall albedo of the GGX microfacet BSDF with dielectric Fresnel,
162 * depending on cosI and roughness, for IOR>1. */
163 precompute_terms["ggx_glass_E"] = {
164 1 << 23,
165 16,
166 16,
167 16,
168 [](const float rough, const float mu, const float z, const float3 rand) {
169 const float ior = ior_parametrization(z);
170 return precompute_ggx_glass_E(rough, mu, ior, rand);
171 }};
172 /* Overall albedo of the GGX microfacet BSDF with dielectric Fresnel,
173 * averaged over cosI, for IOR>1. */
174 precompute_terms["ggx_glass_Eavg"] = {
175 1 << 26, 16, 1, 16, [](const float rough, const float mu, const float z, const float3 rand) {
176 const float ior = ior_parametrization(z);
177 return 2.0f * mu * precompute_ggx_glass_E(rough, mu, ior, rand);
178 }};
179 /* Overall albedo of the GGX microfacet BSDF with dielectric Fresnel,
180 * depending on cosI and roughness, for IOR<1. */
181 precompute_terms["ggx_glass_inv_E"] = {
182 1 << 23,
183 16,
184 16,
185 16,
186 [](const float rough, const float mu, const float z, const float3 rand) {
187 const float ior = ior_parametrization(z);
188 return precompute_ggx_glass_E(rough, mu, 1.0f / ior, rand);
189 }};
190 /* Overall albedo of the GGX microfacet BSDF with dielectric Fresnel,
191 * averaged over cosI, for IOR<1. */
192 precompute_terms["ggx_glass_inv_Eavg"] = {
193 1 << 26, 16, 1, 16, [](const float rough, const float mu, const float z, const float3 rand) {
194 const float ior = ior_parametrization(z);
195 return 2.0f * mu * precompute_ggx_glass_E(rough, mu, 1.0f / ior, rand);
196 }};
197
198 /* Interpolation factor between F0 and F90 for the generalized Schlick Fresnel,
199 * depending on cosI and roughness, for IOR>1, using dielectric Fresnel mode. */
200 precompute_terms["ggx_gen_schlick_ior_s"] = {
201 1 << 20,
202 16,
203 16,
204 16,
205 [](const float rough, const float mu, const float z, const float3 rand) {
206 const float ior = ior_parametrization(z);
207 return precompute_ggx_gen_schlick_s(rough, mu, ior, -1.0f, rand);
208 }};
209
210 /* Interpolation factor between F0 and F90 for the generalized Schlick Fresnel,
211 * depending on cosI and roughness, for IOR>1. */
212 precompute_terms["ggx_gen_schlick_s"] = {
213 1 << 20,
214 16,
215 16,
216 16,
217 [](const float rough, const float mu, const float z, const float3 rand) {
218 /* Remap 0..1 to 0..inf, with 0.5 mapping to 5 (the default value). */
219 const float exponent = 5.0f * ((1.0f - z) / z);
220 return precompute_ggx_gen_schlick_s(rough, mu, 1.0f, exponent, rand);
221 }};
222
223 if (precompute_terms.count(name) == 0) {
224 return false;
225 }
226
227 const PrecomputeTerm &term = precompute_terms[name];
228
229 const int samples = term.samples;
230 const int nz = term.nz;
231 const int ny = term.ny;
232 const int nx = term.nx;
233
234 std::cout << "static const float table_" << name << "[" << nz * ny * nx << "] = {" << std::endl;
235 for (int z = 0; z < nz; z++) {
236 array<float> data(nx * ny);
237 parallel_for(0, nx * ny, [&](int64_t i) {
238 const int y = i / nx;
239 const int x = i % nx;
240 const uint seed = hash_uint2(x, y);
241 double sum = 0.0;
242 for (int sample = 0; sample < samples; sample++) {
243 const float4 rand = sobol_burley_sample_4D(sample, 0, seed, 0xffffffff);
244
245 const float rough = (nx == 1) ? 0.0f : clamp(float(x) / float(nx - 1), 1e-4f, 1.0f);
246 const float mu = (ny == 1) ? rand.w : clamp(float(y) / float(ny - 1), 1e-4f, 1.0f);
247 const float ior = (nz == 1) ? 0.0f : clamp(float(z) / float(nz - 1), 1e-4f, 0.99f);
248
249 float value = term.evaluation(rough, mu, ior, make_float3(rand));
250 if (isnan(value)) {
251 value = 0.0f;
252 }
253 sum += (double)value;
254 }
255 data[y * nx + x] = saturatef(float(sum / double(samples)));
256 });
257
258 /* Print data formatted as C++ array */
259 for (int y = 0; y < ny; y++) {
260 std::cout << " ";
261 for (int x = 0; x < nx; x++) {
262 std::cout << std::to_string(data[y * nx + x]);
263 if (x + 1 < nx) {
264 /* Next number will follow in same line */
265 std::cout << "f, ";
266 }
267 else if (y + 1 < ny || z + 1 < nz) {
268 /* Next number will follow in next line */
269 std::cout << "f,";
270 }
271 else {
272 /* No next number */
273 std::cout << "f";
274 }
275 }
276 std::cout << std::endl;
277 }
278 /* If the array is three-dimensional, put an empty line between each slice. */
279 if (ny > 1 && z + 1 < nz) {
280 std::cout << std::endl;
281 }
282 }
283 std::cout << "};" << std::endl;
284
285 return true;
286}
287
289
290int main(const int argc, const char **argv)
291{
292 if (argc < 2) {
293 return 1;
294 }
295 return ccl::cycles_precompute(argv[1]) ? 0 : 1;
296}
unsigned int uint
BMesh const char void * data
@ GENERALIZED_SCHLICK
ccl_device int bsdf_microfacet_ggx_glass_setup(ccl_private MicrofacetBsdf *bsdf)
ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals kg, const ccl_private ShaderClosure *sc, const float3 Ng, const float3 wi, const float3 rand, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf, ccl_private float2 *sampled_roughness, ccl_private float *eta)
ccl_device int bsdf_microfacet_ggx_setup(ccl_private MicrofacetBsdf *bsdf)
ccl_device float ior_from_F0(const float f0)
Definition bsdf_util.h:250
long long int int64_t
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
static T sum(const btAlignedObjectArray< T > &items)
static unsigned long seed
Definition btSoftBody.h:39
nullptr float
static float precompute_ggx_glass_E(const float rough, const float mu, const float eta, const float3 rand)
float ior_parametrization(const float z)
static CCL_NAMESPACE_BEGIN float precompute_ggx_E(const float rough, const float mu, const float3 rand)
static bool cycles_precompute(std::string name)
static float precompute_ggx_gen_schlick_s(const float rough, const float mu, const float eta, const float exponent, const float3 rand)
#define CCL_NAMESPACE_END
#define saturatef(x)
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define main()
#define isnan
constexpr T clamp(T, U, U) RET
ccl_device_inline uint hash_uint2(const uint kx, const uint ky)
Definition hash.h:139
ccl_device_inline float3 one_float3()
Definition math_float3.h:26
float average(point a)
Definition node_math.h:144
const char * name
#define sqr
#define sqrtf
ccl_device float4 sobol_burley_sample_4D(uint index, const uint dimension_set, uint seed, const uint shuffled_index_mask)
ccl_private void * fresnel
std::function< float(float, float, float, float3)> evaluation
float y
Definition sky_math.h:136
float x
Definition sky_math.h:136
float w
Definition sky_math.h:225
i
Definition text_draw.cc:230
float3 Spectrum