Re: contour shading
- From: Lord Crc <lordcrc@xxxxxxxxxxx>
- Date: Wed, 08 Feb 2006 03:14:44 +0100
On 07 Feb 2006 12:59:57 GMT, "jano trouba" <trouba_1@xxxxxxxxxx>
wrote:
So nobody in here to give me a hint ?
I would have thought this is a fairly common problem ....
I just implemented this idea I had regarding this. It's probably not
the best or quickest solution, but it appears to do what you want.
It operates on a pixel level, but you should be able to make it use
polygons for the contour levels.
Here are a couple of examples, showing the contour input and resulting
shading.
http://img302.imageshack.us/my.php?image=contour17al.png
http://img302.imageshack.us/my.php?image=contour23fy.png
http://img155.imageshack.us/my.php?image=contour30xj.png
http://img54.imageshack.us/my.php?image=contour49xl.png
The general algorithm is as follows:
1) Determine the level at the current pixel (c), and the level below
(c_l) and above (c_h).
2) Locate two distance measures to the level below, and the level
above. The two distance measures are the average distance (a_l & a_h
respectively) and the inverse of the average inverse distance (d_l &
d_h).
3) If both distances exist, compare d_l to d_h. If d_l is less than
d_h, compute
t = d_l / (2 * d_h)
Otherwise compute
t = d_h / (2 * d_l);
4) I wasn't sure how you wanted to handle the case where the distance
to the higher level doesn't exist (the current level is a plateau).
Currently, I compute
t = (d_l / a_l)^2;
if (t > 0.5) then t = 0.5;
5) If t < 0.5 perform the following
color = lerp(palette[c_l], palette[c], t + 0.5);
Else perform
color = lerp(palette[c], palette[c_h], t - 0.5);
where lerp() is linear interpolation.
The hard part is to compute the distances. The way I solved this was
to use a 2d pixel traversal algorithm which tested a "ray". For each
edge pixel, I ran a test for a ray starting at the current pixel,
heading towards the edge pixel.
If the ray hit a pixel with the desired level, it returned the pixels
position. If it hit a level different from the current level (c), it
would terminate, reporting no hit.
If the ray exited the image, it would report a hit only if I was
looking for the edge (which would be used for the totally white areas
in the above images).
If the test reported a hit, it would then compute the distance from
the hit point to the current pixel position. I would then do
dsum = dsum + dist;
disum = disum + 1 / dist;
n = n + 1;
When all rays has been cheked, if n is nonzero, it computes the
averages:
a = dsum / n;
d = 1 / (disum / n);
These values are then assigned to either a_l and d_l or a_h and d_h.
The images it produces is not perfect, but if you apply a gaussian
blur (radius 4-6 in the above images), it looks pretty good imho.
The traversal algorithm I used was based on "A Fast Voxel Traversal
Algorithm for Ray Tracing" by Amanatides & Woo
http://citeseer.ist.psu.edu/amanatides87fast.html
An obvious optimization is to not check against all edge pixels, but
only every k pixel, or similar.
If your contours are polygons, you should be able to simply use a
ray-polygon intersection test to determine the distance.
Hope it helps, if only by a bit :)
- Asbjørn
.
- Follow-Ups:
- Re: contour shading
- From: jano trouba
- Re: contour shading
- Prev by Date: cximage
- Next by Date: hilbert curve
- Previous by thread: Re: contour shading
- Next by thread: Re: contour shading
- Index(es):
Relevant Pages
|