diff options
Diffstat (limited to 'source/blender/draw/engines/clay/shaders')
4 files changed, 420 insertions, 0 deletions
diff --git a/source/blender/draw/engines/clay/shaders/clay_frag.glsl b/source/blender/draw/engines/clay/shaders/clay_frag.glsl new file mode 100644 index 00000000000..d9b372b652a --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/clay_frag.glsl @@ -0,0 +1,207 @@ +uniform vec2 screenres; +uniform sampler2D depthtex; +uniform mat4 WinMatrix; + +/* Matcap */ +uniform sampler2DArray matcaps; +uniform vec3 matcaps_color[24]; + +/* Screen Space Occlusion */ +/* store the view space vectors for the corners of the view frustum here. + * It helps to quickly reconstruct view space vectors by using uv coordinates, + * see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ +uniform vec4 viewvecs[3]; +uniform vec4 ssao_params; + +uniform sampler2D ssao_jitter; +uniform sampler1D ssao_samples; + +/* Material Parameters packed in an UBO */ +struct Material { + vec4 ssao_params_var; + vec4 matcap_hsv_id; + vec4 matcap_rot; /* vec4 to ensure 16 bytes alignement (don't trust compiler) */ +}; + +layout(std140) uniform material_block { + Material matcaps_param[MAX_MATERIAL]; +}; + +int mat_id; + +/* Aliases */ +#define ssao_samples_num ssao_params.x +#define jitter_tilling ssao_params.yz +#define dfdy_sign ssao_params.w + +#define matcap_hsv matcaps_param[mat_id].matcap_hsv_id.xyz +#define matcap_index matcaps_param[mat_id].matcap_hsv_id.w +#define matcap_rotation matcaps_param[mat_id].matcap_rot.xy + +in vec3 normal; +out vec4 fragColor; + +/* TODO Move this to SSAO modules */ +/* simple depth reconstruction, see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer + * we change the factors from the article to fit the OpennGL model. */ +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; + } +} + +/* TODO remove this when switching to geometric normals */ +vec3 calculate_view_space_normal(in vec3 viewposition) +{ + vec3 normal = cross(normalize(dFdx(viewposition)), dfdy_sign * normalize(dFdy(viewposition))); + return normalize(normal); +} + +#ifdef USE_HSV +void rgb_to_hsv(vec3 rgb, out vec3 outcol) +{ + float cmax, cmin, h, s, v, cdelta; + vec3 c; + + cmax = max(rgb[0], max(rgb[1], rgb[2])); + cmin = min(rgb[0], min(rgb[1], rgb[2])); + cdelta = cmax - cmin; + + v = cmax; + if (cmax != 0.0) + s = cdelta / cmax; + else { + s = 0.0; + h = 0.0; + } + + if (s == 0.0) { + h = 0.0; + } + else { + c = (vec3(cmax, cmax, cmax) - rgb.xyz) / cdelta; + + if (rgb.x == cmax) h = c[2] - c[1]; + else if (rgb.y == cmax) h = 2.0 + c[0] - c[2]; + else h = 4.0 + c[1] - c[0]; + + h /= 6.0; + + if (h < 0.0) + h += 1.0; + } + + outcol = vec3(h, s, v); +} + +void hsv_to_rgb(vec3 hsv, out vec3 outcol) +{ + float i, f, p, q, t, h, s, v; + vec3 rgb; + + h = hsv[0]; + s = hsv[1]; + v = hsv[2]; + + if (s == 0.0) { + rgb = vec3(v, v, v); + } + else { + if (h == 1.0) + h = 0.0; + + h *= 6.0; + i = floor(h); + f = h - i; + rgb = vec3(f, f, f); + p = v * (1.0 - s); + q = v * (1.0 - (s * f)); + t = v * (1.0 - (s * (1.0 - f))); + + if (i == 0.0) rgb = vec3(v, t, p); + else if (i == 1.0) rgb = vec3(q, v, p); + else if (i == 2.0) rgb = vec3(p, v, t); + else if (i == 3.0) rgb = vec3(p, q, v); + else if (i == 4.0) rgb = vec3(t, p, v); + else rgb = vec3(v, p, q); + } + + outcol = rgb; +} + +void hue_sat(float hue, float sat, float value, inout vec3 col) +{ + vec3 hsv; + + rgb_to_hsv(col, hsv); + + hsv.x += hue; + hsv.x -= floor(hsv.x); + hsv.y *= sat; + hsv.y = clamp(hsv.y, 0.0, 1.0); + hsv.z *= value; + hsv.z = clamp(hsv.z, 0.0, 1.0); + + hsv_to_rgb(hsv, col); +} +#endif + +#ifdef USE_AO +/* Prototype */ +void ssao_factors(in float depth, in vec3 normal, in vec3 position, in vec2 screenco, out float cavities, out float edges); +#endif + +void main() { + vec2 screenco = vec2(gl_FragCoord.xy) / screenres; + float depth = texture(depthtex, screenco).r; + + vec3 position = get_view_space_from_depth(screenco, depth); + vec3 normal = calculate_view_space_normal(position); + + //mat_id = int(screenco.x*3.0); + + /* Manual Depth test */ + /* Doing this test earlier gives problem with dfdx calculations + * TODO move this before when we have proper geometric normals */ + if (gl_FragCoord.z > depth + 1e-5) + discard; + +#ifdef USE_ROTATION + /* Rotate texture coordinates */ + vec2 rotY = vec2(-matcap_rotation.y, matcap_rotation.x); + vec2 texco = abs(vec2(dot(normal.xy, matcap_rotation), dot(normal.xy, rotY)) * .49 + 0.5); +#else + vec2 texco = abs(normal.xy * .49 + 0.5); +#endif + vec3 col = texture(matcaps, vec3(texco, matcap_index)).rgb; + +#ifdef USE_AO + float cavity, edges; + ssao_factors(depth, normal, position, screenco, cavity, edges); + + col *= mix(vec3(1.0), matcaps_color[int(matcap_index)], cavity); +#endif + +#ifdef USE_HSV + hue_sat(matcap_hsv.x, matcap_hsv.y, matcap_hsv.z, col); +#endif + +#ifdef USE_AO + /* Apply highlights after hue shift */ + col *= edges + 1.0; +#endif + + fragColor = vec4(col, 1.0); +} diff --git a/source/blender/draw/engines/clay/shaders/clay_vert.glsl b/source/blender/draw/engines/clay/shaders/clay_vert.glsl new file mode 100644 index 00000000000..0b598ea0291 --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/clay_vert.glsl @@ -0,0 +1,20 @@ +uniform mat4 ModelViewProjectionMatrix; +uniform mat3 NormalMatrix; + +#if __VERSION__ == 120 +attribute vec3 pos; +attribute vec3 nor; +varying vec3 normal; +#else +in vec3 pos; +in vec3 nor; +out vec3 normal; +#endif + + +void main() +{ + normal = normalize(NormalMatrix * nor); + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); +} + diff --git a/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl b/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl new file mode 100644 index 00000000000..d032fb91c01 --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl @@ -0,0 +1,73 @@ +#define ssao_distance matcaps_param[mat_id].ssao_params_var.x +#define ssao_factor_cavity matcaps_param[mat_id].ssao_params_var.y +#define ssao_factor_edge matcaps_param[mat_id].ssao_params_var.z +#define ssao_attenuation matcaps_param[mat_id].ssao_params_var.w + +/* 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) +{ + /* take the normalized ray direction here */ + vec2 rotX = texture2D(ssao_jitter, screenco.xy * jitter_tilling).rg; + vec2 rotY = vec2(-rotX.y, rotX.x); + + /* 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; + + cavities = edges = 0.0; + int x; + int num_samples = int(ssao_samples_num); + + for (x = 0; x < num_samples; x++) { + /* TODO : optimisation replace by constant */ + vec2 dir_sample = texture1D(ssao_samples, (float(x) + 0.5) / ssao_samples_num).rg; + + /* rotate with random direction to get jittered result */ + vec2 dir_jittered = vec2(dot(dir_sample, rotX), dot(dir_sample, rotY)); + + 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 = texture2D(depthtex, uvcoords).r; + + /* Handle Background case */ + bool is_background = (depth_new == 1.0); + + /* This trick provide good edge effect even if no neighboor is found. */ + vec3 pos_new = get_view_space_from_depth(uvcoords, (is_background) ? depth : depth_new); + + if (is_background) + pos_new.z -= ssao_distance; + + vec3 dir = pos_new - position; + float len = length(dir); + float f_cavities = dot(dir, normal); + float f_edge = -f_cavities; + float f_bias = 0.05 * len + 0.0001; + + float attenuation = 1.0 / (len * (1.0 + len * len * ssao_attenuation)); + + /* use minor bias here to avoid self shadowing */ + if (f_cavities > -f_bias) + cavities += f_cavities * attenuation; + + if (f_edge > f_bias) + edges += f_edge * attenuation; + } + + cavities /= ssao_samples_num; + edges /= ssao_samples_num; + + /* don't let cavity wash out the surface appearance */ + cavities = clamp(cavities * ssao_factor_cavity, 0.0, 1.0); + edges = edges * ssao_factor_edge; +} diff --git a/source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl b/source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl new file mode 100644 index 00000000000..2f29624824e --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl @@ -0,0 +1,120 @@ +#define ssao_distance matcaps_param[mat_id].ssao_params_var.x +#define ssao_factor_cavity matcaps_param[mat_id].ssao_params_var.y +#define ssao_factor_edge matcaps_param[mat_id].ssao_params_var.z +#define ssao_attenuation matcaps_param[mat_id].ssao_params_var.w + +/* Based on Practical Realtime Strategies for Accurate Indirect Occlusion + * http://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pdf + * http://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pptx */ + +#define COSINE_WEIGHTING + +float integrate_arc(in float h1, in float h2, in float gamma, in float n_proj_len) +{ + float a = 0.0; +#ifdef COSINE_WEIGHTING + float cos_gamma = cos(gamma); + float sin_gamma_2 = 2.0 * sin(gamma); + a += -cos(2.0 * h1 - gamma) + cos_gamma + h1 * sin_gamma_2; + a += -cos(2.0 * h2 - gamma) + cos_gamma + h2 * sin_gamma_2; + a *= 0.25; /* 1/4 */ + a *= n_proj_len; +#else + /* Uniform weighting (slide 59) */ + a += 1 - cos(h1); + a += 1 - cos(h2); +#endif + return a; +} + +float get_max_horizon(in vec2 co, in vec3 x, in vec3 omega_o, in float h) +{ + if (co.x > 1.0 || co.x < 0.0 || co.y > 1.0 || co.y < 0.0) + return h; + + float depth = texture2D(depthtex, co).r; + + /* Background case */ + if (depth == 1.0) + return h; + + vec3 s = get_view_space_from_depth(co, depth); /* s View coordinate */ + vec3 omega_s = s - x; + float len = length(omega_s); + + if (len < ssao_distance) { + omega_s /= len; + h = max(h, dot(omega_s, omega_o)); + } + return h; +} + +void ssao_factors(in float depth, in vec3 normal, in vec3 position, in vec2 screenco, out float cavities, out float edges) +{ + /* Renaming */ + vec3 omega_o = -normalize(position); /* viewvec */ + vec2 x_ = screenco; /* x^ Screen coordinate */ + vec3 x = position; /* x view space coordinate */ + +#ifdef SPATIAL_DENOISE + float noise_dir = (1.0 / 16.0) * float(((int(gl_FragCoord.x + gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3)); + float noise_offset = (1.0 / 4.0) * float(int(gl_FragCoord.y - gl_FragCoord.x) & 0x3); +#else + float noise_dir = (1.0 / 16.0) * float(((int(gl_FragCoord.x + gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3)); + float noise_offset = (0.5 / 16.0) + (1.0 / 16.0) * float(((int(gl_FragCoord.x - gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3)); +#endif + + const float phi_step = 16.0; + const float theta_step = 16.0; + const float m_pi = 3.14159265358979323846; + vec2 pixel_ratio = vec2(screenres.y / screenres.x, 1.0); + vec2 pixel_size = vec2(1.0) / screenres.xy; + float min_stride = length(pixel_size); + float homcco = WinMatrix[2][3] * position.z + WinMatrix[3][3]; + float n = max(min_stride * theta_step, ssao_distance / homcco); /* Search distance */ + + /* Integral over PI */ + float A = 0.0; + for (float i = 0.0; i < phi_step; i++) { + float phi = m_pi * ((noise_dir + i) / phi_step); + + vec2 t_phi = vec2(cos(phi), sin(phi)); /* Screen space direction */ + + /* Search maximum horizon angles Theta1 and Theta2 */ + float theta1 = -1.0, theta2 = -1.0; /* init at cos(pi) */ + for (float j = 0.0; j < theta_step; j++) { + vec2 s_ = t_phi * pixel_ratio * n * ((j + noise_offset)/ theta_step); /* s^ Screen coordinate */ + vec2 co; + + co = x_ + s_; + theta1 = get_max_horizon(co, x, omega_o, theta1); + + co = x_ - s_; + theta2 = get_max_horizon(co, x, omega_o, theta2); + } + + /* (Slide 54) */ + theta1 = -acos(theta1); + theta2 = acos(theta2); + + /* Projecting Normal to Plane P defined by t_phi and omega_o */ + vec3 h = normalize(cross(vec3(t_phi, 0.0), omega_o)); /* Normal vector to Integration plane */ + vec3 t = cross(h, omega_o); /* Normal vector to plane */ + vec3 n_proj = normal - h * dot(normal, h); + float n_proj_len = length(n_proj); + vec3 n_proj_norm = normalize(n_proj); + + /* Clamping thetas (slide 58) */ + float gamma = sign(dot(n_proj_norm, t)) * acos(dot(normal, omega_o)); /* Angle between view vec and normal */ + theta1 = gamma + max(theta1 - gamma, -m_pi * 0.5); + theta2 = gamma + min(theta2 - gamma, m_pi * 0.5); + + /* Solving inner integral */ + A += integrate_arc(theta1, theta2, gamma, n_proj_len); + } + + A /= phi_step; + + cavities = 1.0 - A; + edges = 0.0; +}
\ No newline at end of file |