Commit: e402c363888fc1fea38ffcf30b19502da46244d9
Author: Jeroen Bakker
Date:   Fri Jun 22 12:16:23 2018 +0200
Branches: blender2.8
https://developer.blender.org/rBe402c363888fc1fea38ffcf30b19502da46244d9

Studiolight: Spherical Harmonics Windowing

Apply Windowing on the Spherical Harmonics result. This would lead to
better results.

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

M       source/blender/blenkernel/BKE_studiolight.h
M       source/blender/blenkernel/intern/studiolight.c
M       source/blender/blenlib/BLI_utildefines.h

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

diff --git a/source/blender/blenkernel/BKE_studiolight.h 
b/source/blender/blenkernel/BKE_studiolight.h
index 2bd55fdb96e..9e6856f9990 100644
--- a/source/blender/blenkernel/BKE_studiolight.h
+++ b/source/blender/blenkernel/BKE_studiolight.h
@@ -64,17 +64,19 @@
 #define STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL 2
 #define STUDIOLIGHT_SPHERICAL_HARMONICS_MAX_COMPONENTS 9
 
-
 #if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL == 0
 #define STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS 1
+#define STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING_TARGET_LAMPLACIAN 10.0f
 #endif
 
 #if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL == 1
 #define STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS 4
+#define STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING_TARGET_LAMPLACIAN 10.0f
 #endif
 
 #if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL == 2
 #define STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS 9
+#define STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING_TARGET_LAMPLACIAN 10.0f
 #endif
 
 struct GPUTexture;
diff --git a/source/blender/blenkernel/intern/studiolight.c 
b/source/blender/blenkernel/intern/studiolight.c
index 556618c578c..063e5dcf2bc 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -39,6 +39,7 @@
 #include "BLI_fileops_types.h"
 #include "BLI_listbase.h"
 #include "BLI_math.h"
+#include "BLI_math_color.h"
 #include "BLI_path_util.h"
 #include "BLI_rand.h"
 #include "BLI_string.h"
@@ -72,7 +73,7 @@ static ListBase studiolights;
 // #define STUDIOLIGHT_IRRADIANCE_METHOD STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
 #define STUDIOLIGHT_IRRADIANCE_METHOD 
STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS
 
-
+#define STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING
 
 /*
  * Disable this option so caches are not loaded from disk
@@ -207,10 +208,14 @@ static void 
studiolight_load_equirectangular_image(StudioLight *sl)
        if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
                ImBuf *ibuf = NULL;
                ibuf = IMB_loadiffname(sl->path, 0, NULL);
-               if (ibuf) {
-                       IMB_float_from_rect(ibuf);
-                       sl->equirectangular_radiance_buffer = ibuf;
+               if (ibuf == NULL)
+               {
+                       float *colbuf = MEM_mallocN(sizeof(float[4]), __func__);
+                       copy_v4_fl4(colbuf, 1.0f, 0.0f, 1.0f, 1.0f);
+                       ibuf = IMB_allocFromBuffer(NULL, colbuf, 1, 1);
                }
+               IMB_float_from_rect(ibuf);
+               sl->equirectangular_radiance_buffer = ibuf;
        }
        sl->flag |= STUDIOLIGHT_EXTERNAL_IMAGE_LOADED;
 }
@@ -345,6 +350,9 @@ BLI_INLINE void studiolight_evaluate_radiance_buffer(
 
 }
 
+/*
+ * Spherical Harmonics
+ */
 BLI_INLINE float studiolight_area_element(float x, float y)
 {
        return atan2(x * y, sqrtf(x * x + y * y + 1));
@@ -485,6 +493,92 @@ static void 
studiolight_calculate_spherical_harmonics_coefficient(StudioLight *s
        copy_v3_v3(sl->spherical_harmonics_coefs[sh_component], sh);
 }
 
+#ifdef STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING
+static void studiolight_calculate_spherical_harmonics_luminance(StudioLight 
*sl, float luminance[STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS])
+{
+       for (int index = 0; index < STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS; 
index++)
+       {
+               luminance[index] = 
rgb_to_grayscale(sl->spherical_harmonics_coefs[index]);
+       }
+}
+
+static void studiolight_apply_spherical_harmonics_windowing(StudioLight *sl, 
float max_lamplacian)
+{
+       /* From Peter-Pike Sloan's Stupid SH Tricks 
http://www.ppsloan.org/publications/StupidSH36.pdf */
+       float table_l[STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL + 1];
+       float table_b[STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL + 1];
+
+       table_l[0] = 0.0f;
+       table_b[0] = 0.0f;
+
+       /* convert to luminance */
+       float luminance[STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS];
+       studiolight_calculate_spherical_harmonics_luminance(sl, luminance);
+
+       int index = 1;
+       for (int level = 1; level <= STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL; 
level ++)
+       {
+               table_l[level] = (float)(SQUARE(level) * SQUARE(level + 1));
+
+               float b = 0.0f;
+               for (int m = -1; m <= level; m++)
+               {
+                       b += SQUARE(luminance[index++]);
+               }
+               table_b[level] = b;
+       }
+
+       float squared_lamplacian = 0.0f;
+       for (int level = 1; level <= STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL; 
level ++)
+       {
+               squared_lamplacian += table_l[level] * table_b[level];
+       }
+
+       const float target_squared_laplacian = max_lamplacian * max_lamplacian;
+       if (squared_lamplacian <= target_squared_laplacian)
+       {
+               return;
+       }
+
+       float lambda = 0.0f;
+
+       const int no_iterations = 10000000;
+       for (int i = 0; i < no_iterations; ++i)
+       {
+               float f = 0.0f;
+               float fd = 0.0f;
+
+               for (int level = 1; level <= 
(int)STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL; ++level)
+               {
+                       f += table_l[level] * table_b[level] / SQUARE(1.0f + 
lambda * table_l[level]);
+                       fd += (2.0f * SQUARE(table_l[level]) * table_b[level]) 
/ CUBE(1.0f + lambda * table_l[level]);
+               }
+
+               f = target_squared_laplacian - f;
+
+               float delta = -f / fd;
+               lambda += delta;
+
+               if (ABS(delta) < 1e-6f)
+               {
+                       break;
+               }
+       }
+
+       /* Apply windowing lambda */
+       index = 0;
+       for (int level = 0; level <= STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL; 
level ++)
+       {
+               float s = 1.0f / (1.0f + lambda * SQUARE(level) * SQUARE(level 
+ 1.0f));
+
+               for (int m = -1; m <= level; m++)
+               {
+                       mul_v3_fl(sl->spherical_harmonics_coefs[index++], s);
+               }
+       }
+}
+#endif
+
 BLI_INLINE void studiolight_sample_spherical_harmonics(StudioLight *sl, float 
color[3], float normal[3])
 {
        copy_v3_fl(color, 0.0f);
@@ -516,6 +610,11 @@ static void 
studiolight_calculate_diffuse_light(StudioLight *sl)
                for (int comp = 0; comp < 
STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS; comp ++) {
                        
studiolight_calculate_spherical_harmonics_coefficient(sl, comp);
                }
+
+#ifdef STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING
+               studiolight_apply_spherical_harmonics_windowing(sl, 
STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING_TARGET_LAMPLACIAN);
+#endif
+
                if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
                        FILE *fp = BLI_fopen(sl->path_sh_cache, "wb");
                        if (fp) {
@@ -527,11 +626,6 @@ static void 
studiolight_calculate_diffuse_light(StudioLight *sl)
        sl->flag |= STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED;
 }
 
-static float area_element(float x, float y )
-{
-       return atan2f(x * y, sqrt(x * x + y * y + 1));
-}
-
 static float texel_coord_solid_angle(float a_U, float a_V, int a_Size)
 {
        //scale up to [-1, 1] range (inclusive), offset by 0.5 to point to 
texel center.
@@ -546,7 +640,7 @@ static float texel_coord_solid_angle(float a_U, float a_V, 
int a_Size)
        float y0 = v - resolution_inv;
        float x1 = u + resolution_inv;
        float y1 = v + resolution_inv;
-       return area_element(x0, y0) - area_element(x0, y1) - area_element(x1, 
y0) + area_element(x1, y1);
+       return studiolight_area_element(x0, y0) - studiolight_area_element(x0, 
y1) - studiolight_area_element(x1, y0) + studiolight_area_element(x1, y1);
 }
 
 BLI_INLINE void studiolight_evaluate_specular_radiance_buffer(
diff --git a/source/blender/blenlib/BLI_utildefines.h 
b/source/blender/blenlib/BLI_utildefines.h
index 36281ee0fcc..286e1cc6dd5 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -274,11 +274,15 @@ extern "C" {
 #define SQUARE(a)  ({ \
        typeof(a) a_ = (a); \
        ((a_) * (a_)); })
+#define CUBE(a)  ({ \
+       typeof(a) a_ = (a); \
+       ((a_) * (a_) * (a_)); })
 
 #else
 
 #define ABS(a)  ((a) < 0 ? (-(a)) : (a))
 #define SQUARE(a)  ((a) * (a))
+#define CUBE(a)  ((a) * (a) * (a))
 
 #endif

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to