From fbf7e5acfb5085bcec2fc49c2cd673b741c40ffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fukhaut?= Date: Sat, 4 Jun 2016 21:38:03 +0200 Subject: -Finished SSR Integration -Added HiZ bufffer generation for future HiZ raytracing -Rewritten probe choosing code -Fixed glossy aniso mistakes --- source/blender/editors/space_view3d/view3d_draw.c | 10 +- source/blender/gpu/CMakeLists.txt | 4 + source/blender/gpu/GPU_framebuffer.h | 2 + source/blender/gpu/GPU_pbr.h | 2 + source/blender/gpu/GPU_shader.h | 6 +- source/blender/gpu/intern/gpu_draw.c | 62 +++++---- source/blender/gpu/intern/gpu_framebuffer.c | 66 +++++++++ source/blender/gpu/intern/gpu_material.c | 16 ++- source/blender/gpu/intern/gpu_pbr.c | 59 +++++++-- source/blender/gpu/intern/gpu_probe.c | 2 +- source/blender/gpu/intern/gpu_shader.c | 26 ++++ .../shaders/gpu_shader_downsample_maxz_frag.glsl | 65 +++++++++ .../shaders/gpu_shader_downsample_maxz_vert.glsl | 6 + ...gpu_shader_material_bsdf_ambient_occlusion.glsl | 4 +- .../gpu_shader_material_bsdf_anisotropic.glsl | 27 ++-- .../shaders/gpu_shader_material_bsdf_glossy.glsl | 3 +- .../gpu/shaders/gpu_shader_material_utils.glsl | 147 +++++++++++++-------- source/blender/makesrna/intern/rna_space.c | 2 +- 18 files changed, 381 insertions(+), 128 deletions(-) create mode 100644 source/blender/gpu/shaders/gpu_shader_downsample_maxz_frag.glsl create mode 100644 source/blender/gpu/shaders/gpu_shader_downsample_maxz_vert.glsl (limited to 'source') diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 187772a305a..716f5362313 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -2901,12 +2901,13 @@ static void gpu_update_scene_buffer(Scene *scene, View3D *v3d, ARegion *basear) false, (bool)scene->world, true, true, NULL, NULL, NULL, NULL); - GPU_scenebuf_unbind(scene_buffer); - v3d->drawtype = drawtype; v3d->flag2 = flag2; v3d->flag3 = flag3; v3d->pbr_settings.pbr_flag = pbr_flag; + + GPU_scenebuf_unbind(scene_buffer); + GPU_scenebuf_filter_texture(scene_buffer); } static void gpu_update_backface_buffer(Scene *scene, View3D *v3d, ARegion *basear) @@ -2948,12 +2949,13 @@ static void gpu_update_backface_buffer(Scene *scene, View3D *v3d, ARegion *basea false, (bool)scene->world, true, true, NULL, NULL, NULL, NULL); - GPU_scenebuf_unbind(backface_buffer); - v3d->drawtype = drawtype; v3d->flag2 = flag2; v3d->flag3 = flag3; v3d->pbr_settings.pbr_flag = pbr_flag; + + GPU_scenebuf_unbind(backface_buffer); + GPU_scenebuf_filter_texture(backface_buffer); } diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index f043b770870..6bb94b334b5 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -99,6 +99,8 @@ set(SRC shaders/gpu_shader_probe_sh_compute_vert.glsl shaders/gpu_shader_display_sh_frag.glsl shaders/gpu_shader_display_sh_vert.glsl + shaders/gpu_shader_downsample_maxz_frag.glsl + shaders/gpu_shader_downsample_maxz_vert.glsl GPU_basic_shader.h GPU_buffers.h @@ -159,6 +161,8 @@ data_to_c_simple(shaders/gpu_shader_probe_sh_compute_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_probe_sh_compute_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_display_sh_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_display_sh_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_downsample_maxz_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_downsample_maxz_vert.glsl SRC) if(WITH_GAMEENGINE) add_definitions(-DWITH_GAMEENGINE) diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index f81b35c4dde..f7ffecf9511 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -67,6 +67,8 @@ void GPU_framebuffer_blur( GPUFrameBuffer *fb, struct GPUTexture *tex, GPUFrameBuffer *blurfb, struct GPUTexture *blurtex); +void GPU_framebuffer_hiz_construction(GPUFrameBuffer *fb, struct GPUTexture *tex, const bool max); + /* GPU OffScreen * - wrapper around framebuffer and texture for simple offscreen drawing * - changes size if graphics card can't support it */ diff --git a/source/blender/gpu/GPU_pbr.h b/source/blender/gpu/GPU_pbr.h index 6670987acef..1efca5ca68b 100644 --- a/source/blender/gpu/GPU_pbr.h +++ b/source/blender/gpu/GPU_pbr.h @@ -47,6 +47,7 @@ typedef struct GPUScreenBuffer { struct GPUTexture *tex; struct GPUTexture *depth; struct GPUFrameBuffer *fb; + struct GPUFrameBuffer *downsamplingfb; } GPUScreenBuffer; typedef struct GPUPBR { @@ -73,6 +74,7 @@ GPUScreenBuffer *GPU_pbr_scene_buffer(GPUPBR *pbr, int width, int height); GPUScreenBuffer *GPU_pbr_backface_buffer(GPUPBR *pbr, int width, int height); void GPU_scenebuf_bind(GPUScreenBuffer* buf, float winmat[4][4], int winsize[2], float clipsta, float clipend); void GPU_scenebuf_unbind(GPUScreenBuffer* buf); +void GPU_scenebuf_filter_texture(GPUScreenBuffer* buf); void GPU_pbr_settings_validate(struct GPUPBRSettings *pbr_settings); diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index cc7ec4e95e9..6911a8022ff 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -96,9 +96,11 @@ typedef enum GPUBuiltinShader { GPU_SHADER_SEP_GAUSSIAN_BLUR = 1, GPU_SHADER_SMOKE = 2, GPU_SHADER_SMOKE_FIRE = 3, - GPU_SHADER_DISPLAY_SH = 4, + GPU_SHADER_MINZ_DOWNSAMPLE = 4, + GPU_SHADER_MAXZ_DOWNSAMPLE = 5, + GPU_SHADER_DISPLAY_SH = 6, - GPU_SHADER_COMPUTE_SH = 5, /* This reserves the MAX_SH_SAMPLES following values */ + GPU_SHADER_COMPUTE_SH = 7, /* This reserves the MAX_SH_SAMPLES following values */ } GPUBuiltinShader; #define MAX_SH_SAMPLES 10 diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 79f0bbc6d6d..337f573b394 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -1851,47 +1851,45 @@ void GPU_begin_object_materials( } if (v3d->flag3 & V3D_PROBE_CAPTURE) { + Object *pro = (ob->probetype == OB_PROBE_OBJECT && ob->probe) + ? ob->probe /* probe attached */ + : ob; /* object itself */ + GMS.use_ssr = false; GMS.use_ssao = false; GMS.use_backface_depth = false; - } - - /* Picking the right probe */ - /* XXX need to be done clearer */ - if (ob->probetype == OB_PROBE_CUBEMAP || ob->probetype == OB_PROBE_PLANAR) { - - GMS.is_planar_probe = (ob->probetype == OB_PROBE_PLANAR); - if (GMS.is_planar_probe && (v3d->flag3 & V3D_PROBE_CAPTURE)) { - /* Disable planar reflection in probe capture */ - GMS.is_planar_probe = false; - - if (ob->probe && ob->probe->probetype == OB_PROBE_CUBEMAP) { - GMS.gprobe = GPU_probe_object(scene, ob->probe); - GMS.parallax_correc = ob->probe->probeparallax; + /* check if we are not rendering this particular probe to avoid feedback loop */ + if (pro != v3d->probe_source) { + if (pro->probetype == OB_PROBE_CUBEMAP) { + GMS.gprobe = GPU_probe_object(scene, pro); + GMS.parallax_correc = pro->probeparallax; } - else { - /* it will later get the world probe eventualy */ + else if (pro->probetype == OB_PROBE_PLANAR) { + /* fallback to attached probe or world probe */ + if (pro->probe && pro->probe->probetype == OB_PROBE_CUBEMAP + && pro->probe != v3d->probe_source) { + GMS.gprobe = GPU_probe_object(scene, pro->probe); + GMS.parallax_correc = pro->probe->probeparallax; + } } } - else { - GMS.gprobe = GPU_probe_object(scene, ob); - - if (ob->probetype == OB_PROBE_CUBEMAP) - GMS.parallax_correc = ob->probeparallax; - else if (ob->probe && ob->probe->probetype == OB_PROBE_CUBEMAP) - GMS.parallax_correc = ob->probe->probeparallax; - } } - else if (ob->probetype == OB_PROBE_OBJECT && ob->probe) { - /* check if we are not rendering this particular probe to avoid feedback loop */ - if (!((v3d->flag3 & V3D_PROBE_CAPTURE) && (ob->probe == v3d->probe_source))) { - if (ob->probe->probetype == OB_PROBE_CUBEMAP || ob->probe->probetype == OB_PROBE_PLANAR) { - GMS.is_planar_probe = (ob->probe->probetype == OB_PROBE_PLANAR); - GMS.gprobe = GPU_probe_object(scene, ob->probe); + else { + Object *pro = (ob->probetype == OB_PROBE_OBJECT && ob->probe) + ? ob->probe /* probe attached */ + : ob; /* object itself */ - if (ob->probe->probetype == OB_PROBE_CUBEMAP) - GMS.parallax_correc = ob->probe->probeparallax; + if (pro->probetype == OB_PROBE_CUBEMAP) { + GMS.gprobe = GPU_probe_object(scene, pro); + GMS.parallax_correc = pro->probeparallax; + } + else if (pro->probetype == OB_PROBE_PLANAR) { + GMS.is_planar_probe = true; + GMS.gprobe = GPU_probe_object(scene, pro); + /* Pass the parallax info of the fallback cubemap*/ + if (pro->probe && pro->probe->probetype == OB_PROBE_CUBEMAP) { + GMS.parallax_correc = pro->probe->probeparallax; } } } diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index 1d6fb613769..3736d3f673f 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -460,6 +460,72 @@ void GPU_framebuffer_blur( GPU_shader_unbind(); } +void GPU_framebuffer_hiz_construction(GPUFrameBuffer* fb, GPUTexture *tex, const bool max) +{ + int current_dim[2] = {GPU_texture_width(tex), GPU_texture_height(tex)}; + int levels, bindcode; + int lowermip_uniform, lowermipsize_uniform; + GPUShader *shader = GPU_shader_get_builtin_shader((max) ? GPU_SHADER_MAXZ_DOWNSAMPLE : GPU_SHADER_MINZ_DOWNSAMPLE); + + if (!shader) + return; + + GPU_shader_bind(shader); + lowermip_uniform = GPU_shader_get_uniform(shader, "lowermip"); + lowermipsize_uniform = GPU_shader_get_uniform(shader, "lowermipsize"); + + GPU_framebuffer_texture_attach(fb, tex, 0, NULL); + GPU_texture_bind_as_framebuffer(tex); + + bindcode = GPU_texture_opengl_bindcode(tex); + + levels = 1 + (int)floorf(log2f(fmaxf(current_dim[0], current_dim[1]))); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + + /* Avoid warning from GPU_texture_bind */ + glBindTexture(GL_TEXTURE_2D, bindcode); + GPU_shader_uniform_texture(shader, lowermip_uniform, tex); + + for (int i=1; i < levels; i++) { + /* Send previous mip size to the shader */ + GPU_shader_uniform_vector_int(shader, lowermipsize_uniform, 2, 1, current_dim); + + /* calculate next viewport size */ + current_dim[0] /= 2; + current_dim[1] /= 2; + + /* ensure that the viewport size is always at least 1x1 */ + CLAMP_MIN(current_dim[0], 1); + CLAMP_MIN(current_dim[1], 1); + glViewport(0, 0, current_dim[0], current_dim[1]); + + /* bind next level for rendering but first restrict fetches only to previous level */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, i-1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i-1); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, bindcode, i); + + /* Drawing quad */ + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2d(1.0, 1.0); glVertex3f( 1.0, 1.0, 1.0); + glTexCoord2d(0.0, 1.0); glVertex3f(-1.0, 1.0, 1.0); + glTexCoord2d(1.0, 0.0); glVertex3f( 1.0, -1.0, 1.0); + glTexCoord2d(0.0, 0.0); glVertex3f(-1.0, -1.0, 1.0); + glEnd(); + } + + GPU_framebuffer_texture_detach(tex); + GPU_framebuffer_texture_unbind(fb, tex); + + /* reset mipmap level range for the depth image */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels - 1); + + GPU_shader_unbind(); + GPU_texture_unbind(tex); +} + /* GPUOffScreen */ struct GPUOffScreen { diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 6d330681c17..009044a65c9 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -2391,9 +2391,9 @@ static const char *brdf_light_function(GPUBrdfType brdftype, int lamptype) else if (brdftype == GPU_BRDF_ANISO_BECKMANN) { switch (lamptype) { case LA_SUN : - case LA_HEMI : return "bsdf_anisotropic_ggx_sun_light"; - case LA_AREA : return "bsdf_anisotropic_ggx_area_light"; - default : return "bsdf_anisotropic_ggx_sphere_light"; + case LA_HEMI : return "bsdf_anisotropic_beckmann_sun_light"; + case LA_AREA : return "bsdf_anisotropic_beckmann_area_light"; + default : return "bsdf_anisotropic_beckmann_sphere_light"; } } else if (brdftype == GPU_BRDF_ANISO_ASHIKHMIN_SHIRLEY) { @@ -2540,8 +2540,14 @@ static void shade_one_brdf_light(GPUBrdfInput *brdf, GPULamp *lamp) visifac = lamp_get_visibility(mat, lamp, &lv, &dist); /* View Position */ - if (((brdf->type == GPU_BRDF_TRANSLUCENT || brdf->type == GPU_BRDF_DIFFUSE || brdf->type == GPU_BRDF_GLOSSY_GGX || brdf->type == GPU_BRDF_GLOSSY_BECKMANN) && (lamp->type == LA_AREA)) || - ((brdf->type == GPU_BRDF_GLOSSY_GGX || brdf->type == GPU_BRDF_REFRACT_GGX || brdf->type == GPU_BRDF_GLASS_GGX) && (lamp->type == LA_LOCAL || lamp->type == LA_SPOT))) + if (((brdf->type == GPU_BRDF_TRANSLUCENT || + brdf->type == GPU_BRDF_DIFFUSE || + brdf->type == GPU_BRDF_GLOSSY_GGX || + brdf->type == GPU_BRDF_GLOSSY_ASHIKHMIN_SHIRLEY || + brdf->type == GPU_BRDF_GLOSSY_BECKMANN) && (lamp->type == LA_AREA)) || + ((brdf->type == GPU_BRDF_GLOSSY_GGX || + brdf->type == GPU_BRDF_REFRACT_GGX || + brdf->type == GPU_BRDF_GLASS_GGX) && (lamp->type == LA_LOCAL || lamp->type == LA_SPOT))) GPU_link(mat, "set_rgb", GPU_builtin(GPU_VIEW_POSITION), &view); else GPU_link(mat, "shade_view", GPU_builtin(GPU_VIEW_POSITION), &view); diff --git a/source/blender/gpu/intern/gpu_pbr.c b/source/blender/gpu/intern/gpu_pbr.c index bc244941bd8..17d2d4da99b 100644 --- a/source/blender/gpu/intern/gpu_pbr.c +++ b/source/blender/gpu/intern/gpu_pbr.c @@ -43,6 +43,7 @@ #include "GPU_texture.h" #include "GPU_framebuffer.h" #include "GPU_pbr.h" +#include "GPU_draw.h" #include "gpu_codegen.h" @@ -54,6 +55,10 @@ void GPU_scenebuf_free(GPUScreenBuffer *buf) { + if (buf->fb) { + GPU_framebuffer_free(buf->fb); + buf->fb = NULL; + } if (buf->tex) { GPU_texture_free(buf->tex); buf->tex = NULL; @@ -62,9 +67,9 @@ void GPU_scenebuf_free(GPUScreenBuffer *buf) GPU_texture_free(buf->depth); buf->depth = NULL; } - if (buf->fb) { - GPU_framebuffer_free(buf->fb); - buf->fb = NULL; + if (buf->downsamplingfb) { + GPU_framebuffer_free(buf->downsamplingfb); + buf->downsamplingfb = NULL; } MEM_freeN(buf); @@ -76,7 +81,7 @@ static GPUScreenBuffer *gpu_scenebuf_create(int width, int height, bool depth_on buf->w = width; buf->h = height; - buf->tex = NULL; + buf->depth = NULL; buf->fb = GPU_framebuffer_create(); if (!buf->fb) { @@ -84,6 +89,13 @@ static GPUScreenBuffer *gpu_scenebuf_create(int width, int height, bool depth_on return NULL; } + /* DOWNSAMPLING FB */ + buf->downsamplingfb = GPU_framebuffer_create(); + if (!buf->downsamplingfb) { + GPU_scenebuf_free(buf); + return NULL; + } + if (depth_only) { buf->tex = GPU_texture_create_depth(width, height, NULL); if (!buf->tex) { @@ -95,6 +107,12 @@ static GPUScreenBuffer *gpu_scenebuf_create(int width, int height, bool depth_on GPU_scenebuf_free(buf); return NULL; } + + /* check validity at the very end! */ + if (!GPU_framebuffer_check_valid(buf->fb, NULL)) { + GPU_scenebuf_free(buf); + return NULL; + } } else { buf->depth = GPU_texture_create_depth(width, height, NULL); @@ -118,13 +136,14 @@ static GPUScreenBuffer *gpu_scenebuf_create(int width, int height, bool depth_on GPU_scenebuf_free(buf); return NULL; } + + /* check validity at the very end! */ + if (!GPU_framebuffer_check_valid(buf->fb, NULL)) { + GPU_scenebuf_free(buf); + return NULL; + } } - /* check validity at the very end! */ - if (!GPU_framebuffer_check_valid(buf->fb, NULL)) { - GPU_scenebuf_free(buf); - return NULL; - } GPU_framebuffer_restore(); @@ -195,6 +214,28 @@ void GPU_scenebuf_unbind(GPUScreenBuffer* buf) glEnable(GL_SCISSOR_TEST); } +void GPU_scenebuf_filter_texture(GPUScreenBuffer* buf) +{ + return; + /* MinZ Pyramid for depth */ + if (buf->depth) { + GPU_texture_bind(buf->depth, 0); + GPU_generate_mipmap(GL_TEXTURE_2D); + GPU_texture_unbind(buf->depth); + GPU_framebuffer_hiz_construction(buf->downsamplingfb, buf->depth, false); + GPU_framebuffer_texture_attach(buf->fb, buf->depth, 0, NULL); + } + else { + GPU_texture_bind(buf->tex, 0); + GPU_generate_mipmap(GL_TEXTURE_2D); + GPU_texture_unbind(buf->tex); + GPU_framebuffer_hiz_construction(buf->downsamplingfb, buf->tex, true); + GPU_framebuffer_texture_attach(buf->fb, buf->tex, 0, NULL); + } + + GPU_framebuffer_restore(); +} + /* PBR core */ GPUPBR *GPU_pbr_create(void) diff --git a/source/blender/gpu/intern/gpu_probe.c b/source/blender/gpu/intern/gpu_probe.c index cc3d24188eb..e1f5583bccb 100644 --- a/source/blender/gpu/intern/gpu_probe.c +++ b/source/blender/gpu/intern/gpu_probe.c @@ -491,7 +491,7 @@ void GPU_probe_rebuild_mipmaps(GPUProbe *probe) GPU_generate_mipmap(GL_TEXTURE_CUBE_MAP); GPU_texture_unbind(probe->tex); } - if (probe->type == GPU_PROBE_PLANAR) { + else if (probe->type == GPU_PROBE_PLANAR) { GPU_texture_bind(probe->texreflect, 0); GPU_generate_mipmap(GL_TEXTURE_2D); GPU_texture_unbind(probe->texreflect); diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index d58d34b868b..6371259d32c 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -66,6 +66,8 @@ extern char datatoc_gpu_shader_probe_sh_compute_frag_glsl[]; extern char datatoc_gpu_shader_probe_sh_compute_vert_glsl[]; extern char datatoc_gpu_shader_display_sh_frag_glsl[]; extern char datatoc_gpu_shader_display_sh_vert_glsl[]; +extern char datatoc_gpu_shader_downsample_maxz_frag_glsl[]; +extern char datatoc_gpu_shader_downsample_maxz_vert_glsl[]; static struct GPUShadersGlobal { struct { @@ -75,6 +77,8 @@ static struct GPUShadersGlobal { GPUShader *smoke_fire; GPUShader *compute_sh[MAX_SH_SAMPLES]; GPUShader *display_sh; + GPUShader *maxz_downsample; + GPUShader *minz_downsample; /* cache for shader fx. Those can exist in combinations so store them here */ GPUShader *fx_shaders[MAX_FX_SHADERS * 2]; } shaders; @@ -694,6 +698,18 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) NULL, NULL, NULL, 0, 0, 0); retval = GG.shaders.display_sh; break; + case GPU_SHADER_MAXZ_DOWNSAMPLE: + if (!GG.shaders.maxz_downsample) + GG.shaders.maxz_downsample = GPU_shader_create( + datatoc_gpu_shader_downsample_maxz_vert_glsl, datatoc_gpu_shader_downsample_maxz_frag_glsl, + NULL, NULL, NULL, 0, 0, 0); + case GPU_SHADER_MINZ_DOWNSAMPLE: + if (!GG.shaders.minz_downsample) + GG.shaders.minz_downsample = GPU_shader_create( + datatoc_gpu_shader_downsample_maxz_vert_glsl, datatoc_gpu_shader_downsample_maxz_frag_glsl, + NULL, NULL, "#define MIN;\n", 0, 0, 0); + retval = GG.shaders.minz_downsample; + break; } } @@ -822,6 +838,16 @@ void GPU_shader_free_builtin_shaders(void) GG.shaders.display_sh = NULL; } + if (GG.shaders.maxz_downsample) { + GPU_shader_free(GG.shaders.maxz_downsample); + GG.shaders.maxz_downsample = NULL; + } + + if (GG.shaders.minz_downsample) { + GPU_shader_free(GG.shaders.minz_downsample); + GG.shaders.minz_downsample = NULL; + } + for (i = 0; i < 2 * MAX_FX_SHADERS; ++i) { if (GG.shaders.fx_shaders[i]) { GPU_shader_free(GG.shaders.fx_shaders[i]); diff --git a/source/blender/gpu/shaders/gpu_shader_downsample_maxz_frag.glsl b/source/blender/gpu/shaders/gpu_shader_downsample_maxz_frag.glsl new file mode 100644 index 00000000000..3229b41ffdb --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_downsample_maxz_frag.glsl @@ -0,0 +1,65 @@ +/* From http://rastergrid.com/blog/2010/10/hierarchical-z-map-based-occlusion-culling/ */ +#extension GL_EXT_gpu_shader4 : enable + +uniform sampler2D lowermip; +uniform ivec2 lowermipsize; + +float minmax(float a, float b, float c, float d) +{ +#ifdef MIN + return min(min(a, b), min(c, d)); +#else + return max(max(a, b), max(c, d)); +#endif +} + +float minmax(float a, float b, float c) +{ +#ifdef MIN + return min(min(a, b), c); +#else + return max(max(a, b), c); +#endif +} + +float minmax(float a, float b) +{ +#ifdef MIN + return min(a, b); +#else + return max(a, b); +#endif +} + +void main() +{ + vec4 texels; + ivec2 texelPos = ivec2(gl_FragCoord.xy) * 2; + texels.x = texelFetch(lowermip, texelPos, 0).r; + texels.y = texelFetch(lowermip, texelPos + ivec2(1, 0), 0).r; + texels.z = texelFetch(lowermip, texelPos + ivec2(1, 1), 0).r; + texels.w = texelFetch(lowermip, texelPos + ivec2(0, 1), 0).r; + + float minmaxz = minmax(texels.x, texels.y, texels.z, texels.w); + vec3 extra; + /* if we are reducing an odd-width texture then fetch the edge texels */ + if (((lowermipsize.x & 1) != 0) && (int(gl_FragCoord.x) == lowermipsize.x-3)) { + /* if both edges are odd, fetch the top-left corner texel */ + if (((lowermipsize.y & 1) != 0) && (int(gl_FragCoord.y) == lowermipsize.y-3)) { + extra.z = texelFetch(lowermip, texelPos + ivec2(-1, -1), 0).r; + minmaxz = minmax(minmaxz, extra.z); + } + extra.x = texelFetch(lowermip, texelPos + ivec2(0, -1), 0).r; + extra.y = texelFetch(lowermip, texelPos + ivec2(1, -1), 0).r; + minmaxz = minmax(minmaxz, extra.x, extra.y); + } + /* if we are reducing an odd-height texture then fetch the edge texels */ + else if (((lowermipsize.y & 1) != 0) && (int(gl_FragCoord.y) == lowermipsize.y-3)) { + extra.x = texelFetch(lowermip, texelPos + ivec2(0, -1), 0).r; + extra.y = texelFetch(lowermip, texelPos + ivec2(1, -1), 0).r; + minmaxz = minmax(minmaxz, extra.x, extra.y); + } + + gl_FragDepth = minmaxz; + gl_FragColor = vec4(1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_downsample_maxz_vert.glsl b/source/blender/gpu/shaders/gpu_shader_downsample_maxz_vert.glsl new file mode 100644 index 00000000000..203d5322cee --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_downsample_maxz_vert.glsl @@ -0,0 +1,6 @@ + +void main() +{ + gl_Position = gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; +} diff --git a/source/blender/gpu/shaders/gpu_shader_material_bsdf_ambient_occlusion.glsl b/source/blender/gpu/shaders/gpu_shader_material_bsdf_ambient_occlusion.glsl index 8041bb14a6a..8d37e1523de 100644 --- a/source/blender/gpu/shaders/gpu_shader_material_bsdf_ambient_occlusion.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material_bsdf_ambient_occlusion.glsl @@ -112,7 +112,7 @@ void ssao(vec3 viewpos, vec3 viewnor, out float result) if (co.x > unfclip.z || co.x < 0.0 || co.y > unfclip.w || co.y < 0.0) break; - float sampledepth = frontface_depth(ivec2(co.xy)); + float sampledepth = frontface_depth(ivec2(co.xy), 0); /* Background Case */ if (sampledepth == 1.0) @@ -121,7 +121,7 @@ void ssao(vec3 viewpos, vec3 viewnor, out float result) /* We have a hit */ if (sampledepth > ray.z + viewpos.z + homcoord * 0.002 #ifdef USE_BACKFACE - && backface_depth(ivec2(co.xy)) < ray.z + viewpos.z + && backface_depth(ivec2(co.xy), 0) < ray.z + viewpos.z #endif ) { diff --git a/source/blender/gpu/shaders/gpu_shader_material_bsdf_anisotropic.glsl b/source/blender/gpu/shaders/gpu_shader_material_bsdf_anisotropic.glsl index 437f1b6d64b..cad9e28037a 100644 --- a/source/blender/gpu/shaders/gpu_shader_material_bsdf_anisotropic.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material_bsdf_anisotropic.glsl @@ -85,15 +85,14 @@ float D_ggx_aniso_opti(float NH, float XH2, float YH2, float a2, float ax2, floa return M_PI * a2 * tmp*tmp; /* Doing RCP at the end */ } -float D_beckmann_aniso(float NH, float XH2, float YH2, float a2, float ax, float ay) +float D_beckmann_aniso(float NH, float XH, float YH, float a2, float ax, float ay) { - /* Ht is tangent space microfacet normal (global variable) */ - float sx = -Ht.x / (Ht.z * ax); - float sy = -Ht.y / (Ht.z * ay); + float sx = -XH / (NH * ax); + float sy = -YH / (NH * ay); - float costheta4 = Ht.z * Ht.z * Ht.z * Ht.z; + float NH2 = NH * NH; - return exp(-sx*sx - sy*sy) / (M_PI * a2 * costheta4); + return exp(-sx*sx - sy*sy) / (M_PI * a2 * NH2 * NH2); } float pdf_ggx_aniso(float NH, float XH2, float YH2, float a2, float ax2, float ay2) @@ -102,9 +101,9 @@ float pdf_ggx_aniso(float NH, float XH2, float YH2, float a2, float ax2, float a return NH / D; } -float pdf_beckmann_aniso(float NH, float XH2, float YH2, float a2, float ax2, float ay2) +float pdf_beckmann_aniso(float NH, float XH, float YH, float a2, float ax, float ay) { - float D = D_beckmann_aniso(NH, XH2, YH2, a2, ax2, ay2); + float D = D_beckmann_aniso(NH, XH, YH, a2, ax, ay); return NH / D; } @@ -208,14 +207,14 @@ float bsdf_beckmann_aniso(vec3 N, vec3 T, vec3 L, vec3 V, float roughness_x, flo float VY2 = pow(dot(V, Y), 2); /* sinPhiO² */ float LX2 = pow(dot(L, X), 2); /* cosPhiI² */ float LY2 = pow(dot(L, Y), 2); /* sinPhiI² */ - float XH2 = pow(dot(X, H), 2); - float YH2 = pow(dot(Y, H), 2); + float XH = dot(X, H); + float YH = dot(Y, H); float alphaV2 = (VX2 * ax2 + VY2 * ay2) / (VX2 + VY2); float alphaL2 = (LX2 * ax2 + LY2 * ay2) / (LX2 + LY2); float G = G1_Smith_beckmann(NV, alphaV2) * G1_Smith_beckmann(NL, alphaL2); - float D = D_beckmann_aniso(NH, XH2, YH2, a2, ax2, ay2); + float D = D_beckmann_aniso(NH, XH, YH, a2, ax, ay); return NL * D * G * 0.25 / (NL * NV); } @@ -698,10 +697,10 @@ void env_sampling_aniso_beckmann( if (NL > 0.0) { /* Step 1 : Sampling Environment */ float NH = Ht.z; - float XH2 = Ht.x * Ht.x; - float YH2 = Ht.y * Ht.y; + float XH = Ht.x; + float YH = Ht.y; - float pdf = pdf_beckmann_aniso(NH, XH2, YH2, a2, ax, ay); + float pdf = pdf_beckmann_aniso(NH, XH, YH, a2, ax, ay); vec4 sample = sample_reflect_pdf(L, roughness, pdf); diff --git a/source/blender/gpu/shaders/gpu_shader_material_bsdf_glossy.glsl b/source/blender/gpu/shaders/gpu_shader_material_bsdf_glossy.glsl index 839ce99326e..c1c10c38d5c 100644 --- a/source/blender/gpu/shaders/gpu_shader_material_bsdf_glossy.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material_bsdf_glossy.glsl @@ -575,7 +575,8 @@ void env_sampling_glossy_sharp( srgb_to_linearrgb(sample_ssr, sample_ssr); result = mix(sample_probe.rgb, sample_ssr.rgb, contrib); - result = -texelFetch(unfscenebuf, ivec2(gl_FragCoord.xy), 0).aaa / 100; + //result = mix(vec3(0.0), sample_ssr.rgb, contrib); + //result = vec3(texelFetch(unfdepthbuf, ivec2(gl_FragCoord.xy) / int(pow(2,unfssrparam.x-1)), int(unfssrparam.x-1)).r); #else result = sample_probe.rgb; #endif diff --git a/source/blender/gpu/shaders/gpu_shader_material_utils.glsl b/source/blender/gpu/shaders/gpu_shader_material_utils.glsl index ea1dc03d467..b7868a77434 100644 --- a/source/blender/gpu/shaders/gpu_shader_material_utils.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material_utils.glsl @@ -174,9 +174,9 @@ float linear_depth(float z) } } -float backface_depth(ivec2 texelpos) +float backface_depth(ivec2 texelpos, int lod) { - float depth = linear_depth(texelFetch(unfbackfacebuf, texelpos, 0).r); + float depth = linear_depth(texelFetch(unfbackfacebuf, texelpos, lod).r); /* background case */ if (depth == 1.0) @@ -185,9 +185,9 @@ float backface_depth(ivec2 texelpos) return -depth; } -float frontface_depth(ivec2 texelpos) +float frontface_depth(ivec2 texelpos, int lod) { - float depth = linear_depth(texelFetch(unfdepthbuf, texelpos, 0).r); + float depth = linear_depth(texelFetch(unfdepthbuf, texelpos, lod).r); /* background case */ if (depth == 1.0) @@ -907,93 +907,126 @@ bool raycast(vec3 ray_origin, vec3 ray_dir, float jitter, out float hitstep, out P0 = P0.yx; } - /* Track the derivatives */ - float step_sign = sign(delta.x); - float invdx = step_sign / delta.x; - vec2 dP = vec2(step_sign, invdx * delta.y); - vec3 dQ = (Q1 - Q0) * invdx; - float dk = (k1 - k0) * invdx; + /* Track the derivatives */ + float step_sign = sign(delta.x); + float invdx = step_sign / delta.x; + vec2 dP = vec2(step_sign, invdx * delta.y); + vec3 dQ = (Q1 - Q0) * invdx; + float dk = (k1 - k0) * invdx; - /* Stride */ - float stride = 1.0; - - /* Calculate pixel stride based on distance of ray origin from camera. */ - //float stride_scale = 1.0 - min( 1.0, -ray_origin.z); - //stride = 1.0 + stride_scale * stride; + /* Slide each value from the start of the ray to the end */ + vec4 pqk = vec4(P0, Q0.z, k0); - /* Scale derivatives by the desired pixel stride */ - dP *= stride; dQ *= stride; dk *= stride; + /* Scale derivatives by the desired pixel stride */ + vec4 dPQK = vec4(dP, dQ.z, dk) * 1.0; - /* Offset the starting values by the jitter fraction */ - //P0 += dP * jitter; Q0 += dQ * jitter; k0 += dk * jitter; + bool hit = false; - /* Slide each value from the start of the ray to the end */ - vec3 Q = Q0; vec2 P = P0; float k = k0; +#if 1 /* Linear 2D raymarching */ /* We track the ray depth at +/- 1/2 pixel to treat pixels as clip-space solid * voxels. Because the depth at -1/2 for a given pixel will be the same as at * +1/2 for the previous iteration, we actually only have to compute one value * per iteration. */ float prev_zmax = ray_origin.z; - float zmax, zmin; + float zmax, zmin; - /* P1.x is never modified after this point, so pre-scale it by - * the step direction for a signed comparison */ - float end = P1.x * step_sign; + /* P1.x is never modified after this point, so pre-scale it by + * the step direction for a signed comparison */ + float end = P1.x * step_sign; - bool hit = false; for (hitstep = 0.0; hitstep < unfssrparam.x && !hit; hitstep++) { /* Ray finished & no hit*/ - if ((P.x * step_sign) > end) break; + if ((pqk.x * step_sign) > end) break; - P += dP; Q.z += dQ.z; k += dk; + /* step through current cell */ + pqk += dPQK; - hitpixel = permute ? P.yx : P; + hitpixel = permute ? pqk.yx : pqk.xy; zmin = prev_zmax; - zmax = (dQ.z * 0.5 + Q.z) / (dk * 0.5 + k); + zmax = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w); prev_zmax = zmax; swapIfBigger(zmin, zmax); - float frontface = frontface_depth(ivec2(hitpixel)); + float frontface = frontface_depth(ivec2(hitpixel), 0); if (zmax < frontface) { + /* Below surface */ #ifdef USE_BACKFACE - float backface = backface_depth(ivec2(hitpixel)); + float backface = backface_depth(ivec2(hitpixel), 0); #else - float backface = frontface - 1.0; /* Todo find a good thickness */ + float backface = frontface - 0.2; /* Todo find a good thickness */ #endif - hit = (zmin > backface); + hit = (zmax > backface); } } - hitco = (Q0 + dQ * hitstep) / k; - return hit; -} + /* Hit coordinate in 3D */ + hitco = (Q0 + dQ * hitstep) / pqk.w; + +#else /* Hierarchical raymarching */ + + float z, mip, mippow, s; + float level = 1.0; + float steps = 0.0; + float dir = 1.0; + float lastdir = 1.0; + for (hitstep = 0.0; hitstep < unfssrparam.x && level > 0.0; hitstep++) { + mip = level - 1.0; + mippow = pow(2, mip); -#if 0 -/* 3D raycast */ -bool hierarchical_raycast(vec3 ray_origin, vec3 ray_dir, float jitter, out float hitstep, out vec2 hitpixel, out vec3 hitco) -{ - /* ssr_parameters */ - ray_dir *= unfssrparam.y; /* step between samples */ - - hitco = ray_origin; - hitco += ray_dir * jitter; - - hitpixel = vec2(0.0); - float mip = 0.0; - for (hitstep = 0.0; hitstep < unfssrparam.x; hitstep++) { /* step through current cell */ - if (above) mip++; - if (below) mip--; + //s = dir * max(1.0, mippow / 2); + s = dir * mippow; + //s = dir * level; + P += dP * s; Q.z += dQ.z * s; k += dk * s; steps += s; + + hitpixel = permute ? P.yx : P; + z = dQ.z / k; + + float frontface = frontface_depth(ivec2(hitpixel / mippow), int(mip)); + + if (z < frontface) { + /* Below surface */ +#ifdef USE_BACKFACE + float backface = backface_depth(ivec2(hitpixel), 0); +#else + float backface = -1e16; /* Todo find a good thickness */ +#endif + if (z > backface) { + /* Hit */ + /* This will step back the current step */ + //s = -1.0 * level; + //P += dP * s; Q.z += dQ.z * s; k += dk * s; steps += s; + dir = -1.0; + level--; + continue; + } + } + + /* Above surface */ + if (dir != -1.0 && lastdir != -1.0) { + /* Only step up in mip if the last iteration was positive + * This way we don't skip potential occluders */ + level++; + level = min(level, 5.0); + } + lastdir = dir; + dir = 1.0; } - /* No hit */ - return false; -} + hitstep = 1.0; + + hit = (level == 0.0); + + /* Hit coordinate in 3D */ + hitco = (Q0 + dQ * steps) / k; #endif + return hit; +} + float ssr_contribution(vec3 ray_origin, float hitstep, bool hit, inout vec3 hitco) { /* ssr_parameters */ @@ -1010,5 +1043,5 @@ float ssr_contribution(vec3 ray_origin, float hitstep, bool hit, inout vec3 hitc float maxdimension = saturate(max(abs(co.x), abs(co.y))); float screenfade = saturate((0.999999 - maxdimension) * attenuation); - return sqrt(stepfade * screenfade) * float(hit); + return smoothstep(0.0, 1.0, stepfade * screenfade) * float(hit); } diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 272d027d490..4f2c3463c09 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -2366,7 +2366,7 @@ static void rna_def_gpu_pbr_ssr(BlenderRNA *brna) prop = RNA_def_property(srna, "steps", PROP_INT, PROP_NONE); RNA_def_property_ui_text(prop, "Steps", "Number of samples"); - RNA_def_property_range(prop, 1, 128); + RNA_def_property_range(prop, 1, 256); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); } -- cgit v1.2.3