Files
tgcc-artest/Shaders/Edge.gdshader
Matteo Sonaglioni f7b334b21c first commit
2026-03-10 23:54:57 +01:00

114 lines
4.0 KiB
Plaintext

shader_type spatial;
render_mode specular_disabled, ambient_light_disabled;
uniform sampler2D DEPTH_TEXTURE : hint_depth_texture, filter_linear_mipmap;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_nearest;
uniform sampler2D NORMAL_TEXTURE : hint_normal_roughness_texture, filter_nearest;
uniform float lightIntensity = 1.25;
uniform float lineAlpha = 0.7;
uniform bool useLighting = true;
uniform float lineHighlight = 0.2;
uniform float lineShadow = 0.55;
varying vec2 screenUV;
varying float lineMask;
float GetLinearDepth(vec2 sUV, sampler2D depthTexture, mat4 invProjectionMat, float mask){
// Raw depth to linear depth code from:
// https://docs.godotengine.org/en/latest/tutorials/shaders/advanced_postprocessing.html
float depth = texture(depthTexture, sUV).x * mask;
vec3 ndc = vec3(sUV * 2.0 - 1.0, depth);
vec4 view = invProjectionMat * vec4(ndc, 1.0);
view.xyz /= view.w;
return -view.z;
}
vec3 GetNormal(vec2 uv, sampler2D normalTexture, float mask){
vec3 normal = texture(normalTexture, uv).rgb;
normal = normal * 2.0 - 1.0 * mask;
return normal;
}
float NormalEdgeIndicator(vec3 normalEdgeBias, vec3 normal, vec3 neighborNormal, float depthDifference){
//From Kody King: https://threejs.org/examples/webgl_postprocessing_pixel.html
float normalDifference = dot(normal - neighborNormal, normalEdgeBias);
float normalIndicator = clamp(smoothstep(-.01, .01, normalDifference), 0.0, 1.0);
float depthIndicator = clamp(sign(depthDifference * .25 + .0025), 0.0, 1.0);
return (1.0 - dot(normal, neighborNormal)) * depthIndicator * normalIndicator;
}
void vertex(){
POSITION = vec4(VERTEX.xy, 1.0, 1.0);
}
void fragment() {
vec2 texelSize = 1.0 / VIEWPORT_SIZE.xy;
screenUV = SCREEN_UV;
// UV offsets
vec2 UVOffsets[4];
UVOffsets[0] = SCREEN_UV + vec2(0.0, -1.0) * texelSize;
UVOffsets[1] = SCREEN_UV + vec2(0.0, 1.0) * texelSize;
UVOffsets[2] = SCREEN_UV + vec2(1.0, 0.0) * texelSize;
UVOffsets[3] = SCREEN_UV + vec2(-1.0, 0.0) * texelSize;
// Using alpha channel (screen roughness) to mask objects to not receive outlines
float outlineMask = texture(NORMAL_TEXTURE, SCREEN_UV).a;
outlineMask = ceil(outlineMask); // Objects with Roughness = 0 will not have and outline
// Edge detection with Depth
float depthDifference = 0.0;
float invDepthDifference = 0.5;
float depth = GetLinearDepth(SCREEN_UV, DEPTH_TEXTURE, INV_PROJECTION_MATRIX, outlineMask);
for (int i = 0; i < UVOffsets.length(); i++){
float dOff = GetLinearDepth(UVOffsets[i],DEPTH_TEXTURE, INV_PROJECTION_MATRIX, outlineMask);
depthDifference += clamp(dOff - depth, 0.0, 1.0);
invDepthDifference += depth - dOff;
}
invDepthDifference = clamp(invDepthDifference, 0.0, 1.0);
invDepthDifference = clamp(smoothstep(0.9, 0.9, invDepthDifference) * 10.0 , 0.0, 1.0);
depthDifference = smoothstep(0.25, 0.3, depthDifference);
// Edge detection with Normals
float normalDifference = 0.;
vec3 normalEdgeBias = vec3(1.0, 1.0, 1.0);
vec3 normal = GetNormal(SCREEN_UV, NORMAL_TEXTURE, outlineMask);
for (int i = 0; i < UVOffsets.length(); i++){
vec3 nOff = GetNormal(UVOffsets[i],NORMAL_TEXTURE, outlineMask);
normalDifference += NormalEdgeIndicator(normalEdgeBias, normal, nOff, depthDifference);
}
normalDifference = smoothstep(0.2, 0.2, normalDifference);
normalDifference = clamp(normalDifference - invDepthDifference, 0.0, 1.0);
ALBEDO = texture(SCREEN_TEXTURE, SCREEN_UV).rgb;
lineMask = clamp(0.1, lineAlpha, (depthDifference + normalDifference * 5.0));
if (!useLighting){
ALBEDO += clamp((normalDifference - depthDifference), 0.0, 1.0) * lineHighlight;
ALBEDO -= ALBEDO * depthDifference * lineShadow;
}
}
void light (){
if (useLighting){
vec4 normal = texture(NORMAL_TEXTURE, screenUV);
normal = normal * 2.0 - 1.0;
// Calculate light direction
float dotNL = dot(normal.rgb, LIGHT);
dotNL = pow(dotNL, 2.5);
dotNL = clamp(dotNL, 0.0, 1.0);
if(LIGHT_IS_DIRECTIONAL)
DIFFUSE_LIGHT += mix(vec3(1.0), dotNL * LIGHT_COLOR * lightIntensity, lineMask);
}
else
DIFFUSE_LIGHT = vec3(1.0);
}