Code archives/Algorithms/Generate Nice Terrain+Lightmap
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
This Code makes paradisiac islands, generates the colormap and the lightmap. We can update the lightmap in realtime, it may use about 50 ms to render a 256*256 Terrain, so it 's very fast. For bigger Terrain, we could use multiple pass to render the lightmap in realtime. This code is here for free, you may use it for your own project (commercial or not), but eventually, credit are always welcome. Comments are also welcome. ps : Yes, Of course, I love when people say I'm clever ^^ Features : the ColorMap process use a simple "height to ColorLevel" system. the Lightmap use an algorythm of ray to check the height of the terrain along the Sun vector. The generated terrain is a little bit rocky, so you might want to blur the heightmap before any other process. | |||||
Graphics3D 800,600,0,2 SetBuffer BackBuffer() Local World%= CreatePivot (); Local piv = CreatePivot (World); Local cam = CreateCamera (piv); Local CamY# = 10.0 PositionEntity (cam, 0,CamY,0,0); CameraRange (cam, 1,10000); CameraClsColor (cam, 100,150,255); Local Sun% = CreateSphere (10,World) PositionEntity (Sun,1000,500,1000) ScaleEntity (Sun,15,15,15) EntityColor (Sun,250,230,220) EntityFX (Sun,1) PointEntity (Sun,World) Local TSize%= 512 Local Terr = CreateTerrain (TSize,World) Generation_Terrain(Terr,4,250,4,150,.01,.15,20,TSize/3) TerrainColore (Terr) ; ExtractLightMap (Terr,4,250,Sun) EntityFX (Terr,1) Local Plane%= CreatePlane (1,World) EntityColor (Plane,80,50,10) EntityFX (Plane,1) Local Sea% = CreatePlane (1,World) EntityColor (Sea,10,50,100) EntityFX (Sea,1) EntityAlpha (Sea,.5) MoveEntity (Sea,0,250*.08,0) Local MainTime%=MilliSecs() Local OldTime%=0 Repeat msx=MouseXSpeed() msy=MouseYSpeed() msz=MouseZSpeed() TurnEntity piv,0,-msx,0 TurnEntity cam,+msy,0,0 Local vz# = Float ( ( ( KeyDown(200)+KeyDown(17) ) > 0 ) - ( ( KeyDown(208)+KeyDown(31) ) > 0 ) ) Local vx# = Float ( ( ( KeyDown(205)+KeyDown(32) ) > 0 ) - ( ( KeyDown(203)+KeyDown(30) ) > 0 ) ) MoveEntity piv,.1*vx*CamY,0,.1*vz*CamY Px#=EntityX(piv,1) Pz#=EntityZ(piv,1) Py#=TerrainY(Terr,Px,0,Pz) PositionEntity piv,pX,Py,Pz If msz CamY=CamY+CamY*.1*Float(msz):PositionEntity cam,0,CamY,0,0 Time=MilliSecs()-MainTime ; 4*360° / Min AT%=Float(time)*.001 Tour%=4 Dec#=.360 Ang#=Dec*Float(AT*Tour) Rayon#=1500.0 SunPosX#=Rayon*Cos(Ang):SunPosZ#=Rayon*Sin(Ang) PositionEntity Sun,SunPosX,500,SunPosZ,1:PointEntity Sun,World If Time>OldTime ExtractLightMap(Terr,4,250,Sun):OldTime=Time+5000 MoveMouse 400,300 RenderWorld Text 10,10,"Ang="+Ang Flip Until KeyHit(1) FreeEntity World End Function Generation_Terrain(Terrain%,sclX#,sclY#,sclZ#,nbc#,COEF_HAUT1#=.005,COEF_HAUT2#=.02,Zone1#=15,Zone2#=50, smoothterrain%=2) Local Taille#=TerrainSize(Terrain) SeedRnd (MilliSecs()) Local a For a = 0 To nbc ; varie la hauteur de coef1 à coef2 => plus la surface est grande, plus on adoucie ! ; inversement, plus la surface est petite, plus on generera de "pics" Local COEF_HAUT# = Rnd(COEF_HAUT1,COEF_HAUT2) Local ZONE# = Rnd(Zone1/2,Zone2/2);*COEF_HAUT*10 Local Force# = 1.0 / (ZONE*COEF_HAUT); If Force<1 Then Force=1; If Force>10 Then Force=10; ;ZONE=ZONE/2 Local COEF#=90.0/ZONE Local pX#=Rand(ZONE+Taille/10,Taille#-ZONE-Taille/10) Local pZ#=Rand(ZONE+Taille/10,Taille#-ZONE-Taille/10) TFormPoint pX,0,pZ,0,Terrain : pX=TFormedX():pZ=TFormedZ() Local frc% For frc=1 To Force pX=pX+Rand(-ZONE/Force,ZONE/Force) pZ=pZ+Rand(-ZONE/Force,ZONE/Force) Local X#, Z# Local AH_X#, AH_Y#, AH_Z#, AH_T# For X = -ZONE To ZONE AH_X = Cos(X*COEF)*COEF_HAUT For Z# = -ZONE To ZONE AH_Z = Cos(Z*COEF) AH_T = AH_X * AH_Z + TerrainHeight(Terrain,pX+X,pZ+Z) If AH_T>1 Then AH_T=1; ModifyTerrain Terrain, pX+X,pZ+Z,AH_T Next Next Next Next For i = smoothterrain To TerrainSize(Terrain)-1-smoothterrain For j = smoothterrain To TerrainSize(Terrain)-1-smoothterrain Local sum# = 0.0, nb=0 For tx = -smoothterrain To smoothterrain For ty = -smoothterrain To smoothterrain sum=sum+TerrainHeight(Terrain, i+tx,j+ty) nb=nb+1 Next Next ModifyTerrain(Terrain, i,j, sum/nb, True); Next Next ScaleEntity (Terrain,sclX#,sclY#,sclZ#) MoveEntity (Terrain,-sclX*Taille*.5,0,-sclZ*Taille*.5) End Function Function TerrainColore(Terrain%) Tsz = TerrainSize (Terrain) Tex = CreateTexture (Tsz,Tsz):ScaleTexture(Tex,Tsz,Tsz) CBuf%= GraphicsBuffer () TBuf%= TextureBuffer (Tex):SetBuffer(TBuf):LockBuffer(TBuf) For i = 0 To Tsz-1 For j = 0 To Tsz-1 AH_T#=TerrainHeight(Terrain,i,j) If AH_T<.08 ; Sol->Mer => Sol->Sable Dh#=AH_T*1.0/.08 :R=080+030*Dh:G=050+030*Dh:B=010+040*Dh ; fin = 110 / 080 / 050 ElseIf AH_T<.1 ; Sable Dh#=(AH_T-.08)*1/.02:R=110+080*Dh:G=080+080*Dh:B=050+070*Dh ; fin = 190 / 160 / 120 ElseIf AH_T<.15 ; Herbe Dh#=(AH_T-.1)*1/.05 :R=190-170*Dh:G=160-120*Dh:B=120-110*Dh ; fin = 020 / 040 / 010 ElseIf AH_T<.7 ; Roche Dh#=(AH_T-.17)*1/.55:R=020+080*Dh:G=040+060*Dh:B=010+040*Dh ; fin = 120 / 100 / 050 Else ; neige Dh#=(AH_T-.72)*1/.3 :R=120+020*Dh:G=100+050*Dh:B=050+160*Dh ; fin = 180 / 150/ 210 EndIf If R<0 R=0 If G<0 G=0 If B<0 B=0 WritePixelFast i,Tsz-j-1,R Shl(16) + G Shl(8) + B Next Next UnlockBuffer(TBuf):SetBuffer(CBuf) EntityTexture (Terrain,Tex,0,0):FreeTexture(Tex) End Function Dim Terr_Shd#(0,0) Function ExtractLightMap%(Terrain%,Scx#,Scy#,Sun%=0) Local Sz# = TerrainSize(Terrain) Dim Terr_Shd(Sz,Sz) Local LMap = CreateTexture(Sz,Sz):ScaleTexture(LMap,Sz,Sz):EntityTexture(Terrain,LMap,0,2) Local CBuff%= GraphicsBuffer(),TBuff%=TextureBuffer(LMap) If Sun<>0 :TFormNormal(0,0,1,Sun,0) Else :TFormNormal(-1,-.5,-.8,0,0) EndIf Local SunVx#=TFormedX(),SunVy#=TFormedY(),SunVz#=TFormedZ() Scy#=Scy/Scx For i = 0 To Sz-1 For j = 0 To Sz-1 dx#=0.0:dy#=0.0:dz#=0.0:dh#=TerrainHeight(Terrain,i,j)*Scy Repeat dx=dx+SunVx*.95:dy=dy+SunVy*.95:dz=dz+SunVz*.95 If i+dx>=0 And i+dx<Sz And j+dz>=0 And j+dz<Sz TrY#=TerrainHeight(Terrain,i+dx,j+dz)*Scy If TrY>dh+dy Exit Terr_Shd(i+dx,j+dz)=.9-.4*(dh-Try)/Scy Else :Exit EndIf Forever Next Next SetBuffer(TBuff):LockBuffer(TBuff) For i= 0 To Sz-1:For j= 0 To Sz-1 If Terr_Shd(i,j)<>0 :rgb=255*Terr_Shd(i,j) Else :rgb=255 EndIf WritePixelFast i,Sz-j-1,RGB Shl(16) + RGB Shl(8) + RGB + 255 Shl(24) Next:Next UnlockBuffer(TBuff):SetBuffer CBuff FreeTexture (LMap) Dim Terr_Shd(0,0) End Function |
Comments
| ||
and here is the multi pass for shadowing the terrain in realtimeDim Terr_Shd#(0,0) Global LightmapExtracted%=False Function ExtractLightMap%(Terrain%,Scx#,Scy#,Sun%=0,FreeLightmap%=True) Local Sz# = TerrainSize(Terrain) Dim Terr_Shd(Sz,Sz) Local LMap = CreateTexture(Sz,Sz,1+16+32):ScaleTexture(LMap,Sz,Sz):EntityTexture(Terrain,LMap,0,2) Local CBuff%= GraphicsBuffer(),TBuff%=TextureBuffer(LMap) If Sun<>0 :TFormNormal(0,0,1,Sun,0) :Else :TFormNormal(-1,-.5,-.8,0,0) :EndIf Local SunVx#=TFormedX(),SunVy#=TFormedY(),SunVz#=TFormedZ() scy#=Scy/Scx For i = 0 To Sz-1:For j = 0 To Sz-1 :dx#=0.0:dy#=0.0:dz#=0.0:dh#=TerrainHeight(Terrain,i,j)*scy :Repeat dx=dx+SunVx*.95:dy=dy+SunVy*.95:dz=dz+SunVz*.95 If i+dx>=0 And i+dx<Sz And j+dz>=0 And j+dz<Sz TrY#=TerrainHeight(Terrain,i+dx,j+dz)*scy:If TrY>dh+dy:Exit:EndIf:Terr_Shd(i+dx,j+dz)=.9-.4*(dh-Try)/Scy Else :Exit :EndIf Forever :Next:Next SetBuffer(TBuff):LockBuffer(TBuff) For i= 0 To Sz-1:For j= 0 To Sz-1 If terr_Shd(i,j)<>0 :rgb=255*terr_Shd(i,j) :Else :rgb=255 :EndIf WritePixelFast i,Sz-j-1,RGB Shl(16) + RGB Shl(8) + RGB + 255 Shl(24) Next:Next UnlockBuffer(TBuff):SetBuffer CBuff:TextureBlend(LMap,5) If FreeLightmap :FreeTexture(LMap):Dim Terr_Shd(0,0):LightmapExtracted=False Else :LightmapExtracted=True:Return LMap EndIf End Function Global CurseurI%,CurseurJ% Global CurseurFromI%,CurseurToI Global CurseurFromJ%,CurseurToJ Function TerrainRealtimeShadowMap(Terrain%,LMap%,Scx#,scy#,Sun%=0) Local Sz# = TerrainSize(Terrain) If LightmapExtracted=False LMap=ExtractLightMap(Terrain,Scx,Scy,Sun,False) :CurseurToI=Sz-1 :CurseurToJ=Sz-1 :CurseurFromI=0: CurseurFromJ=0 Local CBuff%= GraphicsBuffer(),TBuff%=TextureBuffer(LMap) If Sun<>0 :TFormNormal(0,0,1,Sun,0) :Else :TFormNormal(-1,-.5,-.8,0,0) :EndIf Local SunVx#=TFormedX(),SunVy#=TFormedY(),SunVz#=TFormedZ():scy#=Scy/Scx CurseurFromI=0 :CurseurToI=Sz-1 If CurseurFromJ=Sz-1 :CurseurFromJ=0 :Else :CurseurFromJ=CurseurFromJ+1 :EndIf If CurseurFromJ>Sz-1 CurseurFromJ=Sz-1 CurseurToJ=CurseurFromJ Local dx#,dy#,dz#,dh# For i = CurseurFromI To CurseurToI :For j = CurseurFromJ To CurseurToJ:dx=0:dy=0:dz=0:dh=TerrainHeight(Terrain,i,j)*scy :Repeat dx=dx+SunVx*.95:dy=dy+SunVy*.95:dz=dz+SunVz*.95 If i+dx>=0 And i+dx<Sz And j+dz>=0 And j+dz<Sz TrY#=TerrainHeight(Terrain,i+dx,j+dz)*scy :If TrY>dh+dy:Exit:EndIf:Terr_Shd(i+dx,j+dz)=.9-.4*(dh-Try)/Scy Else :Exit :EndIf Forever:Next:Next SetBuffer(TBuff):LockBuffer(TBuff) For i = CurseurFromI To CurseurToI:For j = CurseurFromJ To CurseurToJ If terr_Shd(i,j)<>0 :rgb=255*terr_Shd(i,j) :Else :rgb=255 :EndIf WritePixelFast i,Sz-j-1,RGB Shl(16) + RGB Shl(8) + RGB; + 255 Shl(24) Next:Next UnlockBuffer(TBuff):SetBuffer CBuff:Return LMap End Function => TerrainRealtimeShadowMap(Terrain%,LMap%,Scx#,scy#,Sun%=0) Specify the LightMap Texture applyied to the terrain So, you 'll have 2 choices : choise 1 : -> Make a first complete rendering using "ExtractLightMap" function For convinience, I had an extra "LightmapExtracted" global, if the Lightmap has not yet been extracted, then the lightmap will be automatically generated... choise 2 : -> Make a cleared texture, apply it to the terrain, and specify the texture to LMap parameter for TerrainRealtimeShadowMap(Terrain%,LMap%,Scx#,scy#,Sun%=0) the function TerrainRealtimeShadowMap() is made to be used inside the main loop it performs line after line shadow render the larger the terrain, most time it needs. It ran it at 500 FPS on a 1024*1024 TerrainSize (Config in Sig) |
| ||
Good !!! if you store in array the value TerrainHeight(Terrain,i+dx,j+dz) obtainend over speed bye |
| ||
Hi have changed your code for litle speed up Bye Graphics3D 800,600,0,2 SetBuffer BackBuffer() Local World%= CreatePivot () Local piv = CreatePivot () Local cam = CreateCamera () Local CamY# = 1000.0 PositionEntity (cam,0,CamY,0,0) CameraRange (cam,1,5000) Local Sun% = CreateSphere (10,World) PositionEntity (Sun,1000,500,1000) ScaleEntity (Sun,15,15,15) EntityColor (Sun,250,230,220) EntityFX (Sun,1) PointEntity (Sun,World) Local TSize%= 256 Local Terr = CreateTerrain (TSize,World) Generation_Terrain(Terr,4,250,4,150,.01,.15,20,TSize/3) TerrainColore (Terr) ; ExtractLightMap (Terr,4,250,Sun) EntityFX (Terr,1) Local Plane%= CreatePlane (1,World) EntityColor (Plane,80,50,10) EntityFX (Plane,1) Local Sea% = CreatePlane (1,World) EntityColor (Sea,10,50,100) EntityFX (Sea,1) EntityAlpha (Sea,.5) MoveEntity (Sea,0,250*.08,0) Global OldTime%=MilliSecs() ;Stop Global TLightMap = ExtractLightMap(Terr,4,250,Sun,False) Repeat spd#=5 ;TurnEntity piv,0,-msx,0 ;TurnEntity cam,+msy,0,0 ;MoveEntity piv,0,0,.1*(KeyDown(200)-KeyDown(208))*CamY MoveEntity cam,(KeyDown(205)-KeyDown(203))*spd,0,((MouseDown(1)Or KeyDown(201))-(MouseDown(2)Or KeyDown(207)))*spd TurnEntity cam,-MouseYSpeed()*0.1,-MouseXSpeed()*0.1,0 RotateEntity cam,EntityPitch(cam,True),EntityYaw(cam,True),0 MoveMouse GraphicsWidth()*.5,GraphicsHeight()*.5 ;PositionEntity cam,0,CamY,0,0 ; Time=MilliSecs()-MainTime ; 4*360° / Min Dec#=Dec#+1.0 Local Rayon#=1000.0 Local SunPosX#=Rayon*Cos(Dec) Local SunPosZ#=Rayon*Sin(Dec) PositionEntity Sun,SunPosX,500,SunPosZ,1:PointEntity Sun,World ;If Time>OldTime TerrainRealtimeShadowMap(Terr,TLightMap,4,250,Sun):OldTime=Time+1 ExtractLightMap(Terr,4,250,Sun,False) ;TerrainRealtimeShadowMap(Terr,TLightMap,4,250,Sun) MoveMouse 400,300 RenderWorld Text 10,10,"Ang : "+Dec Text 10,20,"Fps : "+(MilliSecs()-OldTime) : OldTime%=MilliSecs() Flip(True) Until KeyHit(1) FreeEntity World End Function Generation_Terrain(Terrain%,sclX#,sclY#,sclZ#,nbc#,COEF_HAUT1#=.005,COEF_HAUT2#=.02,Zone1#=15,Zone2#=50) Local Taille#=TerrainSize(Terrain) SeedRnd (MilliSecs()) For a=0 To nbc# ; varie la hauteur de coef1 à coef2 => plus la surface est grande, plus on adoucie ! ; inversement, plus la surface est petite, plus on generera de "pics" Local COEF_HAUT#=Rnd(COEF_HAUT1,COEF_HAUT2) Local ZONE#=Rand(Zone1/2,Zone2/2);*COEF_HAUT*10 Force=1/(ZONE*COEF_HAUT) If Force<1 Force=1 If Force>10 Force=10 ;ZONE=ZONE/2 Local COEF#=90.0/ZONE pX#=Rand(ZONE+Taille/10,Taille#-ZONE-Taille/10) pZ#=Rand(ZONE+Taille/10,Taille#-ZONE-Taille/10) TFormPoint Px,0,Pz,0,Terrain PX=TFormedX():PZ=TFormedZ() For frc=1 To Force Px=Px+Rand(-ZONE/Force,ZONE/Force) Pz=Pz+Rand(-ZONE/Force,ZONE/Force) For X# = -ZONE To ZONE AH_X# = Cos(X*COEF)*COEF_HAUT For Z# = -ZONE To ZONE AH_Z# = Cos(Z*COEF) AH_T# = AH_X*AH_Z+TerrainHeight(Terrain,Px+X,Pz+Z) If AH_T>1 AH_T=1 ModifyTerrain Terrain, Px+X,Pz+Z,AH_T Next Next Next Next ScaleEntity (Terrain,sclX#,sclY#,sclZ#) MoveEntity (Terrain,-sclX*Taille*.5,0,-sclZ*Taille*.5) End Function Function TerrainColore(Terrain%) Local px%,py% Tsz = TerrainSize (Terrain) Tex = CreateTexture (Tsz,Tsz):ScaleTexture(Tex,Tsz,Tsz) CBuf%= GraphicsBuffer () TBuf%= TextureBuffer (Tex):SetBuffer(TBuf):LockBuffer(TBuf) For px = 0 To Tsz-1 For py = 0 To Tsz-1 AH_T#=TerrainHeight(Terrain,px,py) If AH_T<.08 ; Sol->Mer => Sol->Sable Dh#=AH_T*1.0/.08 R=080+030*Dh G=050+030*Dh B=010+040*Dh ; fin = 110 / 080 / 050 ElseIf AH_T<.1 ; Sable Dh#=(AH_T-.08)*1/.02 R=110+080*Dh G=080+080*Dh B=050+070*Dh ; fin = 190 / 160 / 120 ElseIf AH_T<.15 ; Herbe Dh#=(AH_T-.1)*1/.05 R=190-170*Dh G=160-120*Dh B=120-110*Dh ; fin = 020 / 040 / 010 ElseIf AH_T<.7 ; Roche Dh#=(AH_T-.17)*1/.55 R=020+080*Dh G=040+060*Dh B=010+040*Dh ; fin = 120 / 100 / 050 Else ; neige Dh#=(AH_T-.72)*1/.3 R=120+020*Dh G=100+050*Dh B=050+160*Dh ; fin = 180 / 150/ 210 EndIf If R<0 R=0 If G<0 G=0 If B<0 B=0 WritePixelFast px,Tsz-py-1,R Shl(16) + G Shl(8) + B Next Next UnlockBuffer(TBuf):SetBuffer(CBuf) EntityTexture (Terrain,Tex,0,0):FreeTexture(Tex) End Function Dim Terr_Shd#(0,0) Global CurseurI%,CurseurJ% Global CurseurFromI%,CurseurToI Global CurseurFromJ%,CurseurToJ Global LightmapExtracted%=False Function ExtractLightMap%(Terrain%,Scx#,Scy#,Sun%=0,FreeLightmap%=True) ;===> Local Sz# = TerrainSize(Terrain) Local LMap = CreateTexture(Sz,Sz,1+16+32) : TextureBlend(LMap,2) Local CBuff%= GraphicsBuffer() Local TBuff%=TextureBuffer(LMap) Local SunVx#, SunVy#, SunVz#; Local px%,py% Local dx#,dy#,dz#,dh# Local fa#,fb# Local RGB% Local TrY#=0 ;===> Dim Terr_Shd(Sz,Sz) ;===> ScaleTexture(LMap,Sz,Sz) EntityTexture(Terrain,LMap,0,2) If Sun<>0 Then TFormNormal(0,0,1,Sun,0) Else TFormNormal(-1,-.5,-.8,0,0) EndIf SunVx#=TFormedX(); SunVy#=TFormedY(); SunVz#=TFormedZ(); Scy#=Scy/Scx; For px = 0 To Sz-1 For py = 0 To Sz-1 dx#=0.0 dy#=0.0 dz#=0.0 dh#=TerrainHeight(Terrain,px,py)*Scy Repeat ;===> dx = dx+SunVx dy = dy+SunVy dz = dz+SunVz fa = px+dx fb = py+dz ;===> If fa>=0 And fa<Sz And fb>=0 And fb<Sz Then TrY#=TerrainHeight(Terrain,fa,fb)*Scy If TrY>dh+dy Then Exit EndIf Terr_Shd(fa,fb)=.9-.4*(dh-TrY)/Scy Else Exit EndIf Forever Next Next PI_Smooth(Terrain) SetBuffer(TBuff) LockBuffer(TBuff) For px= 0 To Sz-1 For py= 0 To Sz-1 If Terr_Shd(px,py)>0 Then RGB=255-(255*Terr_Shd(px,py)) Else RGB=0 EndIf WritePixelFast px,Sz-py-1, RGB Shl(16) + RGB Shl(8) + RGB + 255 Shl(24) Next Next ;===> UnlockBuffer(TBuff) SetBuffer CBuff ;===> If FreeLightmap Then ;===> FreeTexture(LMap) ;Dim Terr_Shd(0,0) LightmapExtracted=False ;===> Else ;===> LightmapExtracted=True Return LMap ;===> EndIf End Function Function PI_Smooth(Terrain%) ;===> Local Sz# = TerrainSize(Terrain) Local pix#, pix1#, x, y, offsetY, b ;===> ;smoot ;===> For y=0 To Sz-3 For x=0 To Sz-3 ;===> Terr_Shd(x+1,y) = (Terr_Shd(x,y)+Terr_Shd(x+1,y)+Terr_Shd(x+2,y))/3 Terr_Shd(x,y+1) = (Terr_Shd(x,y)+Terr_Shd(x,y+1)+Terr_Shd(x,y+2))/3 ;===> Next ;===> Next ;===> End Function |
Code Archives Forum