Impasto discussion

Matthew Woehlke mw_triad at users.sourceforge.net
Tue Jul 20 01:06:55 CEST 2010


JL VT wrote:
> I'd like to perform thread necromancy now that I have a worthy update
> to mention:
>
> http://pentalis.org/kritablog/?p=157
>
> I decided to follow the Phong Illumination Model to set the color of
> the bumps, and for now I'm only using the pixels above and below, and
> right and left of the reference pixel to calculate its normal vector
> (and therefore, indirectly, "inclination/tilt").
>
> The main references being, as the blog post highlights:
> http://www.mini.pw.edu.pl/~kotowski/Grafika/IlluminationModel/Index.html
> http://www.gamedev.net/columns/hardcore/cgbumpmapping/
>
> The source of the program is:
> http://pentalis.org/kritablog/wp-content/uploads/2010/07/bumpy_source.txt

>         vector_x = [1, 0, height_array[x+1][y] - height_array[x-1][y]]
>         vector_y = [0, 1, height_array[x][y+1] - height_array[x][y-1]]

How do you handle edge pixels?

At first that seemed like an over-simplification, so I decided to write 
my own version and work out the math.

If we construct a four-quad mesh around the pixel being evaluated and 
calculate the normal of the center vertex, we can derive a very simple 
formula for interior pixels (which turns out to be equivalent to the 
above formula), as well as see how to calculate normals for edge pixels 
(simply omit the faces that don't exist). Like so:

// Mesh looks like this:
//
// 1--2--3
// |  |  |
// 4--0--5
// |  |  |
// 6--7--8
//
// ha0 = ha[x,y]; - ha == height_array
// had2 = ha[x,y-1] - ha0;
// had4 = ha[x-1,y] - ha0;
// had5 = ha[x+1,y] - ha0;
// had7 = ha[x,y+1] - ha0;
// cross: [y1*z2 - z1*y2, z1*x2 - x1*z2, x1*y2 - y1*x2]
// n1 = (2 - 0) × (4 - 0) = [ 0, -1, had2] × [-1,  0, had4]
// n3 = (5 - 0) × (2 - 0) = [ 1,  0, had5] × [ 0, -1, had2]
// n6 = (7 - 0) × (5 - 0) = [ 0,  1, had7] × [ 1,  0, had5]
// n8 = (4 - 0) × (7 - 0) = [-1,  0, had4] × [ 0,  1, had7]
// n1 = [-had4, -had2, -1];
// n3 = [ had5, -had2, -1];
// n6 = [ had5,  had7, -1];
// n8 = [-had4,  had7, -1];
// n = n1 + n3 + n6 + n8;
// n = [had5 - had4, had7 - had2, -2]; - can drop the constant scalar
n = [ha[x+1,y] - ha[x-1,y], ha[x,y+1] - ha[x,y-1], -2];
n = n / linalg.norm(n);

I believe if you write out the cross product from your version, you'll 
see it works out the same (allowing for a constant scalar adjustment of 
the Z value). However you should be able to use the above to derive the 
simplified formulas for boundary pixels as well. (And I *would* 
recommend writing out the cross product result explicitly. It's only a 
few basic math operations saved, but even that over thousands or 
millions of pixels can be significant.) Also, I would suggest adding an 
scalar adjustment factor for the height values, especially if they will 
be in 16-bit or better precision. (This would also 'eliminate' the 
mentioned discrepancy in Z value scaling.)

Note that I'm using raster coordinate system in the above, which means 
+x goes right, +y goes down, and +z goes into the screen.

-- 
Matthew
Please do not quote my e-mail address unobfuscated in message bodies.
-- 
ENOWIT: .sig file temporarily unavailable



More information about the kimageshop mailing list