forked from bartvdbraak/blender
Studiolight: Spherical Harmonics Windowing
Apply Windowing on the Spherical Harmonics result. This would lead to better results.
This commit is contained in:
parent
bcdec63570
commit
e402c36388
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user