Eevee: Replace Cubemaps by octahedron maps for env. probes.

This enables us to use 2D texture arrays for multiple probes.
There is a little artifact with very high roughness caused elongated pixel due to the projection (along every 90° meridian).
This commit is contained in:
Clément Foucault 2017-05-29 22:03:57 +02:00
parent 1fa216487d
commit 5773f58762
6 changed files with 238 additions and 123 deletions

@ -62,7 +62,6 @@ static struct {
struct GPUTexture *ltc_mat; struct GPUTexture *ltc_mat;
struct GPUTexture *brdf_lut; struct GPUTexture *brdf_lut;
struct GPUTexture *hammersley;
struct GPUTexture *jitter; struct GPUTexture *jitter;
float camera_pos[3]; float camera_pos[3];
@ -89,35 +88,6 @@ extern char datatoc_background_vert_glsl[];
extern Material defmaterial; extern Material defmaterial;
extern GlobalsUboStorage ts; extern GlobalsUboStorage ts;
/* Van der Corput sequence */
/* From http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html */
static float radical_inverse(int i) {
unsigned int bits = (unsigned int)i;
bits = (bits << 16u) | (bits >> 16u);
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
return (float)bits * 2.3283064365386963e-10f;
}
static struct GPUTexture *create_hammersley_sample_texture(int samples)
{
struct GPUTexture *tex;
float (*texels)[2] = MEM_mallocN(sizeof(float[2]) * samples, "hammersley_tex");
int i;
for (i = 0; i < samples; i++) {
float phi = radical_inverse(i) * 2.0f * M_PI;
texels[i][0] = cos(phi);
texels[i][1] = sinf(phi);
}
tex = DRW_texture_create_1D(samples, DRW_TEX_RG_16, DRW_TEX_WRAP, (float *)texels);
MEM_freeN(texels);
return tex;
}
static struct GPUTexture *create_jitter_texture(int w, int h) static struct GPUTexture *create_jitter_texture(int w, int h)
{ {
struct GPUTexture *tex; struct GPUTexture *tex;
@ -270,36 +240,10 @@ static void EEVEE_engine_init(void *ved)
e_data.default_background = DRW_shader_create_fullscreen(datatoc_default_world_frag_glsl, NULL); e_data.default_background = DRW_shader_create_fullscreen(datatoc_default_world_frag_glsl, NULL);
} }
if (!e_data.probe_filter_sh) {
char *shader_str = NULL;
DynStr *ds_frag = BLI_dynstr_new();
BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
BLI_dynstr_append(ds_frag, datatoc_probe_filter_frag_glsl);
shader_str = BLI_dynstr_get_cstring(ds_frag);
BLI_dynstr_free(ds_frag);
e_data.probe_filter_sh = DRW_shader_create(
datatoc_probe_vert_glsl, datatoc_probe_geom_glsl, shader_str,
"#define HAMMERSLEY_SIZE 8192\n"
"#define NOISE_SIZE 64\n");
MEM_freeN(shader_str);
}
if (!e_data.probe_spherical_harmonic_sh) {
e_data.probe_spherical_harmonic_sh = DRW_shader_create_fullscreen(datatoc_probe_sh_frag_glsl, NULL);
}
if (!e_data.ltc_mat) { if (!e_data.ltc_mat) {
e_data.ltc_mat = DRW_texture_create_2D(64, 64, DRW_TEX_RGBA_16, DRW_TEX_FILTER, ltc_mat_ggx); e_data.ltc_mat = DRW_texture_create_2D(64, 64, DRW_TEX_RGBA_16, DRW_TEX_FILTER, ltc_mat_ggx);
} }
if (!e_data.hammersley) {
e_data.hammersley = create_hammersley_sample_texture(8192);
}
if (!e_data.jitter) { if (!e_data.jitter) {
e_data.jitter = create_jitter_texture(64, 64); e_data.jitter = create_jitter_texture(64, 64);
} }
@ -439,34 +383,6 @@ static void EEVEE_cache_init(void *vedata)
} }
} }
{
psl->probe_prefilter = DRW_pass_create("Probe Filtering", DRW_STATE_WRITE_COLOR);
struct Batch *geom = DRW_cache_fullscreen_quad_get();
DRWShadingGroup *grp = eevee_cube_shgroup(e_data.probe_filter_sh, psl->probe_prefilter, geom);
DRW_shgroup_uniform_float(grp, "sampleCount", &stl->probes->samples_ct, 1);
DRW_shgroup_uniform_float(grp, "invSampleCount", &stl->probes->invsamples_ct, 1);
DRW_shgroup_uniform_float(grp, "roughnessSquared", &stl->probes->roughness, 1);
DRW_shgroup_uniform_float(grp, "lodFactor", &stl->probes->lodfactor, 1);
DRW_shgroup_uniform_float(grp, "lodMax", &stl->probes->lodmax, 1);
DRW_shgroup_uniform_int(grp, "Layer", &stl->probes->layer, 1);
DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
// DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter);
DRW_shgroup_uniform_texture(grp, "probeHdr", txl->probe_rt);
}
{
psl->probe_sh_compute = DRW_pass_create("Probe SH Compute", DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_spherical_harmonic_sh, psl->probe_sh_compute);
DRW_shgroup_uniform_int(grp, "probeSize", &stl->probes->shres, 1);
DRW_shgroup_uniform_float(grp, "lodBias", &stl->probes->lodfactor, 1);
DRW_shgroup_uniform_texture(grp, "probeHdr", txl->probe_rt);
struct Batch *geom = DRW_cache_fullscreen_quad_get();
DRW_shgroup_call_add(grp, geom, NULL);
}
{ {
psl->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); psl->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass); stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass);
@ -512,9 +428,8 @@ static void EEVEE_cache_init(void *vedata)
psl->material_pass = DRW_pass_create("Material Shader Pass", state); psl->material_pass = DRW_pass_create("Material Shader Pass", state);
} }
EEVEE_probes_cache_init(vedata);
EEVEE_lights_cache_init(stl, psl, txl); EEVEE_lights_cache_init(stl, psl, txl);
EEVEE_effects_cache_init(vedata); EEVEE_effects_cache_init(vedata);
} }
@ -669,6 +584,7 @@ static void EEVEE_cache_finish(void *vedata)
EEVEE_FramebufferList *fbl = ((EEVEE_Data *)vedata)->fbl; EEVEE_FramebufferList *fbl = ((EEVEE_Data *)vedata)->fbl;
EEVEE_lights_cache_finish(stl, txl, fbl); EEVEE_lights_cache_finish(stl, txl, fbl);
EEVEE_probes_cache_finish(vedata);
/* Shadows binding */ /* Shadows binding */
eevee_bind_shadow_data data; eevee_bind_shadow_data data;
@ -713,6 +629,7 @@ static void EEVEE_engine_free(void)
{ {
EEVEE_effects_free(); EEVEE_effects_free();
EEVEE_lights_free(); EEVEE_lights_free();
EEVEE_probes_free();
MEM_SAFE_FREE(e_data.frag_shader_lib); MEM_SAFE_FREE(e_data.frag_shader_lib);
DRW_SHADER_FREE_SAFE(e_data.default_lit); DRW_SHADER_FREE_SAFE(e_data.default_lit);
@ -723,7 +640,6 @@ static void EEVEE_engine_free(void)
DRW_SHADER_FREE_SAFE(e_data.probe_spherical_harmonic_sh); DRW_SHADER_FREE_SAFE(e_data.probe_spherical_harmonic_sh);
DRW_TEXTURE_FREE_SAFE(e_data.ltc_mat); DRW_TEXTURE_FREE_SAFE(e_data.ltc_mat);
DRW_TEXTURE_FREE_SAFE(e_data.brdf_lut); DRW_TEXTURE_FREE_SAFE(e_data.brdf_lut);
DRW_TEXTURE_FREE_SAFE(e_data.hammersley);
DRW_TEXTURE_FREE_SAFE(e_data.jitter); DRW_TEXTURE_FREE_SAFE(e_data.jitter);
} }

@ -209,7 +209,7 @@ void EEVEE_lights_cache_finish(EEVEE_StorageList *stl, EEVEE_TextureList *txl, E
} }
} }
if (!txl->shadow_depth_cube_pool) { if (!txl->shadow_depth_cube_pool) {
/* Cubemap / octahedra map pool */ /* Cubemap / octahedral map pool */
/* TODO Cubemap array */ /* TODO Cubemap array */
txl->shadow_depth_cube_pool = DRW_texture_create_2D_array( txl->shadow_depth_cube_pool = DRW_texture_create_2D_array(
512, 512, max_ff(1, linfo->num_cube), DRW_TEX_R_32, 512, 512, max_ff(1, linfo->num_cube), DRW_TEX_R_32,

@ -190,6 +190,8 @@ typedef struct EEVEE_ProbesInfo {
/* For rendering probes */ /* For rendering probes */
float probemat[6][4][4]; float probemat[6][4][4];
int layer; int layer;
float texel_size;
float padding_size;
float samples_ct; float samples_ct;
float invsamples_ct; float invsamples_ct;
float roughness; float roughness;
@ -282,6 +284,7 @@ void EEVEE_probes_cache_add(EEVEE_Data *vedata, Object *ob);
void EEVEE_probes_cache_finish(EEVEE_Data *vedata); void EEVEE_probes_cache_finish(EEVEE_Data *vedata);
void EEVEE_probes_update(EEVEE_Data *vedata); void EEVEE_probes_update(EEVEE_Data *vedata);
void EEVEE_refresh_probe(EEVEE_Data *vedata); void EEVEE_refresh_probe(EEVEE_Data *vedata);
void EEVEE_probes_free(void);
/* eevee_effects.c */ /* eevee_effects.c */
void EEVEE_effects_init(EEVEE_Data *vedata); void EEVEE_effects_init(EEVEE_Data *vedata);

@ -27,6 +27,8 @@
#include "DNA_texture_types.h" #include "DNA_texture_types.h"
#include "DNA_image_types.h" #include "DNA_image_types.h"
#include "BLI_dynstr.h"
#include "DRW_render.h" #include "DRW_render.h"
#include "eevee_engine.h" #include "eevee_engine.h"
@ -39,33 +41,105 @@ typedef struct EEVEE_ProbeData {
} EEVEE_ProbeData; } EEVEE_ProbeData;
/* TODO Option */ /* TODO Option */
#define PROBE_SIZE 512 #define PROBE_CUBE_SIZE 512
#define PROBE_SIZE 1024
static struct {
struct GPUShader *probe_filter_sh;
struct GPUShader *probe_spherical_harmonic_sh;
struct GPUTexture *hammersley;
float camera_pos[3];
} e_data = {NULL}; /* Engine data */
extern char datatoc_probe_filter_frag_glsl[];
extern char datatoc_probe_sh_frag_glsl[];
extern char datatoc_probe_geom_glsl[];
extern char datatoc_probe_vert_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_bsdf_sampling_lib_glsl[];
/* *********** FUNCTIONS *********** */ /* *********** FUNCTIONS *********** */
/* Van der Corput sequence */
/* From http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html */
static float radical_inverse(int i) {
unsigned int bits = (unsigned int)i;
bits = (bits << 16u) | (bits >> 16u);
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
return (float)bits * 2.3283064365386963e-10f;
}
static struct GPUTexture *create_hammersley_sample_texture(int samples)
{
struct GPUTexture *tex;
float (*texels)[2] = MEM_mallocN(sizeof(float[2]) * samples, "hammersley_tex");
int i;
for (i = 0; i < samples; i++) {
float phi = radical_inverse(i) * 2.0f * M_PI;
texels[i][0] = cos(phi);
texels[i][1] = sinf(phi);
}
tex = DRW_texture_create_1D(samples, DRW_TEX_RG_16, DRW_TEX_WRAP, (float *)texels);
MEM_freeN(texels);
return tex;
}
void EEVEE_probes_init(EEVEE_Data *vedata) void EEVEE_probes_init(EEVEE_Data *vedata)
{ {
EEVEE_StorageList *stl = vedata->stl; EEVEE_StorageList *stl = vedata->stl;
EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_TextureList *txl = vedata->txl; EEVEE_TextureList *txl = vedata->txl;
if (!e_data.probe_filter_sh) {
char *shader_str = NULL;
DynStr *ds_frag = BLI_dynstr_new();
BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
BLI_dynstr_append(ds_frag, datatoc_probe_filter_frag_glsl);
shader_str = BLI_dynstr_get_cstring(ds_frag);
BLI_dynstr_free(ds_frag);
e_data.probe_filter_sh = DRW_shader_create(
datatoc_probe_vert_glsl, datatoc_probe_geom_glsl, shader_str,
"#define HAMMERSLEY_SIZE 1024\n"
"#define NOISE_SIZE 64\n");
MEM_freeN(shader_str);
}
if (!e_data.hammersley) {
e_data.hammersley = create_hammersley_sample_texture(1024);
}
if (!e_data.probe_spherical_harmonic_sh) {
e_data.probe_spherical_harmonic_sh = DRW_shader_create_fullscreen(datatoc_probe_sh_frag_glsl, NULL);
}
if (!stl->probes) { if (!stl->probes) {
stl->probes = MEM_callocN(sizeof(EEVEE_ProbesInfo), "EEVEE_ProbesInfo"); stl->probes = MEM_callocN(sizeof(EEVEE_ProbesInfo), "EEVEE_ProbesInfo");
} }
if (!txl->probe_rt) { if (!txl->probe_rt) {
txl->probe_rt = DRW_texture_create_cube(PROBE_SIZE, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); txl->probe_rt = DRW_texture_create_cube(PROBE_CUBE_SIZE, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
txl->probe_depth_rt = DRW_texture_create_cube(PROBE_SIZE, DRW_TEX_DEPTH_24, DRW_TEX_FILTER, NULL); txl->probe_depth_rt = DRW_texture_create_cube(PROBE_CUBE_SIZE, DRW_TEX_DEPTH_24, DRW_TEX_FILTER, NULL);
} }
DRWFboTexture tex_probe[2] = {{&txl->probe_depth_rt, DRW_TEX_DEPTH_24, DRW_TEX_FILTER}, DRWFboTexture tex_probe[2] = {{&txl->probe_depth_rt, DRW_TEX_DEPTH_24, DRW_TEX_FILTER},
{&txl->probe_rt, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}}; {&txl->probe_rt, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}};
DRW_framebuffer_init(&fbl->probe_fb, &draw_engine_eevee_type, PROBE_SIZE, PROBE_SIZE, tex_probe, 2); DRW_framebuffer_init(&fbl->probe_fb, &draw_engine_eevee_type, PROBE_CUBE_SIZE, PROBE_CUBE_SIZE, tex_probe, 2);
if (!txl->probe_pool) { if (!txl->probe_pool) {
/* TODO array */ /* TODO array */
txl->probe_pool = DRW_texture_create_cube(PROBE_SIZE, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); txl->probe_pool = DRW_texture_create_2D(PROBE_SIZE, PROBE_SIZE, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
} }
DRWFboTexture tex_filter = {&txl->probe_pool, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}; DRWFboTexture tex_filter = {&txl->probe_pool, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
@ -78,9 +152,44 @@ void EEVEE_probes_init(EEVEE_Data *vedata)
DRW_framebuffer_init(&fbl->probe_sh_fb, &draw_engine_eevee_type, 9, 1, &tex_sh, 1); DRW_framebuffer_init(&fbl->probe_sh_fb, &draw_engine_eevee_type, 9, 1, &tex_sh, 1);
} }
void EEVEE_probes_cache_init(EEVEE_Data *UNUSED(vedata)) void EEVEE_probes_cache_init(EEVEE_Data *vedata)
{ {
return; EEVEE_StorageList *stl = vedata->stl;
EEVEE_TextureList *txl = vedata->txl;
EEVEE_PassList *psl = vedata->psl;
{
psl->probe_prefilter = DRW_pass_create("Probe Filtering", DRW_STATE_WRITE_COLOR);
struct Batch *geom = DRW_cache_fullscreen_quad_get();
DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.probe_filter_sh, psl->probe_prefilter, geom);
DRW_shgroup_uniform_float(grp, "sampleCount", &stl->probes->samples_ct, 1);
DRW_shgroup_uniform_float(grp, "invSampleCount", &stl->probes->invsamples_ct, 1);
DRW_shgroup_uniform_float(grp, "roughnessSquared", &stl->probes->roughness, 1);
DRW_shgroup_uniform_float(grp, "lodFactor", &stl->probes->lodfactor, 1);
DRW_shgroup_uniform_float(grp, "lodMax", &stl->probes->lodmax, 1);
DRW_shgroup_uniform_float(grp, "texelSize", &stl->probes->texel_size, 1);
DRW_shgroup_uniform_float(grp, "paddingSize", &stl->probes->padding_size, 1);
DRW_shgroup_uniform_int(grp, "Layer", &stl->probes->layer, 1);
DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
// DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter);
DRW_shgroup_uniform_texture(grp, "probeHdr", txl->probe_rt);
DRW_shgroup_call_dynamic_add_empty(grp);
}
{
psl->probe_sh_compute = DRW_pass_create("Probe SH Compute", DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_spherical_harmonic_sh, psl->probe_sh_compute);
DRW_shgroup_uniform_int(grp, "probeSize", &stl->probes->shres, 1);
DRW_shgroup_uniform_float(grp, "lodBias", &stl->probes->lodfactor, 1);
DRW_shgroup_uniform_texture(grp, "probeHdr", txl->probe_rt);
struct Batch *geom = DRW_cache_fullscreen_quad_get();
DRW_shgroup_call_add(grp, geom, NULL);
}
} }
void EEVEE_probes_cache_add(EEVEE_Data *UNUSED(vedata), Object *UNUSED(ob)) void EEVEE_probes_cache_add(EEVEE_Data *UNUSED(vedata), Object *UNUSED(ob))
@ -120,23 +229,36 @@ void EEVEE_refresh_probe(EEVEE_Data *vedata)
DRW_draw_pass(psl->probe_background); DRW_draw_pass(psl->probe_background);
/* 2 - Let gpu create Mipmaps for Filtered Importance Sampling. */ /* 2 - Let gpu create Mipmaps for Filtered Importance Sampling. */
/* Bind next framebuffer to be able to write to probe_rt. */ /* Bind next framebuffer to be able to gen. mips for probe_rt. */
DRW_framebuffer_bind(fbl->probe_filter_fb); DRW_framebuffer_bind(fbl->probe_filter_fb);
DRW_texture_generate_mipmaps(txl->probe_rt); DRW_texture_generate_mipmaps(txl->probe_rt);
/* 3 - Render to probe array to the specified layer, do prefiltering. */ /* 3 - Render to probe array to the specified layer, do prefiltering. */
/* Detach to rebind the right mipmap. */ /* Detach to rebind the right mipmap. */
DRW_framebuffer_texture_detach(txl->probe_pool); DRW_framebuffer_texture_detach(txl->probe_pool);
float mipsize = PROBE_SIZE * 2; float mipsize = PROBE_SIZE;
int miplevels = 1 + (int)floorf(log2f(PROBE_SIZE)); const int maxlevel = (int)floorf(log2f(PROBE_SIZE));
for (int i = 0; i < miplevels - 2; i++) { const int min_lod_level = 3;
for (int i = 0; i < maxlevel - min_lod_level; i++) {
float bias = (i == 0) ? 0.0f : 1.0f; float bias = (i == 0) ? 0.0f : 1.0f;
pinfo->texel_size = 1.0f / mipsize;
mipsize /= 2; pinfo->padding_size = powf(2.0f, (float)(maxlevel - min_lod_level - 1 - i));
CLAMP_MIN(mipsize, 1); /* XXX : WHY THE HECK DO WE NEED THIS ??? */
/* padding is incorrect without this! float precision issue? */
if (pinfo->padding_size > 32) {
pinfo->padding_size += 5;
}
if (pinfo->padding_size > 16) {
pinfo->padding_size += 4;
}
else if (pinfo->padding_size > 8) {
pinfo->padding_size += 2;
}
else if (pinfo->padding_size > 4) {
pinfo->padding_size += 1;
}
pinfo->layer = 0; pinfo->layer = 0;
pinfo->roughness = (float)i / ((float)miplevels - 3.0f); pinfo->roughness = (float)i / ((float)maxlevel - 4.0f);
pinfo->roughness *= pinfo->roughness; /* Disney Roughness */ pinfo->roughness *= pinfo->roughness; /* Disney Roughness */
pinfo->roughness *= pinfo->roughness; /* Distribute Roughness accros lod more evenly */ pinfo->roughness *= pinfo->roughness; /* Distribute Roughness accros lod more evenly */
CLAMP(pinfo->roughness, 1e-8f, 0.99999f); /* Avoid artifacts */ CLAMP(pinfo->roughness, 1e-8f, 0.99999f); /* Avoid artifacts */
@ -154,14 +276,19 @@ void EEVEE_refresh_probe(EEVEE_Data *vedata)
#endif #endif
pinfo->invsamples_ct = 1.0f / pinfo->samples_ct; pinfo->invsamples_ct = 1.0f / pinfo->samples_ct;
pinfo->lodfactor = bias + 0.5f * log((float)(PROBE_SIZE * PROBE_SIZE) * pinfo->invsamples_ct) / log(2); pinfo->lodfactor = bias + 0.5f * log((float)(PROBE_CUBE_SIZE * PROBE_CUBE_SIZE) * pinfo->invsamples_ct) / log(2);
pinfo->lodmax = (float)miplevels - 3.0f; pinfo->lodmax = floorf(log2f(PROBE_CUBE_SIZE)) - 2.0f;
DRW_framebuffer_texture_attach(fbl->probe_filter_fb, txl->probe_pool, 0, i); DRW_framebuffer_texture_attach(fbl->probe_filter_fb, txl->probe_pool, 0, i);
DRW_framebuffer_viewport_size(fbl->probe_filter_fb, mipsize, mipsize); DRW_framebuffer_viewport_size(fbl->probe_filter_fb, mipsize, mipsize);
DRW_draw_pass(psl->probe_prefilter); DRW_draw_pass(psl->probe_prefilter);
DRW_framebuffer_texture_detach(txl->probe_pool); DRW_framebuffer_texture_detach(txl->probe_pool);
mipsize /= 2;
CLAMP_MIN(mipsize, 1);
} }
/* For shading, save max level of the octahedron map */
pinfo->lodmax = (float)(maxlevel - min_lod_level) - 1.0f;
/* reattach to have a valid framebuffer. */ /* reattach to have a valid framebuffer. */
DRW_framebuffer_texture_attach(fbl->probe_filter_fb, txl->probe_pool, 0, 0); DRW_framebuffer_texture_attach(fbl->probe_filter_fb, txl->probe_pool, 0, 0);
@ -173,3 +300,10 @@ void EEVEE_refresh_probe(EEVEE_Data *vedata)
DRW_draw_pass(psl->probe_sh_compute); DRW_draw_pass(psl->probe_sh_compute);
DRW_framebuffer_read_data(0, 0, 9, 1, 3, 0, (float *)pinfo->shcoefs); DRW_framebuffer_read_data(0, 0, 9, 1, 3, 0, (float *)pinfo->shcoefs);
} }
void EEVEE_probes_free(void)
{
DRW_SHADER_FREE_SAFE(e_data.probe_filter_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_spherical_harmonic_sh);
DRW_TEXTURE_FREE_SAFE(e_data.hammersley);
}

@ -4,7 +4,7 @@ uniform vec3 cameraPos;
uniform vec3 eye; uniform vec3 eye;
uniform mat4 ProjectionMatrix; uniform mat4 ProjectionMatrix;
uniform samplerCube probeFiltered; uniform sampler2D probeFiltered;
uniform float lodMax; uniform float lodMax;
uniform vec3 shCoefs[9]; uniform vec3 shCoefs[9];
@ -42,6 +42,44 @@ in vec3 viewNormal;
#define HEMI 3.0 #define HEMI 3.0
#define AREA 4.0 #define AREA 4.0
vec2 mapping_octahedron(vec3 cubevec, vec2 texel_size)
{
/* projection onto octahedron */
cubevec /= dot( vec3(1), abs(cubevec) );
/* out-folding of the downward faces */
if ( cubevec.z < 0.0 ) {
cubevec.xy = (1.0 - abs(cubevec.yx)) * sign(cubevec.xy);
}
/* mapping to [0;1]ˆ2 texture space */
vec2 uvs = cubevec.xy * (0.5) + 0.5;
/* edge filtering fix */
uvs *= 1.0 - 2.0 * texel_size;
uvs += texel_size;
return uvs;
}
vec4 textureLod_octahedron(sampler2D tex, vec3 cubevec, float lod)
{
vec2 texelSize = 1.0 / vec2(textureSize(tex, int(lodMax)));
vec2 uvs = mapping_octahedron(cubevec, texelSize);
return textureLod(tex, uvs, lod);
}
vec4 texture_octahedron(sampler2DArray tex, vec4 cubevec)
{
vec2 texelSize = 1.0 / vec2(textureSize(tex, 0));
vec2 uvs = mapping_octahedron(cubevec.xyz, texelSize);
return texture(tex, vec3(uvs, cubevec.w));
}
void light_shade( void light_shade(
LightData ld, ShadingData sd, vec3 albedo, float roughness, vec3 f0, LightData ld, ShadingData sd, vec3 albedo, float roughness, vec3 f0,
out vec3 diffuse, out vec3 specular) out vec3 diffuse, out vec3 specular)
@ -139,20 +177,7 @@ void light_visibility(LightData ld, ShadingData sd, out float vis)
vec3 cubevec = sd.W - ld.l_position; vec3 cubevec = sd.W - ld.l_position;
float dist = length(cubevec); float dist = length(cubevec);
/* projection onto octahedron */ float z = texture_octahedron(shadowCubes, vec4(cubevec, shid)).r;
cubevec /= dot( vec3(1), abs(cubevec) );
/* out-folding of the downward faces */
if ( cubevec.z < 0.0 ) {
cubevec.xy = (1.0 - abs(cubevec.yx)) * sign(cubevec.xy);
}
vec2 texelSize = vec2(1.0 / 512.0);
/* mapping to [0;1]ˆ2 texture space */
vec2 uvs = cubevec.xy * (0.5) + 0.5;
uvs = uvs * (1.0 - 2.0 * texelSize) + 1.0 * texelSize; /* edge filtering fix */
float z = texture(shadowCubes, vec3(uvs, shid)).r;
float esm_test = min(1.0, exp(-5.0 * dist) * z); float esm_test = min(1.0, exp(-5.0 * dist) * z);
float sh_test = step(0, z - dist); float sh_test = step(0, z - dist);
@ -194,7 +219,7 @@ vec3 eevee_surface_lit(vec3 world_normal, vec3 albedo, vec3 f0, float roughness,
/* Envmaps */ /* Envmaps */
vec2 uv = lut_coords(dot(sd.N, sd.V), roughness); vec2 uv = lut_coords(dot(sd.N, sd.V), roughness);
vec3 brdf_lut = texture(brdfLut, uv).rgb; vec3 brdf_lut = texture(brdfLut, uv).rgb;
vec3 Li = textureLod(probeFiltered, spec_dir, roughness * lodMax).rgb; vec3 Li = textureLod_octahedron(probeFiltered, spec_dir, roughness * lodMax).rgb;
indirect_radiance += Li * F_ibl(f0, brdf_lut.rg); indirect_radiance += Li * F_ibl(f0, brdf_lut.rg);
indirect_radiance += spherical_harmonics(sd.N, shCoefs) * albedo; indirect_radiance += spherical_harmonics(sd.N, shCoefs) * albedo;

@ -1,17 +1,54 @@
uniform samplerCube probeHdr; uniform samplerCube probeHdr;
uniform float roughnessSquared; uniform float roughnessSquared;
uniform float texelSize;
uniform float lodFactor; uniform float lodFactor;
uniform float lodMax; uniform float lodMax;
uniform float paddingSize;
in vec3 worldPosition; in vec3 worldPosition;
out vec4 FragColor; out vec4 FragColor;
vec3 octahedral_to_cubemap_proj(vec2 co)
{
co = co * 2.0 - 1.0;
vec2 abs_co = abs(co);
vec3 v = vec3(co, 1.0 - (abs_co.x + abs_co.y));
if ( abs_co.x + abs_co.y > 1.0 ) {
v.xy = (abs(co.yx) - 1.0) * -sign(co.xy);
}
return v;
}
void main() { void main() {
vec2 uvs = gl_FragCoord.xy * texelSize;
/* Add a N pixel border to ensure filtering is correct
* for N mipmap levels. */
uvs += uvs * texelSize * paddingSize * 2.0;
uvs -= texelSize * paddingSize;
/* edge mirroring : only mirror if directly adjacent
* (not diagonally adjacent) */
vec2 m = abs(uvs - 0.5) + 0.5;
vec2 f = floor(m);
if (f.x - f.y != 0.0) {
uvs = 1.0 - uvs;
}
/* clamp to [0-1] */
uvs = fract(uvs);
/* get cubemap vector */
vec3 cubevec = octahedral_to_cubemap_proj(uvs);
vec3 N, T, B, V; vec3 N, T, B, V;
vec3 R = normalize(worldPosition); vec3 R = normalize(cubevec);
/* Isotropic assumption */ /* Isotropic assumption */
N = V = R; N = V = R;