Blender V4.3
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 "util/math.h"
6#include "util/string.h"
7#include "util/system.h"
8
9#include "util/array.h"
10#include "util/hash.h"
11#include "util/task.h"
12
15
16#include "kernel/sample/lcg.h"
18
19#include "kernel/util/color.h"
20
22
23#include <iostream>
24
26
27static float precompute_ggx_E(float rough, float mu, float3 rand)
28{
29 MicrofacetBsdf bsdf;
30 bsdf.weight = one_float3();
31 bsdf.sample_weight = 1.0f;
32 bsdf.N = make_float3(0.0f, 0.0f, 1.0f);
33 bsdf.alpha_x = bsdf.alpha_y = sqr(rough);
34 bsdf.ior = 1.0f;
35 bsdf.T = make_float3(1.0f, 0.0f, 0.0f);
36
38
39 float3 omega_in;
40 Spectrum eval;
41 float pdf = 0.0f, sampled_eta;
42 float2 sampled_roughness;
44 make_float3(0.0f, 0.0f, 1.0f),
45 make_float3(sqrtf(1.0f - sqr(mu)), 0.0f, mu),
46 rand,
47 &eval,
48 &omega_in,
49 &pdf,
50 &sampled_roughness,
51 &sampled_eta);
52 if (pdf != 0.0f) {
53 return average(eval) / pdf;
54 }
55 return 0.0f;
56}
57
58static float precompute_ggx_glass_E(float rough, float mu, float eta, float3 rand)
59{
60 MicrofacetBsdf bsdf;
61 bsdf.weight = one_float3();
62 bsdf.sample_weight = 1.0f;
63 bsdf.N = make_float3(0.0f, 0.0f, 1.0f);
64 bsdf.alpha_x = bsdf.alpha_y = sqr(rough);
65 bsdf.ior = eta;
66 bsdf.T = make_float3(1.0f, 0.0f, 0.0f);
67
69
70 float3 omega_in;
71 Spectrum eval;
72 float pdf = 0.0f, sampled_eta;
73 float2 sampled_roughness;
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 float rough, float mu, float eta, float exponent, 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, sampled_eta;
115 float2 sampled_roughness;
117 make_float3(0.0f, 0.0f, 1.0f),
118 make_float3(sqrtf(1.0f - sqr(mu)), 0.0f, mu),
119 rand,
120 &eval,
121 &omega_in,
122 &pdf,
123 &sampled_roughness,
124 &sampled_eta);
125 if (pdf != 0.0f) {
126 /* The idea here is that the resulting Fresnel factor is always bounded by
127 * F0..F90, so it's enough to precompute and store the interpolation factor. */
128 return saturatef(eval.x / eval.y);
129 }
130 return 0.0f;
131}
132
133inline float ior_parametrization(float z)
134{
135 /* This parametrization ensures that the entire [1..inf] range of IORs is covered
136 * and that most precision is allocated to the common areas (1-2). */
137 return ior_from_F0(sqr(sqr(z)));
138}
139
142 int nx, ny, nz;
143 std::function<float(float, float, float, float3)> evaluation;
144};
145
146static bool cycles_precompute(std::string name)
147{
148 std::map<string, PrecomputeTerm> precompute_terms;
149 /* Overall albedo of the GGX microfacet BRDF, depending on cosI and roughness. */
150 precompute_terms["ggx_E"] = {1 << 23, 32, 32, 1, [](float rough, float mu, float, float3 rand) {
151 return precompute_ggx_E(rough, mu, rand);
152 }};
153 /* Overall albedo of the GGX microfacet BRDF, averaged over cosI */
154 precompute_terms["ggx_Eavg"] = {
155 1 << 26, 32, 1, 1, [](float rough, float mu, float, float3 rand) {
156 return 2.0f * mu * precompute_ggx_E(rough, mu, rand);
157 }};
158 /* Overall albedo of the GGX microfacet BSDF with dielectric Fresnel,
159 * depending on cosI and roughness, for IOR>1. */
160 precompute_terms["ggx_glass_E"] = {
161 1 << 23, 16, 16, 16, [](float rough, float mu, float z, float3 rand) {
162 float ior = ior_parametrization(z);
163 return precompute_ggx_glass_E(rough, mu, ior, rand);
164 }};
165 /* Overall albedo of the GGX microfacet BSDF with dielectric Fresnel,
166 * averaged over cosI, for IOR>1. */
167 precompute_terms["ggx_glass_Eavg"] = {
168 1 << 26, 16, 1, 16, [](float rough, float mu, float z, float3 rand) {
169 float ior = ior_parametrization(z);
170 return 2.0f * mu * precompute_ggx_glass_E(rough, mu, ior, rand);
171 }};
172 /* Overall albedo of the GGX microfacet BSDF with dielectric Fresnel,
173 * depending on cosI and roughness, for IOR<1. */
174 precompute_terms["ggx_glass_inv_E"] = {
175 1 << 23, 16, 16, 16, [](float rough, float mu, float z, float3 rand) {
176 float ior = ior_parametrization(z);
177 return precompute_ggx_glass_E(rough, mu, 1.0f / ior, rand);
178 }};
179 /* Overall albedo of the GGX microfacet BSDF with dielectric Fresnel,
180 * averaged over cosI, for IOR<1. */
181 precompute_terms["ggx_glass_inv_Eavg"] = {
182 1 << 26, 16, 1, 16, [](float rough, float mu, float z, float3 rand) {
183 float ior = ior_parametrization(z);
184 return 2.0f * mu * precompute_ggx_glass_E(rough, mu, 1.0f / ior, rand);
185 }};
186
187 /* Interpolation factor between F0 and F90 for the generalized Schlick Fresnel,
188 * depending on cosI and roughness, for IOR>1, using dielectric Fresnel mode. */
189 precompute_terms["ggx_gen_schlick_ior_s"] = {
190 1 << 20, 16, 16, 16, [](float rough, float mu, float z, float3 rand) {
191 float ior = ior_parametrization(z);
192 return precompute_ggx_gen_schlick_s(rough, mu, ior, -1.0f, rand);
193 }};
194
195 /* Interpolation factor between F0 and F90 for the generalized Schlick Fresnel,
196 * depending on cosI and roughness, for IOR>1. */
197 precompute_terms["ggx_gen_schlick_s"] = {
198 1 << 20, 16, 16, 16, [](float rough, float mu, float z, float3 rand) {
199 /* Remap 0..1 to 0..inf, with 0.5 mapping to 5 (the default value). */
200 float exponent = 5.0f * ((1.0f - z) / z);
201 return precompute_ggx_gen_schlick_s(rough, mu, 1.0f, exponent, rand);
202 }};
203
204 if (precompute_terms.count(name) == 0) {
205 return false;
206 }
207
208 const PrecomputeTerm &term = precompute_terms[name];
209
210 const int samples = term.samples;
211 const int nz = term.nz, ny = term.ny, nx = term.nx;
212
213 std::cout << "static const float table_" << name << "[" << nz * ny * nx << "] = {" << std::endl;
214 for (int z = 0; z < nz; z++) {
215 array<float> data(nx * ny);
216 parallel_for(0, nx * ny, [&](int64_t i) {
217 int y = i / nx, x = i % nx;
218 uint seed = hash_uint2(x, y);
219 double sum = 0.0;
220 for (int sample = 0; sample < samples; sample++) {
221 float4 rand = sobol_burley_sample_4D(sample, 0, seed, 0xffffffff);
222
223 float rough = (nx == 1) ? 0.0f : clamp(float(x) / float(nx - 1), 1e-4f, 1.0f);
224 float mu = (ny == 1) ? rand.w : clamp(float(y) / float(ny - 1), 1e-4f, 1.0f);
225 float ior = (nz == 1) ? 0.0f : clamp(float(z) / float(nz - 1), 1e-4f, 0.99f);
226
227 float value = term.evaluation(rough, mu, ior, float4_to_float3(rand));
228 if (isnan(value)) {
229 value = 0.0f;
230 }
231 sum += (double)value;
232 }
233 data[y * nx + x] = saturatef(float(sum / double(samples)));
234 });
235
236 /* Print data formatted as C++ array */
237 for (int y = 0; y < ny; y++) {
238 std::cout << " ";
239 for (int x = 0; x < nx; x++) {
240 std::cout << std::to_string(data[y * nx + x]);
241 if (x + 1 < nx) {
242 /* Next number will follow in same line */
243 std::cout << "f, ";
244 }
245 else if (y + 1 < ny || z + 1 < nz) {
246 /* Next number will follow in next line */
247 std::cout << "f,";
248 }
249 else {
250 /* No next number */
251 std::cout << "f";
252 }
253 }
254 std::cout << std::endl;
255 }
256 /* If the array is three-dimensional, put an empty line between each slice. */
257 if (ny > 1 && z + 1 < nz) {
258 std::cout << std::endl;
259 }
260 }
261 std::cout << "};" << std::endl;
262
263 return true;
264}
265
267
268int main(int argc, const char **argv)
269{
270 if (argc < 2) {
271 return 1;
272 }
273 return ccl::cycles_precompute(argv[1]) ? 0 : 1;
274}
unsigned int uint
typedef double(DMatrix)[4][4]
ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals kg, ccl_private const ShaderClosure *sc, float3 Ng, 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)
@ GENERALIZED_SCHLICK
ccl_device int bsdf_microfacet_ggx_glass_setup(ccl_private MicrofacetBsdf *bsdf)
ccl_device int bsdf_microfacet_ggx_setup(ccl_private MicrofacetBsdf *bsdf)
ccl_device float ior_from_F0(float f0)
Definition bsdf_util.h:106
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
static bool cycles_precompute(std::string name)
static CCL_NAMESPACE_BEGIN float precompute_ggx_E(float rough, float mu, float3 rand)
float ior_parametrization(float z)
static float precompute_ggx_glass_E(float rough, float mu, float eta, float3 rand)
static float precompute_ggx_gen_schlick_s(float rough, float mu, float eta, float exponent, 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 sqrtf(x)
draw_view in_light_buf[] float
ccl_device_inline uint hash_uint2(uint kx, uint ky)
Definition hash.h:89
ShaderClosure
ccl_device_inline float average(const float2 a)
ccl_device_inline float3 one_float3()
Definition math_float3.h:24
int main()
ccl_device float4 sobol_burley_sample_4D(uint index, const uint dimension_set, uint seed, uint shuffled_index_mask)
__int64 int64_t
Definition stdint.h:89
ccl_private void * fresnel
std::function< float(float, float, float, float3)> evaluation
SPECTRUM_DATA_TYPE Spectrum
ccl_device_inline float sqr(float a)
Definition util/math.h:782
ccl_device_inline float3 float4_to_float3(const float4 a)
Definition util/math.h:535
ccl_device_inline int clamp(int a, int mn, int mx)
Definition util/math.h:379