diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2020-03-02 21:11:08 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2020-03-03 03:42:31 +0300 |
commit | aae2e1326fe60e8356735dcc079b55727a86bf75 (patch) | |
tree | 8ba85c07010f5d1927f12beafe7bfe37aacb4ee3 | |
parent | 606f1d80b39a978f32aaae5a0cd22e18775dd36a (diff) |
Workbench: Refactor: Add cavity support
18 files changed, 367 insertions, 151 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index c6935dfdd95..692dc300d89 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -255,6 +255,7 @@ data_to_c_simple(engines/workbench/shaders/workbench_composite_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_deferred_composite_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_deferred_background_frag.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_effect_cavity_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_effect_dof_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_effect_fxaa_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_effect_taa_frag.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 index a0e04f252e2..7031328eb2e 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl @@ -28,7 +28,7 @@ layout(std140) uniform samples_block #define ssao_factor_edge ssao_settings.z #define ssao_attenuation ssao_settings.w -vec3 get_view_space_from_depth(in vec2 uvcoords, in float depth) +vec3 view_space_from_depth(in vec2 uvcoords, in float depth) { if (WinMatrix[3][3] == 0.0) { /* Perspective */ @@ -63,7 +63,7 @@ void main() #ifdef USE_CAVITY float depth = texelFetch(depthBuffer, texel, 0).x; - vec3 position = get_view_space_from_depth(screenco, depth); + vec3 position = view_space_from_depth(screenco, depth); vec3 normal_viewport = workbench_normal_decode(texelFetch(normalBuffer, texel, 0).rg); ssao_factors(depth, normal_viewport, position, screenco, cavity, edges); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl index 376b19cdd1b..c1207c0d32f 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl @@ -1,77 +1,86 @@ +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) -/* from The Alchemy screen-space ambient obscurance algorithm +layout(std140) uniform samples_block +{ + vec4 samples_coords[512]; +}; + +uniform sampler2D cavityJitter; + +/* 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) +void cavity_compute(vec2 screenco, + sampler2D depthBuffer, + sampler2D normalBuffer, + 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) { + + float depth = texture(depthBuffer, screenco).x; + + /* Early out if background */ + if (depth == 1.0) { return; } - /* take the normalized ray direction here */ - vec3 noise = texture(ssao_jitter, screenco.xy * jitter_tilling).rgb; + vec3 position = view_space_from_depth(screenco, depth, world_data.viewvecs, ProjectionMatrix); + vec3 normal = workbench_normal_decode(texture(normalBuffer, screenco)); + + vec2 jitter_co = (screenco * world_data.viewport_size.xy) * world_data.cavity_jitter_scale; + vec3 noise = texture(cavityJitter, jitter_co).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; + float homcoord = ProjectionMatrix[2][3] * position.z + ProjectionMatrix[3][3]; + offset.x = ProjectionMatrix[0][0] * world_data.cavity_distance / homcoord; + offset.y = ProjectionMatrix[1][1] * world_data.cavity_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++) { - int sample_index = x + (int(ssao_iteration) * num_samples); - if (sample_index > 500) { - continue; - } - /* ssao_samples[x].xy is sample direction (normalized). - * ssao_samples[x].z is sample distance from disk center. */ - + int sample_start = world_data.cavity_sample_start; + int sample_end = world_data.cavity_sample_end; + for (int i = sample_start; i < sample_end && i < 512; i++) { + /* sample_coord.xy is sample direction (normalized). + * sample_coord.z is sample distance from disk center. */ + vec3 sample_coord = samples_coords[i].xyz; /* Rotate with random direction to get jittered result. */ - vec2 dir_jittered = vec2(dot(ssao_samples[sample_index].xy, rotX), - dot(ssao_samples[sample_index].xy, rotY)); - dir_jittered.xy *= ssao_samples[sample_index].z + noise.b; + vec2 dir_jittered = vec2(dot(sample_coord.xy, rotX), dot(sample_coord.xy, rotY)); + dir_jittered.xy *= sample_coord.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) { + vec2 uvcoords = screenco + dir_jittered * offset; + /* Out of screen case. */ + if (any(greaterThan(abs(uvcoords - 0.5), vec2(0.5)))) { continue; } - - float depth_new = texture(depthBuffer, uvcoords).r; - + /* Sample depth. */ + float s_depth = texture(depthBuffer, uvcoords).r; /* Handle Background case */ - bool is_background = (depth_new == 1.0); - + bool is_background = (s_depth == 1.0); /* This trick provide good edge effect even if no neighbor is found. */ - vec3 pos_new = get_view_space_from_depth(uvcoords, (is_background) ? depth : depth_new); + s_depth = (is_background) ? depth : s_depth; + vec3 s_pos = view_space_from_depth(uvcoords, s_depth, world_data.viewvecs, ProjectionMatrix); if (is_background) { - pos_new.z -= ssao_distance; + s_pos.z -= world_data.cavity_distance; } - vec3 dir = pos_new - position; + vec3 dir = s_pos - 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)); + float attenuation = 1.0 / (len * (1.0 + len * len * world_data.cavity_attenuation)); /* use minor bias here to avoid self shadowing */ if (f_cavities > -f_bias) { @@ -82,11 +91,10 @@ void ssao_factors(in float depth, edges += f_edge * attenuation; } } - - cavities /= ssao_samples_num; - edges /= ssao_samples_num; + cavities *= world_data.cavity_sample_count_inv; + edges *= world_data.cavity_sample_count_inv; /* don't let cavity wash out the surface appearance */ - cavities = clamp(cavities * ssao_factor_cavity, 0.0, 1.0); - edges = edges * ssao_factor_edge; + cavities = clamp(cavities * world_data.cavity_valley_factor, 0.0, 1.0); + edges = edges * world_data.cavity_ridge_factor; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl index 74a745ce74d..0e2eee99a1b 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl @@ -77,3 +77,21 @@ vec3 view_vector_from_screen_uv(vec2 uv, vec4 viewvecs[3], mat4 proj_mat) return vec3(0.0, 0.0, 1.0); } } + +vec3 view_space_from_depth(vec2 uvcoords, float depth, vec4 viewvecs[3], mat4 proj_mat) +{ + if (proj_mat[3][3] == 0.0) { + /* Perspective */ + float d = 2.0 * depth - 1.0; + + float zview = -proj_mat[3][2] / (d + proj_mat[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; + } +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl index 22dc906be83..8754b7147d9 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl @@ -1,6 +1,5 @@ -#ifndef CURVATURE_OFFSET -# define CURVATURE_OFFSET 1 -#endif + +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) float curvature_soft_clamp(float curvature, float control) { @@ -10,33 +9,35 @@ float curvature_soft_clamp(float curvature, float control) return 0.25 / control; } -float calculate_curvature( - usampler2D objectId, sampler2D normalBuffer, ivec2 texel, float ridge, float valley) +void curvature_compute(vec2 uv, + usampler2D objectIdBuffer, + sampler2D normalBuffer, + out float curvature) { - uint object_up = texelFetchOffset(objectId, texel, 0, ivec2(0, CURVATURE_OFFSET)).r; - uint object_down = texelFetchOffset(objectId, texel, 0, ivec2(0, -CURVATURE_OFFSET)).r; - uint object_left = texelFetchOffset(objectId, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).r; - uint object_right = texelFetchOffset(objectId, texel, 0, ivec2(CURVATURE_OFFSET, 0)).r; + curvature = 0.0; + + vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.curvature_offset; + uint object_up = texture(objectIdBuffer, uv + offset.zy).r; + uint object_down = texture(objectIdBuffer, uv - offset.zy).r; + uint object_right = texture(objectIdBuffer, uv + offset.xz).r; + uint object_left = texture(objectIdBuffer, uv - offset.xz).r; + /* Remove object outlines. */ if ((object_up != object_down) || (object_right != object_left)) { - return 0.0; + return; } - vec2 normal_up = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, CURVATURE_OFFSET)).rg; - vec2 normal_down = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, -CURVATURE_OFFSET)).rg; - vec2 normal_left = texelFetchOffset(normalBuffer, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).rg; - vec2 normal_right = texelFetchOffset(normalBuffer, texel, 0, ivec2(CURVATURE_OFFSET, 0)).rg; - - normal_up = workbench_normal_decode(normal_up).rg; - normal_down = workbench_normal_decode(normal_down).rg; - normal_left = workbench_normal_decode(normal_left).rg; - normal_right = workbench_normal_decode(normal_right).rg; + float normal_up = workbench_normal_decode(texture(normalBuffer, uv + offset.zy)).g; + float normal_down = workbench_normal_decode(texture(normalBuffer, uv - offset.zy)).g; + float normal_right = workbench_normal_decode(texture(normalBuffer, uv + offset.xz)).r; + float normal_left = workbench_normal_decode(texture(normalBuffer, uv - offset.xz)).r; - float normal_diff = ((normal_up.g - normal_down.g) + (normal_right.r - normal_left.r)); + float normal_diff = (normal_up - normal_down) + (normal_right - normal_left); if (normal_diff < 0) { - return -2.0 * curvature_soft_clamp(-normal_diff, valley); + curvature = -2.0 * curvature_soft_clamp(-normal_diff, world_data.curvature_valley); + } + else { + curvature = 2.0 * curvature_soft_clamp(normal_diff, world_data.curvature_ridge); } - - return 2.0 * curvature_soft_clamp(normal_diff, ridge); } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl index 75fde40bc94..69aadabe860 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl @@ -16,10 +16,21 @@ struct WorldData { /* - 16 bytes alignment- */ LightData lights[4]; vec4 ambient_color; - int matcap_orientation; + + int cavity_sample_start; + int cavity_sample_end; + float cavity_sample_count_inv; + float cavity_jitter_scale; + + float cavity_valley_factor; + float cavity_ridge_factor; + float cavity_attenuation; + float cavity_distance; + float curvature_ridge; float curvature_valley; - int _pad0; + float curvature_offset; + int matcap_orientation; }; #define viewport_size_inv viewport_size.zw diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl new file mode 100644 index 00000000000..328d50e69e0 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl @@ -0,0 +1,31 @@ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_cavity_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_curvature_lib.glsl) + +uniform sampler2D depthBuffer; +uniform sampler2D normalBuffer; +uniform usampler2D objectIdBuffer; + +in vec4 uvcoordsvar; + +out vec4 fragColor; + +void main() +{ + float cavity = 0.0, edges = 0.0, curvature = 0.0; + +#ifdef USE_CAVITY + cavity_compute(uvcoordsvar.st, depthBuffer, normalBuffer, cavity, edges); +#endif + +#ifdef USE_CURVATURE + curvature_compute(uvcoordsvar.st, objectIdBuffer, normalBuffer, curvature); +#endif + + float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0); + + fragColor.rgb = vec3(final_cavity_factor); + fragColor.a = 1.0; +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl index c38d8fe06bc..c8f0a04918d 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl @@ -41,7 +41,7 @@ float get_view_z_from_depth(float depth) } } -vec3 get_view_space_from_depth(vec2 uvcoords, float depth) +vec3 view_space_from_depth(vec2 uvcoords, float depth) { if (ProjectionMatrix[3][3] == 0.0) { return vec3(viewvecs[0].xy + uvcoords * viewvecs[1].xy, 1.0) * get_view_z_from_depth(depth); @@ -208,8 +208,8 @@ void main() float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r; float depth_end = min(depth, gl_FragCoord.z); - vec3 vs_ray_end = get_view_space_from_depth(screen_uv, depth_end); - vec3 vs_ray_ori = get_view_space_from_depth(screen_uv, 0.0); + vec3 vs_ray_end = view_space_from_depth(screen_uv, depth_end); + vec3 vs_ray_ori = view_space_from_depth(screen_uv, 0.0); vec3 vs_ray_dir = (is_persp) ? (vs_ray_end - vs_ray_ori) : vec3(0.0, 0.0, -1.0); vs_ray_dir /= abs(vs_ray_dir.z); diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index 937c6a33319..0f7a4f8f9c8 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -27,6 +27,7 @@ #include "DNA_userdef_types.h" #include "ED_view3d.h" +#include "ED_screen.h" #include "UI_resources.h" @@ -56,6 +57,8 @@ static void workbench_view_layer_data_free(void *storage) WORKBENCH_ViewLayerData *vldata = (WORKBENCH_ViewLayerData *)storage; DRW_UBO_FREE_SAFE(vldata->world_ubo); + DRW_UBO_FREE_SAFE(vldata->cavity_sample_ubo); + DRW_TEXTURE_FREE_SAFE(vldata->cavity_jitter_tx); BLI_memblock_destroy(vldata->material_ubo_data, NULL); BLI_memblock_destroy(vldata->material_ubo, workbench_ubo_free); @@ -189,11 +192,22 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) WORKBENCH_ViewLayerData *vldata = workbench_view_layer_data_ensure_ex(draw_ctx->view_layer); View3D *v3d = draw_ctx->v3d; + if (draw_ctx->evil_C != NULL) { + struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); + wpd->is_playback = ED_screen_animation_playing(wm) != NULL; + } + else { + wpd->is_playback = false; + } + wpd->ctx_mode = CTX_data_mode_enum_ex( draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode); wpd->preferences = &U; wpd->sh_cfg = draw_ctx->sh_cfg; + wpd->vldata = vldata; + + wpd->taa_sample_len = workbench_taa_calculate_num_iterations(wpd); wpd->world_ubo = vldata->world_ubo; @@ -244,13 +258,12 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) copy_v3_v3(wd->object_outline_color, wpd->shading.object_outline_color); wd->object_outline_color[3] = 1.0f; - wd->curvature_ridge = 0.5f / max_ff(SQUARE(wpd->shading.curvature_ridge_factor), 1e-4f); - wd->curvature_valley = 0.7f / max_ff(SQUARE(wpd->shading.curvature_valley_factor), 1e-4f); + copy_v2_v2(wpd->world_data.viewport_size, DRW_viewport_size_get()); + copy_v2_v2(wpd->world_data.viewport_size_inv, DRW_viewport_invert_size_get()); workbench_shadow_world_data_update(wpd); + workbench_cavity_data_update(wpd); workbench_viewvecs_update(wpd->world_data.viewvecs); - copy_v2_v2(wpd->world_data.viewport_size, DRW_viewport_size_get()); - copy_v2_v2(wpd->world_data.viewport_size_inv, DRW_viewport_invert_size_get()); DRW_uniformbuffer_update(wpd->world_ubo, &wpd->world_data); diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index 4bd0e663650..886fc836ce8 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -192,7 +192,7 @@ static char *workbench_build_cavity_frag(bool cavity, bool curvature, bool high_ return str; } -static GPUShader *workbench_cavity_shader_get(bool cavity, bool curvature) +static GPUShader *workbench__cavity_shader_get(bool cavity, bool curvature) { const bool high_dpi = (U.pixelsize > 1.5f); int index = 0; @@ -547,7 +547,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) { /* AO Samples Tex */ - int num_iterations = workbench_taa_calculate_num_iterations(vedata); + int num_iterations = workbench_taa_calculate_num_iterations(vedata->stl->wpd); const int ssao_samples_single_iteration = scene->display.matcap_ssao_samples; const int ssao_samples = MIN2(num_iterations * ssao_samples_single_iteration, 500); @@ -596,7 +596,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) if (CAVITY_ENABLED(wpd)) { int state = DRW_STATE_WRITE_COLOR; - GPUShader *shader = workbench_cavity_shader_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd)); + GPUShader *shader = workbench__cavity_shader_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd)); psl->cavity_pass = DRW_pass_create("Cavity", state); DRWShadingGroup *grp = DRW_shgroup_create(shader, psl->cavity_pass); DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx); diff --git a/source/blender/draw/engines/workbench/workbench_effect_aa.c b/source/blender/draw/engines/workbench/workbench_effect_aa.c index c03fe5cd5c8..482cb81917f 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_aa.c +++ b/source/blender/draw/engines/workbench/workbench_effect_aa.c @@ -32,15 +32,6 @@ void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx) WORKBENCH_PrivateData *wpd = stl->g_data; WORKBENCH_PassList *psl = vedata->psl; WORKBENCH_EffectInfo *effect_info = stl->effects; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - if (draw_ctx->evil_C != NULL) { - struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); - wpd->is_playback = ED_screen_animation_playing(wm) != NULL; - } - else { - wpd->is_playback = false; - } if (workbench_is_taa_enabled(wpd)) { psl->effect_aa_pass = workbench_taa_create_pass(vedata, tx); diff --git a/source/blender/draw/engines/workbench/workbench_effect_cavity.c b/source/blender/draw/engines/workbench/workbench_effect_cavity.c index 42652cf4299..5f7f8feb42d 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_cavity.c +++ b/source/blender/draw/engines/workbench/workbench_effect_cavity.c @@ -22,57 +22,142 @@ #include "DRW_render.h" +#include "BLI_rand.h" + +#include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */ + #include "workbench_engine.h" #include "workbench_private.h" -#if 0 +#define JITTER_TEX_SIZE 64 + +/* Using Hammersley distribution */ +static float *create_disk_samples(int num_samples, int num_iterations) { + const int total_samples = num_samples * num_iterations; + const float num_samples_inv = 1.0f / num_samples; + /* vec4 to ensure memory alignment. */ + float(*texels)[4] = MEM_mallocN(sizeof(float[4]) * total_samples, __func__); - { - /* AO Samples Tex */ - int num_iterations = workbench_taa_calculate_num_iterations(vedata); + for (int i = 0; i < total_samples; i++) { + float it_add = (i / num_samples) * 0.499f; + float r = fmodf((i + 0.5f + it_add) * num_samples_inv, 1.0f); + double dphi; + BLI_hammersley_1d(i, &dphi); - const int ssao_samples_single_iteration = scene->display.matcap_ssao_samples; - const int ssao_samples = MIN2(num_iterations * ssao_samples_single_iteration, 500); + float phi = (float)dphi * 2.0f * M_PI + it_add; + texels[i][0] = cosf(phi); + texels[i][1] = sinf(phi); + /* This deliberately distribute more samples + * at the center of the disk (and thus the shadow). */ + texels[i][2] = r; + } - 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); - } + return (float *)texels; +} - if (e_data.sampling_ubo == NULL) { - float *samples = create_disk_samples(ssao_samples_single_iteration, num_iterations); - 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); - } +static struct GPUTexture *create_jitter_texture(int num_samples) +{ + float jitter[64 * 64][4]; + 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; + jitter[i][3] = blue_noise[i][1]; } + + 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_RGBA16F, DRW_TEX_WRAP, &jitter[0][0]); } +static void workbench_cavity_samples_ubo_ensure(WORKBENCH_PrivateData *wpd) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + + int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples; + int cavity_sample_count = MIN2(wpd->taa_sample_len * cavity_sample_count_single_iteration, 512); + + if (wpd->vldata->cavity_sample_count != cavity_sample_count) { + DRW_UBO_FREE_SAFE(wpd->vldata->cavity_sample_ubo); + DRW_TEXTURE_FREE_SAFE(wpd->vldata->cavity_jitter_tx); + } + + if (wpd->vldata->cavity_sample_ubo == NULL) { + float *samples = create_disk_samples(cavity_sample_count_single_iteration, + wpd->taa_sample_len); + wpd->vldata->cavity_jitter_tx = create_jitter_texture(cavity_sample_count); + /* NOTE: Uniform buffer needs to always be filled to be valid. */ + wpd->vldata->cavity_sample_ubo = DRW_uniformbuffer_create(sizeof(float[4]) * 512, samples); + wpd->vldata->cavity_sample_count = cavity_sample_count; + MEM_freeN(samples); + } +} + +void workbench_cavity_data_update(WORKBENCH_PrivateData *wpd) +{ + WORKBENCH_UBO_World *wd = &wpd->world_data; + View3DShading *shading = &wpd->shading; + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + + int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples; + + wd->cavity_sample_start = cavity_sample_count_single_iteration * wpd->taa_sample; + wd->cavity_sample_end = min_ff(wd->cavity_sample_start + cavity_sample_count_single_iteration, + wpd->vldata->cavity_sample_count); + wd->cavity_sample_count_inv = 1.0f / (wd->cavity_sample_end - wd->cavity_sample_start); + wd->cavity_jitter_scale = 1.0f / 64.0f; + + wd->cavity_valley_factor = shading->cavity_valley_factor; + wd->cavity_ridge_factor = shading->cavity_ridge_factor; + wd->cavity_attenuation = scene->display.matcap_ssao_attenuation; + wd->cavity_distance = scene->display.matcap_ssao_distance; + + wd->curvature_ridge = 0.5f / max_ff(SQUARE(shading->curvature_ridge_factor), 1e-4f); + wd->curvature_valley = 0.7f / max_ff(SQUARE(shading->curvature_valley_factor), 1e-4f); + wd->curvature_offset = G_draw.block.sizePixel; +} + +void workbench_cavity_cache_init(WORKBENCH_Data *data) +{ + WORKBENCH_PassList *psl = data->psl; + WORKBENCH_PrivateData *wpd = data->stl->wpd; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + struct GPUShader *sh; + DRWShadingGroup *grp; + if (CAVITY_ENABLED(wpd)) { - int state = DRW_STATE_WRITE_COLOR; - GPUShader *shader = workbench_cavity_shader_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd)); - psl->cavity_pass = DRW_pass_create("Cavity", state); - DRWShadingGroup *grp = DRW_shgroup_create(shader, psl->cavity_pass); - DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx); - DRW_shgroup_uniform_block(grp, "samples_block", e_data.sampling_ubo); + workbench_cavity_samples_ubo_ensure(wpd); + + int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL; + DRW_PASS_CREATE(psl->cavity_pass, state); + + sh = workbench_shader_cavity_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd)); + + grp = DRW_shgroup_create(sh, psl->cavity_pass); + DRW_shgroup_uniform_texture(grp, "normalBuffer", wpd->normal_buffer_tx); + DRW_shgroup_uniform_block(grp, "samples_block", wpd->vldata->cavity_sample_ubo); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); if (SSAO_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - 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_texture(grp, "depthBuffer", dtxl->depth); + DRW_shgroup_uniform_texture(grp, "cavityJitter", wpd->vldata->cavity_jitter_tx); } - if (CURVATURE_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); - DRW_shgroup_uniform_vec2(grp, "curvature_settings", &wpd->world_data.curvature_ridge, 1); + DRW_shgroup_uniform_texture(grp, "objectIdBuffer", wpd->object_id_tx); } - - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } -#endif
\ No newline at end of file + else { + psl->cavity_pass = NULL; + } +} diff --git a/source/blender/draw/engines/workbench/workbench_effect_dof.c b/source/blender/draw/engines/workbench/workbench_effect_dof.c index 3709c5600e6..219cf3ba625 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_dof.c +++ b/source/blender/draw/engines/workbench/workbench_effect_dof.c @@ -343,7 +343,7 @@ void workbench_dof_create_pass(WORKBENCH_Data *vedata, #endif { float offset = stl->effects->jitter_index / - (float)workbench_taa_calculate_num_iterations(vedata); + (float)workbench_taa_calculate_num_iterations(vedata->stl->wpd); DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur1_sh, psl->dof_blur1_ps); DRW_shgroup_uniform_block(grp, "dofSamplesBlock", wpd->dof_ubo); DRW_shgroup_uniform_texture(grp, "noiseTex", noise_tex); diff --git a/source/blender/draw/engines/workbench/workbench_effect_taa.c b/source/blender/draw/engines/workbench/workbench_effect_taa.c index 772d859392b..3512836376e 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_taa.c +++ b/source/blender/draw/engines/workbench/workbench_effect_taa.c @@ -21,6 +21,7 @@ */ #include "workbench_private.h" + #include "BLI_jitter_2d.h" static struct { @@ -86,10 +87,8 @@ static void workbench_taa_jitter_init(void) workbench_taa_jitter_init_order(e_data.jitter_32, 32); } -int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata) +int workbench_taa_calculate_num_iterations(WORKBENCH_PrivateData *wpd) { - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; const Scene *scene = DRW_context_state_get()->scene; int result; if (workbench_is_taa_enabled(wpd)) { @@ -211,7 +210,7 @@ void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata) int num_samples = 8; float(*samples)[2]; - num_samples = workbench_taa_calculate_num_iterations(vedata); + num_samples = workbench_taa_calculate_num_iterations(vedata->stl->wpd); switch (num_samples) { default: case 5: diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index ac0a4e6221a..b9017f9bfff 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -83,6 +83,7 @@ static void workbench_cache_init(void *ved) workbench_opaque_cache_init(vedata); workbench_transparent_cache_init(vedata); workbench_shadow_cache_init(vedata); + workbench_cavity_cache_init(vedata); // workbench_aa_create_pass(vedata); // workbench_dof_create_pass(vedata); @@ -415,9 +416,10 @@ static void workbench_draw_scene(void *ved) GPU_framebuffer_bind(dfbl->default_fb); DRW_draw_pass(psl->composite_pass); - /* TODO(fclem) ambient occlusion */ - // GPU_framebuffer_bind(dfbl->color_only_fb); - // DRW_draw_pass(psl->ambient_occlusion_pass); + if (psl->cavity_pass) { + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_draw_pass(psl->cavity_pass); + } } { diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 155deba8380..901509837cb 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -215,10 +215,21 @@ typedef struct WORKBENCH_UBO_World { float shadow_focus, shadow_shift, shadow_mul, shadow_add; WORKBENCH_UBO_Light lights[4]; float ambient_color[4]; - int matcap_orientation; + + int cavity_sample_start; + int cavity_sample_end; + float cavity_sample_count_inv; + float cavity_jitter_scale; + + float cavity_valley_factor; + float cavity_ridge_factor; + float cavity_attenuation; + float cavity_distance; + float curvature_ridge; float curvature_valley; - int _pad0; + float curvature_offset; + int matcap_orientation; } WORKBENCH_UBO_World; BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_World, 16) @@ -252,6 +263,9 @@ typedef struct WORKBENCH_PrivateData { struct GPUShader *transparent_accum_textured_sh; struct GPUShader *transparent_accum_textured_array_sh; struct GPUShader *transparent_accum_vertex_sh; + + struct WORKBENCH_ViewLayerData *vldata; + View3DShading shading; eContextObjectMode ctx_mode; StudioLight *studio_light; @@ -283,6 +297,12 @@ typedef struct WORKBENCH_PrivateData { bool shadow_changed; bool is_playback; + /* Temporal Antialiasing */ + /** Total number of samples to after which TAA stops accumulating samples. */ + int taa_sample_len; + /** Current TAA sample index in [0..taa_sample_len[ range. */ + int taa_sample; + /* Opaque pipeline */ struct GPUTexture *object_id_tx; struct GPUTexture *material_buffer_tx; @@ -375,8 +395,11 @@ typedef struct WORKBENCH_ObjectData { typedef struct WORKBENCH_ViewLayerData { struct GPUUniformBuffer *world_ubo; + struct GPUUniformBuffer *cavity_sample_ubo; + struct GPUTexture *cavity_jitter_tx; struct BLI_memblock *material_ubo; struct BLI_memblock *material_ubo_data; + int cavity_sample_count; } WORKBENCH_ViewLayerData; /* Enumeration containing override options for base color rendering. @@ -524,6 +547,8 @@ GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *wpd); GPUShader *workbench_shader_shadow_pass_get(bool manifold); GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap); +GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature); + void workbench_shader_library_ensure(void); void workbench_shader_free(void); @@ -572,9 +597,13 @@ DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_bu void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata); void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata); void workbench_taa_view_updated(WORKBENCH_Data *vedata); -int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata); +int workbench_taa_calculate_num_iterations(WORKBENCH_PrivateData *wpd); int workbench_num_viewport_rendering_iterations(WORKBENCH_Data *vedata); +/* workbench_cavity.c */ +void workbench_cavity_data_update(WORKBENCH_PrivateData *wpd); +void workbench_cavity_cache_init(WORKBENCH_Data *data); + /* workbench_effect_dof.c */ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera); void workbench_dof_engine_free(void); diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c index c8f74120113..803bf17662f 100644 --- a/source/blender/draw/engines/workbench/workbench_render.c +++ b/source/blender/draw/engines/workbench/workbench_render.c @@ -154,7 +154,7 @@ void workbench_render(WORKBENCH_Data *data, DRW_hair_update(); /* Draw. */ - int num_samples = workbench_taa_calculate_num_iterations(data); + int num_samples = workbench_taa_calculate_num_iterations(data->stl->wpd); for (int sample = 0; sample < num_samples; sample++) { if (RE_engine_test_break(engine)) { break; @@ -179,7 +179,7 @@ void workbench_render(WORKBENCH_Data *data, DRW_hair_update(); /* Draw. */ - int num_samples = workbench_taa_calculate_num_iterations(data); + int num_samples = workbench_taa_calculate_num_iterations(data->stl->wpd); for (int sample = 0; sample < num_samples; sample++) { if (RE_engine_test_break(engine)) { break; diff --git a/source/blender/draw/engines/workbench/workbench_shader.c b/source/blender/draw/engines/workbench/workbench_shader.c index 3470d42608e..cbbc8787fbf 100644 --- a/source/blender/draw/engines/workbench/workbench_shader.c +++ b/source/blender/draw/engines/workbench/workbench_shader.c @@ -34,11 +34,7 @@ extern char datatoc_workbench_prepass_vert_glsl[]; extern char datatoc_workbench_prepass_hair_vert_glsl[]; extern char datatoc_workbench_prepass_frag_glsl[]; -// extern char datatoc_workbench_cavity_frag_glsl[]; -// extern char datatoc_workbench_forward_composite_frag_glsl[]; -// extern char datatoc_workbench_deferred_composite_frag_glsl[]; -// extern char datatoc_workbench_deferred_background_frag_glsl[]; -// extern char datatoc_workbench_ghost_resolve_frag_glsl[]; +extern char datatoc_workbench_effect_cavity_frag_glsl[]; extern char datatoc_workbench_composite_frag_glsl[]; @@ -81,6 +77,8 @@ static struct { struct GPUShader *shadow_depth_pass_sh[2]; struct GPUShader *shadow_depth_fail_sh[2][2]; + struct GPUShader *cavity_sh[2][2]; + struct DRWShaderLibrary *lib; } e_data = {{{{NULL}}}}; @@ -92,28 +90,29 @@ void workbench_shader_library_ensure(void) DRW_SHADER_LIB_ADD(e_data.lib, common_hair_lib); DRW_SHADER_LIB_ADD(e_data.lib, common_view_lib); DRW_SHADER_LIB_ADD(e_data.lib, workbench_shader_interface_lib); - DRW_SHADER_LIB_ADD(e_data.lib, workbench_cavity_lib); DRW_SHADER_LIB_ADD(e_data.lib, workbench_common_lib); DRW_SHADER_LIB_ADD(e_data.lib, workbench_image_lib); DRW_SHADER_LIB_ADD(e_data.lib, workbench_material_lib); DRW_SHADER_LIB_ADD(e_data.lib, workbench_data_lib); DRW_SHADER_LIB_ADD(e_data.lib, workbench_matcap_lib); DRW_SHADER_LIB_ADD(e_data.lib, workbench_object_outline_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_cavity_lib); DRW_SHADER_LIB_ADD(e_data.lib, workbench_curvature_lib); DRW_SHADER_LIB_ADD(e_data.lib, workbench_world_light_lib); } } -static char *workbench_build_defines(WORKBENCH_PrivateData *wpd, bool textured, bool tiled) +static char *workbench_build_defines( + WORKBENCH_PrivateData *wpd, bool textured, bool tiled, bool cavity, bool curvature) { char *str = NULL; DynStr *ds = BLI_dynstr_new(); - if (wpd->shading.light == V3D_LIGHTING_STUDIO) { + if (wpd && wpd->shading.light == V3D_LIGHTING_STUDIO) { BLI_dynstr_append(ds, "#define V3D_LIGHTING_STUDIO\n"); } - else if (wpd->shading.light == V3D_LIGHTING_MATCAP) { + else if (wpd && wpd->shading.light == V3D_LIGHTING_MATCAP) { BLI_dynstr_append(ds, "#define V3D_LIGHTING_MATCAP\n"); } else { @@ -130,6 +129,12 @@ static char *workbench_build_defines(WORKBENCH_PrivateData *wpd, bool textured, if (tiled) { BLI_dynstr_append(ds, "#define TEXTURE_IMAGE_ARRAY\n"); } + if (cavity) { + BLI_dynstr_append(ds, "#define USE_CAVITY\n"); + } + if (curvature) { + BLI_dynstr_append(ds, "#define USE_CURVATURE\n"); + } str = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); @@ -153,7 +158,7 @@ static GPUShader *workbench_shader_get_ex( &e_data.opaque_prepass_sh_cache[wpd->sh_cfg][hair][color]; if (*shader == NULL) { - char *defines = workbench_build_defines(wpd, textured, tiled); + char *defines = workbench_build_defines(wpd, textured, tiled, false, false); char *frag_file = transp ? datatoc_workbench_transparent_accum_frag_glsl : datatoc_workbench_prepass_frag_glsl; @@ -207,7 +212,7 @@ GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd) BLI_assert(light < MAX_LIGHTING); if (*shader == NULL) { - char *defines = workbench_build_defines(wpd, false, false); + char *defines = workbench_build_defines(wpd, false, false, false, false); char *frag = DRW_shader_library_create_shader_string(e_data.lib, datatoc_workbench_composite_frag_glsl); @@ -235,7 +240,7 @@ GPUShader *workbench_shader_merge_infront_get(WORKBENCH_PrivateData *UNUSED(wpd) GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *wpd) { if (e_data.oit_resolve_sh == NULL) { - char *defines = workbench_build_defines(wpd, false, false); + char *defines = workbench_build_defines(wpd, false, false, false, false); e_data.oit_resolve_sh = DRW_shader_create_fullscreen( datatoc_workbench_transparent_resolve_frag_glsl, defines); @@ -283,6 +288,24 @@ GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap) return workbench_shader_shadow_pass_get_ex(false, manifold, cap); } +GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature) +{ + BLI_assert(cavity || curvature); + struct GPUShader **shader = &e_data.cavity_sh[cavity][curvature]; + + if (*shader == NULL) { + char *defines = workbench_build_defines(NULL, false, false, cavity, curvature); + char *frag = DRW_shader_library_create_shader_string( + e_data.lib, datatoc_workbench_effect_cavity_frag_glsl); + + *shader = DRW_shader_create_fullscreen(frag, defines); + + MEM_freeN(defines); + MEM_freeN(frag); + } + return *shader; +} + void workbench_shader_free(void) { for (int j = 0; j < sizeof(e_data.opaque_prepass_sh_cache) / sizeof(void *); j++) { @@ -305,6 +328,10 @@ void workbench_shader_free(void) struct GPUShader **sh_array = &e_data.shadow_depth_fail_sh[0][0]; DRW_SHADER_FREE_SAFE(sh_array[j]); } + for (int j = 0; j < sizeof(e_data.cavity_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.cavity_sh[0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } DRW_SHADER_FREE_SAFE(e_data.oit_resolve_sh); DRW_SHADER_FREE_SAFE(e_data.merge_infront_sh); |