Meshterrain und Nahtstellen

Übersicht BlitzBasic Blitz3D

Neue Antwort erstellen

 

Krischan

Betreff: Meshterrain und Nahtstellen

BeitragDi, Apr 24, 2007 18:51
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

ich beschäftige mich gerade mit Meshterrains und dabei bin ich auf ein Problem gestossen, bei dem ich gerade nicht durchblicke. Ich habe dazu mal eine Demo gebastelt.

Screenshot:
user posted image

Da sieht man das Problem auch gleich gut. Wie schaffe ich es, die Nahtstellen an den vier Seiten des Meshterrains jeweils auf die gleiche Höhe zu bekommen, damit das Terrain nahtlos tiled? Ich habe mich mal daran versucht, die Seiten aneinander anzugleichen, bin aber kläglich gescheitert. Was auch ein bisschen blöd ist, dass die Heightmap 129x129 anstatt 128x128 gross sein muss, da die Übergänge sonst noch viel stärker zu Tage treten. Vielleicht habt Ihr eine Idee?

Das Terrain und die texturen sind übrigens schnell mit dem "Large 3D Terrain Editor" SE generiert worden, cooles Programm.

Code: [AUSKLAPPEN]
Graphics3D 1024,768,32,1

; Pivot für Steuerung und globale Variablen
Global cam, player
Global cam_pitch#, cam_yaw#
Global mvx#,mvy#,mvz#,targetpitch#,targetyaw#

; Kamerageschwindigkeit
Global speed#=0.1

; Playerpivot
player=CreatePivot()
PositionEntity player,64,10,40

; Kamera an Pivot gehängt
cam=CreateCamera(player)
PositionEntity cam,0,0,0
CameraZoom cam,1
CameraRange cam,0.01,10000
AmbientLight 255,255,255
CameraFogMode cam,True
CameraFogRange cam,0,256
CameraFogColor cam,96,64,32
CameraClsColor cam,96,64,32

; Meshterrain mit Colormap und Lightmap generieren
mesh1=LoadMeshTerrain("heightmap.bmp","colormap.jpg","lightmap.jpg")
mesh2=CopyEntity(mesh1)
mesh3=CopyEntity(mesh1)
mesh4=CopyEntity(mesh1)

; das Mesh 4x im Quadrat setzen
PositionEntity mesh1,0,0,0
PositionEntity mesh2,128,0,0
PositionEntity mesh3,128,0,128
PositionEntity mesh4,0,0,128

; Mauszeiger in die Mitte
MoveMouse GraphicsWidth()/2,GraphicsHeight()/2

; Hauptschleife
While Not KeyHit(1)

   ; FPS counter
   FPS_C=FPS_C+1
   If ms<MilliSecs()
      ms=MilliSecs()+1000
      FPS=FPS_C
      FPS_C=0
   EndIf
   
   ; Zusatztasten
   If KeyHit(57) Then wf=1-wf      ; Space = Wireframe an/aus
   If KeyHit(2) Then m1=1-m1      ; 1 = Mesh 1 an/aus
   If KeyHit(3) Then m2=1-m2      ; 2 = Mesh 2 an/aus
   If KeyHit(4) Then m3=1-m3      ; 3 = Mesh 3 an/aus
   If KeyHit(5) Then m4=1-m4      ; 4 = Mesh 4 an/aus
   
   If m1 Then HideEntity mesh1 Else ShowEntity mesh1
   If m2 Then HideEntity mesh2 Else ShowEntity mesh2
   If m3 Then HideEntity mesh3 Else ShowEntity mesh3
   If m4 Then HideEntity mesh4 Else ShowEntity mesh4
   
   ; Maussteuerung
   PlayerControls()
   
   ; rendern
   WireFrame wf
   RenderWorld
   
   ; Infos ausgeben
   Text 0,0,"Tris: "+TrisRendered()+" FPS: "+FPS

   ; Bufferflip
   Flip 0

Wend

End

; Spielersteuerung
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)/8.0
   cam_yaw = cam_yaw + (targetyaw - cam_yaw)/8.0
   
   RotateEntity player,0,cam_yaw,0
   RotateEntity cam,cam_pitch,0,0

   If KeyDown(200) Then mvz=mvz+speed#         ; Pfeil rauf = vorwärts
   If KeyDown(208) Then mvz=mvz-speed#         ; Pfeil runter = rückwärts
   If KeyDown(205) Then mvx=mvx+speed#         ; Pfeil rechts = rechts
   If KeyDown(203) Then mvx=mvx-speed#         ; Pfeil links = links
   
   If MouseDown(1) Then mvy=mvy+speed#         ; LMB = nach oben
   If MouseDown(2) Then mvy=mvy-speed#         ; RMB = nach unten
      
   If KeyDown(17) Then mvz=mvz+speed#         ; W = vorwärts
   If KeyDown(31) Then mvz=mvz-speed#         ; S = rückwärts
   If KeyDown(30) Then mvx=mvx-speed#         ; A = links
   If KeyDown(32) Then mvx=mvx+speed#         ; D = rechts

   If KeyDown(16) Then mvy=mvy+speed#         ; Q = nach oben
   If KeyDown(18) Then mvy=mvy-speed#         ; E = nach unten
   
   TranslateEntity player,0,mvy,0
   MoveEntity player,mvx,0,mvz

   mvx=mvx/1.2
   mvy=mvy/1.2
   mvz=mvz/1.2
   
End Function

; Vertikale Begrenzung
Function ClampValue(Original#, low#, high#)
   If Original<low  Then Return low
   If Original>high Then Return high
   Return Original
End Function


; Meshterrain aus Heightmap laden, evt. Colormap und Shadowmap blenden
Function LoadMeshTerrain(hmap$,tmap$=0,lmap$=0)

   ; Heightmap laden
   temp = LoadImage(hmap$)
   If temp = 0 Then RuntimeError "Heightmap image "+hmap$+" does not exist." : Return 0
   
   ; Grösse speichern
   x = ImageWidth(temp)-1
   y = ImageHeight(temp)-1

   ; Colormap und Shadowmap laden
   tmap = LoadTexture(tmap$)
   lmap = LoadTexture(lmap$)
   
   ; und auf meshgrösse skalieren
   If tmap ScaleTexture tmap,x,y
   If lmap   ScaleTexture lmap,x,y

   ; Terrainmesh erstellen
   mesh = CreateMesh()
   surf = CreateSurface(mesh)

   ; Vertexe erstellen
   For ly = 0 To y
      For lx = 0 To x
         AddVertex surf,lx,0,ly,1.0/lx,1.0/ly
      Next
   Next
   RenderWorld
   
   ; Vertexe mit Faces verbinden
   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
   
   ; Terrain nach 0,0,0
   PositionMesh mesh,-x/2.0,0,-y/2.0

   ; Vertexhöhe richtet sich nach dem Rotanteil der Heightmap
   SetBuffer ImageBuffer(temp)
   LockBuffer ImageBuffer(temp)
   For lx = 0 To x
      For ly = 0 To y
      
         ; Rotanteil des Pixel auslesen
         h=(ReadPixelFast(lx,y-ly) And $ff0000)/$10000
         index = lx + ((x+1)*ly)
         VertexCoords surf,index,VertexX(surf,index),h/10.0,VertexZ(surf,index)

         ; Texturkoordinaten setzen
         VertexTexCoords surf,index,lx,-ly

      Next
   Next
   UnlockBuffer ImageBuffer(temp)
   SetBuffer BackBuffer()
   
   ; Normale updaten
   UpdateNormals mesh
   
   ; Colormap hinzufügen
   If tmap EntityTexture mesh,tmap,0,0
      
   ; Shadowmap hinzufügen
   If lmap EntityTexture mesh,lmap,0,1 : TextureBlend lmap,2
   
   ; Terrain übergeben
   Return Mesh
   
End Function

hectic

Sieger des IS Talentwettbewerb 2006

BeitragDi, Apr 24, 2007 20:30
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich vermute mal, dass du beim auslesen der Highmap folgendes machst:

Highmap mit einer Kantenlänge von 1024 Pixeln beim auslesen in 2 Teile X und 2 Teile Y.

Auslesen der Highmap nun für X1 von 0 bis 511 und für X2 von 512 bis 1023

Hier wird zwar rein rechnerisch nichts überrprungen, aber es findet keine Interpolation zwischen Pixel 511 und 512 statt. Daher müsste man es wie folgt machen:

Auslesen der Highmap nun für X1 von 0 bis 511 und für X2 von 511 bis ~1022

Hier würden dann die überlagerte Kanten die gleichen Maphöhe ergeben. Also die Vertices würden genau übereinander liegen.


Leider konnte ich den Code so auf die Schnelle nicht explizit darauf untersuchen, da ich selber noch reinsteigern müsste. Aber versuche mal, ob es daran liegt. Ansonsten schöne Arbeit. Sieht sehr gut aus.
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D
 

Krischan

BeitragDi, Apr 24, 2007 20:49
Antworten mit Zitat
Benutzer-Profile anzeigen
Den Hauptcode der Heightmap>Meshterrain-Umwandlung hab ich mir hier abgeschaut bzw. einfach kopiert - aber selbst visualisiert *hüstel*.

Interessant ist, dass das Rendern sauschnell ist, ich hab hier auf einem alten T30 mit Radeon 7500 (16MB) bei den max. 130.000 Tris noch 77FPS Smile Da brauch mir aber keiner mehr mit den ollen Blitzterrains um die Ecke kommen Wink

Was mich nur wundert sind diese minimalsten Höhenunterschiede bei den Nähten. Wenn ich eine rein schwarze Heightmap (also alles Level 0) verwende, gibt es diese gar nicht, seltsam (oder man sieht sie nur nicht). Vielleicht liegt es auch an der "Ungenauigkeit" von Blitz3D, was ja "nur" sechs(?) Stellen nach dem Komma berücksichtigt.

hectic

Sieger des IS Talentwettbewerb 2006

BeitragDi, Apr 24, 2007 20:55
Antworten mit Zitat
Benutzer-Profile anzeigen
Ne, die stellen hinter dem Komma reichen schon. Wenn du genau hinsiehst, dann wirst du feststellen, dass immer genau 1 Highmap-Pixel fehlt. Du musst auf jeden fall, die Highmap-Pixelreihe die du bei dem einem Mesh am Ende ausgelesen hast, beim nächsten nochmal auslesen. Die Nahtstellen müssen also bei jedem benachbartem Mesh auch mit rein. Bei Schrägen kannst du das genau erkennen, dass immer genau eine Stufe fehlt.
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D
 

Krischan

BeitragMi, Apr 25, 2007 12:02
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich weiss jetzt woran es liegt. Wenn man die Tileränder der Heightmap mal mit einer Farbpipette vergleicht, dann sieht man, dass es dort minimalste Unterschiede in der Helligkeit gibt. Das kommt davon, wenn man Heightmaps resized, trotz bilinearem Filter.

Die Lösung: Nach dem Resize einfach die gegenüberliegenden Kanten so überblenden, dass sich die Farben auf dem Pixelrand gleichen, der Code oben ist also völlig in Ordnung, klappt sogar mit "geraden" Heightmaps. Den Code hab irgendwo her, weiss aber nicht mehr genau wo der dabei war.

Aufruf: MakeSeamless(image,1)

,1 = 1 Pixel am Rand überblenden

Code: [AUSKLAPPEN]
Function MakeSeamless(Image,Intensity#,Horizontal=True,Vertical=True,Method#=0.5,Variance#=0.0)
   Local Width,Height
   Local Border

   ;Set up the image
   WriteBuff=ImageBuffer(Image)
   Width=ImageWidth(Image)-1
   Height=ImageHeight(Image)-1
   
   Border=((Width+Height)/2)*Intensity/2
   Border2=((Width+Height)/2)*Method/2
   
   ;Lock the buffer
   LockBuffer WriteBuff
   
   ;Make seamless
   If Horizontal Then
   For x=0 To Border
      x2=Width-x
      p#=Float(x)/Float(Border)
      p2#=Float(x)/Float(Border2)
      If p2>1 Then p2=1
      For y=1 To Height
         clr1=ReadPixelFast(x2,y,WriteBuff)
         clr2=ReadPixelFast(x,y,WriteBuff)
         r1=clr1 Shr 16 And $FF:g1=clr1 Shr 8 And $FF:b1=clr1 And $FF
         r2=clr2 Shr 16 And $FF:g2=clr2 Shr 8 And $FF:b2=clr2 And $FF
         
         ;Color filter
         rc=(r1-r2)*(1-p)
         gc=(g1-g2)*(1-p)
         bc=(b1-b2)*(1-p)
         
         If y=0 Then frc#=rc:fgc#=gc:fbc#=bc

         frc#=frc#+Variance*(rc-frc)
         fgc#=fgc#+Variance*(gc-fgc)
         fbc#=fbc#+Variance*(bc-fbc)
         If r2+frc>255 Then frc=255-r2
         If g2+fgc>255 Then fgc=255-g2
         If b2+fbc>255 Then fbc=255-b2
         If r2+frc<0 Then frc=0-r2
         If g2+fgc<0 Then fgc=0-g2
         If b2+fbc<0 Then fbc=0-b2
         
         r2=r2+frc
         g2=g2+fgc
         b2=b2+fbc
         
         ;Clone filter
         r2=(1-p2)*r1+p2*r2
         g2=(1-p2)*g1+p2*g2
         b2=(1-p2)*b1+p2*b2
         
         If r2<0 Then r2=0
         If r2>255 Then r2=255
         If g2<0 Then g2=0
         If g2>255 Then g2=255
         If b2<0 Then b2=0
         If b2>255 Then b2=255
         
         clr2=(r2 Shl 16)+(g2 Shl 8)+(b2)
         WritePixelFast(x,y,clr2,WriteBuff)
      Next
      
   Next
   End If
   If Vertical Then
   For y=0 To Border
      y2=Height-y
      p#=Float(y)/Float(Border)
      p2#=Float(y)/Float(Border2)
      If p2>1 Then p2=1
      For x=0 To Width
         clr1=ReadPixelFast(x,y2,WriteBuff)
         clr2=ReadPixelFast(x,y,WriteBuff)
         r1=clr1 Shr 16 And $FF:g1=clr1 Shr 8 And $FF:b1=clr1 And $FF
         r2=clr2 Shr 16 And $FF:g2=clr2 Shr 8 And $FF:b2=clr2 And $FF
         
         ;Color filter
         rc=(r1-r2)*(1-p)
         gc=(g1-g2)*(1-p)
         bc=(b1-b2)*(1-p)
         
         If x=0 Then frc#=rc:fgc#=gc:fbc#=bc
         
         frc#=frc#+Variance*(rc-frc)
         fgc#=fgc#+Variance*(gc-fgc)
         fbc#=fbc#+Variance*(bc-fbc)
         If r2+frc>255 Then frc=255-r2
         If g2+fgc>255 Then fgc=255-g2
         If b2+fbc>255 Then fbc=255-b2
         If r2+frc<0 Then frc=0-r2
         If g2+fgc<0 Then fgc=0-g2
         If b2+fbc<0 Then fbc=0-b2
         
         r2=r2+frc
         g2=g2+fgc
         b2=b2+fbc
         
         ;Clone filter
         r2=(1-p2)*r1+p2*r2
         g2=(1-p2)*g1+p2*g2
         b2=(1-p2)*b1+p2*b2

         clr2=(r2 Shl 16)+(g2 Shl 8)+(b2)
         WritePixelFast(x,y,clr2,WriteBuff)
      Next
      
   Next
   End If
   
   ;Unlock the buffer
   UnlockBuffer WriteBuff
End Function


Die Performance ist übrigens oberklasse, ich hab einfach mal dutzende Maps plaziert und das auf meinem Desktop (P4 3.2, Radeon 9800Pro) laufen lassen, bei 2.6 Millionen Tris waren es noch 20FPS Smile Und da ist noch viel Raum für Optimierung (es wurden ja alle gleichzeitig angezeigt) Smile

hectic

Sieger des IS Talentwettbewerb 2006

BeitragMi, Apr 25, 2007 17:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Das mit dem korrigieren der Highmap, hast du nichts anderes gemacht, als mein Vorschlag 'zu Fuss' zu erledigen. Bei jeder Highmap musst du nun eine manuelle Korrektur durchführen.

Die Performence ist gut, aber ich finde sie nicht so ganz oberklasse, da sie bei mir bis auf 90 FPS runter gegangen ist. Da sollte auf jeden Fall noch was gemacht werden, meiner Meinung nach. Sonst hat man kaum noch Raum für andere Sachen.
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D
 

Krischan

BeitragDo, Apr 26, 2007 14:26
Antworten mit Zitat
Benutzer-Profile anzeigen
So, ich habe das Ganze noch einmal weiterentwickelt, das Ergebnis habe ich mal "Monkey Island" genannt, weil es mich so an die Draufsicht im gleichnamigen Spiel erinnert.

Download mit Source

Screenshot:
user posted image

Der jetzige Code kann aus einer 256x256 Pixel grossen Heightmap eigenständig ein Meshterrain erstellen, welches dann aus 32x32 = 1024 einzelnen Tiles besteht (ca. 131.000 Tris). Zudem erstellt es aus zwei separaten 2048x2048 Pixel grossen Grafiken (Colormap / Lightmap) je 1024 Texturen (à 64x64), die dann auf die entsprechenden Meshterrains geblendet werden.

@hectic: Der Trick mit den Nahtstellen war übrigens hier, 9x9 anstatt 8x8 Pixel grosse Blöcke aus der Heightmap zu nehmen... Passt halt nur nicht ganz genau mit den UV-Koordinaten zusammen (sieht man aber nur, wenn man nah rangeht, ausserdem siehts durch die JPEG-Kompression der Colormap noch schlimmer aus).

Steuerung:
  • Pfeiltasten oder WASD = Bewegung
  • LMB/RMB oder QE = rauf/runter
  • F1 = Wireframe an/aus
  • Return = Übersichtskarte an/aus
  • Bild rauf = Sichtweite höher
  • Bild runter = Sichtweiter niedriger

Das Ding ist nicht perfekt und ich bin ehrlich gesagt überhaupt froh, dass es so einigermassen aussieht. Grosser Nachteil im Moment sind fehlendes Culling und ein merkwürdiger UV-Fehler an den Nahtstellen (da blendet die Textur nicht so 100% über, eher zu 99.9%).

Durch das fehlende Culling und die vielen Texturen sind die FPS jetzt auch etwas in den Keller gegangen. Wie könnte man hier ein sinnvolles Culling realisieren oder das Ganze noch weiter optimieren? Ich erinnere mich da an meine Mapperzeit im Radiant, da gab es doch sowas wie VIS-Blöcke oder PVS? Ich hab keine Ahnung wie man das umsetzen könnte, evt. irgendwie vorberechnet vielleicht?

Wie schnell läuft das bei Euch? Ich hab hier ca. 45FPS bei 128 Sichtweite und ca. 40.000 Tris im Schnitt.

Code: [AUSKLAPPEN]
; Meshterrain Demo
; Version 1.0
;
; 3D-Flug über eine virtuelle Insel (einfach mal Monkey Island genannt)
; by Krischan
;
; - erstellt ein 32x32=1024 Tiles grosses nahtloses Meshterrain aus einer 256x256 Heightmap
; - zerteilt je eine 2048x2048 Bild in 1024 Texturen und blendet die Color/Lightmap auf jedes Tile
; - Culling nicht implementiert
; - leichte UV-Fehler an den Nahtstellen
;
; Texturen und Heightmap generiert mit Large 3D Terrain SE 2.5 (http://www.bundysoft.com/L3DT)

; Grafikmodus
Graphics3D 1024,768,32,1
SetBuffer FrontBuffer()

; Felder dimensionieren
Dim hm(32,32),cm(32,32),lm(32,32),tile(32,32)

; Pivot für Steuerung und globale Variablen
Global cam, player
Global cam_pitch#, cam_yaw#
Global mvx#,mvy#,mvz#,targetpitch#,targetyaw#

; Einstellungen
Global speed#=0.00981      ; Laufgeschwindigkeit
Global sw=256            ; Standardsichtweite (32-1024)
Global sm=1               ; Karte anfangs anzeigen
Global abstand#=1.00      ; 1.00 = nahtlos, z.B. 1.01 für Anzeige der Tiles

; Playerpivot
player=CreatePivot()
PositionEntity player,129,20,-223
EntityType player,1
EntityRadius player,1

; Kamera an Pivot gehängt
cam=CreateCamera(player)
PositionEntity cam,0,0,0
CameraZoom cam,1
CameraRange cam,0.01,sw
AmbientLight 255,255,255

; Nebel
CameraFogMode cam,True
CameraFogRange cam,0,sw
CameraFogColor cam,50,100,150
CameraClsColor cam,50,100,150

; nur Pixelresize
TFormFilter 0

; Bilder einlesen
Print "Lade Heightmap..."      : hmap=LoadImage("heightmap.png")
Print "Lade Colormap..."      : cmap=LoadImage("colormap.jpg")
Print "Lade Lightmap..."      : lmap=LoadImage("lightmap.jpg")

; Leere Texturen erstellen
Print "Erstelle Texturen..."
For x=1 To 32

   For y=1 To 32

      cm(x,y)=CreateTexture(64,64,1+16+32)   ; leuchtend, UV-Koordinaten fest
      lm(x,y)=CreateTexture(64,64,1+16+32)   ; leuchtend, UV-Koordinaten fest
      hm(x,y)=CreateImage(9,9)            ; Meshtile 9x9

   Next

Next

; Heightmap in 9x9 grosse Stücke zerteilen
Print "Zerschneide Heightmap..."
For y=8 To 256 Step 8

   For x=8 To 256 Step 8

      CopyRect(x-8,y-8,9,9,0,0,ImageBuffer(hmap),ImageBuffer(hm(x/8,y/8)))

   Next

Next

; Colormap und Lightmap als Texturteil für jedes Meshtile aus den Bildern herauskopieren
Print "Zerschneide Colourmap and Lightmap..."
For y=64 To 2048 Step 64

   For x=64 To 2048 Step 64

      CopyRect(x-64,y-64,64,64,0,0,ImageBuffer(cmap),TextureBuffer(cm(x/64,y/64)))
      CopyRect(x-64,y-64,64,64,0,0,ImageBuffer(lmap),TextureBuffer(lm(x/64,y/64)))

   Next

Next

; Colormap für spätere Ausgabe skalieren
ResizeImage cmap,256,256

; und nicht benötigte Grafiken löschen
FreeImage(hmap)
FreeImage(smap)

; Meshterrain erzeugen und positionieren
For x=0 To 256-8 Step 8

   For y=0 To -256+8 Step -8

      tx=1+Abs(x)/8 : ty=1+Abs(y)/8
      
      ; Hauptfunktion: aus dem 9x9 Heightmaptile ein 8x8 Meshtile erzeugen
      tile(tx,ty)=LoadMeshTerrain(hm(tx,ty),cm(tx,ty),lm(tx,ty))
      PositionEntity tile(tx,ty),x*abstand#,0,y*abstand#
      EntityType tile(tx,ty),2

   Next
Next

; Mauszeiger in die Mitte
MoveMouse GraphicsWidth()/2,GraphicsHeight()/2

; Hauptschleife
While Not KeyHit(1)

   ; FPS counter
   FPS_C=FPS_C+1
   If ms<MilliSecs()
      ms=MilliSecs()+1000
      FPS=FPS_C
      FPS_C=0
   EndIf
   
   ; Zusatztasten
   If KeyHit(59) Then wf=1-wf      ; Space = Wireframe an/aus
   If KeyHit(28) Then sm=1-sm      ; Return = Map an/aus
   If KeyHit(201) Then sw=sw+32   ; Bild rauf = Sichtweite höher
   If KeyHit(209) Then sw=sw-32   ; Bild rauf = Sichtweite höher
   
   ; Sichtweite begrenzen
   If sw<32 Then sw=32
   If sw>1024 Then sw=1024
      
   ; Maussteuerung
   PlayerControls()

   ; Position des Players berechnen
   plx#=EntityX(player) : ply#=EntityY(player) : plz#=EntityZ(player)

   ; Spielfeld begrenzen   
   If plx#<5 Then plx#=5
   If plx#>250 Then plx#=250
   If plz#>5 Then plz#=5
   If plz#<-250 Then plz#=-250

   ; ein wenig Schwerkraft simulieren
   ply#=ply#-(speed#*10)
   
   ; Spieler neu positionieren
   PositionEntity player,plx#,ply#,plz#
   
   ; Sichtweite anpassen
   CameraRange cam,0.01,sw
   CameraFogRange cam,0,sw

   ; Kollisionen überprüfen
   Collisions 1,2,2,2      

   ; Rendern
   WireFrame wf
   UpdateWorld
   RenderWorld
   
   ; Infos ausgeben
   Color 255,255,255
   Text 0,0,"Tris: "+TrisRendered()+"   FPS: "+FPS+"   Sichtweite: "+sw+"   Wireframe: "+wf
   
   ; Karte zeigen und Player auf Map als roten Punkt einzeichnen
   If sm Then

      Color 0,0,0
      Rect 0,15,256,256,1

      DrawImage cmap,0,15

      Color 255,255,255
      Text 0,15,"X:"+Int(plx#)+" Y:"+Int(ply#)+" Z:"+Int(plz#)

      Color 255,0,0
      Oval(plx#-1,15+Abs(plz#)-1,3,3,1)
      
   EndIf

   ; Bufferflip
   Flip

Wend

End

; Spielersteuerung
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

   If KeyDown(200) Then mvz=mvz+speed#         ; Pfeil rauf = vorwärts
   If KeyDown(208) Then mvz=mvz-speed#         ; Pfeil runter = rückwärts
   If KeyDown(205) Then mvx=mvx+speed#         ; Pfeil rechts = rechts
   If KeyDown(203) Then mvx=mvx-speed#         ; Pfeil links = links
   
   If MouseDown(1) Then mvy=mvy+speed#         ; LMB = nach oben
   If MouseDown(2) Then mvy=mvy-speed#         ; RMB = nach unten
      
   If KeyDown(17) Then mvz=mvz+speed#         ; W = vorwärts
   If KeyDown(31) Then mvz=mvz-speed#         ; S = rückwärts
   If KeyDown(30) Then mvx=mvx-speed#         ; A = links
   If KeyDown(32) Then mvx=mvx+speed#         ; D = rechts

   If KeyDown(16) Then mvy=mvy+speed#         ; Q = nach oben
   If KeyDown(18) Then mvy=mvy-speed#         ; E = nach unten
   
   TranslateEntity player,0,mvy,0
   MoveEntity player,mvx,0,mvz

   mvx=mvx/1.05
   mvy=mvy/1.05
   mvz=mvz/1.05
   
End Function

; Vertikale Begrenzung
Function ClampValue(Original#, low#, high#)
   If Original<low  Then Return low
   If Original>high Then Return high
   Return Original
End Function


; Meshterrain aus Heightmap laden, evt. Colormap und Shadowmap blenden
Function LoadMeshTerrain(heightmap,colormap=False,lightmap=False)

   ; Grösse speichern
   x = ImageWidth(heightmap)-1
   y = ImageHeight(heightmap)-1

   ; Textur auf Meshgrösse skalieren
   If colormap ScaleTexture colormap,x,y
   If lightmap   ScaleTexture lightmap,x,y

   ; Terrainmesh erstellen
   mesh = CreateMesh()
   surf = CreateSurface(mesh)

   ; Vertexe erstellen
   For ly = 0 To y

      For lx = 0 To x

         AddVertex surf,lx,0,ly,1.0/lx,1.0/ly

      Next

   Next

   ; Vertexe mit Faces verbinden
   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
   
   ; Terrain nach 0,0,0
   PositionMesh mesh,-x/2.0,0,-y/2.0

   ; Vertexhöhe richtet sich nach dem Rotanteil der Heightmap
   SetBuffer ImageBuffer(heightmap)
   LockBuffer ImageBuffer(heightmap)
   For lx = 0 To x
      For ly = 0 To y
      
         ; Rotanteil des Pixel auslesen
         h=(ReadPixelFast(lx,y-ly) And $ff0000)/$10000
         index = lx + ((x+1)*ly)
         VertexCoords surf,index,VertexX(surf,index),h/8.0,VertexZ(surf,index)

         ; Texturkoordinaten setzen
         VertexTexCoords surf,index,lx,y-ly


      Next
   Next
   UnlockBuffer ImageBuffer(heightmap)
   SetBuffer BackBuffer()
   
   ; Normale updaten
   UpdateNormals mesh
   
   ; Colormap hinzufügen
   If colormap EntityTexture mesh,colormap,0,0
      
   ; Shadowmap hinzufügen
   If lightmap EntityTexture mesh,lightmap,0,1 : TextureBlend lightmap,2
   
   ; Terrain übergeben
   Return Mesh
   
End Function
 

martin_moehler

BeitragDi, Sep 25, 2007 21:55
Antworten mit Zitat
Benutzer-Profile anzeigen
Also bei den Standarteinstellung komm ich grad ma auf 25 FPS!
Auch wenn ich dazu sagen muss da meine Hardware schon leicht veraltet ist.
aber 25 FPS... is nich viel!! Sad

Aber sieht echt geil aus!!
 

Moses

BeitragDo, Sep 27, 2007 12:14
Antworten mit Zitat
Benutzer-Profile anzeigen
finds ziehmlich gut bis jetzt, fps gehen bei nem 1,4 er k7 mit ner g4ti auf 18 runter ... bei 130000 tris (kartenecke)

mit den kanten die manchmal nicht sauber abschliessen, man könnte man doch die werte der von den vertexen von der kante des benachbarten tiles gleich fürs nächste verwenden, anstatt sie nochmal von der higmap zu lesen, oder du gehtst alle kanten nochmal durch und 'snappst' die vertexe aufeinander...

mit den textur-nähten bin ich aber auch überfordert, so nach 100 einheiten fällt es ja weniger auf aber davor isses übel Sad

zur performanceoptimierung währe es wünschenswert tiles die von anderen komplett verdeckt werden auch gleich mal auszublenden ...

dazu könnte man:
- den winkel des vektors von der cam zum höchstem vertex des zu prüfenden tile (dafür ymax-koordinaten für jedes tile hinterlegen) ermitteln
- mit den winkeln der vektoren von der cam zu den niedrigsten vertexes der tiles die davor liegen vergleichen (hierfür ymin-koordinaten für jedes tile hinterlegen) ...

user posted image

die grafik verdeutlicht das nochmal, und der enscheidungsfall wenn beide zuvergleichende koordinaten dieselben sind bzw, die winkel gleich ist auch einleuchtend, ob sich der rechenaufand lohnt kommt darauf an wie deatailiert die tiles sind und wie viele tiles du hast... aso landschaftreflektionen auf wasserflächen oder spiegelde objekte fällt damit natürlich flach...

... hoffe das war jetzt kein bockmist ^^
 

Dreamora

BeitragDo, Sep 27, 2007 16:29
Antworten mit Zitat
Benutzer-Profile anzeigen
Das wird wohl immer soweit runter gehen.
Die Menge an Surfaces und das fehlende Geomipmapping erzeugen hier einen gigantischen Overhead für die Grafikkarte.

Da schon vor jahren mit P4 1.5 Ghz und GeForce 4MX 500'000 Polygon Terrains (also 500'000 sichtbar!) mit bedeutend grösseren Texturen und grösseren Heightmaps möglich waren, ohne das man Sichtbarkeitschecks eingebaut hat (bei 20FPS), denke ich, dass hier noch einiges optimiert werden kann.

Der Haupttrick besteht da drin, dafür zu sorgen, dass die Anzahl Blöcke des Terrains und die Anzahl Polygone (Vertices pro Kantenrichtung) in ein gescheites Verhältnis kommen.

Gut sind hier normalerweise Terrainblöcke mit einer 32x32 Unterteilung. Dadurch hat man normalerweise nicht zuviele Polygone, so das die Grafikkarte durch den Wechsel der Tiles beeinträchtigt wird, noch hat man zuviele Surfaces was bei 8 und 16 zu einem massiven Problem wird, denn mehr als 800-1200 Surfaces kann man nicht haben im ganzen, deswegen soll und darf man die unter keinen umständen mit dem Terrain auch nur im Ansatz erreichen.
Ihr findet die aktuellen Projekte unter Gayasoft und könnt mich unter @gayasoft auf Twitter erreichen.
  • Zuletzt bearbeitet von Dreamora am Do, Sep 27, 2007 19:08, insgesamt einmal bearbeitet

hectic

Sieger des IS Talentwettbewerb 2006

BeitragDo, Sep 27, 2007 17:23
Antworten mit Zitat
Benutzer-Profile anzeigen
Kann Dreamora schonmal Recht geben. Habe vorgestern selbst mal ein Meshterrain erstellt, um zu testen wie ich es so hinbekomme. Bis jetzt läuft mein Meshterrain so etwa doppelt so schnell (etwa gleiche Anzahl Triangles, gleiche Quelldateien) auf meinem System. Ich habe Tileblöcke von 64x64 (65x65 Vertices, 64x64 Quads) erstellt.
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D

Neue Antwort erstellen


Übersicht BlitzBasic Blitz3D

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group