From 5773f587622ebf58f6aa3bf4ae60431e8b0f39ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 29 May 2017 22:03:57 +0200 Subject: Eevee: Replace Cubemaps by octahedron maps for env. probes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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). --- source/blender/draw/engines/eevee/eevee_engine.c | 90 +---------- source/blender/draw/engines/eevee/eevee_lights.c | 2 +- source/blender/draw/engines/eevee/eevee_private.h | 3 + source/blender/draw/engines/eevee/eevee_probes.c | 170 ++++++++++++++++++--- .../engines/eevee/shaders/lit_surface_frag.glsl | 57 +++++-- .../engines/eevee/shaders/probe_filter_frag.glsl | 39 ++++- 6 files changed, 238 insertions(+), 123 deletions(-) (limited to 'source/blender') diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 48fdc1ea093..ccd098b24a8 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -62,7 +62,6 @@ static struct { struct GPUTexture *ltc_mat; struct GPUTexture *brdf_lut; - struct GPUTexture *hammersley; struct GPUTexture *jitter; float camera_pos[3]; @@ -89,35 +88,6 @@ extern char datatoc_background_vert_glsl[]; extern Material defmaterial; 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) { 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); } - 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) { 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) { 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); 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); } - + EEVEE_probes_cache_init(vedata); EEVEE_lights_cache_init(stl, psl, txl); - EEVEE_effects_cache_init(vedata); } @@ -669,6 +584,7 @@ static void EEVEE_cache_finish(void *vedata) EEVEE_FramebufferList *fbl = ((EEVEE_Data *)vedata)->fbl; EEVEE_lights_cache_finish(stl, txl, fbl); + EEVEE_probes_cache_finish(vedata); /* Shadows binding */ eevee_bind_shadow_data data; @@ -713,6 +629,7 @@ static void EEVEE_engine_free(void) { EEVEE_effects_free(); EEVEE_lights_free(); + EEVEE_probes_free(); MEM_SAFE_FREE(e_data.frag_shader_lib); 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_TEXTURE_FREE_SAFE(e_data.ltc_mat); DRW_TEXTURE_FREE_SAFE(e_data.brdf_lut); - DRW_TEXTURE_FREE_SAFE(e_data.hammersley); DRW_TEXTURE_FREE_SAFE(e_data.jitter); } diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index f6d68f27c15..2423fda2dd3 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -209,7 +209,7 @@ void EEVEE_lights_cache_finish(EEVEE_StorageList *stl, EEVEE_TextureList *txl, E } } if (!txl->shadow_depth_cube_pool) { - /* Cubemap / octahedra map pool */ + /* Cubemap / octahedral map pool */ /* TODO Cubemap array */ txl->shadow_depth_cube_pool = DRW_texture_create_2D_array( 512, 512, max_ff(1, linfo->num_cube), DRW_TEX_R_32, diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 482b8f075a5..ae984fa5056 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -190,6 +190,8 @@ typedef struct EEVEE_ProbesInfo { /* For rendering probes */ float probemat[6][4][4]; int layer; + float texel_size; + float padding_size; float samples_ct; float invsamples_ct; 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_update(EEVEE_Data *vedata); void EEVEE_refresh_probe(EEVEE_Data *vedata); +void EEVEE_probes_free(void); /* eevee_effects.c */ void EEVEE_effects_init(EEVEE_Data *vedata); diff --git a/source/blender/draw/engines/eevee/eevee_probes.c b/source/blender/draw/engines/eevee/eevee_probes.c index 8a97373f9e4..41ed2b0bf40 100644 --- a/source/blender/draw/engines/eevee/eevee_probes.c +++ b/source/blender/draw/engines/eevee/eevee_probes.c @@ -27,6 +27,8 @@ #include "DNA_texture_types.h" #include "DNA_image_types.h" +#include "BLI_dynstr.h" + #include "DRW_render.h" #include "eevee_engine.h" @@ -39,33 +41,105 @@ typedef struct EEVEE_ProbeData { } EEVEE_ProbeData; /* 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 *********** */ +/* 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) { EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; 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) { stl->probes = MEM_callocN(sizeof(EEVEE_ProbesInfo), "EEVEE_ProbesInfo"); } 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_depth_rt = DRW_texture_create_cube(PROBE_SIZE, DRW_TEX_DEPTH_24, DRW_TEX_FILTER, 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_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}, {&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) { /* 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}; @@ -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); } -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)) @@ -120,23 +229,36 @@ void EEVEE_refresh_probe(EEVEE_Data *vedata) DRW_draw_pass(psl->probe_background); /* 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_texture_generate_mipmaps(txl->probe_rt); /* 3 - Render to probe array to the specified layer, do prefiltering. */ /* Detach to rebind the right mipmap. */ DRW_framebuffer_texture_detach(txl->probe_pool); - float mipsize = PROBE_SIZE * 2; - int miplevels = 1 + (int)floorf(log2f(PROBE_SIZE)); - for (int i = 0; i < miplevels - 2; i++) { + float mipsize = PROBE_SIZE; + const int maxlevel = (int)floorf(log2f(PROBE_SIZE)); + const int min_lod_level = 3; + for (int i = 0; i < maxlevel - min_lod_level; i++) { float bias = (i == 0) ? 0.0f : 1.0f; - - mipsize /= 2; - CLAMP_MIN(mipsize, 1); - + pinfo->texel_size = 1.0f / mipsize; + pinfo->padding_size = powf(2.0f, (float)(maxlevel - min_lod_level - 1 - i)); + /* 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->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; /* Distribute Roughness accros lod more evenly */ CLAMP(pinfo->roughness, 1e-8f, 0.99999f); /* Avoid artifacts */ @@ -154,14 +276,19 @@ void EEVEE_refresh_probe(EEVEE_Data *vedata) #endif 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->lodmax = (float)miplevels - 3.0f; + pinfo->lodfactor = bias + 0.5f * log((float)(PROBE_CUBE_SIZE * PROBE_CUBE_SIZE) * pinfo->invsamples_ct) / log(2); + pinfo->lodmax = floorf(log2f(PROBE_CUBE_SIZE)) - 2.0f; DRW_framebuffer_texture_attach(fbl->probe_filter_fb, txl->probe_pool, 0, i); DRW_framebuffer_viewport_size(fbl->probe_filter_fb, mipsize, mipsize); DRW_draw_pass(psl->probe_prefilter); 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. */ 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_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); +} \ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl index bff7c05537a..ca3cec62bdb 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -4,7 +4,7 @@ uniform vec3 cameraPos; uniform vec3 eye; uniform mat4 ProjectionMatrix; -uniform samplerCube probeFiltered; +uniform sampler2D probeFiltered; uniform float lodMax; uniform vec3 shCoefs[9]; @@ -42,6 +42,44 @@ in vec3 viewNormal; #define HEMI 3.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( LightData ld, ShadingData sd, vec3 albedo, float roughness, vec3 f0, 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; float dist = length(cubevec); - /* 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); - } - 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 z = texture_octahedron(shadowCubes, vec4(cubevec, shid)).r; float esm_test = min(1.0, exp(-5.0 * dist) * z); 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 */ vec2 uv = lut_coords(dot(sd.N, sd.V), roughness); 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 += spherical_harmonics(sd.N, shCoefs) * albedo; diff --git a/source/blender/draw/engines/eevee/shaders/probe_filter_frag.glsl b/source/blender/draw/engines/eevee/shaders/probe_filter_frag.glsl index bee674e3e76..33714c5293c 100644 --- a/source/blender/draw/engines/eevee/shaders/probe_filter_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/probe_filter_frag.glsl @@ -1,17 +1,54 @@ uniform samplerCube probeHdr; uniform float roughnessSquared; +uniform float texelSize; uniform float lodFactor; uniform float lodMax; +uniform float paddingSize; in vec3 worldPosition; 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() { + 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 R = normalize(worldPosition); + vec3 R = normalize(cubevec); /* Isotropic assumption */ N = V = R; -- cgit v1.2.3