3D Visualization of a Height Map

Previous topic - Next topic

Kitty Hello

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.
Code (glbasic) Select
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:


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.

bigsofty

Excellent.

How could this be optimised?... triangle strips along the whole height map or GL vertrex arrays, or even a vertex shader for example?
Cheers,

Ian.

"It is practically impossible to teach good programming style to students that have had prior exposure to BASIC.  As potential programmers, they are mentally mutilated beyond hope of regeneration."
(E. W. Dijkstra)

Kitty Hello

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".

bigsofty

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?
Cheers,

Ian.

"It is practically impossible to teach good programming style to students that have had prior exposure to BASIC.  As potential programmers, they are mentally mutilated beyond hope of regeneration."
(E. W. Dijkstra)

Kitty Hello

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.

bigsofty

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?
Cheers,

Ian.

"It is practically impossible to teach good programming style to students that have had prior exposure to BASIC.  As potential programmers, they are mentally mutilated beyond hope of regeneration."
(E. W. Dijkstra)

Kitty Hello

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".

bigsofty

Cheers,

Ian.

"It is practically impossible to teach good programming style to students that have had prior exposure to BASIC.  As potential programmers, they are mentally mutilated beyond hope of regeneration."
(E. W. Dijkstra)

Kitty Hello