-new edge detection filter also based on normal & depth but now constant edge size even if you zoom out, more exact detection thanks to a 9x9 kernel instead of old 2*2 (cross) and noise removal with sin function.
-----
Here is a shader I've done which is using depth and normals to find edges.
Depth can't be used alone because edges which are inside of an object have a continuous depth, that's why I'm also using normals.
Please, if you find a faster/better may to do it, post it
Note : on the screenshot, the floor have strange white stuff, it's because it contain grass
Result :
VS:
Code: Select all
// simple vertex shader
// Author:Stefbuet
// Date:20/04/2010
//This shader can be used by a wide range of pixel shader.
//It is just giving to the PS the texture coords, vertex pos & color.
varying vec4 textureCoord;
void main() {
//texture coordinate'll be interpolated to the PS
textureCoord=gl_MultiTexCoord0;
//don't change any vertex position & color
gl_FrontColor=gl_Color;
gl_Position=ftransform();
}
Code: Select all
// edge detection pixel shader
// Author:Stefbuet
// Date:14/06/2010
// Last update:07/03/2011
//this shader is doing an edge detection with depth and normal map
uniform sampler2D depthMap;
uniform float SCREENX, SCREENY;
varying vec4 textureCoord;
vec2 offsetArray[8];
void main() {
vec2 textCoord=textureCoord.xy;
textCoord.x*=-1.0;
float currentDepth=texture2D(depthMap, -textCoord).w;
vec3 normal=texture2D(depthMap, -textCoord).xyz*2.0-vec3(1.0,1.0,1.0);
offsetArray[0] = vec2(1.0/SCREENX, 1.0/SCREENY);
offsetArray[1] = vec2(1.0/SCREENX, 0.0);
offsetArray[2] = vec2(1.0/SCREENX, -1.0/SCREENY);
offsetArray[3] = vec2(0.0, 1.0/SCREENY);
offsetArray[4] = vec2(0.0, -1.0/SCREENY);
offsetArray[5] = vec2(-1.0/SCREENX, 1.0/SCREENY);
offsetArray[6] = vec2(-1.0/SCREENX, 0.0);
offsetArray[7] = vec2(-1.0/SCREENX, -1.0/SCREENY);
//depth
float depthDif=0.0;
float minD=0.005;
depthDif+=min(minD,abs(texture2D(depthMap, -textCoord+offsetArray[0]).w-currentDepth));
depthDif+=min(minD,abs(texture2D(depthMap, -textCoord+offsetArray[1]).w-currentDepth));
depthDif+=min(minD,abs(texture2D(depthMap, -textCoord+offsetArray[2]).w-currentDepth));
depthDif+=min(minD,abs(texture2D(depthMap, -textCoord+offsetArray[3]).w-currentDepth));
depthDif+=min(minD,abs(texture2D(depthMap, -textCoord+offsetArray[4]).w-currentDepth));
depthDif+=min(minD,abs(texture2D(depthMap, -textCoord+offsetArray[5]).w-currentDepth));
depthDif+=min(minD,abs(texture2D(depthMap, -textCoord+offsetArray[6]).w-currentDepth));
depthDif+=min(minD,abs(texture2D(depthMap, -textCoord+offsetArray[7]).w-currentDepth));
depthDif/=(1.0+5.0*currentDepth);
if(depthDif<0.01) depthDif=0;
depthDif*=25.0;
depthDif=min(1.0, depthDif);
depthDif=sin(depthDif*2.0);
//normals
float t=1-abs(dot(normal, texture2D(depthMap, -textureCoord.xy+offsetArray[0]).xyz*2.0-vec3(1.0,1.0,1.0)));
t+=1-abs(dot(normal, texture2D(depthMap, -textCoord+offsetArray[1]).xyz*2.0-vec3(1.0,1.0,1.0)));
t+=1-abs(dot(normal, texture2D(depthMap, -textCoord+offsetArray[2]).xyz*2.0-vec3(1.0,1.0,1.0)));
t+=1-abs(dot(normal, texture2D(depthMap, -textCoord+offsetArray[3]).xyz*2.0-vec3(1.0,1.0,1.0)));
t+=1-abs(dot(normal, texture2D(depthMap, -textCoord+offsetArray[4]).xyz*2.0-vec3(1.0,1.0,1.0)));
t+=1-abs(dot(normal, texture2D(depthMap, -textCoord+offsetArray[5]).xyz*2.0-vec3(1.0,1.0,1.0)));
t+=1-abs(dot(normal, texture2D(depthMap, -textCoord+offsetArray[6]).xyz*2.0-vec3(1.0,1.0,1.0)));
t+=1-abs(dot(normal, texture2D(depthMap, -textCoord+offsetArray[7]).xyz*2.0-vec3(1.0,1.0,1.0)));
t/=15.0;
t/=(1.0+2.5*currentDepth);
if(t<0.16) t=0.0;
t=sin(t*3.74);
depthDif+=t;
if(depthDif>0.2) {
gl_FragColor=vec4(1.0,1.0,1.0,1.0);
}
else {
gl_FragColor=vec4(0.0,0.0,0.0,0.0);
}
}
depthMap : Rendertarget : XYZ = normal, W = depth (view space)
SCREENX, SCREENY : depthMap size, must be floats.
This is a postprocess effect, so you might apply this shader to the quad you're using to do this post processing and put the depthMap texture on it.
Now, here is the antialiasing stuff :
We blur detected edge with a simple 3x3 blur kernel.
Result of the effect :
new pixel shader :
PS :
Code: Select all
// antialiasing pixel shader
// Author:Stefbuet
// Date:14/06/2010
// Last update:07/03/2011
//this shader is doing an edge detection with depth and normal map
//then it blur edges with a more or less good quelity filter (user selected)
uniform sampler2D depthMap;
uniform sampler2D renderMap;
uniform float SCREENX, SCREENY;
varying vec4 textureCoord;
vec2 offsetArray[8];
void main() {
vec2 textCoord=textureCoord.xy;
textCoord.x*=-1.0;
float currentDepth=texture2D(depthMap, -textCoord).w;
vec3 normal=texture2D(depthMap, -textCoord).xyz*2.0-vec3(1.0,1.0,1.0);
offsetArray[0] = vec2(1.0/SCREENX, 1.0/SCREENY);
offsetArray[1] = vec2(1.0/SCREENX, 0.0);
offsetArray[2] = vec2(1.0/SCREENX, -1.0/SCREENY);
offsetArray[3] = vec2(0.0, 1.0/SCREENY);
offsetArray[4] = vec2(0.0, -1.0/SCREENY);
offsetArray[5] = vec2(-1.0/SCREENX, 1.0/SCREENY);
offsetArray[6] = vec2(-1.0/SCREENX, 0.0);
offsetArray[7] = vec2(-1.0/SCREENX, -1.0/SCREENY);
//depth
float depthDif=0.0;
float minD=0.005;
depthDif+=min(minD,abs(texture2D(depthMap, -textCoord+offsetArray[0]).w-currentDepth));
depthDif+=min(minD,abs(texture2D(depthMap, -textCoord+offsetArray[1]).w-currentDepth));
depthDif+=min(minD,abs(texture2D(depthMap, -textCoord+offsetArray[2]).w-currentDepth));
depthDif+=min(minD,abs(texture2D(depthMap, -textCoord+offsetArray[3]).w-currentDepth));
depthDif+=min(minD,abs(texture2D(depthMap, -textCoord+offsetArray[4]).w-currentDepth));
depthDif+=min(minD,abs(texture2D(depthMap, -textCoord+offsetArray[5]).w-currentDepth));
depthDif+=min(minD,abs(texture2D(depthMap, -textCoord+offsetArray[6]).w-currentDepth));
depthDif+=min(minD,abs(texture2D(depthMap, -textCoord+offsetArray[7]).w-currentDepth));
depthDif/=(1.0+5.0*currentDepth);
if(depthDif<0.01) depthDif=0;
depthDif*=25.0;
depthDif=min(1.0, depthDif);
depthDif=sin(depthDif*2.0);
//normals
float t=1-abs(dot(normal, texture2D(depthMap, -textureCoord.xy+offsetArray[0]).xyz*2.0-vec3(1.0,1.0,1.0)));
t+=1-abs(dot(normal, texture2D(depthMap, -textCoord+offsetArray[1]).xyz*2.0-vec3(1.0,1.0,1.0)));
t+=1-abs(dot(normal, texture2D(depthMap, -textCoord+offsetArray[2]).xyz*2.0-vec3(1.0,1.0,1.0)));
t+=1-abs(dot(normal, texture2D(depthMap, -textCoord+offsetArray[3]).xyz*2.0-vec3(1.0,1.0,1.0)));
t+=1-abs(dot(normal, texture2D(depthMap, -textCoord+offsetArray[4]).xyz*2.0-vec3(1.0,1.0,1.0)));
t+=1-abs(dot(normal, texture2D(depthMap, -textCoord+offsetArray[5]).xyz*2.0-vec3(1.0,1.0,1.0)));
t+=1-abs(dot(normal, texture2D(depthMap, -textCoord+offsetArray[6]).xyz*2.0-vec3(1.0,1.0,1.0)));
t+=1-abs(dot(normal, texture2D(depthMap, -textCoord+offsetArray[7]).xyz*2.0-vec3(1.0,1.0,1.0)));
t/=15.0;
t/=(1.0+2.5*currentDepth);
if(t<0.16) t=0.0;
t=sin(t*3.74);
depthDif+=t;
if(depthDif>0.2) {
vec4 finalColor=texture2D(renderMap, -textCoord.xy);
for(int i=0; i<8; i++)
finalColor+=texture2D(renderMap, -textCoord.xy+offsetArray[i]);
finalColor/=8.0;
gl_FragColor=finalColor;
}
else {
gl_FragColor=texture2D(renderMap, -textCoord);
}
}
renderMap : render target which contain your scene.
This method is used by Stalker to do antialiasing.
See http://http.developer.nvidia.com/GPUGem ... ter09.html after the deferred lighting part.
I saw that bluring far away things may let them too blurred. Maybe modulate the blur in function of the depth of pixels is a good idea, but I haven't tested it yet!
Hope you will enjoy it