diff --git a/assets/materials/grunk_jittery.material b/assets/materials/grunk_jittery.material index e67f5be..60595a0 100644 Binary files a/assets/materials/grunk_jittery.material and b/assets/materials/grunk_jittery.material differ diff --git a/assets/materials/grunk_overlays/bright_overlay.material b/assets/materials/grunk_overlays/bright_overlay.material index 3cdf6bc..b4ad647 100644 Binary files a/assets/materials/grunk_overlays/bright_overlay.material and b/assets/materials/grunk_overlays/bright_overlay.material differ diff --git a/assets/materials/grunk_overlays/crystal_overlay.material b/assets/materials/grunk_overlays/crystal_overlay.material index 9cd186c..e7870ad 100644 Binary files a/assets/materials/grunk_overlays/crystal_overlay.material and b/assets/materials/grunk_overlays/crystal_overlay.material differ diff --git a/assets/materials/grunk_overlays/danger_overlay.material b/assets/materials/grunk_overlays/danger_overlay.material index b3b846d..5e51ed9 100644 Binary files a/assets/materials/grunk_overlays/danger_overlay.material and b/assets/materials/grunk_overlays/danger_overlay.material differ diff --git a/assets/materials/grunk_overlays/debug_overlay.material b/assets/materials/grunk_overlays/debug_overlay.material index fed355f..befaf67 100644 Binary files a/assets/materials/grunk_overlays/debug_overlay.material and b/assets/materials/grunk_overlays/debug_overlay.material differ diff --git a/assets/materials/grunk_overlays/gunk_overlay.material b/assets/materials/grunk_overlays/gunk_overlay.material index a8fb140..39a9cb1 100644 Binary files a/assets/materials/grunk_overlays/gunk_overlay.material and b/assets/materials/grunk_overlays/gunk_overlay.material differ diff --git a/assets/materials/grunk_overlays/lowrez_overlay.material b/assets/materials/grunk_overlays/lowrez_overlay.material index 08a4e36..f68b700 100644 Binary files a/assets/materials/grunk_overlays/lowrez_overlay.material and b/assets/materials/grunk_overlays/lowrez_overlay.material differ diff --git a/assets/materials/grunk_overlays/oily_overlay.material b/assets/materials/grunk_overlays/oily_overlay.material index 049abf1..5a3e29d 100644 Binary files a/assets/materials/grunk_overlays/oily_overlay.material and b/assets/materials/grunk_overlays/oily_overlay.material differ diff --git a/assets/npc/shambler/shambler.material b/assets/npc/shambler/shambler.material index 6dd35b5..58a356c 100644 Binary files a/assets/npc/shambler/shambler.material and b/assets/npc/shambler/shambler.material differ diff --git a/src/shaders/gunk/canvas_grunk.gdshader b/src/shaders/gunk/canvas_grunk.gdshader index a6210a0..48b8f7f 100644 --- a/src/shaders/gunk/canvas_grunk.gdshader +++ b/src/shaders/gunk/canvas_grunk.gdshader @@ -1,3 +1,4 @@ +// -*- mode: glsl -*- /* Gunk shader adapted to a canvas item */ shader_type canvas_item; diff --git a/src/shaders/gunk/common.gdshaderinc b/src/shaders/gunk/common.gdshaderinc index 2661020..86c144f 100644 --- a/src/shaders/gunk/common.gdshaderinc +++ b/src/shaders/gunk/common.gdshaderinc @@ -1,3 +1,4 @@ +// -*- mode: glsl -*- // Common logic for gunk shaders group_uniforms gunk_material; @@ -36,6 +37,23 @@ uniform sampler2D overlay_albedo: hint_default_transparent, filter_nearest; uniform sampler2D overlay_emission: hint_default_transparent, filter_nearest; uniform float overlay_emission_scale = 1.0; +#if defined(USE_MASK) +group_uniforms gunk_mask; +uniform float edge_bleed = 0.25; +uniform sampler2D gunk_mask; +#endif + + +float bump_sample(vec2 uv, vec3 uvt, float dx, float dy) { + vec2 offset = vec2(dx / pixellation, dy / pixellation); + float height = texture(gunk_noise, uvt + vec3(offset, 0.0)).r; +#if defined(USE_MASK) + float mask = texture(gunk_mask, uv + offset).r; + height *= smoothstep(1.0, 0.0, mask); +#endif + return height; +} + vec3 rim_glow( vec3 normal, vec3 view, @@ -89,3 +107,82 @@ vec3 base_emission(vec2 uv, float value) { float base_specular() { return 0.5 * inversesqrt(specular_contribution); } + +// Convolution methods + +vec3 godot_convolution(vec2 uv, vec3 uvt) { + // from https://github.com/godotengine/godot/blob/master/core/io/image.cpp#L3758 + float here = bump_sample(uv, uvt, 0.0, 0.0); + float to_right = bump_sample(uv, uvt, 1.0, 0.0); + float above = bump_sample(uv, uvt, 0.0, -1.0); + vec3 up = vec3(0.0, 1.0, (here - above) * bump_strength); + vec3 across = vec3(1.0, 0.0, (to_right - here) * bump_strength); + return normalize(cross(across, up)); +} + +vec3 minimal_convolution(vec2 uv, vec3 uvt) { + float h_center = bump_sample(uv, uvt, 0.0, 0.0); + float h_right = bump_sample(uv, uvt, 1.0, 0.0); + float h_down = bump_sample(uv, uvt, 0.0, 1.0); + float dX = (h_center - h_right); + float dY = (h_center - h_down); + float dZ = 1.0 / bump_strength; + return normalize(vec3(dX, dY, dZ)); +} + +vec3 cross_convolution(vec2 uv, vec3 uvt) { + float h_right = bump_sample(uv, uvt, 1.0, 0.0); + float h_down = bump_sample(uv, uvt, 0.0, 1.0); + float h_left = bump_sample(uv, uvt, -1.0, 0.0); + float h_up = bump_sample(uv, uvt, 0.0, -1.0); + float dX = (h_left - h_right); + float dY = (h_right - h_down); + float dZ = 1.0 / bump_strength * 2.0; + return normalize(vec3(dX, dY, dZ)); +} + +vec3 sobel_convolution(vec2 uv, vec3 uvt) { + float tl = bump_sample(uv, uvt, -1.0, -1.0); + float l = bump_sample(uv, uvt, -1.0, 0.0); + float bl = bump_sample(uv, uvt, -1.0, 1.0); + float t = bump_sample(uv, uvt, 0.0, -1.0); + float b = bump_sample(uv, uvt, 0.0, 1.0); + float tr = bump_sample(uv, uvt, 1.0, -1.0); + float r = bump_sample(uv, uvt, 1.0, 0.0); + float br = bump_sample(uv, uvt, 1.0, 1.0); + float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl); + float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr); + float dZ = 1.0 / bump_strength * 8.0; + return normalize(vec3(dX, dY, dZ)); +} + +vec3 scharr_convolution(vec2 uv, vec3 uvt) { + float tl = bump_sample(uv, uvt, -1.0, -1.0); + float l = bump_sample(uv, uvt, -1.0, 0.0); + float bl = bump_sample(uv, uvt, -1.0, 1.0); + float t = bump_sample(uv, uvt, 0.0, -1.0); + float b = bump_sample(uv, uvt, 0.0, 1.0); + float tr = bump_sample(uv, uvt, 1.0, -1.0); + float r = bump_sample(uv, uvt, 1.0, 0.0); + float br = bump_sample(uv, uvt, 1.0, 1.0); + float dX = 3.0*tl + 10.0*l + 3.0*bl - 3.0*tr - 10.0*r - 3.0*br; + float dY = 3.0*tl + 10.0*t + 3.0*tr - 3.0*bl - 10.0*b - 3.0*br; + float dZ = 1.0 / bump_strength * 12.0; + return normalize(vec3(dX, dY, dZ)); +} + +vec3 sobel_5x5_convolution(vec2 uv, vec3 uvt) { + // Expensive!! + // TODO this can be decomposed into a few small matrix ops + float s[25]; + for (int i = 0; i < 5; i++) { + for (int j = 0; j < 5; j++) { + s[i*5 + j] = bump_sample(uv, uvt, float(i - 2), float(j - 2)); + } + } + + float dX = 4.0 * (s[3] + s[23] - s[1] - s[21]) + 5.0 * (s[4] + s[24] - s[0] - s[20]) + 8.0 * (s[9] + s[19] - s[5] - s[15]) + 10.0 * (s[8] + s[14] + s[18] - s[6] - s[10] - s[16]) + 20.0 * (s[13] - s[11]); + float dY = 4.0 * (s[19] + s[15] - s[9] - s[5]) + 5.0 * (s[24] + s[20] - s[4] - s[0]) + 8.0 * (s[23] + s[21] - s[3] - s[1]) + 10.0 * (s[18] + s[22] + s[16] - s[8] - s[2] - s[6]) + 20.0 * (s[17] - s[7]); + float dZ = 1.0 / bump_strength * 240.0; + return normalize(vec3(dX, dY, dZ)); +} diff --git a/src/shaders/gunk/debug_overlay.gdshader b/src/shaders/gunk/debug_overlay.gdshader index ce61a08..27395f9 100644 --- a/src/shaders/gunk/debug_overlay.gdshader +++ b/src/shaders/gunk/debug_overlay.gdshader @@ -1,31 +1,16 @@ +// -*- mode: glsl -*- shader_type spatial; render_mode depth_prepass_alpha, unshaded; +#define USE_MASK #include "common.gdshaderinc" -group_uniforms gunk_mask; -uniform float edge_bleed = 0.25; -uniform sampler2D gunk_mask; - - -float bump_sample(vec2 uv, vec3 uvt, float dx, float dy) { - vec2 offset = vec2(dx / pixellation, dy / pixellation); - float height = texture(gunk_noise, uvt + vec3(offset, 0.0)).r; - float mask = texture(gunk_mask, uv + offset / uv_scale).r; - return height * smoothstep(1.0, 0.0, mask); -} void fragment() { vec3 uvt = scale_uvt(UV, TIME); float value = sample_noise(uvt); - // Build normal map from bump map - float h_center = bump_sample(UV, uvt, 0.0, 0.0); - float h_right = bump_sample(UV, uvt, 1.0, 0.0); - float h_down = bump_sample(UV, uvt, 0.0, 1.0); - float dx = (h_center - h_right) * bump_strength; - float dy = (h_center - h_down) * bump_strength; - vec3 normal_diff_map = normalize(vec3(dx, dy, 1.0)); - ALBEDO = normal_diff_map / 2.0 + 0.5; + vec3 nmap = sobel_convolution(UV, uvt); + ALBEDO = nmap / 2.0 + 0.5; } diff --git a/src/shaders/gunk/gunk.gdshader b/src/shaders/gunk/gunk.gdshader index 7eeb42d..a2109b5 100644 --- a/src/shaders/gunk/gunk.gdshader +++ b/src/shaders/gunk/gunk.gdshader @@ -1,3 +1,4 @@ +// -*- mode: glsl -*- shader_type spatial; render_mode depth_prepass_alpha; @@ -23,11 +24,6 @@ void vertex() { VERTEX *= 1.0 + jitter; } -float bump_sample(vec3 uvt, float dx, float dy) { - vec2 offset = vec2(dx / pixellation, dy / pixellation); - return texture(gunk_noise, uvt + vec3(offset, 0.0)).r; -} - void fragment() { vec3 uvt = scale_uvt(UV, TIME); float value = sample_noise(uvt); @@ -36,17 +32,11 @@ void fragment() { EMISSION = base_emission(UV, value); SPECULAR = base_specular(); - // Build normal map from bump map - float h_center = bump_sample(uvt, 0.0, 0.0); - float h_right = bump_sample(uvt, 1.0, 0.0); - float h_down = bump_sample(uvt, 0.0, 1.0); - float dx = (h_center - h_right) * bump_strength; - float dy = (h_center - h_down) * bump_strength; - vec3 normal_diff_map = normalize(vec3(dx, dy, 1.0)); - NORMAL_MAP = normal_diff_map / 2.0 + 0.5; + vec3 nmap = sobel_convolution(UV, uvt); + NORMAL_MAP = nmap / 2.0 + 0.5; // add fresnel - vec3 world_normal = mat3(TANGENT, BINORMAL, NORMAL) * normal_diff_map; + vec3 world_normal = mat3(TANGENT, BINORMAL, NORMAL) * nmap; EMISSION += rim_glow( world_normal, VIEW, diff --git a/src/shaders/gunk/gunk_overlay.gdshader b/src/shaders/gunk/gunk_overlay.gdshader index 8593895..3027073 100644 --- a/src/shaders/gunk/gunk_overlay.gdshader +++ b/src/shaders/gunk/gunk_overlay.gdshader @@ -1,20 +1,10 @@ +// -*- mode: glsl -*- shader_type spatial; render_mode depth_prepass_alpha; +#define USE_MASK #include "common.gdshaderinc" -group_uniforms gunk_mask; -uniform float edge_bleed = 0.25; -uniform sampler2D gunk_mask; - - -float bump_sample(vec2 uv, vec3 uvt, float dx, float dy) { - vec2 offset = vec2(dx / pixellation, dy / pixellation); - float height = texture(gunk_noise, uvt + vec3(offset, 0.0)).r; - float mask = texture(gunk_mask, uv + offset / uv_scale).r; - return height * smoothstep(1.0, 0.0, mask); -} - void fragment() { vec3 uvt = scale_uvt(UV, TIME); float value = sample_noise(uvt); @@ -23,17 +13,16 @@ void fragment() { EMISSION = base_emission(UV, value); SPECULAR = base_specular(); - // Build normal map from bump map - float h_center = bump_sample(UV, uvt, 0.0, 0.0); - float h_right = bump_sample(UV, uvt, 1.0, 0.0); - float h_down = bump_sample(UV, uvt, 0.0, 1.0); - float dx = (h_center - h_right) * bump_strength; - float dy = (h_center - h_down) * bump_strength; - vec3 normal_diff_map = normalize(vec3(dx, dy, 1.0)); - NORMAL_MAP = normal_diff_map / 2.0 + 0.5; + // vec3 nmap = minimal_convolution(UV, uvt); + // vec3 nmap = cross_convolution(UV, uvt); + vec3 nmap = sobel_convolution(UV, uvt); + // vec3 nmap = sobel_5x5_convolution(UV, uvt); + // vec3 nmap = scharr_convolution(UV, uvt); + // vec3 nmap = godot_convolution(UV, uvt); + NORMAL_MAP = nmap / 2.0 + 0.5; // add fresnel - vec3 world_normal = mat3(TANGENT, BINORMAL, NORMAL) * normal_diff_map; + vec3 world_normal = mat3(TANGENT, BINORMAL, NORMAL) * nmap; EMISSION += rim_glow( world_normal, VIEW,