Page MenuHome
Paste P1099

(An Untitled Masterwork)
ActivePublic

Authored by Clément Foucault (fclem) on Sep 13 2019, 5:55 PM.
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
index 261b7f00e42..90d23e2914b 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.c
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -828,7 +828,7 @@ static void eevee_lightbake_render_world_sample(void *ved, void *user_data)
sldata->common_data.ray_depth = 1;
DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
EEVEE_lightbake_render_world(sldata, vedata, lbake->rt_fb);
- EEVEE_lightbake_filter_diffuse(sldata, vedata, lbake->rt_color, lbake->store_fb, 0, 1.0f);
+ EEVEE_lightbake_filter_diffuse(sldata, vedata, lbake->rt_color, lbake->store_fb, 0, 1.0f, clamp);
/* Clear the cache to avoid white values in the grid. */
GPU_framebuffer_texture_attach(lbake->store_fb, lbake->grid_prev, 0, 0);
@@ -920,6 +920,7 @@ static void eevee_lightbake_render_grid_sample(void *ved, void *user_data)
LightCache *lcache = scene_eval->eevee.light_cache;
int grid_loc[3], sample_id, sample_offset, stride;
float pos[3];
+ float clamp = scene_eval->eevee.gi_glossy_clamp;
const bool is_last_bounce_sample = ((egrid->offset + lbake->grid_sample) ==
(lbake->total_irr_samples - 1));
@@ -956,7 +957,7 @@ static void eevee_lightbake_render_grid_sample(void *ved, void *user_data)
SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex);
EEVEE_lightbake_filter_diffuse(
- sldata, vedata, lbake->rt_color, lbake->store_fb, sample_offset, prb->intensity);
+ sldata, vedata, lbake->rt_color, lbake->store_fb, sample_offset, prb->intensity, clamp);
if (lbake->bounce_curr == 0) {
/* We only need to filter the visibility for the first bounce. */
@@ -1295,7 +1296,7 @@ void EEVEE_lightbake_update_world_quick(EEVEE_ViewLayerData *sldata,
sldata->common_data.ray_depth = 1;
DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
EEVEE_lightbake_render_world(sldata, vedata, lbake.rt_fb);
- EEVEE_lightbake_filter_diffuse(sldata, vedata, lbake.rt_color, lbake.store_fb, 0, 1.0f);
+ EEVEE_lightbake_filter_diffuse(sldata, vedata, lbake.rt_color, lbake.store_fb, 0, 1.0f, clamp);
/* Don't hide grids if they are already rendered. */
lcache->grid_len = max_ii(1, lcache->grid_len);
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index 19f3983998e..33fdc1cfc8a 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -270,6 +270,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata,
DRW_shgroup_uniform_float(grp, "lodMax", &pinfo->lod_rt_max, 1);
DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
#endif
+ DRW_shgroup_uniform_float(grp, "fireflyFactor", &pinfo->firefly_fac, 1);
DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1);
DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
@@ -1113,13 +1114,98 @@ void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata,
}
}
+BLI_INLINE float area_element(float x, float y)
+{
+ return atan2(x * y, sqrtf(x * x + y * y + 1));
+}
+
+BLI_INLINE float texel_solid_angle(float x, float y, float halfpix)
+{
+ float v1x = (x - halfpix) * 2.0f - 1.0f;
+ float v1y = (y - halfpix) * 2.0f - 1.0f;
+ float v2x = (x + halfpix) * 2.0f - 1.0f;
+ float v2y = (y + halfpix) * 2.0f - 1.0f;
+
+ return area_element(v1x, v1y) - area_element(v1x, v2y) - area_element(v2x, v1y) +
+ area_element(v2x, v2y);
+}
+
+static void cube_face_uv_to_direction(float r_dir[3], float x, float y, int face)
+{
+ float matinv[4][4];
+ copy_v3_fl3(r_dir, x * 2.0f - 1.0f, y * 2.0f - 1.0f, -1.0f);
+ /* Same as inverse in this case. */
+ transpose_m4_m4(matinv, cubefacemat[face]);
+ mul_mat3_m4_v3(matinv, r_dir);
+ normalize_v3(r_dir);
+}
+
+static void direction_to_cube_face_uv(float r_uv[2], int *r_face, const float dir[3])
+{
+ if (fabsf(dir[0]) > fabsf(dir[1]) && fabsf(dir[0]) > fabsf(dir[2])) {
+ *r_face = (dir[0] > 0.0f) ? 0 : 1;
+ }
+ else if (fabsf(dir[1]) > fabsf(dir[0]) && fabsf(dir[1]) > fabsf(dir[2])) {
+ *r_face = (dir[1] > 0.0f) ? 2 : 3;
+ }
+ else {
+ *r_face = (dir[2] > 0.0f) ? 4 : 5;
+ }
+ float tmp[3];
+ mul_v3_mat3_m4v3(tmp, cubefacemat[*r_face], dir);
+ mul_v2_fl(tmp, 1.0f / fabsf(tmp[2]));
+ r_uv[0] = clamp_f(tmp[0] * 0.5f + 0.5f, 0.0f, 0.99999f);
+ r_uv[1] = clamp_f(tmp[1] * 0.5f + 0.5f, 0.0f, 0.99999f);
+}
+
+static void cubemap_dir(int i, int j, int f, int cube_half_size, float r_dir[3])
+{
+ float x = 0.5f * ((float)i + 0.5f) / (float)cube_half_size;
+ float y = 0.5f * ((float)j + 0.5f) / (float)cube_half_size;
+ cube_face_uv_to_direction(r_dir, x, y, f);
+ /* TODO Fix cube_face_uv_to_direction instead. */
+ // r_dir[2] = -r_dir[2];
+}
+
+static int cubemap_uv_to_cdf_coord(float dir[3], int cdf_u_len, int cdf_v_len)
+{
+ /* TODO do not modify original */
+ normalize_v2(dir);
+ float cdf_x = atan2(dir[1], dir[0]) * M_1_PI * 0.5 + 0.5;
+ float cdf_y = acos(dir[2]) * M_1_PI;
+ int cdf_u = (int)clamp_f(cdf_x * cdf_u_len, 0.0, cdf_u_len - 1);
+ int cdf_v = (int)clamp_f(cdf_y * cdf_v_len, 0.0, cdf_v_len - 1);
+ return cdf_v * cdf_u_len + cdf_u;
+}
+
+static float cubemap_texel_solid_angle(int i, int j, int cube_half_size)
+{
+ const float halfpix = 0.25f / cube_half_size;
+ float x = 0.5f * i / (float)cube_half_size;
+ float y = 0.5f * j / (float)cube_half_size;
+ return texel_solid_angle(x, y, halfpix);
+}
+
+static float brightness_clamped(float texel[3], float ofs)
+{
+ return max_ff(texel[0] - ofs, 0.0f) + max_ff(texel[1] - ofs, 0.0f) +
+ max_ff(texel[2] - ofs, 0.0f);
+}
+
+// static char convert_to_unicode_grayscale(float x)
+// {
+// char table[10] = " .:-=+*#%@";
+// return table[(int)clamp_f(x * 9.0f + 0.5, 0.0, 9.0)];
+// }
+
/* Diffuse filter rt_color to light_cache->grid_tx.tex at index grid_offset */
void EEVEE_lightbake_filter_diffuse(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUTexture *rt_color,
struct GPUFrameBuffer *fb,
int grid_offset,
- float intensity)
+ float intensity,
+ float lamp_threshold)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
@@ -1157,6 +1243,7 @@ void EEVEE_lightbake_filter_diffuse(EEVEE_ViewLayerData *sldata,
pinfo->shres = 32; /* Less texture fetches & reduce branches */
pinfo->lod_rt_max = 2.0f; /* Improve cache reuse */
#endif
+ pinfo->firefly_fac = (lamp_threshold > 0.0) ? lamp_threshold : 1e16;
/* Start fresh */
GPU_framebuffer_ensure_config(&fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_NONE});
@@ -1169,6 +1256,162 @@ void EEVEE_lightbake_filter_diffuse(EEVEE_ViewLayerData *sldata,
GPU_framebuffer_bind(fb);
GPU_framebuffer_viewport_set(fb, x, y, size[0], size[1]);
DRW_draw_pass(psl->probe_diffuse_compute);
+
+ if (grid_offset > 0) {
+ return;
+ }
+
+ /* Build Environment Importance Map. */
+ int cube_size = GPU_texture_width(rt_color);
+ int cube_half_size = cube_size / 2;
+
+ float(*data)[4] = GPU_texture_read(rt_color, GPU_DATA_FLOAT, 0);
+
+ int cdf_u_len = 128;
+ int cdf_v_len = 64;
+ float *cdf_u = MEM_callocN(sizeof(float) * cdf_v_len * cdf_u_len, "Environment CDF");
+ float *cdf_v = MEM_callocN(sizeof(float) * cdf_v_len, "Environment CDF");
+ float *cdf_u_inv = MEM_callocN(sizeof(float) * cdf_v_len * cdf_u_len, "Environment CDF");
+ float *cdf_v_inv = MEM_callocN(sizeof(float) * cdf_v_len, "Environment CDF");
+
+#define NORMALIZE_CDF(cdf, cdf_len) \
+ do { \
+ if ((cdf)[cdf_len - 1] < 1e-8f) { \
+ for (int _i = 0; _i < cdf_len; _i++) { \
+ (cdf)[_i] = (float)_i / (cdf_len - 1); \
+ } \
+ } \
+ else { \
+ for (int _i = 0; _i < cdf_len - 1; _i++) { \
+ (cdf)[_i] /= (cdf)[cdf_len - 1]; \
+ } \
+ (cdf)[cdf_len - 1] = 1.0f; \
+ } \
+ } while (0)
+
+ /* Create 2D CDFs and invert them. */
+ for (int f = 0; f < 6; f++) {
+ for (int j = 0; j < cube_size; j++) {
+ for (int i = 0; i < cube_size; i++) {
+ int t = f * cube_size * cube_size + j * cube_size + i;
+ float dir[3];
+ cubemap_dir(i, j, f, cube_half_size, dir);
+
+ // float dbg_col[4];
+ // linearrgb_to_srgb_v4(dbg_col, data[t]);
+ // DRW_debug_sphere(dir, 0.01f, dbg_col);
+
+ float solid_angle = cubemap_texel_solid_angle(i, j, cube_half_size);
+ float weight = brightness_clamped(data[t], pinfo->firefly_fac);
+ BLI_assert(!isnan(weight) && !isnan(solid_angle));
+ // float dbg = weight * solid_angle * 100.0f;
+ // DRW_debug_sphere(dir, 0.01f, (float[4]){dbg, dbg, dbg, 1.0f});
+
+ int coord = cubemap_uv_to_cdf_coord(dir, cdf_u_len, cdf_v_len);
+ cdf_u[coord] += weight * solid_angle;
+ }
+ }
+ }
+
+ // for (int i = 0; i < cdf_v_len; i++) {
+ // for (int j = 0; j < cdf_u_len; j++) {
+ // printf("%c", convert_to_unicode_grayscale(cdf_u[i * cdf_u_len + j] * 20.0f));
+ // }
+ // printf("\n");
+ // }
+ // printf("\n");
+
+ cdf_v[0] = 0.0f; /* FIXME recover lost energy */
+ for (int i = 0; i < cdf_v_len; i++) {
+ int u_ofs = i * cdf_u_len;
+ cdf_u[u_ofs] = 0.0f; /* FIXME recover lost energy */
+ for (int j = 1; j < cdf_u_len; j++) {
+ cdf_u[u_ofs + j] += cdf_u[u_ofs + j - 1];
+ }
+ cdf_v[i] = cdf_v[max_ii(i - 1, 0)] + cdf_u[u_ofs + cdf_u_len - 1];
+ NORMALIZE_CDF(&cdf_u[u_ofs], cdf_u_len);
+ EEVEE_cdf_invert(&cdf_u[u_ofs], &cdf_u_inv[u_ofs], cdf_u_len);
+ }
+ NORMALIZE_CDF(cdf_v, cdf_v_len);
+ EEVEE_cdf_invert(cdf_v, cdf_v_inv, cdf_v_len);
+
+ // for (int i = 0; i < cdf_v_len; i++) {
+ // for (int j = 0; j < cdf_u_len; j++) {
+ // printf("%c", convert_to_unicode_grayscale(cdf_u[i * cdf_u_len + j]));
+ // }
+ // printf(" %.2f", cdf_v[i]);
+ // printf("\n");
+ // }
+ // printf("\n");
+
+ // for (int i = 0; i < cdf_v_len; i++) {
+ // for (int j = 0; j < cdf_u_len; j++) {
+ // printf("%c", convert_to_unicode_grayscale(cdf_u_inv[i * cdf_u_len + j]));
+ // }
+ // printf(" %.2f", cdf_v_inv[i]);
+ // printf("\n");
+ // }
+ // printf("\n");
+
+ /* Debug */
+ static double samples[512][2];
+ BLI_hammersley_2d_sequence(512, &samples[0][0]);
+
+ zero_v3(pinfo->env_light_dir);
+ zero_v3(pinfo->env_light_color);
+ for (int j = 0; j < 512; j++) {
+ float _x = samples[j][0];
+ float _y = samples[j][1];
+
+ /* Importance sampling */
+ _y = EEVEE_cdf_eval(cdf_v_inv, _y, cdf_v_len);
+ float _y_v = _y * cdf_v_len;
+ float _y_v_fract = _y_v - floor(_y_v);
+ int u_ofs = clamp_i(floor(_y_v), 0, cdf_v_len - 2) * cdf_u_len;
+ float _x1 = EEVEE_cdf_eval(&cdf_u_inv[u_ofs], _x, cdf_u_len);
+ float _x2 = EEVEE_cdf_eval(&cdf_u_inv[u_ofs + 1], _x, cdf_u_len);
+ _x = _x1 * (1.0 - _y_v_fract) + _x2 * _y_v_fract;
+
+ _x = (_x * 2.0f - 1.0f) * M_PI;
+ _y = _y * M_PI;
+ float sin_y = sinf(_y);
+ float vec[3] = {cosf(_x) * sin_y, sinf(_x) * sin_y, cosf(_y)};
+
+ /* Uniform distribution */
+ // _x = _x * 2.0 * M_PI;
+ // _y = _y * 2.0 - 1.0; /* cos */
+ // float sin_y = sqrtf(max_ff(0.0f, 1.0f - _y * _y));
+ // float vec[3] = {cosf(_x) * sin_y, sinf(_x) * sin_y, _y};
+
+ float cube_uv[2];
+ int cube_face;
+ direction_to_cube_face_uv(cube_uv, &cube_face, vec);
+
+ cube_uv[0] *= cube_size;
+ cube_uv[1] *= cube_size;
+ int t = (int)cube_uv[0] + (int)cube_uv[1] * cube_size + cube_face * cube_size * cube_size;
+
+ t = clamp_i(t, 0, cube_size * cube_size * 6 - 1);
+
+ float dbg_col[4] = {cube_uv[0], cube_uv[1], 0, 1};
+ linearrgb_to_srgb_v4(dbg_col, data[t]);
+ DRW_debug_sphere(vec, 0.02f, dbg_col);
+
+ for (int i = 0; i < 3; i++) {
+ pinfo->env_light_color[i] += max_ff(data[t][i] - pinfo->firefly_fac, 0.0f);
+ }
+ madd_v3_v3fl(pinfo->env_light_dir, vec, data[t][1]);
+ }
+ normalize_v3(pinfo->env_light_dir);
+ mul_v3_fl(pinfo->env_light_color, 1.0f / 512.0f);
+
+ DRW_debug_sphere(pinfo->env_light_dir, 0.05f, pinfo->env_light_color);
+
+ MEM_freeN(cdf_u);
+ MEM_freeN(cdf_v);
+ MEM_freeN(cdf_u_inv);
+ MEM_freeN(cdf_v_inv);
+ MEM_freeN(data);
}
/* Filter rt_depth to light_cache->grid_tx.tex at index grid_offset */
@@ -1305,6 +1548,7 @@ void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
if ((light_cache->flag & LIGHTCACHE_UPDATE_WORLD) &&
(light_cache->flag & LIGHTCACHE_BAKED) == 0) {
EEVEE_lightbake_update_world_quick(sldata, vedata, scene_eval);
+ DRW_uniformbuffer_update(sldata->light_ubo, sldata->lights->light_data);
}
}
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index 126ec8d81c4..a704bf1274c 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -175,6 +175,28 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
EEVEE_LightsInfo *linfo = sldata->lights;
linfo->num_light = 0;
+ /* World Environment Directional Light */
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ EEVEE_Light *evli = linfo->light_data;
+ /* HACK REPLACE THIS! */
+ Light la = {
+ .r = pinfo->env_light_color[0],
+ .g = pinfo->env_light_color[1],
+ .b = pinfo->env_light_color[2],
+ .energy = 0.02f, /* FIXME */
+ .sun_angle = DEG2RADF(8.0f),
+ .type = LA_SUN,
+ };
+ Object ob = {
+ .obmat = {{0}},
+ .data = &la,
+ };
+ unit_m4(ob.obmat);
+ copy_v3_v3(ob.obmat[2], pinfo->env_light_dir);
+ orthogonalize_m4(ob.obmat, 2);
+ eevee_light_setup(&ob, evli);
+ linfo->num_light++;
+
EEVEE_shadows_cache_init(sldata, vedata);
}
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index f4f40d40de6..35def88db0a 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -467,6 +467,9 @@ typedef struct EEVEE_LightProbesInfo {
/* Update */
bool do_cube_update;
bool do_grid_update;
+ /* Environment Directional light */
+ float env_light_dir[3];
+ float env_light_color[3];
/* For rendering probes */
float probemat[6][4][4];
int layer;
@@ -898,6 +901,13 @@ void EEVEE_sample_ellipse(int sample_ofs,
float rsample[3]);
void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4]);
+void EEVEE_cdf_compute(float (*func)(float x, void *data),
+ void *userdata,
+ float cdf[],
+ int table_len);
+void EEVEE_cdf_invert(const float cdf[], float invert_cdf[], int table_len);
+float EEVEE_cdf_eval(float table[], float x, int table_len);
+
/* eevee_shaders.c */
void EEVEE_shaders_lightprobe_shaders_init(void);
struct GPUShader *EEVEE_shaders_probe_filter_glossy_sh_get(void);
@@ -951,7 +961,8 @@ void EEVEE_lightbake_filter_diffuse(EEVEE_ViewLayerData *sldata,
struct GPUTexture *rt_color,
struct GPUFrameBuffer *fb,
int grid_offset,
- float intensity);
+ float intensity,
+ float firefly_fac);
void EEVEE_lightbake_filter_visibility(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUTexture *rt_depth,
diff --git a/source/blender/draw/engines/eevee/eevee_sampling.c b/source/blender/draw/engines/eevee/eevee_sampling.c
index 5e951928c5a..517ef4b5aee 100644
--- a/source/blender/draw/engines/eevee/eevee_sampling.c
+++ b/source/blender/draw/engines/eevee/eevee_sampling.c
@@ -24,6 +24,10 @@
#include "BLI_rand.h"
+/* -------------------------------------------------------------------- */
+/** \name Random sample distribution
+ * \{ */
+
/**
* Special ball distribution:
* Point are distributed in a way that when they are orthogonally
@@ -127,3 +131,66 @@ void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4])
rotate_m4(r_mat, 'Y', ht_point[1] * scale);
rotate_m4(r_mat, 'Z', ht_point[2] * scale);
}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cumulative Distribution Functions
+ * \{ */
+
+/* Compute cumulative distribution function of a discrete function. */
+void EEVEE_cdf_compute(float (*func)(float x, void *data),
+ void *userdata,
+ float cdf[],
+ int table_len)
+{
+ cdf[0] = 0.0f;
+ /* Actual CDF evaluation. */
+ for (int u = 0; u < table_len - 1; u++) {
+ float x = (float)(u + 1) / (float)(table_len - 1);
+ cdf[u + 1] = cdf[u] + func(x, userdata);
+ }
+ /* Normalize the CDF. */
+ for (int u = 0; u < table_len - 1; u++) {
+ cdf[u] /= cdf[table_len - 1];
+ }
+ /* Just to make sure. */
+ cdf[table_len - 1] = 1.0f;
+}
+
+/* Invert a cdf table. */
+void EEVEE_cdf_invert(const float cdf[], float invert_cdf[], int table_len)
+{
+ for (int u = 0; u < table_len; u++) {
+ float x = (float)u / (float)(table_len - 1);
+ int i;
+ for (i = 0; i < table_len; i++) {
+ if (cdf[i] >= x) {
+ break;
+ }
+ }
+ if (i == 0) {
+ invert_cdf[u] = 0.0f;
+ }
+ else if (i >= table_len - 1) {
+ invert_cdf[u] = 1.0f;
+ }
+ else {
+ float t = (x - cdf[i - 1]) / (cdf[i] - cdf[i - 1]);
+ invert_cdf[u] = ((float)i + t) / (float)(table_len - 1);
+ }
+ }
+}
+
+/* Evaluate a discrete function table with linear interpolation. */
+float EEVEE_cdf_eval(float table[], float x, int table_len)
+{
+ CLAMP(x, 0.0f, 1.0f);
+ x = x * (table_len - 1);
+
+ int index = min_ii((int)(x), table_len - 1);
+ int nindex = min_ii(index + 1, table_len - 1);
+ float t = x - index;
+
+ return (1.0f - t) * table[index] + t * table[nindex];
+}
diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
index e5f89aab4d1..e0fe1bbfa78 100644
--- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
+++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
@@ -50,64 +50,14 @@ static float UNUSED_FUNCTION(filter_box)(float UNUSED(x))
return 1.0f;
}
-static float filter_blackman_harris(float x)
+static float filter_blackman_harris(float x, void *UNUSED(data))
{
/* Hardcoded 1px footprint [-0.5..0.5]. We resize later. */
const float width = 1.0f;
- x = 2.0f * M_PI * (x / width + 0.5f);
+ x = 2.0f * M_PI * ((x - 0.5f) / width + 0.5f);
return 0.35875f - 0.48829f * cosf(x) + 0.14128f * cosf(2.0f * x) - 0.01168f * cosf(3.0f * x);
}
-/* Compute cumulative distribution function of a discrete function. */
-static void compute_cdf(float (*func)(float x), float cdf[FILTER_CDF_TABLE_SIZE])
-{
- cdf[0] = 0.0f;
- /* Actual CDF evaluation. */
- for (int u = 0; u < FILTER_CDF_TABLE_SIZE - 1; u++) {
- float x = (float)(u + 1) / (float)(FILTER_CDF_TABLE_SIZE - 1);
- cdf[u + 1] = cdf[u] + func(x - 0.5f); /* [-0.5..0.5]. We resize later. */
- }
- /* Normalize the CDF. */
- for (int u = 0; u < FILTER_CDF_TABLE_SIZE - 1; u++) {
- cdf[u] /= cdf[FILTER_CDF_TABLE_SIZE - 1];
- }
- /* Just to make sure. */
- cdf[FILTER_CDF_TABLE_SIZE - 1] = 1.0f;
-}
-
-static void invert_cdf(const float cdf[FILTER_CDF_TABLE_SIZE],
- float invert_cdf[FILTER_CDF_TABLE_SIZE])
-{
- for (int u = 0; u < FILTER_CDF_TABLE_SIZE; u++) {
- float x = (float)u / (float)(FILTER_CDF_TABLE_SIZE - 1);
- for (int i = 0; i < FILTER_CDF_TABLE_SIZE; i++) {
- if (cdf[i] >= x) {
- if (i == FILTER_CDF_TABLE_SIZE - 1) {
- invert_cdf[u] = 1.0f;
- }
- else {
- float t = (x - cdf[i]) / (cdf[i + 1] - cdf[i]);
- invert_cdf[u] = ((float)i + t) / (float)(FILTER_CDF_TABLE_SIZE - 1);
- }
- break;
- }
- }
- }
-}
-
-/* Evaluate a discrete function table with linear interpolation. */
-static float eval_table(float *table, float x)
-{
- CLAMP(x, 0.0f, 1.0f);
- x = x * (FILTER_CDF_TABLE_SIZE - 1);
-
- int index = min_ii((int)(x), FILTER_CDF_TABLE_SIZE - 1);
- int nindex = min_ii(index + 1, FILTER_CDF_TABLE_SIZE - 1);
- float t = x - index;
-
- return (1.0f - t) * table[index] + t * table[nindex];
-}
-
static void eevee_create_cdf_table_temporal_sampling(void)
{
float *cdf_table = MEM_mallocN(sizeof(float) * FILTER_CDF_TABLE_SIZE, "Eevee Filter CDF table");
@@ -117,10 +67,10 @@ static void eevee_create_cdf_table_temporal_sampling(void)
{
/* Use blackman-harris filter. */
filter_width *= 2.0f;
- compute_cdf(filter_blackman_harris, cdf_table);
+ EEVEE_cdf_compute(filter_blackman_harris, NULL, cdf_table, FILTER_CDF_TABLE_SIZE);
}
- invert_cdf(cdf_table, e_data.inverted_cdf);
+ EEVEE_cdf_invert(cdf_table, e_data.inverted_cdf, FILTER_CDF_TABLE_SIZE);
/* Scale and offset table. */
for (int i = 0; i < FILTER_CDF_TABLE_SIZE; i++) {
@@ -135,8 +85,9 @@ void EEVEE_temporal_sampling_offset_calc(const double ht_point[2],
const float filter_size,
float r_offset[2])
{
- r_offset[0] = eval_table(e_data.inverted_cdf, (float)(ht_point[0])) * filter_size;
- r_offset[1] = eval_table(e_data.inverted_cdf, (float)(ht_point[1])) * filter_size;
+ r_offset[0] = EEVEE_cdf_eval(e_data.inverted_cdf, (float)(ht_point[0]), FILTER_CDF_TABLE_SIZE);
+ r_offset[1] = EEVEE_cdf_eval(e_data.inverted_cdf, (float)(ht_point[1]), FILTER_CDF_TABLE_SIZE);
+ mul_v2_fl(r_offset, filter_size);
}
void EEVEE_temporal_sampling_matrices_calc(EEVEE_EffectsInfo *effects, const double ht_point[2])
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
index 296c1581545..de6cd4a5b2b 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
@@ -4,6 +4,7 @@ uniform int probeSize;
uniform float lodFactor;
uniform float lodMax;
uniform float intensityFac;
+uniform float fireflyFactor;
in vec3 worldPosition;
@@ -176,7 +177,8 @@ void main()
/* http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html : Equation 13 */
float lod = clamp(lodFactor - 0.5 * log2(pdf * dist), 0.0, lodMax);
- out_radiance += textureLod(probeHdr, L, lod).rgb * NL;
+ /* Hard clamp here. We restiture the energy using sunlight. */
+ out_radiance += min(textureLod(probeHdr, L, lod).rgb, fireflyFactor) * NL;
weight += NL;
}
}