Voxelrenderer für Terrains

Übersicht BlitzBasic Codearchiv

Neue Antwort erstellen

Noobody

Betreff: Voxelrenderer für Terrains

BeitragSo, Apr 26, 2009 22:44
Antworten mit Zitat
Benutzer-Profile anzeigen
Als kleines Sonntagsprojekt habe ich mich daran gemacht, einen kleinen Voxelrenderer zu schreiben.

In einem Voxelrenderer bestehen die Objekte, anders als in einem Rasterizer, aus einzelnen Voxeln, die eigentlich nichts anderes als kleine Würfel sind (Voxel = Volumetric Pixel). Es werden also nicht Dreiecke gezeichnet, sondern dreidimensionale Pixel.

Voxelrenderer wurden in früheren Spielen eingesetzt, als noch nicht von 3D - Hardwarebeschleunigung ausgegangen werden konnte. In letzter Zeit sind sie wieder am kommen (unter anderem Crysis verwendete Voxelrendering für die Terrains).

Meine Version ist relativ simpel gehalten, um noch einigermassen flüssig zu laufen (B3D ist halt nicht die schnellste Sprache) und beschränkt sich ausserdem nur auf Terrains.
Das Terrain ist relativ niedrig aufgelöst und sieht daher sehr retro aus:

user posted image

Die Konstanten im Code sind relativ selbsterklärend: ANGLEOFVIEW beschreibt, wie gross der Sichtwinkel ist (bei grossen Zahlen sieht man mehr, allerdings ist alles sehr gequetscht), STEPSIZE bestimmt, wie genau gerendert werden soll (je kleiner, desto genauer, allerdings auch langsamer) und DIST_NEAR und DIST_FAR beschreiben die Sichtweite der Kamera, ungefähr gleich wie die Parameter bei CameraRange von B3D. Je geringer die Sichtweite ist, desto schneller wird gerendert, aber man sieht dann halt auch weniger.

Der Code: BlitzBasic: [AUSKLAPPEN]
Const GWIDTH = 800
Const GHEIGHT = 600

Graphics GWIDTH, GHEIGHT, 0, 2
SetBuffer BackBuffer()

Const ANGLEOFVIEW = 60
Const CASTINGSTEP# = ANGLEOFVIEW/Float( GWIDTH )
Const DIST_NEAR = 1
Const DIST_FAR = 196
Const STEPSIZE# = 0.8

Dim HeightMap( 0, 0 )
Dim MapColor( 0, 0 )
Dim YBuffer( GWIDTH - 1 )

Global CamX# = 106, CamY# = 200, CamHeight# = 0, CamAngle# = -37, CamScale# = 1, ScaleY# = 200
Global MapWidth, MapHeight, Interpolate = True

LoadHeightMap( "Heightmap2.png" )
LoadColorMap( "Albedo.jpg" )

Timer = CreateTimer( 60 )

While Not KeyHit( 1 )
Cls

LockBuffer BackBuffer()
RenderMap()
UnlockBuffer BackBuffer()

UserInput()

Flip 0
WaitTimer Timer
Wend
End

Function UserInput()
CamX# = CamX# + Cos( CamAngle# )*( KeyDown( 200 ) - KeyDown( 208 ) )
CamY# = CamY# - Sin( CamAngle# )*( KeyDown( 200 ) - KeyDown( 208 ) )

CamHeight# = 500
If CamX# >= 0 And CamX# < MapWidth Then
If CamY# >= 0 And CamY# < MapHeight Then
CamHeight# = HeightMap( CamX#, CamY# ) + 500
EndIf
EndIf

CamAngle# = CamAngle# + KeyDown( 205 ) - KeyDown( 203 )

Interpolate = Interpolate Xor KeyHit( 57 )
End Function

Function LoadHeightMap( Path$ )
Image = LoadImage( Path$ )

If Image Then
MapWidth = ImageWidth( Image )
MapHeight = ImageHeight( Image )

Dim HeightMap( MapWidth - 1, MapHeight - 1 )

LockBuffer ImageBuffer( Image )
For X = 0 To MapWidth - 1
For Y = 0 To MapHeight - 1
HeightMap( X, Y ) = ( ReadPixelFast( X, Y, ImageBuffer( Image ) ) And $FF )*ScaleY#
Next
Next

FreeImage Image
Else
RuntimeError "Heightmap does not exist!"
EndIf
End Function

Function LoadColorMap( Path$ )
Image = LoadImage( Path$ )

If Image Then
Dim MapColor( MapWidth - 1, MapHeight - 1 )

LockBuffer ImageBuffer( Image )
For X = 0 To MapWidth - 1
For Y = 0 To MapHeight - 1
MapColor( X, Y ) = ReadPixelFast( X, Y, ImageBuffer( Image ) ) And $FFFFFF
Next
Next

FreeImage Image
Else
RuntimeError "Colormap does not exist!"
EndIf
End Function

Function RenderMap()
For X = 0 To GWIDTH - 1
Angle# = -ANGLEOFVIEW/2 + X*CASTINGSTEP# + CamAngle#

VX# = Cos( Angle# )
VY# = -Sin( Angle# )

XStart# = CamX# + VX#*DIST_NEAR
YStart# = CamY# + VY#*DIST_NEAR
XEnd# = CamX# + VX#*DIST_FAR
YEnd# = CamY# + VY#*DIST_FAR

TraceHeightMap( XStart#, YStart#, XEnd#, YEnd#, X )
Next

Dim YBuffer( GWIDTH - 1 )
End Function

Function TraceHeightMap( StartX#, StartY#, EndX#, EndY#, Column )
DX = EndX# - StartX#
DY = EndY# - StartY#

ADX = Abs( DX )
ADY = Abs( DY )

SDX = Sgn( DX )
SDY = Sgn( DY )

If ADX > ADY Then
PDX = SDX
PDY = 0

DDX = SDX
DDY = SDY
ErrorFast = ADY
ErrorSlow = ADX
Else
PDX = 0
PDY = SDY
DDX = SDX
DDY = SDY
ErrorFast = ADX
ErrorSlow = ADY
EndIf

X# = StartX#
Y# = StartY#

Error# = ErrorSlow/2

For i = 1 To ErrorSlow/STEPSIZE
Error = Error - ErrorFast*STEPSIZE

If Error < 0 Then
Error = Error + ErrorSlow*STEPSIZE

X = X + DDX*STEPSIZE
Y = Y + DDY*STEPSIZE
Else
X = X + PDX*STEPSIZE
Y = Y + PDY*STEPSIZE
EndIf

If X >= 0 And X < MAPWIDTH Then
If Y >= 0 And Y < MAPHEIGHT Then
Z# = Sqr( ( X - CamX# )*( X - CamX# ) + ( Y - CamY# )*( Y - CamY# ) )

If Interpolate Then
Height# = ( HeightMap( Int( X# - 0.5 ), Int( Y# - 0.5 ) ) + HeightMap( Int( X# + 0.5 ), Int( Y# - 0.5 ) ) + HeightMap( Int( X# - 0.5 ), Int( Y# + 0.5 ) ) + HeightMap( Int( X# + 0.5 ), Int( Y# + 0.5 ) ) )/4.
ProjY# = ( Height# - CamHeight# )*CamScale#/Z# + GHEIGHT/2
Else
ProjY# = ( HeightMap( X, Y ) - CamHeight# )*CamScale#/Z# + GHEIGHT/2
EndIf

If ProjY# > YBuffer( Column ) Then
If Interpolate Then
R = ( ( MapColor( Int( X# - 0.5 ), Int( Y# - 0.5 ) ) Shr 16 ) + ( MapColor( Int( X# + 0.5 ), Int( Y# - 0.5 ) ) Shr 16 ) + ( MapColor( Int( X# - 0.5 ), Int( Y# + 0.5 ) ) Shr 16 ) + ( MapColor( Int( X# + 0.5 ), Int( Y# + 0.5 ) ) Shr 16 ) )/4
G = ( ( ( MapColor( Int( X# - 0.5 ), Int( Y# - 0.5 ) ) Shr 8 ) And $FF ) + ( ( MapColor( Int( X# + 0.5 ), Int( Y# - 0.5 ) ) Shr 8 ) And $FF ) + ( ( MapColor( Int( X# - 0.5 ), Int( Y# + 0.5 ) ) Shr 8 ) And $FF ) + ( ( MapColor( Int( X# + 0.5 ), Int( Y# + 0.5 ) ) Shr 8 ) And $FF ) )/4
B = ( ( MapColor( Int( X# - 0.5 ), Int( Y# - 0.5 ) ) And $FF ) + ( MapColor( Int( X# + 0.5 ), Int( Y# - 0.5 ) ) And $FF ) + ( MapColor( Int( X# - 0.5 ), Int( Y# + 0.5 ) ) And $FF ) + ( MapColor( Int( X# + 0.5 ), Int( Y# + 0.5 ) ) And $FF ) )/4
Color R, G, B
Else
Color MapColor( X, Y ) Shr 16, ( MapColor( X, Y ) Shr 8 ) And $FF, MapColor( X, Y ) And $FF
EndIf

Line Column, GHEIGHT - ProjY#, Column, GHEIGHT - YBuffer( Column )
YBuffer( Column ) = ProjY#
EndIf
EndIf
EndIf
Next
End Function

Gesteuert wird mit den Pfeiltasten, mit der Leertaste lässt sich ausserdem die Interpolation ein- und ausschalten (standardmässig an, ohne ist es aber schneller).

Damit das Ganze einigermassen gut aussieht, verwende ich eine Heightmap und eine Textur für das Terrain - entweder sucht man sich selber entsprechende Grafiken, oder man nimmt dieselben, die ich verwendet habe:
Download
Das Paket enthält ausserdem noch eine .exe, damit man es direkt testen kann.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

AnniXa

BeitragSo, Apr 26, 2009 23:37
Antworten mit Zitat
Benutzer-Profile anzeigen
... also sowas als sontagsprojekt :O ich hätte für sowas 3 wochen gebraucht und es wäre nicht so toll.
|moonForge|
Ich bin Pokémon Meisterin seit 1998!

kriD

BeitragMo, Apr 27, 2009 0:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Noobody is ja auch highskilled, wie man sieht! (nicht falsch verstehen, AnniXa.)

richtig krass das ding.. ob man damit geschwindigkeit gegenüber normalem rendering rausholen kann?

lg kriD
Wenn ich du wäre, wäre ich lieber ich!

ozzi789

BeitragMo, Apr 27, 2009 8:05
Antworten mit Zitat
Benutzer-Profile anzeigen
OMFG
Sieht ja so was von cool aus Cool

Blicke den Code nicht ganz durch, werd aber da mal fps messen, interessiert mich ^^
0x2B || ! 0x2B
C# | C++13 | Java 7 | PHP 5

Nicdel

BeitragMo, Apr 27, 2009 13:12
Antworten mit Zitat
Benutzer-Profile anzeigen
Genialer Retro-Style! Man glaubt gar nicht, dass das nur 2D ist.

Edit: Läuft bei mir aber grad mal mit 10 FPS...
Desktop: Intel Pentium 4 2650 Mhz, 2 GB RAM, ATI Radeon HD 3850 512 MB, Windows XP
Notebook: Intel Core i7 720 QM 1.6 Ghz, 4 GB DDR3 RAM, nVidia 230M GT, Windows 7
  • Zuletzt bearbeitet von Nicdel am Mo, Apr 27, 2009 18:18, insgesamt einmal bearbeitet

Blackside

BeitragMo, Apr 27, 2009 18:15
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich komm einfach nicht über das: "als kleines Sonntagsprojekt" weg :O
Du hast aber auch ganz schön viele kleine Sonntagsprojekte oder?(Im Codearchiv wimmelts nur so von deinen Codes Razz)
Aber dazu muss man natürlich sagen: Tolle Leistung! Very Happy
Hier sollte eigentlich eine Signatur stehen!

Chrise

BeitragMo, Apr 27, 2009 18:16
Antworten mit Zitat
Benutzer-Profile anzeigen
Sehr geiles Ergebnis, auch wenn mir grad nicht einfallen würde, für was ich sowas brauchen sollte. Aber für Leute die Retro-sytle Games machen wollen, gibt es nichts besseres ^^
Llama 1 Llama 2 Llama 3
Vielen Dank an Pummelie, der mir auf seinem Server einen Platz für LlamaNet bietet.

MikeDee

BeitragMo, Apr 27, 2009 18:36
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich wünschte mir, ich könnte das auch -.-
Zitat:
auch wenn mir grad nicht einfallen würde, für was ich sowas brauchen sollte. Aber für Leute die Retro-sytle Games machen wollen, gibt es nichts besseres

Wenn du die Voxel kleiner machst, z.B. auf Pixelgröße^^, dann kannst du auch solche Ergebnisse bekommen
http://www.youtube.com/watch?v=VpEpAFGplnI
dafür braucht man dann auch keine 3D-Karte und muss das ganze nicht mit einer Textur hinterlegen, sondern kann jedes Voxel einzeln Färben. So hab ich das ganze jedenfalls noch in erinnerung^^
Nicht wenige benutzen die Anonymität des Internets um berühmt zu werden.

Eingeproggt

BeitragMo, Apr 27, 2009 18:51
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich blick den Code auch nicht wirklich aber hab ne voreilige Frage (Die sich am Ende vlt als dumm herausstellt aber es interessiert mich grad):
Warum zeichnest du mit Line? Deine Voxels sind doch alles Rechtecke? Oder hast es mit Rect schon getestet und wars dann aus welchem Grund auch immer langsamer?
EDIT: Achso, das wird "Pixelspaltenweise" berechnet... Aber wär n Test mit Rect iwie möglich / sinnvoll?

Ach bevor ichs vergesse: Trotz hohen Ressourcenanforderungen absolut faszinierend.
Gewinner des BCC 18, 33 und 65 sowie MiniBCC 9

Noobody

BeitragMo, Apr 27, 2009 19:01
Antworten mit Zitat
Benutzer-Profile anzeigen
MikeDee hat Folgendes geschrieben:
Wenn du die Voxel kleiner machst, z.B. auf Pixelgröße^^, dann kannst du auch solche Ergebnisse bekommen
http://www.youtube.com/watch?v=VpEpAFGplnI

Hehe, das ist dann doch etwas ausser Reichweite Wink
Der Code ist ja explizit auf Terrains ausgelegt, um jede Menge Voxel einzusparen, ausserdem ist die Kamerabewegung limitiert auf X, Y, Z und Drehung um die Y - Achse.
Im Video kann man sich aber um alle Achsen drehen, ausserdem handelt es sich um ein komplexes Objekt und nicht so etwas einfaches wie ein Terrain.
Um so etwas hinzubekommen, muss man massiv optimieren - wie der Titel schon sagt, wird das per Octrees erledigt.

Dieser Renderer war ausserdem mal im c't und ist ungeheuer komplex - dass ich mit B3D so etwas hinbekommen würde, ist relativ unwahrscheinlich Razz

Eingeproggt hat Folgendes geschrieben:
Warum zeichnest du mit Line? Deine Voxels sind doch alles Rechtecke?

Wenn man den Buffer vor dem zeichnen sperrt (LockBuffer), sind Lines unheimlich viel schneller als Rects. Rects funktionieren leider nicht auf gesperrtem Buffer.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

MikeDee

BeitragMo, Apr 27, 2009 19:13
Antworten mit Zitat
Benutzer-Profile anzeigen
Noobody hat Folgendes geschrieben:

Dieser Renderer war ausserdem mal im c't und ist ungeheuer komplex - dass ich mit B3D so etwas hinbekommen würde, ist relativ unwahrscheinlich Razz


Hehe, durch die c't habe ich zum erstenmal von Voxel erfahren, die Technik hat Potenzial, auch wenn sie eigendlich schon alt ist^^
Nicht wenige benutzen die Anonymität des Internets um berühmt zu werden.

The_Nici

BeitragMo, Apr 27, 2009 19:26
Antworten mit Zitat
Benutzer-Profile anzeigen
Chrise hat Folgendes geschrieben:
Sehr geiles Ergebnis, auch wenn mir grad nicht einfallen würde, für was ich sowas brauchen sollte. Aber für Leute die Retro-sytle Games machen wollen, gibt es nichts besseres ^^


Noobody sagte schon:
Zitat:
(unter anderem Crysis verwendete Voxelrendering für die Terrains).

Heisst: Gogogo noobs, Crysis1337 muss programmiert werden! ;D

Sehr geile Sache Noobody, ich freue mich auf mehr!

MfG

Neue Antwort erstellen


Übersicht BlitzBasic Codearchiv

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group