T55333 Workbench: Cavity Shader

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
This commit is contained in:
Jeroen Bakker 2018-06-06 14:47:54 +02:00
parent 4a52531a11
commit f1fd5ed74f
17 changed files with 445 additions and 12 deletions

View 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,

View 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()

View 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;
}
}
}
}
}
}
}

View 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)

View File

@ -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);
}

View File

@ -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;
}

View 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

View 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 */

View 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

View 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])

View 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);

View 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;
}

View 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)
@ -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 {

View 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;

View 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 */

View 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);

View 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");