T55333 Workbench: Cavity Shader
authorJeroen Bakker <j.bakker@atmind.nl>
Wed, 6 Jun 2018 12:47:54 +0000 (14:47 +0200)
committerJeroen Bakker <j.bakker@atmind.nl>
Wed, 6 Jun 2018 12:51:18 +0000 (14:51 +0200)
A cavity shader based on SSAO. Works on all workbench deferred passes.

Per 3d viewport the cavity shader options can be set as different
shading needed different options. Some global options are in the
Viewport Display of the scene like num samples and distance.

Experimental: Naming of Ridges and Valleys

17 files changed:
release/scripts/startup/bl_ui/properties_scene.py
release/scripts/startup/bl_ui/space_view3d.py
source/blender/blenloader/intern/versioning_280.c
source/blender/draw/CMakeLists.txt
source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl [new file with mode: 0644]
source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl [new file with mode: 0644]
source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
source/blender/draw/engines/workbench/workbench_data.c
source/blender/draw/engines/workbench/workbench_deferred.c
source/blender/draw/engines/workbench/workbench_materials.c
source/blender/draw/engines/workbench/workbench_private.h
source/blender/editors/space_view3d/space_view3d.c
source/blender/makesdna/DNA_view3d_types.h
source/blender/makesrna/intern/rna_scene.c
source/blender/makesrna/intern/rna_space.c

index 1b9c7b5..33e8901 100644 (file)
@@ -476,6 +476,24 @@ class SCENE_PT_viewport_display(SceneButtonsPanel, Panel):
         col.prop(scene.display, "shadow_shift")
 
 
+class SCENE_PT_viewport_display_ssao(SceneButtonsPanel, Panel):
+    bl_label = "Viewport Display SSAO"
+    bl_parent_id = "SCENE_PT_viewport_display"
+
+    @classmethod
+    def poll(cls, context):
+        return True
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        scene = context.scene
+        col = layout.column()
+        col.prop(scene.display, "matcap_ssao_samples")
+        col.prop(scene.display, "matcap_ssao_distance")
+        col.prop(scene.display, "matcap_ssao_attenuation")
+
+
 class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, Panel):
     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
     _context_path = "scene"
@@ -492,6 +510,7 @@ classes = (
     SCENE_PT_color_management,
     SCENE_PT_color_management_curves,
     SCENE_PT_viewport_display,
+    SCENE_PT_viewport_display_ssao,
     SCENE_PT_audio,
     SCENE_PT_physics,
     SCENE_PT_rigid_body_world,
index 1a70092..149f932 100644 (file)
@@ -3527,6 +3527,14 @@ class VIEW3D_PT_shading(Panel):
             sub.active = shading.show_shadows and not shading.show_xray
             sub.prop(shading, "shadow_intensity", text="")
 
+            row = col.row()
+            row.active = not shading.show_xray
+            row.prop(shading, "show_cavity")
+            sub = row.column()
+            sub.active = not shading.show_xray and shading.show_cavity
+            sub.prop(shading, "cavity_ridge_factor")
+            sub.prop(shading, "cavity_valley_factor")
+
             row = col.row()
             row.prop(shading, "show_object_outline")
             sub = row.row()
index f4c61e4..83a0f21 100644 (file)
@@ -1568,5 +1568,18 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
                                }
                        }
                }
+               if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "cavity_valley_factor")) {
+                       for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+                               for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+                                       for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+                                               if (sl->spacetype == SPACE_VIEW3D) {
+                                                       View3D *v3d = (View3D *)sl;
+                                                       v3d->shading.cavity_valley_factor = 1.0f;
+                                                       v3d->shading.cavity_ridge_factor = 1.0f;
+                                               }
+                                       }
+                               }
+                       }
+               }
        }
 }
index 40fd876..9c3aa34 100644 (file)
@@ -219,6 +219,8 @@ data_to_c_simple(engines/eevee/shaders/volumetric_scatter_frag.glsl SRC)
 data_to_c_simple(engines/eevee/shaders/volumetric_integration_frag.glsl SRC)
 
 data_to_c_simple(engines/workbench/shaders/workbench_background_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_cavity_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_cavity_frag.glsl SRC)
 data_to_c_simple(engines/workbench/shaders/workbench_checkerboard_depth_frag.glsl SRC)
 data_to_c_simple(engines/workbench/shaders/workbench_common_lib.glsl SRC)
 data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC)
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl
new file mode 100644 (file)
index 0000000..f6ddd54
--- /dev/null
@@ -0,0 +1,71 @@
+out vec4 fragColor;
+
+uniform sampler2D depthBuffer;
+uniform sampler2D colorBuffer;
+uniform sampler2D normalBuffer;
+uniform sampler2D positionBuffer;
+
+uniform vec2 invertedViewportSize;
+uniform mat4 WinMatrix; /* inverse WinMatrix */
+
+uniform vec4 viewvecs[3];
+uniform vec4 ssao_params;
+uniform vec4 ssao_settings;
+uniform sampler2D ssao_jitter;
+
+layout(std140) uniform samples_block {
+       vec4 ssao_samples[500];
+};
+
+#define ssao_samples_num       ssao_params.x
+#define jitter_tilling         ssao_params.yz
+#define dfdy_sign                      ssao_params.w
+
+#define ssao_distance          ssao_settings.x
+#define ssao_factor_cavity     ssao_settings.y
+#define ssao_factor_edge       ssao_settings.z
+#define ssao_attenuation       ssao_settings.a
+
+vec3 get_view_space_from_depth(in vec2 uvcoords, in float depth)
+{
+       if (WinMatrix[3][3] == 0.0) {
+               /* Perspective */
+               float d = 2.0 * depth - 1.0;
+
+               float zview = -WinMatrix[3][2] / (d + WinMatrix[2][2]);
+
+               return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz);
+       }
+       else {
+               /* Orthographic */
+               vec3 offset = vec3(uvcoords, depth);
+
+               return viewvecs[0].xyz + offset * viewvecs[1].xyz;
+       }
+}
+
+/* forward declartion */
+void ssao_factors(
+        in float depth, in vec3 normal, in vec3 position, in vec2 screenco,
+        out float cavities, out float edges);
+
+
+void main()
+{
+       vec2 screenco = vec2(gl_FragCoord.xy) * invertedViewportSize;
+       ivec2 texel = ivec2(gl_FragCoord.xy);
+
+       float depth = texelFetch(depthBuffer, texel, 0).x;
+       vec3 position = get_view_space_from_depth(screenco, depth);
+
+       vec4 diffuse_color = texelFetch(colorBuffer, texel, 0);
+       vec3 normal_viewport = normal_decode(texelFetch(normalBuffer, texel, 0).rg);
+       if (diffuse_color.a == 0.0) {
+               normal_viewport = -normal_viewport;
+       }
+
+       float cavity = 0.0, edges = 0.0;
+       ssao_factors(depth, normal_viewport, position, screenco, cavity, edges);
+
+       fragColor = vec4(cavity, edges, 0.0, 1.0);
+}
\ No newline at end of file
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
new file mode 100644 (file)
index 0000000..da0198a
--- /dev/null
@@ -0,0 +1,79 @@
+
+
+/*  from The Alchemy screen-space ambient obscurance algorithm
+ * http://graphics.cs.williams.edu/papers/AlchemyHPG11/VV11AlchemyAO.pdf */
+
+void ssao_factors(
+        in float depth, in vec3 normal, in vec3 position, in vec2 screenco,
+        out float cavities, out float edges)
+{
+       cavities = edges = 0.0;
+       /* early out if there is no need for SSAO */
+       if (ssao_factor_cavity == 0.0 && ssao_factor_edge == 0.0)
+               return;
+
+       /* take the normalized ray direction here */
+       vec3 noise = texture(ssao_jitter, screenco.xy * jitter_tilling).rgb;
+
+       /* find the offset in screen space by multiplying a point
+        * in camera space at the depth of the point by the projection matrix. */
+       vec2 offset;
+       float homcoord = WinMatrix[2][3] * position.z + WinMatrix[3][3];
+       offset.x = WinMatrix[0][0] * ssao_distance / homcoord;
+       offset.y = WinMatrix[1][1] * ssao_distance / homcoord;
+       /* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */
+       offset *= 0.5;
+
+       int num_samples = int(ssao_samples_num);
+
+       /* Note. Putting noise usage here to put some ALU after texture fetch. */
+       vec2 rotX = noise.rg;
+       vec2 rotY = vec2(-rotX.y, rotX.x);
+
+       for (int x = 0; x < num_samples && x < 500; x++) {
+               /* ssao_samples[x].xy is sample direction (normalized).
+                * ssao_samples[x].z is sample distance from disk center. */
+
+               /* Rotate with random direction to get jittered result. */
+               vec2 dir_jittered = vec2(dot(ssao_samples[x].xy, rotX), dot(ssao_samples[x].xy, rotY));
+               dir_jittered.xy *= ssao_samples[x].z + noise.b;
+
+               vec2 uvcoords = screenco.xy + dir_jittered * offset;
+
+               if (uvcoords.x > 1.0 || uvcoords.x < 0.0 || uvcoords.y > 1.0 || uvcoords.y < 0.0)
+                       continue;
+
+               float depth_new = texture(depthBuffer, uvcoords).r;
+
+               /* Handle Background case */
+               bool is_background = (depth_new == 1.0);
+
+               /* This trick provide good edge effect even if no neighboor is found. */
+               vec3 pos_new = get_view_space_from_depth(uvcoords, (is_background) ? depth : depth_new);
+
+               if (is_background)
+                       pos_new.z -= ssao_distance;
+
+               vec3 dir = pos_new - position;
+               float len = length(dir);
+               float f_cavities = dot(dir, normal);
+               float f_edge = -f_cavities;
+               float f_bias = 0.05 * len + 0.0001;
+
+               float attenuation = 1.0 / (len * (1.0 + len * len * ssao_attenuation));
+
+               /* use minor bias here to avoid self shadowing */
+               if (f_cavities > -f_bias)
+                       cavities += f_cavities * attenuation;
+
+               if (f_edge > f_bias)
+                       edges += f_edge * attenuation;
+       }
+
+       cavities /= ssao_samples_num;
+       edges /= ssao_samples_num;
+
+       /* don't let cavity wash out the surface appearance */
+       cavities = clamp(cavities * ssao_factor_cavity, 0.0, 1.0);
+       edges = edges * ssao_factor_edge;
+}
index 326837b..9116e2e 100644 (file)
@@ -5,6 +5,8 @@ uniform sampler2D colorBuffer;
 uniform sampler2D specularBuffer;
 uniform sampler2D normalBuffer;
 /* normalBuffer contains viewport normals */
+uniform sampler2D cavityBuffer;
+
 uniform vec2 invertedViewportSize;
 uniform float shadowMultiplier;
 uniform float lightMultiplier;
@@ -77,7 +79,6 @@ void main()
 #endif
 
 #ifdef V3D_LIGHTING_MATCAP
-       /* TODO: if pixel data is matcap. then */
        vec3 diffuse_light = texelFetch(specularBuffer, texel, 0).rgb;
 #endif
 
@@ -93,6 +94,12 @@ void main()
 #endif
        vec3 shaded_color = diffuse_light * diffuse_color.rgb + specular_color;
 
+#ifdef V3D_SHADING_CAVITY
+       vec2 cavity = texelFetch(cavityBuffer, texel, 0).rg;
+       shaded_color *= 1.0 - cavity.x;
+       shaded_color *= 1.0 + cavity.y;
+#endif
+
 #ifdef V3D_SHADING_SHADOW
        float light_factor = -dot(normal_viewport, world_data.light_direction_vs.xyz);
        /* The step function might be ok for meshes but it's
index 5931a11..d33ef9a 100644 (file)
@@ -9,9 +9,9 @@ uniform sampler2D image;
 #endif
 
 #ifdef NORMAL_VIEWPORT_PASS_ENABLED
-in vec3 position_viewport;
 in vec3 normal_viewport;
 #endif /* NORMAL_VIEWPORT_PASS_ENABLED */
+
 #ifdef OB_TEXTURE
 in vec2 uv_interp;
 #endif /* OB_TEXTURE */
index 7da9c26..82443e7 100644 (file)
@@ -18,6 +18,7 @@ flat out float hair_rand;
 #ifdef NORMAL_VIEWPORT_PASS_ENABLED
 out vec3 normal_viewport;
 #endif
+
 #ifdef OB_TEXTURE
 out vec2 uv_interp;
 #endif
@@ -57,6 +58,7 @@ void main()
 #ifdef OB_TEXTURE
        uv_interp = uv;
 #endif
+
 #ifdef NORMAL_VIEWPORT_PASS_ENABLED
        normal_viewport = NormalMatrix * nor;
 #  ifndef HAIR_SHADER
index 7468d74..3a4bb1d 100644 (file)
@@ -58,6 +58,64 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
        wd->object_outline_color[3] = 1.0f;
 
        wpd->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), &wpd->world_data);
+
+       /* Cavity settings */
+       {
+               const int ssao_samples = scene->display.matcap_ssao_samples;
+
+               float invproj[4][4];
+               float dfdyfacs[2];
+               const bool is_persp = DRW_viewport_is_persp_get();
+               /* view vectors for the corners of the view frustum.
+                * Can be used to recreate the world space position easily */
+               float viewvecs[3][4] = {
+                   {-1.0f, -1.0f, -1.0f, 1.0f},
+                   {1.0f, -1.0f, -1.0f, 1.0f},
+                   {-1.0f, 1.0f, -1.0f, 1.0f}
+               };
+               int i;
+               const float *size = DRW_viewport_size_get();
+
+               DRW_state_dfdy_factors_get(dfdyfacs);
+
+               wpd->ssao_params[0] = ssao_samples;
+               wpd->ssao_params[1] = size[0] / 64.0;
+               wpd->ssao_params[2] = size[1] / 64.0;
+               wpd->ssao_params[3] = dfdyfacs[1]; /* dfdy sign for offscreen */
+
+               /* distance, factor, factor, attenuation */
+               copy_v4_fl4(wpd->ssao_settings, scene->display.matcap_ssao_distance, wpd->shading.cavity_valley_factor, wpd->shading.cavity_ridge_factor, scene->display.matcap_ssao_attenuation);
+
+               /* invert the view matrix */
+               DRW_viewport_matrix_get(wpd->winmat, DRW_MAT_WIN);
+               invert_m4_m4(invproj, wpd->winmat);
+
+               /* convert the view vectors to view space */
+               for (i = 0; i < 3; i++) {
+                       mul_m4_v4(invproj, viewvecs[i]);
+                       /* normalized trick see:
+                        * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
+                       mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]);
+                       if (is_persp)
+                               mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]);
+                       viewvecs[i][3] = 1.0;
+
+                       copy_v4_v4(wpd->viewvecs[i], viewvecs[i]);
+               }
+
+               /* we need to store the differences */
+               wpd->viewvecs[1][0] -= wpd->viewvecs[0][0];
+               wpd->viewvecs[1][1] = wpd->viewvecs[2][1] - wpd->viewvecs[0][1];
+
+               /* calculate a depth offset as well */
+               if (!is_persp) {
+                       float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f};
+                       mul_m4_v4(invproj, vec_far);
+                       mul_v3_fl(vec_far, 1.0f / vec_far[3]);
+                       wpd->viewvecs[1][2] = vec_far[2] - wpd->viewvecs[0][2];
+               }
+       }
+
 }
 
 void workbench_private_data_get_light_direction(WORKBENCH_PrivateData *wpd, float light_direction[3])
index a91e9ab..caee998 100644 (file)
@@ -30,6 +30,7 @@
 #include "BLI_alloca.h"
 #include "BLI_dynstr.h"
 #include "BLI_utildefines.h"
+#include "BLI_rand.h"
 
 #include "BKE_node.h"
 #include "BKE_particle.h"
@@ -44,6 +45,7 @@
 #include "GPU_shader.h"
 #include "GPU_texture.h"
 
+#include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */
 
 /* *********** STATIC *********** */
 
@@ -56,6 +58,7 @@
 static struct {
        struct GPUShader *prepass_sh_cache[MAX_SHADERS];
        struct GPUShader *composite_sh_cache[MAX_SHADERS];
+       struct GPUShader *cavity_sh;
        struct GPUShader *shadow_fail_sh;
        struct GPUShader *shadow_fail_manifold_sh;
        struct GPUShader *shadow_pass_sh;
@@ -65,6 +68,7 @@ static struct {
 
        struct GPUTexture *object_id_tx; /* ref only, not alloced */
        struct GPUTexture *color_buffer_tx; /* ref only, not alloced */
+       struct GPUTexture *cavity_buffer_tx; /* ref only, not alloced */
        struct GPUTexture *specular_buffer_tx; /* ref only, not alloced */
        struct GPUTexture *normal_buffer_tx; /* ref only, not alloced */
        struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
@@ -73,6 +77,10 @@ static struct {
        float light_direction_vs[3];
        int next_object_id;
        float normal_world_matrix[3][3];
+
+       struct GPUUniformBuffer *sampling_ubo;
+       struct GPUTexture *jitter_tx;
+       int cached_sample_num;
 } e_data = {{NULL}};
 
 /* Shaders */
@@ -80,6 +88,7 @@ extern char datatoc_common_hair_lib_glsl[];
 
 extern char datatoc_workbench_prepass_vert_glsl[];
 extern char datatoc_workbench_prepass_frag_glsl[];
+extern char datatoc_workbench_cavity_frag_glsl[];
 extern char datatoc_workbench_deferred_composite_frag_glsl[];
 
 extern char datatoc_workbench_shadow_vert_glsl[];
@@ -88,6 +97,7 @@ extern char datatoc_workbench_shadow_caps_geom_glsl[];
 extern char datatoc_workbench_shadow_debug_frag_glsl[];
 
 extern char datatoc_workbench_background_lib_glsl[];
+extern char datatoc_workbench_cavity_lib_glsl[];
 extern char datatoc_workbench_common_lib_glsl[];
 extern char datatoc_workbench_data_lib_glsl[];
 extern char datatoc_workbench_object_outline_lib_glsl[];
@@ -146,6 +156,21 @@ static char *workbench_build_prepass_vert(void)
        return str;
 }
 
+static char *workbench_build_cavity_frag(void)
+{
+       char *str = NULL;
+
+       DynStr *ds = BLI_dynstr_new();
+
+       BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
+       BLI_dynstr_append(ds, datatoc_workbench_cavity_frag_glsl);
+       BLI_dynstr_append(ds, datatoc_workbench_cavity_lib_glsl);
+
+       str = BLI_dynstr_get_cstring(ds);
+       BLI_dynstr_free(ds);
+       return str;
+}
+
 static void ensure_deferred_shaders(WORKBENCH_PrivateData *wpd, int index, int drawtype, bool is_hair)
 {
        if (e_data.prepass_sh_cache[index] == NULL) {
@@ -185,6 +210,50 @@ static void select_deferred_shaders(WORKBENCH_PrivateData *wpd)
        wpd->composite_sh = e_data.composite_sh_cache[index_solid];
 }
 
+
+/* Using Hammersley distribution */
+static float *create_disk_samples(int num_samples)
+{
+       /* vec4 to ensure memory alignment. */
+       float (*texels)[4] = MEM_mallocN(sizeof(float[4]) * num_samples, "concentric_tex");
+       const float num_samples_inv = 1.0f / num_samples;
+
+       for (int i = 0; i < num_samples; i++) {
+               float r = (i + 0.5f) * num_samples_inv;
+               double dphi;
+               BLI_hammersley_1D(i, &dphi);
+
+               float phi = (float)dphi * 2.0f * M_PI;
+               texels[i][0] = cosf(phi);
+               texels[i][1] = sinf(phi);
+               /* This deliberatly distribute more samples
+                * at the center of the disk (and thus the shadow). */
+               texels[i][2] = r;
+       }
+
+       return (float *)texels;
+}
+
+static struct GPUTexture *create_jitter_texture(int num_samples)
+{
+       float jitter[64 * 64][3];
+       const float num_samples_inv = 1.0f / num_samples;
+
+       for (int i = 0; i < 64 * 64; i++) {
+               float phi = blue_noise[i][0] * 2.0f * M_PI;
+               /* This rotate the sample per pixels */
+               jitter[i][0] = cosf(phi);
+               jitter[i][1] = sinf(phi);
+               /* This offset the sample along it's direction axis (reduce banding) */
+               float bn = blue_noise[i][1] - 0.5f;
+               CLAMP(bn, -0.499f, 0.499f); /* fix fireflies */
+               jitter[i][2] = bn * num_samples_inv;
+       }
+
+       UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx, ltc_disk_integral);
+
+       return DRW_texture_create_2D(64, 64, GPU_RGB16F, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]);
+}
 /* Functions */
 
 
@@ -244,6 +313,10 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
                        datatoc_workbench_shadow_caps_geom_glsl,
                        shadow_frag,
                        "#define SHADOW_FAIL\n");
+
+               char *cavity_frag = workbench_build_cavity_frag();
+               e_data.cavity_sh = DRW_shader_create_fullscreen(cavity_frag, NULL);
+               MEM_freeN(cavity_frag);
        }
 
        if (!stl->g_data) {
@@ -251,13 +324,15 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
                stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
        }
 
-       workbench_private_data_init(stl->g_data);
+       WORKBENCH_PrivateData *wpd = stl->g_data;
+       workbench_private_data_init(wpd);
 
        {
                const float *viewport_size = DRW_viewport_size_get();
                const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
                e_data.object_id_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_R32UI, &draw_engine_workbench_solid);
                e_data.color_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8, &draw_engine_workbench_solid);
+               e_data.cavity_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RG16, &draw_engine_workbench_solid);
                e_data.specular_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8, &draw_engine_workbench_solid);
                e_data.composite_buffer_tx = DRW_texture_pool_query_2D(
                        size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_solid);
@@ -278,18 +353,59 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
                        GPU_ATTACHMENT_TEXTURE(e_data.specular_buffer_tx),
                        GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx),
                });
+               GPU_framebuffer_ensure_config(&fbl->cavity_fb, {
+                       GPU_ATTACHMENT_NONE,
+                       GPU_ATTACHMENT_TEXTURE(e_data.cavity_buffer_tx),
+               });
                GPU_framebuffer_ensure_config(&fbl->composite_fb, {
                        GPU_ATTACHMENT_TEXTURE(dtxl->depth),
                        GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx),
                });
        }
 
+       {
+               const DRWContextState *draw_ctx = DRW_context_state_get();
+               Scene *scene = draw_ctx->scene;
+               /* AO Samples Tex */
+               const int ssao_samples = scene->display.matcap_ssao_samples;
+               if (e_data.sampling_ubo && (e_data.cached_sample_num != ssao_samples)) {
+                       DRW_UBO_FREE_SAFE(e_data.sampling_ubo);
+                       DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx);
+               }
+
+               if (e_data.sampling_ubo == NULL) {
+                       float *samples = create_disk_samples(ssao_samples);
+                       e_data.jitter_tx = create_jitter_texture(ssao_samples);
+                       e_data.sampling_ubo = DRW_uniformbuffer_create(sizeof(float[4]) * ssao_samples, samples);
+                       e_data.cached_sample_num = ssao_samples;
+                       MEM_freeN(samples);
+               }
+       }
+
        /* Prepass */
        {
                int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
                psl->prepass_pass = DRW_pass_create("Prepass", state);
                psl->prepass_hair_pass = DRW_pass_create("Prepass", state);
        }
+       
+       {
+               int state = DRW_STATE_WRITE_COLOR;
+               psl->cavity_pass = DRW_pass_create("Cavity", state);
+               DRWShadingGroup *grp = DRW_shgroup_create(e_data.cavity_sh, psl->cavity_pass);
+               DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+               DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &e_data.color_buffer_tx);
+               DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx);
+
+               DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
+               DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
+               DRW_shgroup_uniform_vec4(grp, "ssao_params", wpd->ssao_params, 1);
+               DRW_shgroup_uniform_vec4(grp, "ssao_settings", wpd->ssao_settings, 1);
+               DRW_shgroup_uniform_mat4(grp, "WinMatrix", wpd->winmat);
+               DRW_shgroup_uniform_texture(grp, "ssao_jitter", e_data.jitter_tx);
+               DRW_shgroup_uniform_block(grp, "samples_block", e_data.sampling_ubo);
+               DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+       }
 }
 
 void workbench_deferred_engine_free()
@@ -298,21 +414,29 @@ void workbench_deferred_engine_free()
                DRW_SHADER_FREE_SAFE(e_data.prepass_sh_cache[index]);
                DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]);
        }
+       DRW_SHADER_FREE_SAFE(e_data.cavity_sh);
+       DRW_UBO_FREE_SAFE(e_data.sampling_ubo);
+       DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx);
+
        DRW_SHADER_FREE_SAFE(e_data.shadow_pass_sh);
        DRW_SHADER_FREE_SAFE(e_data.shadow_pass_manifold_sh);
        DRW_SHADER_FREE_SAFE(e_data.shadow_fail_sh);
        DRW_SHADER_FREE_SAFE(e_data.shadow_fail_manifold_sh);
        DRW_SHADER_FREE_SAFE(e_data.shadow_caps_sh);
        DRW_SHADER_FREE_SAFE(e_data.shadow_caps_manifold_sh);
+
 }
 
 static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp)
 {
        DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &e_data.color_buffer_tx);
        DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx);
-       if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) {
+       if (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd)) {
                DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx);
        }
+       if (CAVITY_ENABLED(wpd)) {
+               DRW_shgroup_uniform_texture_ref(grp, "cavityBuffer", &e_data.cavity_buffer_tx);
+       }
        if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || MATCAP_ENABLED(wpd)) {
                DRW_shgroup_uniform_texture_ref(grp, "specularBuffer", &e_data.specular_buffer_tx);
 
@@ -715,6 +839,12 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
        GPU_framebuffer_bind(fbl->prepass_fb);
        DRW_draw_pass(psl->prepass_pass);
        DRW_draw_pass(psl->prepass_hair_pass);
+
+       if (CAVITY_ENABLED(wpd)) {
+               GPU_framebuffer_bind(fbl->cavity_fb);
+               DRW_draw_pass(psl->cavity_pass);
+       }
+
        if (SHADOW_ENABLED(wpd)) {
 #ifdef DEBUG_SHADOW_VOLUME
                GPU_framebuffer_bind(fbl->composite_fb);
index 2e2e6f8..d74c060 100644 (file)
@@ -52,6 +52,9 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, int drawtype,
        if (wpd->shading.flag & V3D_SHADING_SHADOW) {
                BLI_dynstr_appendf(ds, "#define V3D_SHADING_SHADOW\n");
        }
+       if (CAVITY_ENABLED(wpd)) {
+               BLI_dynstr_appendf(ds, "#define V3D_SHADING_CAVITY\n");
+       }
        if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) {
                BLI_dynstr_appendf(ds, "#define V3D_SHADING_SPECULAR_HIGHLIGHT\n");
        }
@@ -137,12 +140,13 @@ int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, int drawtype
        /* 1 bit V3D_SHADING_SPECULAR_HIGHLIGHT */
        SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT, 1 << 3);
        SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SHADOW, 1 << 4);
-       SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE, 1 << 5);
+       SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_CAVITY, 1 << 5);
+       SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE, 1 << 6);
        /* 2 bits STUDIOLIGHT_ORIENTATION */
-       SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD, 1 << 6);
-       SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL, 1 << 7);
+       SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD, 1 << 7);
+       SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL, 1 << 8);
        /* 1 bit for hair */
-       SET_FLAG_FROM_TEST(index, is_hair, 1 << 8);
+       SET_FLAG_FROM_TEST(index, is_hair, 1 << 9);
        return index;
 }
 
index ac85f4c..758cc2b 100644 (file)
@@ -38,7 +38,7 @@
 
 #define WORKBENCH_ENGINE "BLENDER_WORKBENCH"
 #define M_GOLDEN_RATION_CONJUGATE 0.618033988749895
-#define MAX_SHADERS (1 << 9)
+#define MAX_SHADERS (1 << 10)
 
 #define OB_SOLID_ENABLED(wpd) (wpd->drawtype & OB_SOLID)
 #define OB_TEXTURE_ENABLED(wpd) (wpd->drawtype & OB_TEXTURE)
 #define STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd) (STUDIOLIGHT_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD))
 #define STUDIOLIGHT_ORIENTATION_CAMERA_ENABLED(wpd) (STUDIOLIGHT_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_CAMERA))
 #define STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd) (MATCAP_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL))
-#define OBJECT_ID_PASS_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE)
+#define CAVITY_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_CAVITY)
 #define SHADOW_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_SHADOW)
 #define SPECULAR_HIGHLIGHT_ENABLED(wpd) ((wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT) && (!STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd)))
-#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) (MATCAP_ENABLED(wpd) || STUDIOLIGHT_ENABLED(wpd) || SHADOW_ENABLED(wpd) || SPECULAR_HIGHLIGHT_ENABLED(wpd))
+#define OBJECT_ID_PASS_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE)
+#define NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) (MATCAP_ENABLED(wpd) || STUDIOLIGHT_ENABLED(wpd) || SHADOW_ENABLED(wpd) || SPECULAR_HIGHLIGHT_ENABLED(wpd))
+#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) || CAVITY_ENABLED(wpd))
 #define NORMAL_ENCODING_ENABLED() (true)
 #define WORKBENCH_REVEALAGE_ENABLED
 
@@ -59,6 +61,7 @@
 typedef struct WORKBENCH_FramebufferList {
        /* Deferred render buffers */
        struct GPUFrameBuffer *prepass_fb;
+       struct GPUFrameBuffer *cavity_fb;
        struct GPUFrameBuffer *composite_fb;
 
        /* Forward render buffers */
@@ -78,6 +81,7 @@ typedef struct WORKBENCH_PassList {
        /* deferred rendering */
        struct DRWPass *prepass_pass;
        struct DRWPass *prepass_hair_pass;
+       struct DRWPass *cavity_pass;
        struct DRWPass *shadow_depth_pass_pass;
        struct DRWPass *shadow_depth_pass_mani_pass;
        struct DRWPass *shadow_depth_fail_pass;
@@ -168,6 +172,12 @@ typedef struct WORKBENCH_PrivateData {
        float shadow_near_max[3];
        float shadow_near_sides[2][4]; /* This is a parallelogram, so only 2 normal and distance to the edges. */
        bool shadow_changed;
+
+       /* Ssao */
+       float winmat[4][4];
+       float viewvecs[3][4];
+       float ssao_params[4];
+       float ssao_settings[4];
 } WORKBENCH_PrivateData; /* Transient data */
 
 typedef struct WORKBENCH_MaterialData {
index 7d8df34..3bd416d 100644 (file)
@@ -326,6 +326,8 @@ static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene)
        v3d->shading.light = V3D_LIGHTING_STUDIO;
        v3d->shading.shadow_intensity = 0.5f;
        v3d->shading.xray_alpha = 0.5f;
+       v3d->shading.cavity_valley_factor = 1.0f;
+       v3d->shading.cavity_ridge_factor = 1.0f;
        copy_v3_fl(v3d->shading.single_color, 0.8f);
 
        v3d->overlay.flag = V3D_OVERLAY_LOOK_DEV;
index c0f1330..ea90ac2 100644 (file)
@@ -150,6 +150,9 @@ typedef struct View3DShading {
 
        float object_outline_color[3];
        float xray_alpha;
+
+       float cavity_valley_factor;
+       float cavity_ridge_factor;
 } View3DShading;
 
 /* 3D Viewport Overlay setings */
@@ -347,6 +350,7 @@ enum {
        V3D_SHADING_SHADOW              = (1 << 2),
        V3D_SHADING_SCENE_LIGHT         = (1 << 3),
        V3D_SHADING_SPECULAR_HIGHLIGHT  = (1 << 4),
+       V3D_SHADING_CAVITY              = (1 << 5),
 };
 
 /* View3DShading->single_color_type */
index 80a7d0c..8055c8f 100644 (file)
@@ -5759,7 +5759,7 @@ static void rna_def_scene_display(BlenderRNA *brna)
        RNA_def_property_range(prop, 0.0f, 250.0f);
 
        prop = RNA_def_property(srna, "matcap_ssao_factor_edge", PROP_FLOAT, PROP_NONE);
-               RNA_def_property_float_default(prop, 1.0f);
+       RNA_def_property_float_default(prop, 1.0f);
        RNA_def_property_ui_text(prop, "Edge Strength", "Strength of the Edge effect");
        RNA_def_property_range(prop, 0.0f, 250.0f);
 
index 284e0ea..3c9484c 100644 (file)
@@ -2350,6 +2350,30 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Matcap", "Matcap material and lighting");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 
+       prop = RNA_def_property(srna, "show_cavity", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "shading.flag", V3D_SHADING_CAVITY);
+       RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+       RNA_def_property_ui_text(prop, "Cavity", "Show Cavity");
+       RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+       prop = RNA_def_property(srna, "cavity_ridge_factor", PROP_FLOAT, PROP_FACTOR);
+       RNA_def_property_float_sdna(prop, NULL, "shading.cavity_ridge_factor");
+       RNA_def_property_float_default(prop, 1.0f);
+       RNA_def_property_ui_text(prop, "Ridge", "Factor for the ridges");
+       RNA_def_property_range(prop, 0.0f, 250.0f);
+       RNA_def_property_ui_range(prop, 0.00f, 2.5f, 1, 3);
+       RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+       RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+       prop = RNA_def_property(srna, "cavity_valley_factor", PROP_FLOAT, PROP_FACTOR);
+       RNA_def_property_float_sdna(prop, NULL, "shading.cavity_valley_factor");
+       RNA_def_property_float_default(prop, 1.0);
+       RNA_def_property_ui_text(prop, "Valley", "Factor for the valleys");
+       RNA_def_property_range(prop, 0.0f, 250.0f);
+       RNA_def_property_ui_range(prop, 0.00f, 2.5f, 1, 3);
+       RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+       RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
        prop = RNA_def_property(srna, "studio_light_orientation", PROP_ENUM, PROP_NONE);
        RNA_define_verify_sdna(0);
        RNA_def_property_enum_sdna(prop, NULL, "shading.flag");