PDA

View Full Version : Real-time "Free Hand" shader edge effect?



Stuart McDonald
01-10-2011, 02:13 AM
Hi,
Given a simple flat scene, like the one below, but with more shapes, is there a way I could generate something like the second picture? i.e. add a sort of "free hand" edge effect to the shapes? Doesn't have to be exactly like that, just some kind of "drawn by a human" edge effect.

The only idea I could think of was something like detecting the horizontal and vertical components and rendering each multiple times, "wiggling" the horizontal up/down and the vertical left/right,. However I'm a newbie so I don't place much trust in my ideas.

Any ideas much appreciated. Thanks,

Stuart.

ZbuffeR
01-10-2011, 03:00 AM
The search terms you look for are : NPR - non-photorealistic rendering
http://en.wikipedia.org/wiki/Non-photorealistic_rendering

There is a lot of different ways to do that, with different pros and cons.
For a start, I would use a "edge detection" shader, and offset the source coordinates according to a blurred-noise texture.

Stuart McDonald
01-10-2011, 06:27 AM
Thanks for the pointer. I've been having a browse, but I think there's a fundamental concept I'm missing. You say "offset the source coordinates", but what coordinates?

Similary I found a reference on Bonzai Software site that says "To simulate the shaking hand of an artist, the edges and colors are distorted with a perlin noise texture", but again I don't see how do that.

Given a texture of the edges of the scene how can I change that to be "shaky". Most of the references I've found seem to keep the original edges e.g. cel shading outline stuff.

Thanks.

ZbuffeR
01-10-2011, 08:18 AM
Idea is, for each destination fragment, to read the color values from the noise texture at the current texcoord, and read the rendered scene texture at current texcoord + noise value.

If you want the hand drawn line to wiggle even when everything is static, add an offset to noise texture coordinate, and change it every frame.

Stuart McDonald
01-20-2011, 03:09 AM
First off, thanks again Zbuffer for your invaluable help!

To make this topic more useful for anyone coming across it I thought I'd share what I came up with.
First, I render the scene to a 4x smaller texture (since I can scale it back up to get a "fuzzy" effect") using a convolution matrix shader
// Max width*height of convolution kernel
const int MaxKernelSize = 9;

// Offsets to pixels to read for the kernel
uniform vec2 TexOffsets[MaxKernelSize];

// Actual size of kernel (width*height) being used
uniform int KernelSize;

// Values for the convolution kernel
uniform float KernelValues[MaxKernelSize];

// Texture to read from
uniform sampler2D Tex0;

void main()
{
int i;
vec4 sum = vec4(0.0);
for (i = 0; i < KernelSize; i++)
{
vec4 clr = texture2D(Tex0, gl_TexCoord[0].st + TexOffsets[i]);
sum += clr * KernelValues[i];
}
gl_FragColor = sum;
}
I set this up with the following uniform values
TexOffsets = -1P,+1P, 0,+1P, +1P,+1P,
-1P,0 0,0 +1P,0
-1P,-1P, 0,-1P, +1P,-1P

KernelValues = -1, -1, -1,
-1, 8, -1,
-1, -1, -1
Where "1P" = one pixel i.e. 1/output texture width (for X) or 1/height (for Y).

I then created a seamless simplex noise texture and use it with the following shader to "wiggle" the edge texture created above.
// Edges texture
uniform sampler2D Tex0;
// Simplex noise ALPHA texture
uniform sampler2D Tex1;

void main()
{
vec2 offset = vec2(-0.5, -0.5);
offset.x += texture2D(Tex1, gl_TexCoord[0].st).a;
offset.y += texture2D(Tex1, gl_TexCoord[0].ts).a;
offset.xy *= vec2(0.15,0.15);
gl_FragColor = texture2D(Tex0, gl_TexCoord[0].st+offset);
}This reads the alpha value from the noise texture and uses it (scaled by 0.15 to stop too much wiggle) to offset where to read the edge texture.

That's the basics, I do some more scaling and blending to get the effect I want, plus the 0.15 will end up in a uniform to give me dynamic wiggle :)
~