Very nice. Very clear. When I have a little time I may extend this further to something like this:
Global terrain = load_terrain("heightmap.bmp, texture.bmp,lightmap.bmp")
Global terrain = load_terrain("heightmap.bmp, texture.bmp,lightmap.bmp")
| This function is exactly like the LoadTerrain command in blitz, except it uses a blitz mesh instead of a blitz terrain. There's no LOD, but it should be alot faster in many circumstances. Same syntax as the Blitz function. Also centres the mesh, unlike the original function. EDIT<<< I have redone this routine, as it had many errors and inaccurate workings: - It will now properly apply the heightmap without a strange seem appearing. - I have added the functionality to adjust the Y scale. - You can load three textures, and state flags, and they will be applied. - The UV mapping has been fixed now. - The function returns the mesh back, which i don't think it did before? Global terrain = load_terrain("heightmap.bmp",0.5); load the terrain half scale (since Red pixel colours highest value is 255, the highest value will now be 128.) To load a texture and apply it to the terrain. Global terrain = load_terrain("heightmap.bmp",0.5,"terrain_texture.bmp",1+16+32); load the terrain, and apply a texture, with the clamping flags and colour flag. Note, you must clamp the texture if it encompasses the whole mesh, or it's edges will bleed to the other side. |
; Y position is calculated by: scale * pixel colour on loaded image. ; PLEASE NOTE: You must clamp the texture your applying if it is spread across the whole mesh. ; If you don't, it will bleed across to the opposite side. Clamp with flags 16 + 32 Function load_terrain(heightmap$,y_scale#=1,texture1$="",t_flag1 = 1,texture2$="",t_flag2 = 1,texture3$="",t_flag3 = 1) temp = LoadImage(heightmap$) If temp = 0 Then Return 0 x = ImageWidth(temp) DebugLog(" image width = "+x) y = ImageHeight(temp) mesh = CreateMesh() surf = CreateSurface(mesh) For ly = 0 To y-1 ; your doing -1 because the image pixels start at 1 and the vertex ; indices start at 0 For lx = 0 To x-1 AddVertex surf,lx , 0, -ly, Float(lx)/(x-1), Float(ly)/(y-1) Next Next RenderWorld AddTriangle surf, 0, 65,64 AddTriangle surf, 0, 1 ,65 For ly = 0 To y-2 For lx = 0 To x-2 ; leave the vertex counting an extra unit short, as the code below reaches ; reaches one unit ahead to create the triangles ; below is to simply explain the creation process and order of the triangles. ; Triangles must be created in clockwise order, facing the camera, to be seen. current_y = ly*y next_y = (ly+1)*y current_x = lx next_x = lx+1 ;create the quad AddTriangle surf, current_y+current_x, next_y+next_x , next_y + current_x AddTriangle surf, current_y+current_x, current_y+next_x , next_y + next_x Next Next PositionMesh mesh, -x/2.0,0,y/2.0 ; centre the mesh on the world axis. SetBuffer ImageBuffer(temp) For ly = 0 To y-1 For lx = 0 To x-1 GetColor lx,ly index = (ly*y) + lx VertexCoords surf, index , VertexX(surf,index), ColorRed()*y_scale, VertexZ(surf,index) Next Next SetBuffer BackBuffer() UpdateNormals mesh If texture1 <> "" Then t1 = LoadTexture(texture1,t_flag1) If t1 = 0 Then RuntimeError(" Error in load_terrain() function: Texture1 not found from filename given") EntityTexture mesh,t1,0,0 End If If texture2 <> "" Then t2 = LoadTexture(texture2,t_flag2) If t2 = 0 Then RuntimeError(" Error in load_terrain() function: Texture2 not found from filename given") EntityTexture mesh,t2,0,1 End If If texture3 <> "" Then t3 = LoadTexture(texture3,t_flag3) If t3 = 0 Then RuntimeError(" Error in load_terrain() function: Texture3 not found from filename given") EntityTexture mesh,t3,0,2 End If Return mesh End Function |
LoadTerrain3( "hmap.bmp","tmap.bmp","lmap.bmp")
Function LoadTerrain3(hmap$,tmap$=0,lmap$=0) ; load the heightmap temp = LoadImage(hmap$) If temp = 0 Then RuntimeError "Heightmap image "+hmap$+" does not exist." : Return 0 ; store heightmap dimensions x = ImageWidth(temp) y = ImageHeight(temp) ; load texture and lightmaps tmap = LoadTexture(tmap$) lmap = LoadTexture(lmap$) ; auto scale the textures to the right size If tmap ScaleTexture tmap,x,y If lmap ScaleTexture lmap,x,y ; start building the terrain mesh = CreateMesh() surf = CreateSurface(mesh) ; create some verts for the terrain For ly = 0 To y For lx = 0 To x AddVertex surf,lx,0,ly,1.0/lx,1.0/ly Next Next RenderWorld ; connect the verts with faces For ly = 0 To y-1 For lx = 0 To x-1 AddTriangle surf,lx+((x+1)*ly),lx+((x+1)*ly)+(x+1),(lx+1)+((x+1)*ly) AddTriangle surf,(lx+1)+((x+1)*ly),lx+((x+1)*ly)+(x+1),(lx+1)+((x+1)*ly)+(x+1) Next Next ; position the terrain to center 0,0,0 PositionMesh mesh, -x/2.0,0,-y/2.0 ; alter vertice height to match the heightmap red channel SetBuffer ImageBuffer(temp) For lx = 0 To x For ly = 0 To y GetColor lx,y-ly index = lx + ((x+1)*ly) VertexCoords surf, index , VertexX(surf,index), ColorRed()/20.0,VertexZ(surf,index) ; set the terrain texture coordinates VertexTexCoords surf,index,lx,-ly Next Next SetBuffer BackBuffer() ; update the terrain normals so lighting will look correct UpdateNormals mesh ; apply texture map to index 0 If tmap EntityTexture mesh,tmap,0,0 ; apply lightmap to index 1 with flag 2 If lmap EntityTexture mesh,lmap,0,1 : TextureBlend lmap,2 Return Mesh End Function
; from: AddTriangle surf,lx+((x+1)*ly),lx+((x+1)*ly)+(x+1),(lx+1)+((x+1)*ly) vertice = lx+((x+1)*ly)
If lx+((x+1)*ly) > CountVertices(surf) then ... End If

; Meshterrain Demo, Version 1.001 by Krischan (webmaster@...) ; ; Make sure there are three images in the current folder: ; ; - a Heightmap (standard: 256x256 PNG) ; - a Colormap (standard: 2048x2048 JPG) ; - a detail Texture (standard: 512x512 PNG) ; ; This script will cut the images and display the heightmap/colormap as a tiled Mesh Terrain ; ; Textures and Heightmap generated with Large 3D Terrain SE 2.5 (http://www.bundysoft.com/L3DT) ; Based on a script from Ross C and this thread: ; ; <a href="http://www.blitzbasic.com/codearcs/codearcs.php?code=1609" target="_blank">http://www.blitzbasic.com/codearcs/codearcs.php?code=1609</a> ; Settings Global speed# = 0.1 ; Walk speed Global scale# = 100.00 ; map scale Global tiles = 16 ; how many tiles in X -AND- Y direction? must be power of 2 Global mapsize = 256 ; overview map size Global range# = 100 ; initial view range (100 = 100% map size) Global showmap = 1 ; show map Global fog = 1 ; use fog or not Global gravity = 1 ; use gravity or not Global wired = 0 ; show wireframe or not Global raster = 0 ; show tile raster or not Global border# = 0.99 ; 1.00 = 100% = walk along the borderline Global vscale# = 8.0 ; vertical terrain scale divider (increase if using smaller hmaps) Global ipos = 50 ; initial player y position AppTitle "Monkey Island Meshterrain Demo 1.001" Graphics3D 1024,768,32,1 ms=MilliSecs() : SeedRnd(ms) Dim hm(tiles,tiles),cm(tiles,tiles),tile(tiles,tiles) Global cam,player,cam_pitch#,cam_yaw#,mvx#,mvy#,mvz#,targetpitch#,targetyaw#,sp# hmap=LoadImage("heightmap.png") cmap=LoadImage("colormap.jpg") detail=LoadTexture("detail.png") hmw=ImageWidth(hmap) : hmh=ImageHeight(hmap) : hmws=hmw/tiles : hmhs=hmh/tiles cmw=ImageWidth(cmap) : cmh=ImageHeight(cmap) : cmws=cmw/tiles : cmhs=cmh/tiles Global sw=hmw*range# ; create textures and heightmap tiles x=1 Repeat y=1 Repeat cm(x,y)=CreateTexture(cmw/tiles,cmh/tiles,1+16+32) hm(x,y)=CreateImage((hmw/tiles)+1,(hmh/tiles)+1) y=y+1 Until y>tiles x=x+1 Until x>tiles ; cut heightmap x=hmws Repeat y=hmhs Repeat CopyRect(x-hmws,y-hmhs,hmws+1,hmhs+1,0,0,ImageBuffer(hmap),ImageBuffer(hm(x/hmws,y/hmhs))) y=y+hmhs Until y>hmh x=x+hmws Until x>hmw ; cut colormap x=cmws Repeat y=cmhs Repeat CopyRect(x-cmws,y-cmhs,cmws,cmhs,0,0,ImageBuffer(cmap),TextureBuffer(cm(x/cmws,y/cmhs))) If raster Then SetBuffer TextureBuffer(cm(x/cmws,y/cmhs)) Color 255,0,0 Rect(0,0,cmws,cmhs,0) EndIf y=y+cmhs Until y>cmh x=x+cmws Until x>cmw ; resize and free unused images ResizeImage cmap,mapsize,mapsize FreeImage(hmap) mf#=mapsize*1.0/hmw ; create mesh terrain tiles x=0 Repeat y=0 Repeat tx=1+Abs(x)/hmws : ty=1+Abs(y)/hmhs tile(tx,ty)=LoadMeshTerrain(hm(tx,ty),cm(tx,ty),detail,tx,ty) PositionEntity tile(tx,ty),(x*scale#)-((hmw/2)*scale#),0,(y*scale#)+((hmh/2)*scale#) EntityType tile(tx,ty),2 ScaleEntity tile(tx,ty),scale#,scale#,scale# y=y-hmhs Until y<(-hmh+hmhs) x=x+hmws Until x>(hmw-hmws) player=CreatePivot() PositionEntity player,0,ipos*scale#,0 EntityType player,1 EntityRadius player,1.0*scale# cam=CreateCamera(player) PositionEntity cam,0,0,0 CameraZoom cam,2 CameraFogColor cam,100,150,200 CameraClsColor cam,100,150,200 cam_yaw=230 targetyaw=230 AmbientLight 255,255,255 s=Speed(ms) MoveMouse GraphicsWidth()/2,GraphicsHeight()/2 Collisions 1,2,2,3 ; Main loop While Not KeyHit(1) FPS_C=FPS_C+1 If ms<MilliSecs() ms=MilliSecs()+1000 FPS=FPS_C FPS_C=0 EndIf old=pos : pos=MouseZSpeed() ; Keys If KeyHit(59) Then wired=1-wired ; F1 = Wireframe on/off If KeyHit(60) Then gravity=1-gravity ; F2 = Gravity on/off If KeyHit(61) Then fog=1-fog ; F3 = Fog on/off If KeyHit(28) Then showmap=1-showmap ; Return = Map on/off If KeyDown(201) Then sw=sw+hmw/16 ; Page up = slow range increase If KeyDown(209) Then sw=sw-hmw/16 ; Page down = slow range decrease If old=1 Then sw=sw+hmw ; Mouse Wheel up = fast range increase If old=-1 Then sw=sw-hmw ; Mouse Wheel down = fast range decrease If sw<hmw Then sw=hmw PlayerControls() plx#=EntityX(player) : ply#=EntityY(player) : plz#=EntityZ(player) If gravity Then ply#=ply#-(sp#*50) If plx#<((-hmw*border#)/2)*scale# Then plx=((-hmw*border#)/2)*scale# If plx#>((hmw*border#)/2)*scale# Then plx#=((hmw*border#)/2)*scale# If plz#<((-hmh*border#)/2)*scale# Then plz#=((-hmh*border#)/2)*scale# If plz#>((hmw*border#)/2)*scale# Then plz#=((hmw*border#)/2)*scale# PositionEntity player,plx#,ply#,plz# CameraFogMode cam,fog CameraRange cam,0.1,sw CameraFogRange cam,0,sw WireFrame wired UpdateWorld RenderWorld Color 255,255,255 Text 0,0,"Tris: "+TrisRendered()+" FPS: "+FPS+" Range: "+sw+" Wireframe: "+wired+" Gravity: "+gravity+" Fog: "+fog+" Build time: "+(s/1000.0)+" sec." If showmap Then Color 0,0,0 : Rect 0,25,mapsize,mapsize,1 : DrawImage cmap,0,25 Color 255,255,255 : Text 0,12,"X:"+Int(plx#)+" Y:"+Int(ply#)+" Z:"+Int(plz#)+" Pitch: "+cam_pitch+" Yaw: "+cam_yaw Color 255,0,0 : Oval((mapsize/2)+(plx#/scale#*mf#)-2,25+(mapsize/2)+(plz#*-1/scale#*mf#)-2,4,4,1) EndIf Flip 0 Wend End Function Speed(ms) : s=(MilliSecs()-ms) : Return s : End Function Function PlayerControls() mxspd# = MouseXSpeed()*0.25 myspd# = MouseYSpeed()*0.25 MoveMouse GraphicsWidth()/2,GraphicsHeight()/2 targetpitch = targetpitch + myspd targetpitch = ClampValue(targetpitch, -85,85) targetyaw = targetyaw - mxspd cam_pitch = cam_pitch + (targetpitch - cam_pitch)/16.0 cam_yaw = cam_yaw + (targetyaw - cam_yaw)/16.0 RotateEntity player,0,cam_yaw,0 RotateEntity cam,cam_pitch,0,0 sp#=speed# If KeyDown(42) Or KeyDown(54) Then sp#=(speed#*5) ; Shift = Turbo If KeyDown(200) Then mvz=mvz+sp# ; Arrow up = forward If KeyDown(208) Then mvz=mvz-sp# ; Arrow down = backward If KeyDown(205) Then mvx=mvx+sp# ; Arrow right = right If KeyDown(203) Then mvx=mvx-sp# ; Arrow left = left If MouseDown(1) Then mvy=mvy+sp# ; LMB = raise If MouseDown(2) Then mvy=mvy-sp# ; RMB = lower If KeyDown(17) Then mvz=mvz+sp# ; W = forward If KeyDown(31) Then mvz=mvz-sp# ; S = backward If KeyDown(30) Then mvx=mvx-sp# ; A = left If KeyDown(32) Then mvx=mvx+sp# ; D = right If KeyDown(16) Then mvy=mvy+sp# ; Q = raise If KeyDown(18) Then mvy=mvy-sp# ; E = lower TranslateEntity player,0,mvy,0 MoveEntity player,mvx,0,mvz mvx=mvx/1.01 mvy=mvy/1.01 mvz=mvz/1.01 End Function Function ClampValue(Original#, low#, high#) If Original<low Then Return low If Original>high Then Return high Return Original End Function Function LoadMeshTerrain(heightmap,colormap=False,detail=False,tx=0,ty=0) lessx=1 : If tx=ti Then lessx=2 lessy=1 : If ty=ti Then lessy=2 x = ImageWidth(heightmap)-lessx : y = ImageHeight(heightmap)-lessy mesh = CreateMesh() : surf = CreateSurface(mesh) For ly = 0 To y For lx = 0 To x AddVertex surf,lx,0,ly,1.0/lx,1.0/ly Next Next For ly = 0 To y-1 For lx = 0 To x-1 AddTriangle surf,lx+((x+1)*ly),lx+((x+1)*ly)+(x+1),(lx+1)+((x+1)*ly) AddTriangle surf,(lx+1)+((x+1)*ly),lx+((x+1)*ly)+(x+1),(lx+1)+((x+1)*ly)+(x+1) Next Next PositionMesh mesh,0,0,-y SetBuffer ImageBuffer(heightmap) : LockBuffer ImageBuffer(heightmap) For lx = 0 To x For ly = 0 To y h=(ReadPixelFast(lx,y-ly) And $ff0000)/$10000 index = lx + ((x+1)*ly) VertexCoords surf,index,VertexX(surf,index),h/vscale#,VertexZ(surf,index) VertexTexCoords surf,index,lx,(y-ly) Next Next UnlockBuffer ImageBuffer(heightmap) : SetBuffer BackBuffer() UpdateNormals mesh If colormap EntityTexture mesh,colormap,0,0 : ScaleTexture colormap,x,y If detail EntityTexture mesh,detail,0,2 : ScaleTexture detail,2,2 : TextureBlend detail,5 Return Mesh End Function