diff options
Diffstat (limited to 'source/blender')
15 files changed, 418 insertions, 12 deletions
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index f4c61e424ae..83a0f21002a 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -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; + } + } + } + } + } } } diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 40fd8762821..9c3aa34b5d8 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -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 index 00000000000..f6ddd54b7f7 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl @@ -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 index 00000000000..da0198ab2e7 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl @@ -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; +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl index 326837bc69f..9116e2e7ef5 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl @@ -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 diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl index 5931a11f184..d33ef9a0abb 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl @@ -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 */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl index 7da9c2644fe..82443e7336b 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl @@ -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 diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index 7468d748986..3a4bb1db749 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -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]) diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index a91e9ab10df..caee998e427 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -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); diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index 2e2e6f8127a..d74c0606b5d 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -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; } diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index ac85f4c5296..758cc2be826 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -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) @@ -48,10 +48,12 @@ #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 { diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 7d8df34264e..3bd416d7251 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -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; diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index c0f13308df6..ea90ac261da 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -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 */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 80a7d0c6915..8055c8fe4d6 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -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); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 284e0ea20bc..3c9484cc390 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -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"); |