If you have a heightmap like: height
- [y] and want to draw it in 3D, here's some code (complete project) to create smooth interpolation between each of the center points of the height map.
DIM world[15][10]
// Dummy Data
FOR x=0 TO 14
FOR y=0 TO 9
world[x][y]=RND(15)/10
NEXT
NEXT
// Create World Object
X_OBJSTART 0
X_AUTONORMALS 2
FOR x=0 TO 14
FOR y=0 TO 9
MakeTile(world[], x,y, -15/2, -10/2)
NEXT
NEXT
X_OBJEND
// some dummy texture:
FILLRECT 0,0,128,128, RGB(0,0,255)
FILLRECT 4,4,124,124, RGB(255,255,255)
FILLRECT 5,62,123,66, RGB(0,255,0)
FILLRECT 62,5,66,123, RGB(0,255,0)
FILLRECT 62,62,66,66, RGB(255,0,0)
PRINT "GLBasic", 8,8
GRABSPRITE 0, 0,0,128,128
BLACKSCREEN
WHILE TRUE
X_MAKE3D 1,100, 45
X_CAMERA 1,12,10, 0,0,0
X_SETTEXTURE 0,-1
X_ROTATION GETTIMERALL()/100, 0,1,0
X_DRAWOBJ 0,0
SHOWSCREEN
WEND
FUNCTION MakeTile: heights[], x,y, offsetx, offsety
// Triangle Strip is:
// 0--2--4-.
// | /| /| .
// |/ |/ |/
// 1--3--5-.
// We need:
// 0-1-2
// |\|/|
// 3-4-5
// |/|\|
// 6-7-8
LOCAL pts[]
LOCAL i, px, py, mx, my
DIM pts[9][3] // 9 points[x,y,z]
pts[0][0]=-1; pts[0][1]=-1
pts[1][0]=.0; pts[1][1]=-1
pts[2][0]= 1; pts[2][1]=-1
pts[3][0]=-1; pts[3][1]=.0
pts[4][0]=.0; pts[4][1]=.0
pts[5][0]= 1; pts[5][1]=.0
pts[6][0]=-1; pts[6][1]= 1
pts[7][0]=.0; pts[7][1]= 1
pts[8][0]= 1; pts[8][1]= 1
// now calculate Z for each point
mx = BOUNDS(heights[], 0)-1
my = BOUNDS(heights[], 1)-1
FOR i=0 TO 8
// Get neighbour point
// but stop at array border
px = MIN(mx, MAX(0, x+pts[i][0]))
py = MIN(my, MAX(0, y+pts[i][1]))
pts[i][2] = ( heights[px][py]+ _
heights[ x][ y]+ _
heights[px][ y]+ _
heights[ x][py])/4
NEXT
// Next a function to create 2 triangles:
INC x, offsetx
INC y, offsety
AddQuad(pts[], x,y,1,0,4,3)
AddQuad(pts[], x,y,1,4,2,5)
AddQuad(pts[], x,y,3,6,4,7)
AddQuad(pts[], x,y,5,4,8,7)
ENDFUNCTION
FUNCTION AddQuad: pts[], x,y,a,b,c,d
// here we build a triangle stipped quad
// for the points a,b,c,d
// we divide coordinates by 2, so we get a
// rectangle of size 1x1 (-0.5 -> 0.5)
// for the texture we divide by 2 and add 0.5
// (0.0 -> 1.0)
// last: we swap y and z, since y is vertical in GLBasic
LOCAL cl
cl =RGB(255,255,255)
X_OBJADDVERTEX x+pts[a][0]/2,pts[a][2],y+pts[a][1]/2, pts[a][0]/2+.5, pts[a][1]/2+.5,cl
X_OBJADDVERTEX x+pts[b][0]/2,pts[b][2],y+pts[b][1]/2, pts[b][0]/2+.5, pts[b][1]/2+.5,cl
X_OBJADDVERTEX x+pts[c][0]/2,pts[c][2],y+pts[c][1]/2, pts[c][0]/2+.5, pts[c][1]/2+.5,cl
X_OBJADDVERTEX x+pts[d][0]/2,pts[d][2],y+pts[d][1]/2, pts[d][0]/2+.5, pts[d][1]/2+.5,cl
X_OBJNEWGROUP
ENDFUNCTION
And this is what it looks like:
(http://img243.imageshack.us/img243/9220/junk3gg7.th.png) (http://img243.imageshack.us/my.php?image=junk3gg7.png)
The red dots are the height coordinates, the blue rects are the tiles and the green lines are where I split the tiles for smooth interpolation.
Excellent.
How could this be optimised?... triangle strips along the whole height map or GL vertrex arrays, or even a vertex shader for example?
strips are converted to triangles internally, anyway. I don't see much optimization space here. Well, shaders could be used to make the thing look "rounder".
Cool, how could I get the height of a point, say, if I give it an X & Y co-ordinate to place an object on it?
The easiest method is to use X_COLLISIONRAY. You can do it (for simple MxN meshes with numerical solution, too). No time right now. I can post some code later.
CollisionRay probably will do a scan of all the triangles on a mesh, then do a normal check, once the correct triangle is found etc... Ill give a custom solution a go... Ill cache the grid coordinates, find the right quad with a division and the use interpolation to find the correct hight... I think that would be quicker?
Yes, sure. Get the INTEGER(x_pos / scale) and INTEGER(y_pos / scale) and you have the upper-left index of the map
- [y] array. Check for out-of-bounds and then interpolate. You have to take care, since the "anticline?" of the 2 triangles flips by 90° for each "quad".
Almost... "decline" ;)
(http://img83.imageshack.us/img83/3843/unbenanntpaint12bd2.png) (http://imageshack.us)
The red lines ;)