Sign in to follow this  
w00

[XNA] edge detection problem

Recommended Posts

w00    122
I have a toon + edge detection shader in my game project. I used the example from this website for that. But for some reason the edge detection doesn't always render the edge properly. I was hoping anyone here had an idea of what the problem could be. Take a look at the following screenshots. You can clearly see that the right image renders WITH edge detection, while the left image does it without. I all depends on where the camera is rotated around the character. I just have no idea why it sometimes doesn't render the edge and sometimes it does. Screenshot: http://i44.tinypic.com/11c9or4.png

Share this post


Link to post
Share on other sites
e3d_ALiVE    209
depens on what project u moved from
my guess[u still mapping texel to pixels and u don't have to or the inverse]

for more info it would better if u past shader code and on what api it worked

Share this post


Link to post
Share on other sites
w00    122
Quote:
Original post by e3d_ALiVE
depens on what project u moved from
my guess[u still mapping texel to pixels and u don't have to or the inverse]

for more info it would better if u past shader code and on what api it worked


I'm working with XNA 3.1. Here's the shader code i'm using for th edge detection:

I've already tried to play with the Threshold settings, it does optimize it a bit, but that only gives me a bery thin, light edge around my character and on other areas a normal thick one.

BTW, not sure what you mean with 'texel mapping'. So i can't tell if that's the problem.


float4x4 World;
float4x4 View;
float4x4 Projection;

float EdgeWidth = 0.8f;
float EdgeIntensity = 1;

// How sensitive should the edge detection be to tiny variations in the input data?
// Smaller settings will make it pick up more subtle edges, while larger values get
// rid of unwanted noise.
float NormalThreshold = 0.5;
float DepthThreshold = 0.1;

// How dark should the edges get in response to changes in the input data?
float NormalSensitivity = 1;
float DepthSensitivity = 10;

// Pass in the current screen resolution.
float2 ScreenResolution;

texture SceneTexture;

//----------------------------
// Structures
//----------------------------

sampler SceneSampler : register(s0) = sampler_state
{
Texture = (SceneTexture);

MinFilter = Linear;
MagFilter = Linear;

AddressU = Clamp;
AddressV = Clamp;
};


// This texture contains normals (in the color channels) and depth (in alpha)
// for the main scene image. Differences in the normal and depth data are used
// to detect where the edges of the model are.
texture NormalDepthTexture;

sampler NormalDepthSampler : register(s1) = sampler_state
{
Texture = (NormalDepthTexture);

MinFilter = Linear;
MagFilter = Linear;

AddressU = Clamp;
AddressV = Clamp;
};

//----------------------------
// Pixel Shader
//----------------------------

float4 PixelShader(float2 texCoord : TEXCOORD0) : COLOR0
{
// Look up the original color from the main scene.
float3 scene = tex2D(SceneSampler, texCoord);

// Apply the edge detection filter?
// Look up four values from the normal/depth texture, offset along the
// four diagonals from the pixel we are currently shading.
float2 edgeOffset = EdgeWidth / ScreenResolution;

float4 n1 = tex2D(NormalDepthSampler, texCoord + float2(-1, -1) * edgeOffset);
float4 n2 = tex2D(NormalDepthSampler, texCoord + float2( 1, 1) * edgeOffset);
float4 n3 = tex2D(NormalDepthSampler, texCoord + float2(-1, 1) * edgeOffset);
float4 n4 = tex2D(NormalDepthSampler, texCoord + float2( 1, -1) * edgeOffset);

// Work out how much the normal and depth values are changing.
float4 diagonalDelta = abs(n1 - n2) + abs(n3 - n4);

float normalDelta = dot(diagonalDelta.xyz, 1);
float depthDelta = diagonalDelta.w;

// Filter out very small changes, in order to produce nice clean results.
normalDelta = saturate((normalDelta - NormalThreshold) * NormalSensitivity);
depthDelta = saturate((depthDelta - DepthThreshold) * DepthSensitivity);

// Does this pixel lie on an edge?
float edgeAmount = saturate(normalDelta + depthDelta) * EdgeIntensity;

// Apply the edge detection result to the main scene color.
scene *= (1 - edgeAmount);

return float4(scene, 1);
}

//----------------------------
// Technique
//----------------------------

technique EdgeDetect
{
pass P0
{
PixelShader = compile ps_2_0 PixelShader();
}
}

Share this post


Link to post
Share on other sites
remigius    1172

If it works best for camera positions close to the starting camera position, it might help to check if the NormalDepthTexture is being updated as the camera moves. It's a bit of a wild guess, but I think the information in this texture is only 'valid' for the camera position it has been rendered from.

Share this post


Link to post
Share on other sites
Zoner    232
A cross (4 or 5 fetches) or sobel filter (9 fetches) against depth information can do it all with just depth. This will get you the exterior silhouettes fairly accurately.

Edges on convex junctions (say the corner of a 90 degree wall) need another approach. A similar filter pattern, but using dot products against the normals if available, or comparing material ids for equality if you have those available.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this