From c476c36e400883d929a7149def8dcb6ad6157a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 11 Mar 2020 17:07:43 +0100 Subject: Workbench Simplification Refactor This patch is (almost) a complete rewrite of workbench engine. The features remain unchanged but the code quality is greatly improved. Hair shading is brighter but also more correct. This also introduce the concept of `DRWShaderLibrary` to make a simple include system inside the GLSL files. Differential Revision: https://developer.blender.org/D7060 --- .../workbench/shaders/workbench_cavity_frag.glsl | 81 ----------- .../workbench/shaders/workbench_cavity_lib.glsl | 97 +++++++------ .../workbench/shaders/workbench_common_lib.glsl | 154 +++------------------ .../shaders/workbench_composite_frag.glsl | 44 ++++++ .../workbench/shaders/workbench_curvature_lib.glsl | 47 ++++--- .../workbench/shaders/workbench_data_lib.glsl | 34 ++++- .../workbench_deferred_background_frag.glsl | 30 ---- .../shaders/workbench_deferred_composite_frag.glsl | 103 -------------- .../shaders/workbench_effect_cavity_frag.glsl | 31 +++++ .../shaders/workbench_effect_fxaa_frag.glsl | 14 -- .../shaders/workbench_effect_outline_frag.glsl | 24 ++++ .../shaders/workbench_effect_smaa_frag.glsl | 44 ++++++ .../shaders/workbench_effect_smaa_vert.glsl | 21 +++ .../shaders/workbench_effect_taa_frag.glsl | 11 +- .../shaders/workbench_forward_composite_frag.glsl | 36 ----- .../shaders/workbench_forward_depth_frag.glsl | 20 --- .../workbench_forward_transparent_accum_frag.glsl | 118 ---------------- .../shaders/workbench_ghost_resolve_frag.glsl | 13 -- .../workbench/shaders/workbench_image_lib.glsl | 83 +++++++++++ .../workbench/shaders/workbench_matcap_lib.glsl | 30 ++++ .../workbench/shaders/workbench_material_lib.glsl | 21 +++ .../shaders/workbench_merge_infront_frag.glsl | 18 +++ .../shaders/workbench_object_outline_lib.glsl | 12 -- .../workbench/shaders/workbench_prepass_frag.glsl | 97 +++---------- .../shaders/workbench_prepass_hair_vert.glsl | 94 +++++++++++++ .../workbench/shaders/workbench_prepass_vert.glsl | 114 +++------------ .../shaders/workbench_shader_interface_lib.glsl | 21 +++ .../shaders/workbench_shadow_debug_frag.glsl | 16 ++- .../shaders/workbench_transparent_accum_frag.glsl | 89 ++++++++++++ .../workbench_transparent_resolve_frag.glsl | 26 ++++ .../workbench/shaders/workbench_volume_frag.glsl | 37 ++--- .../workbench/shaders/workbench_volume_vert.glsl | 3 + .../shaders/workbench_world_light_lib.glsl | 88 +++++++----- 33 files changed, 798 insertions(+), 873 deletions(-) delete mode 100644 source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl create mode 100644 source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl delete mode 100644 source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl delete mode 100644 source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl create mode 100644 source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl delete mode 100644 source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl create mode 100644 source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl create mode 100644 source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl create mode 100644 source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl delete mode 100644 source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl delete mode 100644 source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl delete mode 100644 source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl delete mode 100644 source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl create mode 100644 source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl create mode 100644 source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl create mode 100644 source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl create mode 100644 source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl delete mode 100644 source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl create mode 100644 source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl create mode 100644 source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl create mode 100644 source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl create mode 100644 source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl (limited to 'source/blender/draw/engines/workbench/shaders') diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl deleted file mode 100644 index a0e04f252e2..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl +++ /dev/null @@ -1,81 +0,0 @@ -out vec4 fragColor; - -uniform sampler2D depthBuffer; -uniform sampler2D colorBuffer; -uniform sampler2D normalBuffer; -uniform usampler2D objectId; - -uniform vec2 invertedViewportSize; -uniform mat4 WinMatrix; /* inverse WinMatrix */ - -uniform vec4 viewvecs[3]; -uniform vec4 ssao_params; -uniform vec4 ssao_settings; -uniform vec2 curvature_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 ssao_iteration 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.w - -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 declaration */ -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 cavity = 0.0, edges = 0.0, curvature = 0.0; - -#ifdef USE_CAVITY - float depth = texelFetch(depthBuffer, texel, 0).x; - vec3 position = get_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); -#endif - -#ifdef USE_CURVATURE - curvature = calculate_curvature( - objectId, normalBuffer, texel, curvature_settings.x, curvature_settings.y); -#endif - - float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0); - - /* Using UNORM render target so compress the range. */ - fragColor = vec4(final_cavity_factor / CAVITY_BUFFER_RANGE); -} 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..87d04144cde 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,87 @@ +#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 and infront. */ + if (depth == 1.0 || depth == 0.0) { return; } - /* take the normalized ray direction here */ - vec3 noise = texture(ssao_jitter, screenco.xy * jitter_tilling).rgb; + vec3 position = view_position_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_position_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 +92,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 c0d7719180b..25eaf003e07 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl @@ -1,30 +1,16 @@ -#define NO_OBJECT_ID uint(0) + #define EPSILON 0.00001 #define M_PI 3.14159265358979323846 #define CAVITY_BUFFER_RANGE 4.0 -/* 4x4 bayer matrix prepared for 8bit UNORM precision error. */ -#define P(x) (((x + 0.5) * (1.0 / 16.0) - 0.5) * (1.0 / 255.0)) -const vec4 dither_mat4x4[4] = vec4[4](vec4(P(0.0), P(8.0), P(2.0), P(10.0)), - vec4(P(12.0), P(4.0), P(14.0), P(6.0)), - vec4(P(3.0), P(11.0), P(1.0), P(9.0)), - vec4(P(15.0), P(7.0), P(13.0), P(5.0))); - -float bayer_dither_noise() -{ - ivec2 tx1 = ivec2(gl_FragCoord.xy) % 4; - ivec2 tx2 = ivec2(gl_FragCoord.xy) % 2; - return dither_mat4x4[tx1.x][tx1.y]; -} - #ifdef WORKBENCH_ENCODE_NORMALS # define WB_Normal vec2 /* From http://aras-p.info/texts/CompactNormalStorage.html * Using Method #4: Spheremap Transform */ -vec3 workbench_normal_decode(WB_Normal enc) +vec3 workbench_normal_decode(vec4 enc) { vec2 fenc = enc.xy * 4.0 - 2.0; float f = dot(fenc, fenc); @@ -37,8 +23,9 @@ vec3 workbench_normal_decode(WB_Normal enc) /* From http://aras-p.info/texts/CompactNormalStorage.html * Using Method #4: Spheremap Transform */ -WB_Normal workbench_normal_encode(vec3 n) +WB_Normal workbench_normal_encode(bool front_face, vec3 n) { + n = normalize(front_face ? n : -n); float p = sqrt(n.z * 8.0 + 8.0); n.xy = clamp(n.xy / p + 0.5, 0.0, 1.0); return n.xy; @@ -47,161 +34,64 @@ WB_Normal workbench_normal_encode(vec3 n) #else # define WB_Normal vec3 /* Well just do nothing... */ -# define workbench_normal_encode(a) (a) -# define workbench_normal_decode(a) (a) +# define workbench_normal_encode(f, a) (a) +# define workbench_normal_decode(a) (a.xyz) #endif /* WORKBENCH_ENCODE_NORMALS */ -/* Encoding into the alpha of a RGBA8 UNORM texture. */ +/* Encoding into the alpha of a RGBA16F texture. (10bit mantissa) */ #define TARGET_BITCOUNT 8u #define METALLIC_BITS 3u /* Metallic channel is less important. */ #define ROUGHNESS_BITS (TARGET_BITCOUNT - METALLIC_BITS) -#define TOTAL_BITS (METALLIC_BITS + ROUGHNESS_BITS) /* Encode 2 float into 1 with the desired precision. */ float workbench_float_pair_encode(float v1, float v2) { - // const uint total_mask = ~(0xFFFFFFFFu << TOTAL_BITS); // const uint v1_mask = ~(0xFFFFFFFFu << ROUGHNESS_BITS); // const uint v2_mask = ~(0xFFFFFFFFu << METALLIC_BITS); /* Same as above because some compiler are dumb af. and think we use mediump int. */ - const int total_mask = 0xFF; const int v1_mask = 0x1F; const int v2_mask = 0x7; int iv1 = int(v1 * float(v1_mask)); int iv2 = int(v2 * float(v2_mask)) << int(ROUGHNESS_BITS); - return float(iv1 | iv2) * (1.0 / float(total_mask)); + return float(iv1 | iv2); } void workbench_float_pair_decode(float data, out float v1, out float v2) { - // const uint total_mask = ~(0xFFFFFFFFu << TOTAL_BITS); // const uint v1_mask = ~(0xFFFFFFFFu << ROUGHNESS_BITS); // const uint v2_mask = ~(0xFFFFFFFFu << METALLIC_BITS); /* Same as above because some compiler are dumb af. and think we use mediump int. */ - const int total_mask = 0xFF; const int v1_mask = 0x1F; const int v2_mask = 0x7; - int idata = int(data * float(total_mask)); + int idata = int(data); v1 = float(idata & v1_mask) * (1.0 / float(v1_mask)); v2 = float(idata >> int(ROUGHNESS_BITS)) * (1.0 / float(v2_mask)); } -float calculate_transparent_weight(float z, float alpha) -{ -#if 0 - /* Eq 10 : Good for surfaces with varying opacity (like particles) */ - float a = min(1.0, alpha * 10.0) + 0.01; - float b = -gl_FragCoord.z * 0.95 + 1.0; - float w = a * a * a * 3e2 * b * b * b; -#else - /* Eq 7 put more emphasis on surfaces closer to the view. */ - // float w = 10.0 / (1e-5 + pow(abs(z) / 5.0, 2.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 7 */ - // float w = 10.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 8 */ - // float w = 10.0 / (1e-5 + pow(abs(z) / 200.0, 4.0)); /* Eq 9 */ - /* Same as eq 7, but optimized. */ - float a = abs(z) / 5.0; - float b = abs(z) / 200.0; - b *= b; - float w = 10.0 / ((1e-5 + a * a) + b * (b * b)); /* Eq 7 */ -#endif - return alpha * clamp(w, 1e-2, 3e2); -} - -/* Special function only to be used with calculate_transparent_weight(). */ -float linear_zdepth(float depth, vec4 viewvecs[3], mat4 proj_mat) +vec3 view_vector_from_screen_uv(vec2 uv, vec4 viewvecs[3], mat4 proj_mat) { if (proj_mat[3][3] == 0.0) { - float d = 2.0 * depth - 1.0; - return -proj_mat[3][2] / (d + proj_mat[2][2]); + return normalize(viewvecs[0].xyz + vec3(uv, 0.0) * viewvecs[1].xyz); } else { - /* Return depth from near plane. */ - return depth * viewvecs[1].z; - } -} - -vec3 view_vector_from_screen_uv(vec2 uv, vec4 viewvecs[3], mat4 proj_mat) -{ - return (proj_mat[3][3] == 0.0) ? normalize(viewvecs[0].xyz + vec3(uv, 0.0) * viewvecs[1].xyz) : - vec3(0.0, 0.0, 1.0); -} - -vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped) -{ - /* Quick creation of an orthonormal basis */ - float a = 1.0 / (1.0 + I.z); - float b = -I.x * I.y * a; - vec3 b1 = vec3(1.0 - I.x * I.x * a, b, -I.x); - vec3 b2 = vec3(b, 1.0 - I.y * I.y * a, -I.y); - vec2 matcap_uv = vec2(dot(b1, N), dot(b2, N)); - if (flipped) { - matcap_uv.x = -matcap_uv.x; + return vec3(0.0, 0.0, 1.0); } - return matcap_uv * 0.496 + 0.5; } -bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map) +vec3 view_position_from_depth(vec2 uvcoords, float depth, vec4 viewvecs[3], mat4 proj_mat) { - vec2 tile_pos = floor(co.xy); - - if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10) - return false; - - float tile = 10.0 * tile_pos.y + tile_pos.x; - if (tile >= textureSize(map, 0).x) - return false; - - /* Fetch tile information. */ - float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x; - if (tile_layer < 0.0) - return false; - - vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0); - - co = vec3(((co.xy - tile_pos) * tile_info.zw) + tile_info.xy, tile_layer); - return true; -} + if (proj_mat[3][3] == 0.0) { + /* Perspective */ + float d = 2.0 * depth - 1.0; -vec4 workbench_sample_texture(sampler2D image, - vec2 coord, - bool nearest_sampling, - bool premultiplied) -{ - vec2 tex_size = vec2(textureSize(image, 0).xy); - /* TODO(fclem) We could do the same with sampler objects. - * But this is a quick workaround instead of messing with the GPUTexture itself. */ - vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord; - vec4 color = texture(image, uv); + float zview = -proj_mat[3][2] / (d + proj_mat[2][2]); - /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */ - if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) { - color.rgb = color.rgb / color.a; + return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz); } + else { + /* Orthographic */ + vec3 offset = vec3(uvcoords, depth); - return color; -} - -vec4 workbench_sample_texture_array(sampler2DArray tile_array, - sampler1DArray tile_data, - vec2 coord, - bool nearest_sampling, - bool premultiplied) -{ - vec2 tex_size = vec2(textureSize(tile_array, 0).xy); - - vec3 uv = vec3(coord, 0); - if (!node_tex_tile_lookup(uv, tile_array, tile_data)) - return vec4(1.0, 0.0, 1.0, 1.0); - - /* TODO(fclem) We could do the same with sampler objects. - * But this is a quick workaround instead of messing with the GPUTexture itself. */ - uv.xy = nearest_sampling ? (floor(uv.xy * tex_size) + 0.5) / tex_size : uv.xy; - vec4 color = texture(tile_array, uv); - - /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */ - if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) { - color.rgb = color.rgb / color.a; + return viewvecs[0].xyz + offset * viewvecs[1].xyz; } - - return color; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl new file mode 100644 index 00000000000..cdb9823096c --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl @@ -0,0 +1,44 @@ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl) + +uniform sampler2D materialBuffer; +uniform sampler2D normalBuffer; + +in vec4 uvcoordsvar; + +out vec4 fragColor; + +void main() +{ + /* Normal and Incident vector are in viewspace. Lighting is evaluated in viewspace. */ + vec3 I = view_vector_from_screen_uv(uvcoordsvar.st, world_data.viewvecs, ProjectionMatrix); + vec3 N = workbench_normal_decode(texture(normalBuffer, uvcoordsvar.st)); + vec4 mat_data = texture(materialBuffer, uvcoordsvar.st); + + vec3 base_color = mat_data.rgb; + + float roughness, metallic; + workbench_float_pair_decode(mat_data.a, roughness, metallic); + +#ifdef V3D_LIGHTING_MATCAP + /* When using matcaps, mat_data.a is the backface sign. */ + N = (mat_data.a > 0.0) ? N : -N; + + fragColor.rgb = get_matcap_lighting(base_color, N, I); +#endif + +#ifdef V3D_LIGHTING_STUDIO + fragColor.rgb = get_world_lighting(base_color, roughness, metallic, N, I); +#endif + +#ifdef V3D_LIGHTING_FLAT + fragColor.rgb = base_color; +#endif + + fragColor.rgb *= get_shadow(N); + + fragColor.a = 1.0; +} 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..e6bc4c7bbc6 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.ui_scale; + 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 0c984b094d3..5f3283e1643 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl @@ -5,12 +5,42 @@ struct LightData { }; struct WorldData { + vec4 viewvecs[3]; + vec4 viewport_size; vec4 object_outline_color; vec4 shadow_direction_vs; + float shadow_focus; + float shadow_shift; + float shadow_mul; + float shadow_add; + /* - 16 bytes alignment- */ LightData lights[4]; vec4 ambient_color; - int num_lights; - 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; + float ui_scale; + float _pad0; + + int matcap_orientation; + bool use_specular; + int _pad1; + int _pad2; +}; + +#define viewport_size_inv viewport_size.zw + +layout(std140) uniform world_block +{ + WorldData world_data; }; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl deleted file mode 100644 index 22fa2babbbf..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl +++ /dev/null @@ -1,30 +0,0 @@ - -uniform usampler2D objectId; - -uniform vec2 invertedViewportSize; - -out vec4 fragColor; - -layout(std140) uniform world_block -{ - WorldData world_data; -}; - -void main() -{ - vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; - -#ifndef V3D_SHADING_OBJECT_OUTLINE - - fragColor = vec4(0.0); - -#else /* !V3D_SHADING_OBJECT_OUTLINE */ - - ivec2 texel = ivec2(gl_FragCoord.xy); - uint object_id = texelFetch(objectId, texel, 0).r; - float object_outline = calculate_object_outline(objectId, texel, object_id); - - fragColor = vec4(world_data.object_outline_color.rgb, 1.0) * (1.0 - object_outline); - -#endif /* !V3D_SHADING_OBJECT_OUTLINE */ -} 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 deleted file mode 100644 index fd4cea4279a..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl +++ /dev/null @@ -1,103 +0,0 @@ -out vec4 fragColor; - -uniform usampler2D objectId; -uniform sampler2D materialBuffer; -uniform sampler2D normalBuffer; -/* normalBuffer contains viewport normals */ -uniform sampler2D cavityBuffer; -uniform sampler2D matcapDiffuseImage; -uniform sampler2D matcapSpecularImage; - -uniform vec2 invertedViewportSize; -uniform vec4 viewvecs[3]; -uniform float shadowMultiplier; -uniform float lightMultiplier; -uniform float shadowShift = 0.1; -uniform float shadowFocus = 1.0; - -uniform vec3 materialSingleColor; - -layout(std140) uniform world_block -{ - WorldData world_data; -}; - -void main() -{ - ivec2 texel = ivec2(gl_FragCoord.xy); - vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; - - float roughness, metallic; - vec3 base_color; - -#ifndef MATDATA_PASS_ENABLED - base_color = materialSingleColor; - metallic = 0.0; - roughness = 0.5; -#else - vec4 material_data = texelFetch(materialBuffer, texel, 0); - base_color = material_data.rgb; - workbench_float_pair_decode(material_data.a, roughness, metallic); -#endif - -/* Do we need normals */ -#ifdef NORMAL_VIEWPORT_PASS_ENABLED - vec3 normal_viewport = workbench_normal_decode(texelFetch(normalBuffer, texel, 0).rg); -#endif - - vec3 I_vs = view_vector_from_screen_uv(uv_viewport, viewvecs, ProjectionMatrix); - - /* -------- SHADING --------- */ -#ifdef V3D_LIGHTING_FLAT - vec3 shaded_color = base_color; - -#elif defined(V3D_LIGHTING_MATCAP) - /* When using matcaps, the metallic is the backface sign. */ - normal_viewport = (metallic > 0.0) ? normal_viewport : -normal_viewport; - bool flipped = world_data.matcap_orientation != 0; - vec2 matcap_uv = matcap_uv_compute(I_vs, normal_viewport, flipped); - vec3 matcap_diffuse = textureLod(matcapDiffuseImage, matcap_uv, 0.0).rgb; - -# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - vec3 matcap_specular = textureLod(matcapSpecularImage, matcap_uv, 0.0).rgb; -# else - vec3 matcap_specular = vec3(0.0); -# endif - - vec3 shaded_color = matcap_diffuse * base_color + matcap_specular; - -#elif defined(V3D_LIGHTING_STUDIO) - -# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - vec3 specular_color = mix(vec3(0.05), base_color, metallic); - vec3 diffuse_color = mix(base_color, vec3(0.0), metallic); -# else - roughness = 0.0; - vec3 specular_color = vec3(0.0); - vec3 diffuse_color = base_color; -# endif - - vec3 shaded_color = get_world_lighting( - world_data, diffuse_color, specular_color, roughness, normal_viewport, I_vs); -#endif - - /* -------- POST EFFECTS --------- */ -#ifdef WB_CAVITY - /* Using UNORM texture so decompress the range */ - shaded_color *= texelFetch(cavityBuffer, texel, 0).r * CAVITY_BUFFER_RANGE; -#endif - -#ifdef V3D_SHADING_SHADOW - float light_factor = -dot(normal_viewport, world_data.shadow_direction_vs.xyz); - float shadow_mix = smoothstep(shadowFocus, shadowShift, light_factor); - shaded_color *= mix(lightMultiplier, shadowMultiplier, shadow_mix); -#endif - -#ifdef V3D_SHADING_OBJECT_OUTLINE - uint object_id = texelFetch(objectId, texel, 0).r; - float object_outline = calculate_object_outline(objectId, texel, object_id); - shaded_color = mix(world_data.object_outline_color.rgb, shaded_color, object_outline); -#endif - - fragColor = vec4(shaded_color, 1.0); -} 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_effect_fxaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl deleted file mode 100644 index 95ca2c0c297..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl +++ /dev/null @@ -1,14 +0,0 @@ - -in vec4 uvcoordsvar; - -out vec4 FragColor; - -uniform sampler2D colorBuffer; -uniform vec2 invertedViewportSize; - -void main() -{ - ivec2 texel = ivec2(gl_FragCoord.xy); - FragColor = FxaaPixelShader( - uvcoordsvar.st, colorBuffer, invertedViewportSize, 1.0, 0.166, 0.0833); -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl new file mode 100644 index 00000000000..fb6fdb93462 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl @@ -0,0 +1,24 @@ + +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) + +uniform usampler2D objectIdBuffer; + +in vec4 uvcoordsvar; + +out vec4 fragColor; + +void main() +{ + vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.ui_scale; + vec2 uv = uvcoordsvar.st; + + uint center_id = texture(objectIdBuffer, uv).r; + uvec4 adjacent_ids = uvec4(texture(objectIdBuffer, uv + offset.zy).r, + texture(objectIdBuffer, uv - offset.zy).r, + texture(objectIdBuffer, uv + offset.xz).r, + texture(objectIdBuffer, uv - offset.xz).r); + + float outline_opacity = 1.0 - dot(vec4(equal(uvec4(center_id), adjacent_ids)), vec4(0.25)); + + fragColor = world_data.object_outline_color * outline_opacity; +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl new file mode 100644 index 00000000000..2dea2fc4883 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl @@ -0,0 +1,44 @@ + +uniform sampler2D edgesTex; +uniform sampler2D areaTex; +uniform sampler2D searchTex; +uniform sampler2D blendTex; +uniform sampler2D colorTex; +uniform float mixFactor; +uniform float taaSampleCountInv; + +in vec2 uvs; +in vec2 pixcoord; +in vec4 offset[3]; + +#if SMAA_STAGE == 0 +out vec2 fragColor; +#else +out vec4 fragColor; +#endif + +void main() +{ +#if SMAA_STAGE == 0 + /* Detect edges in color and revealage buffer. */ + fragColor = SMAALumaEdgeDetectionPS(uvs, offset, colorTex); + /* Discard if there is no edge. */ + if (dot(fragColor, float2(1.0, 1.0)) == 0.0) { + discard; + } + +#elif SMAA_STAGE == 1 + fragColor = SMAABlendingWeightCalculationPS( + uvs, pixcoord, offset, edgesTex, areaTex, searchTex, vec4(0)); + +#elif SMAA_STAGE == 2 + fragColor = vec4(0.0); + if (mixFactor > 0.0) { + fragColor += SMAANeighborhoodBlendingPS(uvs, offset[0], colorTex, blendTex) * mixFactor; + } + if (mixFactor < 1.0) { + fragColor += texture(colorTex, uvs) * (1.0 - mixFactor); + } + fragColor *= taaSampleCountInv; +#endif +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl new file mode 100644 index 00000000000..07734d19972 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl @@ -0,0 +1,21 @@ + +out vec2 uvs; +out vec2 pixcoord; +out vec4 offset[3]; + +void main() +{ + int v = gl_VertexID % 3; + float x = -1.0 + float((v & 1) << 2); + float y = -1.0 + float((v & 2) << 1); + gl_Position = vec4(x, y, 1.0, 1.0); + uvs = (gl_Position.xy + 1.0) * 0.5; + +#if SMAA_STAGE == 0 + SMAAEdgeDetectionVS(uvs, offset); +#elif SMAA_STAGE == 1 + SMAABlendingWeightCalculationVS(uvs, pixcoord, offset); +#elif SMAA_STAGE == 2 + SMAANeighborhoodBlendingVS(uvs, offset[0]); +#endif +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl index 5795268f794..b877c2c3f76 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl @@ -1,14 +1,11 @@ -uniform sampler2D historyBuffer; + uniform sampler2D colorBuffer; -out vec4 colorOutput; +in vec4 uvcoordsvar; -uniform float mixFactor; +out vec4 fragColor; void main() { - ivec2 texel = ivec2(gl_FragCoord.xy); - vec4 color_buffer = texelFetch(colorBuffer, texel, 0); - vec4 history_buffer = texelFetch(historyBuffer, texel, 0); - colorOutput = mix(history_buffer, color_buffer, mixFactor); + fragColor = texture(colorBuffer, uvcoordsvar.st); } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl deleted file mode 100644 index 0a4d64b37ad..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl +++ /dev/null @@ -1,36 +0,0 @@ -out vec4 fragColor; - -uniform usampler2D objectId; -uniform sampler2D transparentAccum; -uniform sampler2D transparentRevealage; -uniform vec2 invertedViewportSize; - -#ifndef ALPHA_COMPOSITE -layout(std140) uniform world_block -{ - WorldData world_data; -}; -#endif - -/* TODO: Bypass the whole shader if there is no xray pass and no outline pass. */ -void main() -{ - ivec2 texel = ivec2(gl_FragCoord.xy); - vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; - - /* Listing 4 */ - vec4 trans_accum = texelFetch(transparentAccum, texel, 0); - float trans_revealage = trans_accum.a; - trans_accum.a = texelFetch(transparentRevealage, texel, 0).r; - - vec3 trans_color = trans_accum.rgb / clamp(trans_accum.a, 1e-4, 5e4); - - fragColor.a = 1.0 - trans_revealage; - fragColor.rgb = trans_color * fragColor.a; - -#ifdef V3D_SHADING_OBJECT_OUTLINE - uint object_id = texelFetch(objectId, texel, 0).r; - float outline = calculate_object_outline(objectId, texel, object_id); - fragColor = mix(vec4(world_data.object_outline_color.rgb, 1.0), fragColor, outline); -#endif -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl deleted file mode 100644 index abd8c1f6579..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl +++ /dev/null @@ -1,20 +0,0 @@ - -layout(location = 0) out uint objectId; - -uniform float ImageTransparencyCutoff = 0.1; -#ifdef V3D_SHADING_TEXTURE_COLOR -uniform sampler2D image; - -in vec2 uv_interp; -#endif - -void main() -{ -#ifdef V3D_SHADING_TEXTURE_COLOR - if (texture(image, uv_interp).a < ImageTransparencyCutoff) { - discard; - } -#endif - - objectId = uint(resource_id + 1) & 0xFFu; -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl deleted file mode 100644 index 559dc07c107..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl +++ /dev/null @@ -1,118 +0,0 @@ - -uniform float ImageTransparencyCutoff = 0.1; -#ifdef TEXTURE_IMAGE_ARRAY -uniform sampler2DArray image_tile_array; -uniform sampler1DArray image_tile_data; -#else -uniform sampler2D image; -#endif -uniform bool imageNearest; -uniform bool imagePremultiplied; - -uniform float alpha = 0.5; -uniform vec2 invertedViewportSize; -uniform vec4 viewvecs[3]; - -uniform vec4 materialColorAndMetal; -uniform float materialRoughness; - -uniform float shadowMultiplier = 0.5; -uniform float lightMultiplier = 1.0; -uniform float shadowShift = 0.1; -uniform float shadowFocus = 1.0; - -#ifdef NORMAL_VIEWPORT_PASS_ENABLED -in vec3 normal_viewport; -#endif /* NORMAL_VIEWPORT_PASS_ENABLED */ -#ifdef V3D_SHADING_TEXTURE_COLOR -in vec2 uv_interp; -#endif -#ifdef V3D_SHADING_VERTEX_COLOR -in vec3 vertexColor; -#endif -#ifdef V3D_LIGHTING_MATCAP -uniform sampler2D matcapDiffuseImage; -uniform sampler2D matcapSpecularImage; -#endif - -layout(std140) uniform world_block -{ - WorldData world_data; -}; - -layout(location = 0) out vec4 transparentAccum; -layout(location = 1) out - float revealageAccum; /* revealage actually stored in transparentAccum.a */ - -void main() -{ - vec4 base_color; - -#if defined(V3D_SHADING_TEXTURE_COLOR) -# ifdef TEXTURE_IMAGE_ARRAY - base_color = workbench_sample_texture_array( - image_tile_array, image_tile_data, uv_interp, imageNearest, imagePremultiplied); -# else - base_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied); -# endif - if (base_color.a < ImageTransparencyCutoff) { - discard; - } -#elif defined(V3D_SHADING_VERTEX_COLOR) - base_color.rgb = vertexColor; -#else - base_color.rgb = materialColorAndMetal.rgb; -#endif /* V3D_SHADING_TEXTURE_COLOR */ - - vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; - vec3 I_vs = view_vector_from_screen_uv(uv_viewport, viewvecs, ProjectionMatrix); - -#ifdef NORMAL_VIEWPORT_PASS_ENABLED - vec3 nor = normalize(normal_viewport); -#endif - - /* -------- SHADING --------- */ -#ifdef V3D_LIGHTING_FLAT - vec3 shaded_color = base_color.rgb; - -#elif defined(V3D_LIGHTING_MATCAP) - bool flipped = world_data.matcap_orientation != 0; - vec2 matcap_uv = matcap_uv_compute(I_vs, nor, flipped); - vec3 matcap_diffuse = textureLod(matcapDiffuseImage, matcap_uv, 0.0).rgb; -# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - vec3 matcap_specular = textureLod(matcapSpecularImage, matcap_uv, 0.0).rgb; -# else - vec3 matcap_specular = vec3(0.0); -# endif - vec3 shaded_color = matcap_diffuse * base_color.rgb + matcap_specular; - -#elif defined(V3D_LIGHTING_STUDIO) -# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - float metallic = materialColorAndMetal.a; - vec3 specular_color = mix(vec3(0.05), base_color.rgb, metallic); - vec3 diffuse_color = mix(base_color.rgb, vec3(0.0), metallic); -# else - vec3 specular_color = vec3(0.0); - vec3 diffuse_color = base_color.rgb; -# endif - - vec3 shaded_color = get_world_lighting( - world_data, diffuse_color, specular_color, materialRoughness, nor, I_vs); -#endif - -#ifdef V3D_SHADING_SHADOW - float light_factor = -dot(nor, world_data.shadow_direction_vs.xyz); - float shadow_mix = smoothstep(shadowFocus, shadowShift, light_factor); - shaded_color *= mix(lightMultiplier, shadowMultiplier, shadow_mix); -#endif - - /* Based on : - * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of - * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013 - */ - /* Listing 4 */ - float z = linear_zdepth(gl_FragCoord.z, viewvecs, ProjectionMatrix); - float weight = calculate_transparent_weight(z, alpha); - transparentAccum = vec4(shaded_color * weight, alpha); - revealageAccum = weight; -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl deleted file mode 100644 index d223a7650c5..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl +++ /dev/null @@ -1,13 +0,0 @@ -uniform sampler2D depthBuffer; - -void main(void) -{ - float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r; - - /* background, discard */ - if (depth >= 1.0) { - discard; - } - - gl_FragDepth = depth; -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl new file mode 100644 index 00000000000..6f99739f259 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl @@ -0,0 +1,83 @@ + +/* TODO(fclem) deduplicate code. */ +bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map) +{ + vec2 tile_pos = floor(co.xy); + + if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10) + return false; + + float tile = 10.0 * tile_pos.y + tile_pos.x; + if (tile >= textureSize(map, 0).x) + return false; + + /* Fetch tile information. */ + float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x; + if (tile_layer < 0.0) + return false; + + vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0); + + co = vec3(((co.xy - tile_pos) * tile_info.zw) + tile_info.xy, tile_layer); + return true; +} + +vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool nearest_sampling) +{ + vec2 tex_size = vec2(textureSize(image, 0).xy); + /* TODO(fclem) We could do the same with sampler objects. + * But this is a quick workaround instead of messing with the GPUTexture itself. */ + vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord; + return texture(image, uv); +} + +vec4 workbench_sample_texture_array(sampler2DArray tile_array, + sampler1DArray tile_data, + vec2 coord, + bool nearest_sampling) +{ + vec2 tex_size = vec2(textureSize(tile_array, 0).xy); + + vec3 uv = vec3(coord, 0); + if (!node_tex_tile_lookup(uv, tile_array, tile_data)) + return vec4(1.0, 0.0, 1.0, 1.0); + + /* TODO(fclem) We could do the same with sampler objects. + * But this is a quick workaround instead of messing with the GPUTexture itself. */ + uv.xy = nearest_sampling ? (floor(uv.xy * tex_size) + 0.5) / tex_size : uv.xy; + return texture(tile_array, uv); +} + +uniform sampler2DArray imageTileArray; +uniform sampler1DArray imageTileData; +uniform sampler2D imageTexture; + +uniform float imageTransparencyCutoff = 0.1; +uniform bool imageNearest; +uniform bool imagePremult; + +vec3 workbench_image_color(vec2 uvs) +{ +#ifdef V3D_SHADING_TEXTURE_COLOR +# ifdef TEXTURE_IMAGE_ARRAY + vec4 color = workbench_sample_texture_array(imageTileArray, imageTileData, uvs, imageNearest); +# else + vec4 color = workbench_sample_texture(imageTexture, uvs, imageNearest); +# endif + + /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */ + if (imagePremult && !(color.a == 0.0 || color.a == 1.0)) { + color.rgb /= color.a; + } + +# ifdef GPU_FRAGMENT_SHADER + if (color.a < imageTransparencyCutoff) { + discard; + } +# endif + + return color.rgb; +#else + return vec3(1.0); +#endif +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl new file mode 100644 index 00000000000..2d18cc1b014 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl @@ -0,0 +1,30 @@ + +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) + +vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped) +{ + /* Quick creation of an orthonormal basis */ + float a = 1.0 / (1.0 + I.z); + float b = -I.x * I.y * a; + vec3 b1 = vec3(1.0 - I.x * I.x * a, b, -I.x); + vec3 b2 = vec3(b, 1.0 - I.y * I.y * a, -I.y); + vec2 matcap_uv = vec2(dot(b1, N), dot(b2, N)); + if (flipped) { + matcap_uv.x = -matcap_uv.x; + } + return matcap_uv * 0.496 + 0.5; +} + +uniform sampler2D matcapDiffuseImage; +uniform sampler2D matcapSpecularImage; + +vec3 get_matcap_lighting(vec3 base_color, vec3 N, vec3 I) +{ + bool flipped = world_data.matcap_orientation != 0; + vec2 uv = matcap_uv_compute(I, N, flipped); + + vec3 diffuse = textureLod(matcapDiffuseImage, uv, 0.0).rgb; + vec3 specular = textureLod(matcapSpecularImage, uv, 0.0).rgb; + + return diffuse * base_color + specular * float(world_data.use_specular); +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl new file mode 100644 index 00000000000..1d8950e34b3 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl @@ -0,0 +1,21 @@ + +layout(std140) uniform material_block +{ + vec4 mat_data[4096]; +}; + +/* If set to -1, the resource handle is used instead. */ +uniform int materialIndex; + +void workbench_material_data_get( + int handle, out vec3 color, out float alpha, out float roughness, out float metallic) +{ + handle = (materialIndex != -1) ? materialIndex : handle; + vec4 data = mat_data[uint(handle) & 0xFFFu]; + color = data.rgb; + + uint encoded_data = floatBitsToUint(data.w); + alpha = float((encoded_data >> 16u) & 0xFFu) * (1.0 / 255.0); + roughness = float((encoded_data >> 8u) & 0xFFu) * (1.0 / 255.0); + metallic = float(encoded_data & 0xFFu) * (1.0 / 255.0); +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl new file mode 100644 index 00000000000..58becb03290 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl @@ -0,0 +1,18 @@ + +uniform sampler2D depthBuffer; + +in vec4 uvcoordsvar; + +out vec4 fragColor; + +void main() +{ + float depth = texture(depthBuffer, uvcoordsvar.st).r; + /* Discard background pixels. */ + if (depth == 1.0) { + discard; + } + /* Make this fragment occlude any fragment that will try to + * render over it in the normal passes. */ + gl_FragDepth = 0.0; +} \ No newline at end of file diff --git a/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl deleted file mode 100644 index a4a5d9c31a3..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl +++ /dev/null @@ -1,12 +0,0 @@ -#define OBJECT_OUTLINE_OFFSET 1 - -float calculate_object_outline(usampler2D objectId, ivec2 texel, uint object_id) -{ - uvec4 oid_offset = uvec4( - texelFetchOffset(objectId, texel, 0, ivec2(0, OBJECT_OUTLINE_OFFSET)).r, - texelFetchOffset(objectId, texel, 0, ivec2(0, -OBJECT_OUTLINE_OFFSET)).r, - texelFetchOffset(objectId, texel, 0, ivec2(-OBJECT_OUTLINE_OFFSET, 0)).r, - texelFetchOffset(objectId, texel, 0, ivec2(OBJECT_OUTLINE_OFFSET, 0)).r); - - return dot(vec4(equal(uvec4(object_id), oid_offset)), vec4(0.25)); -} 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 94e41b4bcd4..6d24b001d4d 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl @@ -1,92 +1,29 @@ -uniform vec4 materialColorAndMetal; -uniform float materialRoughness; +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_image_lib.glsl) -#ifdef TEXTURE_IMAGE_ARRAY -uniform sampler2DArray image_tile_array; -uniform sampler1DArray image_tile_data; -#else -uniform sampler2D image; -#endif -uniform float ImageTransparencyCutoff = 0.1; -uniform bool imageNearest; -uniform bool imagePremultiplied; - -#ifdef NORMAL_VIEWPORT_PASS_ENABLED -in vec3 normal_viewport; -#endif - -#ifdef V3D_SHADING_TEXTURE_COLOR -in vec2 uv_interp; -#endif -#ifdef V3D_SHADING_VERTEX_COLOR -in vec3 vertexColor; -#endif - -#ifdef HAIR_SHADER -flat in float hair_rand; -#endif - -#ifdef MATDATA_PASS_ENABLED layout(location = 0) out vec4 materialData; -#endif -#ifdef OBJECT_ID_PASS_ENABLED -layout(location = 1) out uint objectId; -#endif -#ifdef NORMAL_VIEWPORT_PASS_ENABLED -layout(location = 2) out WB_Normal normalViewport; -#endif +layout(location = 1) out WB_Normal normalData; +layout(location = 2) out uint objectId; + +uniform bool useMatcap = false; void main() { -#ifdef MATDATA_PASS_ENABLED - float metallic, roughness; - vec4 color; - -# if defined(V3D_SHADING_TEXTURE_COLOR) -# ifdef TEXTURE_IMAGE_ARRAY - color = workbench_sample_texture_array( - image_tile_array, image_tile_data, uv_interp, imageNearest, imagePremultiplied); -# else - color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied); -# endif - if (color.a < ImageTransparencyCutoff) { - discard; - } -# elif defined(V3D_SHADING_VERTEX_COLOR) - color.rgb = vertexColor; -# else - color.rgb = materialColorAndMetal.rgb; -# endif - -# ifdef V3D_LIGHTING_MATCAP - /* Encode front facing in metallic channel. */ - metallic = float(gl_FrontFacing); - roughness = 0.0; -# else - metallic = materialColorAndMetal.a; - roughness = materialRoughness; -# endif + normalData = workbench_normal_encode(gl_FrontFacing, normal_interp); -# ifdef HAIR_SHADER - /* Add some variation to the hairs to avoid uniform look. */ - float hair_variation = hair_rand * 0.1; - color = clamp(color - hair_variation, 0.0, 1.0); - metallic = clamp(materialColorAndMetal.a - hair_variation, 0.0, 1.0); - roughness = clamp(materialRoughness - hair_variation, 0.0, 1.0); -# endif + materialData = vec4(color_interp, packed_rough_metal); - materialData.rgb = color.rgb; - materialData.a = workbench_float_pair_encode(roughness, metallic); -#endif /* MATDATA_PASS_ENABLED */ + objectId = uint(object_id); -#ifdef OBJECT_ID_PASS_ENABLED - objectId = uint(resource_id + 1) & 0xFFu; -#endif + if (useMatcap) { + /* For matcaps, save front facing in alpha channel. */ + materialData.a = float(gl_FrontFacing); + } -#ifdef NORMAL_VIEWPORT_PASS_ENABLED - vec3 n = (gl_FrontFacing) ? normal_viewport : -normal_viewport; - n = normalize(n); - normalViewport = workbench_normal_encode(n); +#ifdef V3D_SHADING_TEXTURE_COLOR + materialData.rgb = workbench_image_color(uv_interp); #endif } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl new file mode 100644 index 00000000000..6a7bc185fe9 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl @@ -0,0 +1,94 @@ +#pragma BLENDER_REQUIRE(common_hair_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_material_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_image_lib.glsl) + +uniform samplerBuffer ac; /* active color layer */ +uniform samplerBuffer au; /* active texture layer */ + +/* From http://libnoise.sourceforge.net/noisegen/index.html */ +float integer_noise(int n) +{ + n = (n >> 13) ^ n; + int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; + return (float(nn) / 1073741824.0); +} + +vec3 workbench_hair_random_normal(vec3 tan, vec3 binor, float rand) +{ + /* To "simulate" anisotropic shading, randomize hair normal per strand. */ + vec3 nor = cross(tan, binor); + nor = normalize(mix(nor, -tan, rand * 0.1)); + float cos_theta = (rand * 2.0 - 1.0) * 0.2; + float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta)); + nor = nor * sin_theta + binor * cos_theta; + return nor; +} + +void workbench_hair_random_material(float rand, + inout vec3 color, + inout float roughness, + inout float metallic) +{ + /* Center noise around 0. */ + rand -= 0.5; + rand *= 0.1; + /* Add some variation to the hairs to avoid uniform look. */ + metallic = clamp(metallic + rand, 0.0, 1.0); + roughness = clamp(roughness + rand, 0.0, 1.0); + /* Modulate by color intensity to reduce very high contrast when color is dark. */ + color = clamp(color + rand * (color + 0.05), 0.0, 1.0); +} + +void main() +{ + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + float time, thick_time, thickness; + vec3 world_pos, tan, binor; + hair_get_pos_tan_binor_time(is_persp, + ModelMatrixInverse, + ViewMatrixInverse[3].xyz, + ViewMatrixInverse[2].xyz, + world_pos, + tan, + binor, + time, + thickness, + thick_time); + + gl_Position = point_world_to_ndc(world_pos); + + float hair_rand = integer_noise(hair_get_strand_id()); + vec3 nor = workbench_hair_random_normal(tan, binor, hair_rand); + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif + + uv_interp = hair_get_customdata_vec2(au); + + normal_interp = normalize(normal_world_to_view(nor)); + +#ifdef OPAQUE_MATERIAL + float metallic, roughness; +#endif + workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic); + + if (materialIndex == 0) { + color_interp = hair_get_customdata_vec3(ac); + } + + /* Hairs have lots of layer and can rapidly become the most prominent surface. + * So we lower their alpha artificially. */ + alpha_interp *= 0.3; + + workbench_hair_random_material(hair_rand, color_interp, roughness, metallic); + +#ifdef OPAQUE_MATERIAL + packed_rough_metal = workbench_float_pair_encode(roughness, metallic); +#endif + + object_id = int((uint(resource_id) + 1u) & 0xFFu); +} 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 0a3252f0b9b..31e298d1540 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl @@ -1,110 +1,40 @@ -#ifndef HAIR_SHADER +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_material_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_image_lib.glsl) + in vec3 pos; in vec3 nor; -in vec2 au; /* active texture layer */ -# ifdef V3D_SHADING_VERTEX_COLOR in vec4 ac; /* active color */ -# endif -# define uv au -#else /* HAIR_SHADER */ - -# ifdef V3D_SHADING_TEXTURE_COLOR -uniform samplerBuffer au; /* active texture layer */ -# endif -# ifdef V3D_SHADING_VERTEX_COLOR -uniform samplerBuffer ac; /* active color layer */ -# endif - -flat out float hair_rand; -#endif /* HAIR_SHADER */ - -#ifdef NORMAL_VIEWPORT_PASS_ENABLED -out vec3 normal_viewport; -#endif - -#ifdef V3D_SHADING_TEXTURE_COLOR -out vec2 uv_interp; -#endif -#ifdef V3D_SHADING_VERTEX_COLOR -out vec3 vertexColor; -#endif - -#ifdef OBJECT_ID_PASS_ENABLED -RESOURCE_ID_VARYING -#endif - -/* From http://libnoise.sourceforge.net/noisegen/index.html */ -float integer_noise(int n) -{ - n = (n >> 13) ^ n; - int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; - return (float(nn) / 1073741824.0); -} - -vec3 workbench_hair_hair_normal(vec3 tan, vec3 binor, float rand) -{ - /* To "simulate" anisotropic shading, randomize hair normal per strand. */ - vec3 nor = cross(tan, binor); - nor = normalize(mix(nor, -tan, rand * 0.1)); - float cos_theta = (rand * 2.0 - 1.0) * 0.2; - float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta)); - nor = nor * sin_theta + binor * cos_theta; - return nor; -} +in vec2 au; /* active texture layer */ void main() { -#ifdef HAIR_SHADER -# ifdef V3D_SHADING_TEXTURE_COLOR - vec2 uv = hair_get_customdata_vec2(au); -# endif - float time, thick_time, thickness; - vec3 world_pos, tan, binor; - hair_get_pos_tan_binor_time((ProjectionMatrix[3][3] == 0.0), - ModelMatrixInverse, - ViewMatrixInverse[3].xyz, - ViewMatrixInverse[2].xyz, - world_pos, - tan, - binor, - time, - thickness, - thick_time); - - hair_rand = integer_noise(hair_get_strand_id()); - vec3 nor = workbench_hair_hair_normal(tan, binor, hair_rand); -#else vec3 world_pos = point_object_to_world(pos); -#endif gl_Position = point_world_to_ndc(world_pos); -#ifdef V3D_SHADING_TEXTURE_COLOR - uv_interp = uv; +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); #endif -#ifdef V3D_SHADING_VERTEX_COLOR -# ifndef HAIR_SHADER - vertexColor = ac.rgb; -# else - vertexColor = hair_get_customdata_vec4(ac).rgb; -# endif -#endif + uv_interp = au; -#ifdef NORMAL_VIEWPORT_PASS_ENABLED -# ifndef HAIR_SHADER - normal_viewport = normal_object_to_view(nor); - normal_viewport = normalize(normal_viewport); -# else - normal_viewport = normal_world_to_view(nor); -# endif -#endif + normal_interp = normalize(normal_object_to_view(nor)); -#ifdef OBJECT_ID_PASS_ENABLED - PASS_RESOURCE_ID +#ifdef OPAQUE_MATERIAL + float metallic, roughness; #endif + workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic); -#ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance(world_pos); + if (materialIndex == 0) { + color_interp = ac.rgb; + } + +#ifdef OPAQUE_MATERIAL + packed_rough_metal = workbench_float_pair_encode(roughness, metallic); #endif + + object_id = int((uint(resource_id) + 1u) & 0xFFu); } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl new file mode 100644 index 00000000000..8e2f7ba4735 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl @@ -0,0 +1,21 @@ + +#ifdef GPU_VERTEX_SHADER +# define IN_OUT out +#else +# define IN_OUT in +#endif + +IN_OUT ShaderStageInterface +{ + vec3 normal_interp; + vec3 color_interp; + float alpha_interp; + vec2 uv_interp; +#ifdef TRANSPARENT_MATERIAL + flat float roughness; + flat float metallic; +#else + flat float packed_rough_metal; +#endif + flat int object_id; +}; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl index 6b0741b6d1b..6fa76510e6e 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl @@ -1,15 +1,19 @@ out vec4 fragColor; +layout(location = 0) out vec4 materialData; +layout(location = 1) out vec4 normalData; +layout(location = 2) out uint objectId; + void main() { - const float intensity = 0.25; + const float a = 0.25; #ifdef SHADOW_PASS - fragColor = vec4( - (gl_FrontFacing) ? vec3(intensity, -intensity, 0.0) : vec3(-intensity, intensity, 0.0), 1.0); + materialData.rgb = gl_FrontFacing ? vec3(a, -a, 0.0) : vec3(-a, a, 0.0); #else - fragColor = vec4((gl_FrontFacing) ? vec3(intensity, intensity, -intensity) : - vec3(-intensity, -intensity, intensity), - 1.0); + materialData.rgb = gl_FrontFacing ? vec3(a, a, -a) : vec3(-a, -a, a); #endif + materialData.a = 0.0; + normalData = vec4(0.0); + objectId = 0u; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl new file mode 100644 index 00000000000..3c2d1a9c0c7 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl @@ -0,0 +1,89 @@ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_image_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl) + +/* Revealage is actually stored in transparentAccum alpha channel. + * This is a workaround to older hardware not having separate blend equation per render target. */ +layout(location = 0) out vec4 transparentAccum; +layout(location = 1) out vec4 revealageAccum; + +/* Note: Blending will be skipped on objectId because output is a non-normalized integer buffer. */ +layout(location = 2) out uint objectId; + +/* Special function only to be used with calculate_transparent_weight(). */ +float linear_zdepth(float depth, vec4 viewvecs[3], mat4 proj_mat) +{ + if (proj_mat[3][3] == 0.0) { + float d = 2.0 * depth - 1.0; + return -proj_mat[3][2] / (d + proj_mat[2][2]); + } + else { + /* Return depth from near plane. */ + return depth * viewvecs[1].z; + } +} + +/* Based on : + * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of + * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013 + */ +float calculate_transparent_weight(void) +{ + float z = linear_zdepth(gl_FragCoord.z, world_data.viewvecs, ProjectionMatrix); +#if 0 + /* Eq 10 : Good for surfaces with varying opacity (like particles) */ + float a = min(1.0, alpha * 10.0) + 0.01; + float b = -gl_FragCoord.z * 0.95 + 1.0; + float w = a * a * a * 3e2 * b * b * b; +#else + /* Eq 7 put more emphasis on surfaces closer to the view. */ + // float w = 10.0 / (1e-5 + pow(abs(z) / 5.0, 2.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 7 */ + // float w = 10.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 8 */ + // float w = 10.0 / (1e-5 + pow(abs(z) / 200.0, 4.0)); /* Eq 9 */ + /* Same as eq 7, but optimized. */ + float a = abs(z) / 5.0; + float b = abs(z) / 200.0; + b *= b; + float w = 10.0 / ((1e-5 + a * a) + b * (b * b)); /* Eq 7 */ +#endif + return clamp(w, 1e-2, 3e2); +} + +void main() +{ + /* Normal and Incident vector are in viewspace. Lighting is evaluated in viewspace. */ + vec2 uv_viewport = gl_FragCoord.xy * world_data.viewport_size_inv; + vec3 I = view_vector_from_screen_uv(uv_viewport, world_data.viewvecs, ProjectionMatrix); + vec3 N = normalize(normal_interp); + + vec3 color = color_interp; + +#ifdef V3D_SHADING_TEXTURE_COLOR + color = workbench_image_color(uv_interp); +#endif + +#ifdef V3D_LIGHTING_MATCAP + vec3 shaded_color = get_matcap_lighting(color, N, I); +#endif + +#ifdef V3D_LIGHTING_STUDIO + vec3 shaded_color = get_world_lighting(color, roughness, metallic, N, I); +#endif + +#ifdef V3D_LIGHTING_FLAT + vec3 shaded_color = color; +#endif + + shaded_color *= get_shadow(N); + + /* Listing 4 */ + float weight = calculate_transparent_weight() * alpha_interp; + transparentAccum = vec4(shaded_color * weight, alpha_interp); + revealageAccum = vec4(weight); + + objectId = uint(object_id); +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl new file mode 100644 index 00000000000..d985737a35b --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl @@ -0,0 +1,26 @@ + +uniform sampler2D transparentAccum; +uniform sampler2D transparentRevealage; + +in vec4 uvcoordsvar; + +out vec4 fragColor; + +/* Based on : + * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of + * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013 + */ + +void main() +{ + /* Revealage is actually stored in transparentAccum alpha channel. + * This is a workaround to older hardware not having separate blend equation per render target. + */ + vec4 trans_accum = texture(transparentAccum, uvcoordsvar.st); + float trans_weight = texture(transparentRevealage, uvcoordsvar.st).r; + float trans_reveal = trans_accum.a; + + /* Listing 4 */ + fragColor.rgb = trans_accum.rgb / clamp(trans_weight, 1e-4, 5e4); + fragColor.a = 1.0 - trans_reveal; +} 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 585e48ae7ec..e957f8bbe9c 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl @@ -1,4 +1,9 @@ +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_obinfos_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) + uniform sampler2D depthBuffer; uniform sampler3D densityTexture; @@ -8,10 +13,9 @@ uniform sampler1D flameColorTexture; uniform sampler1D transferTexture; uniform int samplesLen = 256; -uniform float noiseOfs = 0.0f; +uniform float noiseOfs = 0.0; uniform float stepLength; /* Step length in local space. */ uniform float densityScale; /* Simple Opacity multiplicator. */ -uniform vec4 viewvecs[3]; uniform vec3 activeColor; uniform float slicePosition; @@ -23,34 +27,11 @@ in vec3 localPos; out vec4 fragColor; -#define M_PI 3.1415926535897932 /* pi */ - float phase_function_isotropic() { return 1.0 / (4.0 * M_PI); } -float get_view_z_from_depth(float depth) -{ - if (ProjectionMatrix[3][3] == 0.0) { - float d = 2.0 * depth - 1.0; - return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]); - } - else { - return viewvecs[0].z + depth * viewvecs[1].z; - } -} - -vec3 get_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); - } - else { - return viewvecs[0].xyz + vec3(uvcoords, depth) * viewvecs[1].xyz; - } -} - float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); @@ -209,8 +190,10 @@ 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_position_from_depth( + screen_uv, depth_end, world_data.viewvecs, ProjectionMatrix); + vec3 vs_ray_ori = view_position_from_depth( + screen_uv, 0.0, world_data.viewvecs, ProjectionMatrix); 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/shaders/workbench_volume_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl index 3542a1a91fc..1a32a202290 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl @@ -1,4 +1,7 @@ +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_obinfos_lib.glsl) + uniform float slicePosition; uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl index 690ce5d527f..81f6e651be0 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl @@ -1,4 +1,6 @@ +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) + /* [Drobot2014a] Low Level Optimizations for GCN */ vec4 fast_rcp(vec4 v) { @@ -41,9 +43,19 @@ vec4 wrapped_lighting(vec4 NL, vec4 w) return clamp((NL + w) * denom, 0.0, 1.0); } -vec3 get_world_lighting( - WorldData world_data, vec3 diffuse_color, vec3 specular_color, float roughness, vec3 N, vec3 I) +vec3 get_world_lighting(vec3 base_color, float roughness, float metallic, vec3 N, vec3 I) { + vec3 specular_color, diffuse_color; + + if (world_data.use_specular) { + diffuse_color = mix(base_color, vec3(0.0), metallic); + specular_color = mix(vec3(0.05), base_color, metallic); + } + else { + diffuse_color = base_color; + specular_color = vec3(0.0); + } + vec3 specular_light = world_data.ambient_color.rgb; vec3 diffuse_light = world_data.ambient_color.rgb; vec4 wrap = vec4(world_data.lights[0].diffuse_color_wrap.a, @@ -51,37 +63,37 @@ vec3 get_world_lighting( world_data.lights[2].diffuse_color_wrap.a, world_data.lights[3].diffuse_color_wrap.a); -#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - /* Prepare Specular computation. Eval 4 lights at once. */ - vec3 R = -reflect(I, N); - vec4 spec_angle, spec_NL, wrap_NL; - prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x); - prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y); - prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z); - prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w); - - vec4 gloss = vec4(1.0 - roughness); - /* Reduce gloss for smooth light. (simulate bigger light) */ - gloss *= 1.0 - wrap; - vec4 shininess = exp2(10.0 * gloss + 1.0); - - vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL); - - /* Simulate Env. light. */ - vec4 w = mix(wrap, vec4(1.0), roughness); - vec4 spec_env = wrapped_lighting(wrap_NL, w); - - spec_light = mix(spec_light, spec_env, wrap * wrap); - - /* Multiply result by lights specular colors. */ - specular_light += spec_light.x * world_data.lights[0].specular_color.rgb; - specular_light += spec_light.y * world_data.lights[1].specular_color.rgb; - specular_light += spec_light.z * world_data.lights[2].specular_color.rgb; - specular_light += spec_light.w * world_data.lights[3].specular_color.rgb; - - float NV = clamp(dot(N, I), 0.0, 1.0); - specular_color = brdf_approx(specular_color, roughness, NV); -#endif + if (world_data.use_specular) { + /* Prepare Specular computation. Eval 4 lights at once. */ + vec3 R = -reflect(I, N); + vec4 spec_angle, spec_NL, wrap_NL; + prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x); + prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y); + prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z); + prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w); + + vec4 gloss = vec4(1.0 - roughness); + /* Reduce gloss for smooth light. (simulate bigger light) */ + gloss *= 1.0 - wrap; + vec4 shininess = exp2(10.0 * gloss + 1.0); + + vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL); + + /* Simulate Env. light. */ + vec4 w = mix(wrap, vec4(1.0), roughness); + vec4 spec_env = wrapped_lighting(wrap_NL, w); + + spec_light = mix(spec_light, spec_env, wrap * wrap); + + /* Multiply result by lights specular colors. */ + specular_light += spec_light.x * world_data.lights[0].specular_color.rgb; + specular_light += spec_light.y * world_data.lights[1].specular_color.rgb; + specular_light += spec_light.z * world_data.lights[2].specular_color.rgb; + specular_light += spec_light.w * world_data.lights[3].specular_color.rgb; + + float NV = clamp(dot(N, I), 0.0, 1.0); + specular_color = brdf_approx(specular_color, roughness, NV); + } specular_light *= specular_color; /* Prepare diffuse computation. Eval 4 lights at once. */ @@ -107,3 +119,13 @@ vec3 get_world_lighting( return diffuse_light + specular_light; } + +uniform bool forceShadowing = false; + +float get_shadow(vec3 N) +{ + float light_factor = -dot(N, world_data.shadow_direction_vs.xyz); + float shadow_mix = smoothstep(world_data.shadow_shift, world_data.shadow_focus, light_factor); + shadow_mix *= forceShadowing ? 0.0 : world_data.shadow_mul; + return shadow_mix + world_data.shadow_add; +} \ No newline at end of file -- cgit v1.2.3