What is it - better normals from Depth texture, best quality normals.
Based on iq shader https://www.shadertoy.com/view/fsVczR
And original source https://atyuwen.github.io/posts/normal-reconstruction/
(just to inform Godot-people who need it)
Godot shader: (small description below)
(this shader is just port to Godot, you can look on original Shadertoy code linked above)
shader_type spatial;
render_mode blend_mix,depth_draw_never,cull_back,unshaded;
// test this shader on MeshInstanse-Plane in Godot 3)
uniform bool use_NormalImproved=true;
varying flat mat4 model_view_matrix;
void vertex(){
// plane face camera (comment it, to use below)
MODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],CAMERA_MATRIX[1],CAMERA_MATRIX[2],WORLD_MATRIX[3]);
model_view_matrix = MODELVIEW_MATRIX;
// plane stay on place (uncommend only one of it (top^ or bottom this)
//model_view_matrix = CAMERA_MATRIX*MODELVIEW_MATRIX;
}
vec3 getPos(float depth, mat4 mvm, mat4 ipm, vec2 suv, mat4 wm, mat4 icm){
vec4 pos = inverse(mvm) * ipm * vec4((suv * 2.0 - 1.0), depth * 2.0 - 1.0, 1.0);
pos.xyz /= (pos.w+0.0001*(1.-abs(sign(pos.w))));
return (pos*icm).xyz+wm[3].xyz;
}
// using improved version from https://www.shadertoy.com/view/fsVczR
vec3 computeNormalImproved( sampler2D depth_tx, mat4 mvm, mat4 ipm, vec2 suv, mat4 wm, mat4 icm, vec2 iResolution)
{
vec2 e = vec2(1./iResolution);
float c0 = texture(depth_tx,suv ).r;
float l2 = texture(depth_tx,suv-vec2(2,0)*e).r;
float l1 = texture(depth_tx,suv-vec2(1,0)*e).r;
float r1 = texture(depth_tx,suv+vec2(1,0)*e).r;
float r2 = texture(depth_tx,suv+vec2(2,0)*e).r;
float b2 = texture(depth_tx,suv-vec2(0,2)*e).r;
float b1 = texture(depth_tx,suv-vec2(0,1)*e).r;
float t1 = texture(depth_tx,suv+vec2(0,1)*e).r;
float t2 = texture(depth_tx,suv+vec2(0,2)*e).r;
float dl = abs(l1*l2/(2.0*l2-l1)-c0);
float dr = abs(r1*r2/(2.0*r2-r1)-c0);
float db = abs(b1*b2/(2.0*b2-b1)-c0);
float dt = abs(t1*t2/(2.0*t2-t1)-c0);
vec3 ce = getPos(c0, mvm, ipm, suv, wm, icm);
vec3 dpdx = (dl<dr) ? ce-getPos(l1, mvm, ipm, suv-vec2(1,0)*e, wm, icm) :
-ce+getPos(r1, mvm, ipm, suv+vec2(1,0)*e, wm, icm) ;
vec3 dpdy = (db<dt) ? ce-getPos(b1, mvm, ipm, suv-vec2(0,1)*e, wm, icm) :
-ce+getPos(t1, mvm, ipm, suv+vec2(0,1)*e, wm, icm) ;
return normalize(cross(dpdx,dpdy));
}
vec3 computeNormalNaive( sampler2D depth_tx, mat4 mvm, mat4 ipm, vec2 suv, mat4 wm, mat4 icm, vec2 iResolution)
{
vec2 e = vec2(1./iResolution);
vec3 l1 = getPos(texture(depth_tx, suv-vec2(1,0)*e).x,mvm, ipm, suv-vec2(1,0)*e, wm, icm);
vec3 r1 = getPos(texture(depth_tx, suv+vec2(1,0)*e).x,mvm, ipm, suv+vec2(1,0)*e, wm, icm);
vec3 t1 = getPos(texture(depth_tx, suv+vec2(0,1)*e).x,mvm, ipm, suv+vec2(0,1)*e, wm, icm);
vec3 b1 = getPos(texture(depth_tx, suv-vec2(0,1)*e).x,mvm, ipm, suv-vec2(0,1)*e, wm, icm);
vec3 dpdx = r1-l1;
vec3 dpdy = t1-b1;
return normalize(cross(dpdx,dpdy));
// alternative
//vec3 pos = getPos(texture(depth_tx, suv).x,mvm, ipm, suv, wm, icm);
//return normalize(cross(dFdx(pos),dFdy(pos)));
}
void fragment() {
if(use_NormalImproved)
ALBEDO = computeNormalImproved(DEPTH_TEXTURE, model_view_matrix, INV_PROJECTION_MATRIX, SCREEN_UV, WORLD_MATRIX, INV_CAMERA_MATRIX, VIEWPORT_SIZE.xy);
else
ALBEDO = computeNormalNaive(DEPTH_TEXTURE, model_view_matrix, INV_PROJECTION_MATRIX, SCREEN_UV, WORLD_MATRIX, INV_CAMERA_MATRIX, VIEWPORT_SIZE.xy);
}
Description - problem of computeNormalNaive
is edges that ruin normals very hard.
Look this image:

And computeNormalImproved
fix this problem, result normal from Improved function almost same good as from original normals.
Screenshot from https://github.com/danilw/godot-utils-and-other Edge_Cavity_example_test project there, there link to web version, read description. (Improved normals in Edge_Cavity_example_test project used only when Edge shader set to Use Norm Depth, and Use Norm Texture unclicked)