MakeDot3
BlitzMax Forums/BlitzMax Programming/MakeDot3
| ||
Filter to convert a heightmap to normal map. It's similar to a Sobel filter, but more accurate:Strict Import brl.pixmap Function PixmapFilterDot3:TPixmap(pixmap:TPixmap,height#=1.0,parallax=0) Local lp,rp,tp,bp Local bumpmap:TPixmap Local vx#,vy#,vz#,m# Local tl#,bl#,ml#,tr#,mr#,br#,mm#,bm#,tm# Local isq2#,sum#,al#,ar#,at#,ab#,r,g,b,a,x,y Local format If parallax bumpmap=CreatePixmap(pixmap.width,pixmap.height,PF_RGBA8888) Else bumpmap=CreatePixmap(pixmap.width,pixmap.height,PF_RGB888) EndIf For x=0 To pixmap.width-1 For y=0 To pixmap.height-1 lp=x-1 rp=x+1 tp=y-1 bp=y+1 If lp<0 lp=pixmap.width-1 If lp>pixmap.width-1 lp=0 If rp<0 rp=pixmap.width-1 If rp>pixmap.width-1 rp=0 If tp<0 tp=pixmap.width-1 If tp>pixmap.height-1 tp=0 If bp<0 bp=pixmap.width-1 If bp>pixmap.height-1 bp=0 tl#=ReadHeight(pixmap,x-1,y-1) tm#=ReadHeight(pixmap,x,y-1) tr#=ReadHeight(pixmap,x+1,y-1) ml#=ReadHeight(pixmap,x-1,y) mm#=ReadHeight(pixmap,x,y) mr#=ReadHeight(pixmap,x+1,y) bl#=ReadHeight(pixmap,x-1,y+1) bm#=ReadHeight(pixmap,x,y+1) br#=ReadHeight(pixmap,x+1,y+1) vx#=0.0 vy#=0.0 vz#=1.0 isq2#=1.0/Sqr(2.0) sum#=1.0+isq2+isq2 al#=(tl*isq2+ml+bl*isq2)/sum ar#=(tr*isq2+mr+br*isq2)/sum at#=(tl*isq2+tm+tr*isq2)/sum ab#=(bl*isq2+bm+br*isq2)/sum vx#=(al-ar)/255.0 vy#=(at-ab)/255.0 m=Max(0,vx*vx+vy*vy) m=Min(m,1.0) vz=Sqr(1.0-m) If height<>0.0 vz:/height m#=Sqr(vx*vx+vy*vy+vz*vz) vx:/m vy:/m vz:/m EndIf r=vx*127.5+127.5+0.5'0.5 added for rounding g=vy*127.5+127.5+0.5 b=vz*127.5+127.5+0.5 a=mm'store height value in alpha channel r=Min(r,255) r=Max(r,0) g=Min(g,255) g=Max(g,0) b=Min(b,255) b=Max(b,0) WritePixel bumpmap,x,y,b+(g Shl 8)+(r Shl 16)+(a Shl 24) Next Next Return bumpmap EndFunction Private Function ReadHeight:Float(pixmap:TPixmap,x,y) Local hue,r,g,b While x<0 x:+pixmap.width Wend While x>pixmap.width-1 x:-pixmap.width Wend While y<0 y:+pixmap.height Wend While y>pixmap.height-1 y:-pixmap.height Wend hue=ReadPixel(pixmap,x,y) r=(hue & $00FF0000) Shr 16 g=(hue & $0000FF00) Shr 8 b=(hue & $000000FF) Return Float(r)*0.3+Float(g)*0.59+Float(b)*0.11 EndFunction Public |
| ||
Sweet. |
| ||
Josh that's awesome. You never cease to amaze that's for sure. What I'm wondering is how this will look using the dot3 flag in Blitz3D. But I'm at work atm... |
| ||
Heya, I'm interested in where you got the 1/sqr(2) bit from?!? This appears to be the equivalent of a 'fudge factor' I use in my own routines for specifying texture 'depth' - by modifying this fudge factor, you can make surfaces appear more/less bumpy. However, if there's another/better way to do this I'm all ears... |
| ||
ISq2 is inverse square root of 2. It is used to give the diagonal pixels slightly less influence over the averages than the pixels that are directly touching the pixel we are working on. Without this, bumpmaps come out looking very pixelated. First it samples all pixels around the center; top-left, top-middle, top-right, etc. MM is the center pixel itself. It will wrap around from the other side of the texture if you are on an edge. Then it computes an average for the four pixels directly around the center...average left, average right, avg. top, avg. bottom. The horizontal normal of the pixel is determined by comparing the average left and right pixels. If left=right the X normal is 0.0. If left-right=255 the horizontal normal is 1.0. The vertical component is calculated the same way. After the X and Z component are calculated, that leaves the Z component, which is calculated like this: 1.0 = Sqr( x*x + y*y + z*z ) 1.0 = x*x + y*y + z*z 1.0 - ( x*x +y*y ) = z*z Sqr( 1.0 - ( x*x +y*y ) ) = z The results seem to always come out with a magnitude of 1.0, which is good. ATI's tool seems to do some scaling for low-contrast images, and this just performs the math on the true pixels. If it is correct, then I think this is better because it lets you work on low-bumpiness textures and you can keep things more uniform. |
| ||
Hey cool - never really considered the diagonals. My dot3 generators to date have been pretty primitive compared to this! Another thing: shouldn't 'x*128.5+128.5' etc be 'x*127.5+127.5' etc? Or is there something else cute going on there? |
| ||
127.5 is correct. Please let me know if you find anything else off. |
| ||
I use in my own routines for specifying texture 'depth' so this is an evidence of the 3d module existence! :D |
| ||
So this:r=vx*128.5+128.5 g=vy*128.5+128.5 b=vz*128.5+128.5 should be: r=vx*127.5+127.5 g=vy*127.5+127.5 b=vz*127.5+127.5? If so can you change the original post Josh. |