diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-06-26 21:37:41 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-06-26 22:04:53 +0300 |
commit | 0394c04a7f0301803a5084ee5a5cb2f294d5de70 (patch) | |
tree | 9e58f018dd66f95175e5e6f40b1be6acca5b1b1e | |
parent | daf02baaeaaf8f0a7c68ae236a2d0782c08aea2f (diff) |
Eevee: Add Planar reflection blurring.
This method is very cheap and inaccurate. This will fill the gap untill better model is supported.
10 files changed, 143 insertions, 10 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index eb3a016f295..31deb59b7fc 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -137,6 +137,9 @@ data_to_c_simple(engines/eevee/shaders/effect_dof_vert.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_dof_geom.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_dof_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.glsl SRC) +data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl SRC) +data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl SRC) +data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl SRC) data_to_c_simple(engines/eevee/shaders/prepass_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/prepass_vert.glsl SRC) data_to_c_simple(engines/eevee/shaders/shadow_frag.glsl SRC) diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index c024eb609b3..88f16e41d6b 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -71,12 +71,11 @@ static void EEVEE_engine_init(void *ved) static void EEVEE_cache_init(void *vedata) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; - EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; EEVEE_SceneLayerData *sldata = EEVEE_scene_layer_data_get(); EEVEE_materials_cache_init(vedata); EEVEE_lights_cache_init(sldata, psl); - EEVEE_lightprobes_cache_init(sldata, psl, stl); + EEVEE_lightprobes_cache_init(sldata, vedata); EEVEE_effects_cache_init(vedata); } diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 8ec603030c5..b85116adc81 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -57,6 +57,7 @@ static struct { struct GPUShader *probe_filter_diffuse_sh; struct GPUShader *probe_grid_display_sh; struct GPUShader *probe_planar_display_sh; + struct GPUShader *probe_planar_downsample_sh; struct GPUShader *probe_cube_display_sh; struct GPUTexture *hammersley; @@ -78,6 +79,9 @@ extern char datatoc_lightprobe_geom_glsl[]; extern char datatoc_lightprobe_vert_glsl[]; extern char datatoc_lightprobe_planar_display_frag_glsl[]; extern char datatoc_lightprobe_planar_display_vert_glsl[]; +extern char datatoc_lightprobe_planar_downsample_frag_glsl[]; +extern char datatoc_lightprobe_planar_downsample_geom_glsl[]; +extern char datatoc_lightprobe_planar_downsample_vert_glsl[]; extern char datatoc_lightprobe_cube_display_frag_glsl[]; extern char datatoc_lightprobe_cube_display_vert_glsl[]; extern char datatoc_lightprobe_grid_display_frag_glsl[]; @@ -254,6 +258,12 @@ void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *UNUSED(ved MEM_freeN(shader_str); + e_data.probe_planar_downsample_sh = DRW_shader_create( + datatoc_lightprobe_planar_downsample_vert_glsl, + datatoc_lightprobe_planar_downsample_geom_glsl, + datatoc_lightprobe_planar_downsample_frag_glsl, + NULL); + e_data.hammersley = create_hammersley_sample_texture(1024); } @@ -296,8 +306,11 @@ void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *UNUSED(ved } } -void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, EEVEE_StorageList *stl) +void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_TextureList *txl = vedata->txl; + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; EEVEE_LightProbesInfo *pinfo = sldata->probes; pinfo->num_cube = 1; /* at least one for the world */ @@ -406,6 +419,15 @@ void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList * DRW_shgroup_uniform_float(grp, "lodMax", &sldata->probes->lodmax, 1); DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool); } + + { + psl->probe_planar_downsample_ps = DRW_pass_create("LightProbe Planar Downsample", DRW_STATE_WRITE_COLOR); + + struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); + DRWShadingGroup *grp = stl->g_data->planar_downsample = DRW_shgroup_instance_create(e_data.probe_planar_downsample_sh, psl->probe_planar_downsample_ps, geom); + DRW_shgroup_uniform_buffer(grp, "source", &txl->planar_pool); + DRW_shgroup_uniform_vec2(grp, "texelSize", stl->g_data->texel_size, 1); + } } void EEVEE_lightprobes_cache_add(EEVEE_SceneLayerData *sldata, Object *ob) @@ -688,6 +710,7 @@ static void EEVEE_lightprobes_updates(EEVEE_SceneLayerData *sldata, EEVEE_PassLi void EEVEE_lightprobes_cache_finish(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_StorageList *stl = vedata->stl; EEVEE_LightProbesInfo *pinfo = sldata->probes; Object *ob; @@ -705,6 +728,9 @@ void EEVEE_lightprobes_cache_finish(EEVEE_SceneLayerData *sldata, EEVEE_Data *ve /* XXX this should be run each frame as it ensure planar_depth is set */ planar_pool_ensure_alloc(vedata, pinfo->num_planar); + /* Setup planar filtering pass */ + DRW_shgroup_set_instance_count(stl->g_data->planar_downsample, pinfo->num_planar); + if (!sldata->probe_pool) { sldata->probe_pool = DRW_texture_create_2D_array(PROBE_OCTAHEDRON_SIZE, PROBE_OCTAHEDRON_SIZE, max_ff(1, pinfo->num_cube), DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); @@ -772,6 +798,24 @@ void EEVEE_lightprobes_cache_finish(EEVEE_SceneLayerData *sldata, EEVEE_Data *ve DRW_uniformbuffer_update(sldata->planar_ubo, &sldata->probes->planar_data); } +static void downsample_planar(void *vedata, int level) +{ + EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; + EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + + const float *size = DRW_viewport_size_get(); + copy_v2_v2(stl->g_data->texel_size, size); + for (int i = 0; i < level - 1; ++i) { + stl->g_data->texel_size[0] /= 2.0f; + stl->g_data->texel_size[1] /= 2.0f; + min_ff(floorf(stl->g_data->texel_size[0]), 1.0f); + min_ff(floorf(stl->g_data->texel_size[1]), 1.0f); + } + invert_v2(stl->g_data->texel_size); + + DRW_draw_pass(psl->probe_planar_downsample_ps); +} + /* Glossy filter probe_rt to probe_pool at index probe_idx */ static void glossy_filter_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, int probe_idx) { @@ -1099,6 +1143,7 @@ static void lightprobe_cell_location_get(EEVEE_LightGrid *egrid, int cell_idx, f void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_TextureList *txl = vedata->txl; EEVEE_PassList *psl = vedata->psl; EEVEE_LightProbesInfo *pinfo = sldata->probes; Object *ob; @@ -1246,6 +1291,11 @@ update_planar: ped->probe_id = i; } } + + /* If there is at least one planar probe */ + if (pinfo->num_planar > 0) { + DRW_framebuffer_recursive_downsample(vedata->fbl->minmaxz_fb, txl->planar_pool, 5, &downsample_planar, vedata); + } } void EEVEE_lightprobes_free(void) @@ -1255,6 +1305,7 @@ void EEVEE_lightprobes_free(void) DRW_SHADER_FREE_SAFE(e_data.probe_filter_diffuse_sh); DRW_SHADER_FREE_SAFE(e_data.probe_grid_display_sh); DRW_SHADER_FREE_SAFE(e_data.probe_planar_display_sh); + DRW_SHADER_FREE_SAFE(e_data.probe_planar_downsample_sh); DRW_SHADER_FREE_SAFE(e_data.probe_cube_display_sh); DRW_TEXTURE_FREE_SAFE(e_data.hammersley); DRW_TEXTURE_FREE_SAFE(e_data.planar_pool_placeholder); diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index a1abb6c71e2..14b0d270dc9 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -78,6 +78,7 @@ typedef struct EEVEE_PassList { struct DRWPass *probe_glossy_compute; struct DRWPass *probe_diffuse_compute; struct DRWPass *probe_display; + struct DRWPass *probe_planar_downsample_ps; /* Effects */ struct DRWPass *motion_blur; @@ -394,10 +395,13 @@ typedef struct EEVEE_PrivateData { struct DRWShadingGroup *depth_shgrp_clip; struct DRWShadingGroup *depth_shgrp_clip_cull; struct DRWShadingGroup *cube_display_shgrp; + struct DRWShadingGroup *planar_downsample; struct GHash *material_hash; struct GHash *hair_material_hash; struct GPUTexture *minmaxz; float background_alpha; /* TODO find a better place for this. */ + /* For planar probes */ + float texel_size[2]; } EEVEE_PrivateData; /* Transient data */ /* eevee_data.c */ @@ -431,7 +435,7 @@ void EEVEE_lights_free(void); /* eevee_lightprobes.c */ void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); -void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, EEVEE_StorageList *stl); +void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); void EEVEE_lightprobes_cache_add(EEVEE_SceneLayerData *sldata, Object *ob); void EEVEE_lightprobes_cache_finish(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index 2aa51039e71..3327c5c4427 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -1,5 +1,6 @@ #define M_PI 3.14159265358979323846 /* pi */ +#define M_2PI 6.28318530717958647692 /* 2*pi */ #define M_PI_2 1.57079632679489661923 /* pi/2 */ #define M_1_PI 0.318309886183790671538 /* 1/pi */ #define M_1_2PI 0.159154943091895335768 /* 1/(2*pi) */ diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl new file mode 100644 index 00000000000..fa70fb5590f --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl @@ -0,0 +1,27 @@ +/** + * Simple downsample shader. Takes the average of the 4 texels of lower mip. + **/ + +uniform sampler2DArray source; +uniform vec2 texelSize; + +in vec2 uvs; +flat in float layer; + +out vec4 FragColor; + +void main() +{ + /* Reconstructing Target uvs like this avoid missing pixels */ + vec2 uvs = floor(gl_FragCoord.xy) * 2.0 * texelSize + texelSize; + + /* Downsample with a 4x4 box filter */ + vec4 d = texelSize.xyxy * vec4(-1, -1, +1, +1); + + FragColor = texture(source, vec3(uvs + d.xy, layer)).rgba; + FragColor += texture(source, vec3(uvs + d.zy, layer)).rgba; + FragColor += texture(source, vec3(uvs + d.xw, layer)).rgba; + FragColor += texture(source, vec3(uvs + d.zw, layer)).rgba; + + FragColor /= 4.0; +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl new file mode 100644 index 00000000000..40b04c986f3 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl @@ -0,0 +1,24 @@ + +layout(triangles) in; +layout(triangle_strip, max_vertices=3) out; + +in int instance[]; +in vec2 vPos[]; + +flat out float layer; + +void main() { + gl_Layer = instance[0]; + layer = float(instance[0]); + + gl_Position = vec4(vPos[0], 0.0, 0.0); + EmitVertex(); + + gl_Position = vec4(vPos[1], 0.0, 0.0); + EmitVertex(); + + gl_Position = vec4(vPos[2], 0.0, 0.0); + EmitVertex(); + + EndPrimitive(); +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl new file mode 100644 index 00000000000..ac4e3da4158 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl @@ -0,0 +1,10 @@ + +in vec2 pos; + +out int instance; +out vec2 vPos; + +void main() { + instance = gl_InstanceID; + vPos = pos; +}
\ 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 8202acc959a..d6cc170f025 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -409,7 +409,21 @@ vec3 eevee_surface_lit(vec3 world_normal, vec3 albedo, vec3 f0, float roughness, refco = pd.reflectionmat * vec4(ref_pos, 1.0); refco.xy /= refco.w; - vec3 sample = textureLod(probePlanars, vec3(refco.xy, i), 0.0).rgb; + /* Distance to roughness */ + float linear_roughness = sqrt(roughness); + float distance_roughness = min(linear_roughness, ref_depth * linear_roughness); + linear_roughness = mix(distance_roughness, linear_roughness, linear_roughness); + + /* Decrease influence for high roughness */ + influ_spec *= saturate((1.0 - linear_roughness) * 5.0 - 2.0); + + float lod = linear_roughness * 2.5 * 5.0; + vec3 sample = textureLod(probePlanars, vec3(refco.xy, i), lod).rgb; + + /* Use a second sample randomly rotated to blur out the lowres aspect */ + vec2 rot_sample = (1.0 / vec2(textureSize(probePlanars, 0).xy)) * vec2(cos(rand.a * M_2PI), sin(rand.a * M_2PI)) * lod; + sample += textureLod(probePlanars, vec3(refco.xy + rot_sample, i), lod).rgb; + sample *= 0.5; spec_accum.rgb += sample * influ_spec; spec_accum.a += influ_spec; diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index ddf0e83309c..cb782358f91 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -575,11 +575,11 @@ void GPU_framebuffer_recursive_downsample( /* bind next level for rendering but first restrict fetches only to previous level */ GPU_texture_bind(tex, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, i-1); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i-1); + glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, i-1); + glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, i-1); GPU_texture_unbind(tex); - glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, GPU_texture_opengl_bindcode(tex), i); + glFramebufferTexture(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), i); callback(userData, i); } @@ -588,8 +588,8 @@ void GPU_framebuffer_recursive_downsample( /* reset mipmap level range for the depth image */ GPU_texture_bind(tex, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, num_iter - 1); + glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, num_iter); GPU_texture_unbind(tex); } |