[Bf-blender-cvs] [0b89f591b4d] principled-v2: Add precomputation code that reproduces the albedo tables

Lukas Stockner noreply at git.blender.org
Mon Jul 4 23:56:12 CEST 2022


Commit: 0b89f591b4d0847ef2cde989d090e6480116d54d
Author: Lukas Stockner
Date:   Mon Jul 4 23:31:47 2022 +0200
Branches: principled-v2
https://developer.blender.org/rB0b89f591b4d0847ef2cde989d090e6480116d54d

Add precomputation code that reproduces the albedo tables

===================================================================

M	intern/cycles/app/CMakeLists.txt
A	intern/cycles/app/cycles_precompute.cpp
M	intern/cycles/app/cycles_standalone.cpp

===================================================================

diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt
index 6aea962eab5..4e7911fc1ce 100644
--- a/intern/cycles/app/CMakeLists.txt
+++ b/intern/cycles/app/CMakeLists.txt
@@ -60,6 +60,7 @@ include_directories(SYSTEM ${INC_SYS})
 if(WITH_CYCLES_STANDALONE)
   set(SRC
     cycles_standalone.cpp
+    cycles_precompute.cpp
     cycles_xml.cpp
     cycles_xml.h
     oiio_output_driver.cpp
diff --git a/intern/cycles/app/cycles_precompute.cpp b/intern/cycles/app/cycles_precompute.cpp
new file mode 100644
index 00000000000..eb5fe2f13f9
--- /dev/null
+++ b/intern/cycles/app/cycles_precompute.cpp
@@ -0,0 +1,249 @@
+#include "util/math.h"
+#include "util/string.h"
+#include "util/system.h"
+
+#include "util/hash.h"
+#include "util/task.h"
+
+#include "kernel/device/cpu/compat.h"
+#include "kernel/device/cpu/globals.h"
+
+#include "kernel/sample/lcg.h"
+#include "kernel/sample/mapping.h"
+
+#include "kernel/closure/bsdf_microfacet.h"
+#include "kernel/closure/bsdf_microfacet_glass.h"
+
+#include <iostream>
+
+CCL_NAMESPACE_BEGIN
+
+/* From PBRT: core/montecarlo.h */
+inline float VanDerCorput(uint32_t n, uint32_t scramble)
+{
+  n = (n << 16) | (n >> 16);
+  n = ((n & 0x00ff00ff) << 8) | ((n & 0xff00ff00) >> 8);
+  n = ((n & 0x0f0f0f0f) << 4) | ((n & 0xf0f0f0f0) >> 4);
+  n = ((n & 0x33333333) << 2) | ((n & 0xcccccccc) >> 2);
+  n = ((n & 0x55555555) << 1) | ((n & 0xaaaaaaaa) >> 1);
+  n ^= scramble;
+  return ((n >> 8) & 0xffffff) / float(1 << 24);
+}
+inline float Sobol2(uint32_t n, uint32_t scramble)
+{
+  for (uint32_t v = 1 << 31; n != 0; n >>= 1, v ^= v >> 1)
+    if (n & 0x1)
+      scramble ^= v;
+  return ((scramble >> 8) & 0xffffff) / float(1 << 24);
+}
+
+static float precompute_ggx_E(float rough, float mu, float u1, float u2)
+{
+  MicrofacetBsdf bsdf;
+  bsdf.weight = one_float3();
+  bsdf.type = CLOSURE_BSDF_MICROFACET_GGX_ID;
+  bsdf.sample_weight = 1.0f;
+  bsdf.N = make_float3(0.0f, 0.0f, 1.0f);
+  bsdf.alpha_x = bsdf.alpha_y = sqr(rough);
+  bsdf.ior = 1.0f;
+  bsdf.extra = nullptr;
+  bsdf.T = make_float3(1.0f, 0.0f, 0.0f);
+
+  float3 eval, omega_in, domega_in_dx, domega_in_dy;
+  float pdf = 0.0f;
+  bsdf_microfacet_ggx_sample((ShaderClosure *)&bsdf,
+                             make_float3(0.0f, 0.0f, 1.0f),
+                             make_float3(sqrtf(1.0f - sqr(mu)), 0.0f, mu),
+                             zero_float3(),
+                             zero_float3(),
+                             u1,
+                             u2,
+                             &eval,
+                             &omega_in,
+                             &domega_in_dx,
+                             &domega_in_dy,
+                             &pdf);
+  if (pdf != 0.0f) {
+    return average(eval) / pdf;
+  }
+  return 0.0f;
+}
+
+static float precompute_ggx_refract_E(float rough, float mu, float eta, float u1, float u2)
+{
+  MicrofacetBsdf bsdf;
+  bsdf.weight = one_float3();
+  bsdf.type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
+  bsdf.sample_weight = 1.0f;
+  bsdf.N = make_float3(0.0f, 0.0f, 1.0f);
+  bsdf.alpha_x = bsdf.alpha_y = sqr(rough);
+  bsdf.ior = eta;
+  bsdf.extra = nullptr;
+  bsdf.T = make_float3(1.0f, 0.0f, 0.0f);
+
+  float3 eval, omega_in, domega_in_dx, domega_in_dy;
+  float pdf = 0.0f;
+  bsdf_microfacet_ggx_sample((ShaderClosure *)&bsdf,
+                             make_float3(0.0f, 0.0f, 1.0f),
+                             make_float3(sqrtf(1.0f - sqr(mu)), 0.0f, mu),
+                             zero_float3(),
+                             zero_float3(),
+                             u1,
+                             u2,
+                             &eval,
+                             &omega_in,
+                             &domega_in_dx,
+                             &domega_in_dy,
+                             &pdf);
+  if (pdf != 0.0f) {
+    return average(eval) / pdf;
+  }
+  return 0.0f;
+}
+
+static float precompute_ggx_glass_E(
+    float rough, float mu, float eta, float u1, float u2, uint *rng)
+{
+  MicrofacetBsdf bsdf;
+  bsdf.weight = one_float3();
+  bsdf.type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
+  bsdf.sample_weight = 1.0f;
+  bsdf.N = make_float3(0.0f, 0.0f, 1.0f);
+  bsdf.alpha_x = bsdf.alpha_y = sqr(rough);
+  bsdf.ior = eta;
+  bsdf.extra = nullptr;
+  bsdf.T = make_float3(1.0f, 0.0f, 0.0f);
+
+  float3 eval, omega_in, domega_in_dx, domega_in_dy;
+  float pdf = 0.0f;
+  bsdf_microfacet_ggx_glass_sample((ShaderClosure *)&bsdf,
+                                   make_float3(0.0f, 0.0f, 1.0f),
+                                   make_float3(sqrtf(1.0f - sqr(mu)), 0.0f, mu),
+                                   zero_float3(),
+                                   zero_float3(),
+                                   u1,
+                                   u2,
+                                   &eval,
+                                   &omega_in,
+                                   &domega_in_dx,
+                                   &domega_in_dy,
+                                   &pdf,
+                                   rng);
+  if (pdf != 0.0f) {
+    return average(eval) / pdf;
+  }
+  return 0.0f;
+}
+
+struct PrecomputeTerm {
+  int dim, samples, res;
+  std::function<float(float, float, float, float, float, uint *)> evaluation;
+};
+
+bool cycles_precompute(std::string name);
+bool cycles_precompute(std::string name)
+{
+  std::map<string, PrecomputeTerm> precompute_terms;
+  precompute_terms["ggx_E"] = {
+      2, 1 << 23, 32, [](float rough, float mu, float ior, float u1, float u2, uint *rng) {
+        return precompute_ggx_E(rough, mu, u1, u2);
+      }};
+  precompute_terms["ggx_E_avg"] = {
+      1, 1 << 23, 32, [](float rough, float mu, float ior, float u1, float u2, uint *rng) {
+        return 2.0f * mu * precompute_ggx_E(rough, mu, u1, u2);
+      }};
+  precompute_terms["ggx_glass_E"] = {
+      3, 1 << 20, 16, [](float rough, float mu, float ior, float u1, float u2, uint *rng) {
+        return precompute_ggx_glass_E(rough, mu, ior, u1, u2, rng);
+      }};
+  precompute_terms["ggx_glass_inv_E"] = {
+      3, 1 << 20, 16, [](float rough, float mu, float ior, float u1, float u2, uint *rng) {
+        return precompute_ggx_glass_E(rough, mu, 1.0f / ior, u1, u2, rng);
+      }};
+  precompute_terms["ggx_refract_E"] = {
+      3, 1 << 20, 16, [](float rough, float mu, float ior, float u1, float u2, uint *rng) {
+        return precompute_ggx_refract_E(rough, mu, ior, u1, u2);
+      }};
+  precompute_terms["ggx_refract_inv_E"] = {
+      3, 1 << 20, 16, [](float rough, float mu, float ior, float u1, float u2, uint *rng) {
+        return precompute_ggx_refract_E(rough, mu, 1.0f / ior, u1, u2);
+      }};
+
+  if (precompute_terms.count(name) == 0) {
+    return false;
+  }
+
+  const PrecomputeTerm &term = precompute_terms[name];
+
+  const int samples = term.samples;
+  const int res = term.res;
+  const int nz = (term.dim > 2) ? res : 1, ny = res, nx = (term.dim > 1) ? res : 1;
+
+  if (nz > 1) {
+    std::cout << "static const float table_" << name << "[" << nz << "][" << ny << "][" << nx
+              << "] = {" << std::endl;
+  }
+  for (int z = 0; z < nz; z++) {
+    float *data = new float[nx * ny];
+    parallel_for(0, ny, [&](int64_t y) {
+      for (int x = 0; x < nx; x++) {
+        uint rng = hash_uint2(x, y);
+        uint scramble1 = lcg_step_uint(&rng), scramble2 = lcg_step_uint(&rng);
+        double sum = 0.0;
+        for (int i = 0; i < samples; i++) {
+          float rough = 1.0f - (float(y) + lcg_step_float(&rng)) / float(ny);
+          float mu = (float(x) + lcg_step_float(&rng)) / float(nx);
+          float ior = (float(z) + lcg_step_float(&rng)) / float(nz);
+          /* Encode IOR remapped as sqrt(0.5*(IOR-1)) for more resolution at the start, where most of the
+           * changes happen (also places the most common range around 1.5 in the center) */
+          ior = 1.0f + 2.0f * sqr(ior);
+          float u1 = VanDerCorput(i, scramble1);
+          float u2 = Sobol2(i, scramble2);
+
+          float value = term.evaluation(rough, mu, ior, u1, u2, &rng);
+          if (isnan(value)) {
+            value = 0.0f;
+          }
+          sum += (double)value;
+        }
+        data[y * nx + x] = float(sum / double(samples));
+      }
+    });
+
+    string filename = name;
+    if (nz > 1) {
+      filename += string_printf("_%02d", z);
+      std::cout << "  {" << std::endl;
+    }
+    else {
+      std::cout << "static const float table_" << name << "[" << ny << "][" << nx << "] = {"
+                << std::endl;
+    }
+
+    for (int y = 0; y < ny; y++) {
+      std::cout << "    {";
+      for (int x = 0; x < nx; x++) {
+        std::cout << data[y * nx + x] << ((x + 1 == nx) ? "f" : "f, ");
+      }
+      std::cout << ((y + 1 == ny) ? "}" : "},") << std::endl;
+    }
+    if (nz > 1) {
+      std::cout << ((z + 1 == nz) ? "  }" : "  },") << std::endl;
+    }
+    else {
+      std::cout << "};" << std::endl;
+    }
+
+    FILE *f = fopen((filename + ".pfm").c_str(), "w");
+    fprintf(f, "Pf\n%d %d\n-1.0\n", nx, ny);
+    fwrite(data, sizeof(float), nx * ny, f);
+    fclose(f);
+  }
+  if (nz > 1) {
+    std::cout << "};" << std::endl;
+  }
+
+  return true;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp
index 8b40adc8d92..6184b4ad445 100644
--- a/intern/cycles/app/cycles_standalone.cpp
+++ b/intern/cycles/app/cycles_standalone.cpp
@@ -37,6 +37,8 @@
 
 CCL_NAMESPACE_BEGIN
 
+bool cycles_precompute(std::string name);
+
 struct Options {
   Session *session;
   Scene *scene;
@@ -536,6 +538,10 @@ int main(int argc, const char **argv)
   path_init();
   options_parse(argc, argv);
 
+  if (cycles_precompute(options.filepath)) {
+    return 0;
+  }
+
 #ifdef WITH_CYCLES_STANDALONE_GUI
   if (options.session_params.background) {
 #endif



More information about the Bf-blender-cvs mailing list