Raycaster

Übersicht BlitzBasic Codearchiv

Neue Antwort erstellen

Noobody

Betreff: Raycaster

BeitragMo, März 31, 2008 17:53
Antworten mit Zitat
Benutzer-Profile anzeigen
Wie der Titel schon sagt, stelle ich hier den Raycaster vor, der innerhalb der letzten Wochen entstanden ist.
Wer nicht weiss, was Raycasting ist, der kann sich hier darüber informieren.
Kurz gefasst ist es eine alternative 3D - Renderart, die in den ersten 3D - Spielen eingesetzt wurde (Wolfenstein 3D und eine fortgeschrittene Version in Doom).
Meine Version ist nicht besonders komplex, beherrscht jedoch das Rendern von Boden, Decke, texturierten Wänden und Sprites, was eigentlich schon genug ist für eine sehr simple 3D - Simulation (beispielsweise der Labyrinth - Bildschirmschoner früherer Windowseditionen).

Ich habe versucht, den Algorithmus so weit wie möglich zu optimieren, jedoch frisst das Berechnen der Sprites leider (zu) viel Rechenleistung, da mir unter anderem kein schneller Sichtbarkeitscheck engefallen ist.
Man kann auch das WaitTimer rausnehmen und schauen, wie schnell es bei ihm läuft - auf meinem Intel Celeron läuft es (mit ausgeschaltetem Debugger!) zwischen 100 - 200 FPS, was noch genug Freiraum für anderweitige Berechnungen zulässt..
Achtung: Das ist kein Aufruf, seine FPS hier zu posten!

Da sich das Programm auf Metadaten verlässt, habe ich das ganze gezippt hier hochgeladen.
Die Texturen und das Sprite sind auch bei den B3D - Samples beigelegt und sind schnell gefunden, sollte der Link tot sein.


EDIT: Fehler wegen dem WritePixelFast fixed!

BlitzBasic: [AUSKLAPPEN]
Const MAPSIZE = 16
Const GRIDSIZE = 64
Const GRIDSHIFTS = 6
Const GWIDTH = 320
Const GHEIGHT = 200
Const ANGLEOFVIEW = 60
Const CASTINGSTEP# = ANGLEOFVIEW/Float( GWIDTH )
Const TILES = 2
Const TEXTURESIZE = 64
Const SCALEFACTOR# = TEXTURESIZE/GRIDSIZE
Const FLOORTILE = 2
Const CEILINGTILE = 2
Const HD = ( SCALEFACTOR# <> 1 )
Const CEILING = True

Graphics GWIDTH, GHEIGHT, 32, 2

Global CamX# = 5*GRIDSIZE + GRIDSIZE/2, CamY# = 5*GRIDSIZE + GRIDSIZE/2, ProjectionDistance# = ( GWIDTH/2 )/Tan( ANGLEOFVIEW/2 )
Global CameraAngle = 270, PlayerHeight = 32, PlaneDisplacement

Dim MapData( MAPSIZE - 1, MAPSIZE - 1 )
Dim TextureData( TILES*( TEXTURESIZE)*( TEXTURESIZE ) )
Dim Distances#( GWIDTH - 1 )

For i = 0 To Tiles - 1
Texture = LoadImage( "Tile" + ( i + 1 ) + ".png" )
SetBuffer ImageBuffer( Texture )
LockBuffer ImageBuffer( Texture )
For x = 0 To TEXTURESIZE - 1
For y = 0 To TEXTURESIZE - 1
TextureData( i*TEXTURESIZE*TEXTURESIZE + ( x*TEXTURESIZE + y ) ) = ReadPixelFast( x, y )
Next
Next

FreeImage Texture
Next

Type Sprite
Field X#
Field Y#
Field Height
Field Width
Field ImageData[ 256*256 ]
End Type

Dummy = LoadImage( "Alien.png" )
LockBuffer ImageBuffer( Dummy )
For i = 1 To 10
Drink.Sprite = New Sprite
Drink\X# = Rnd( 0, MAPSIZE*GRIDSIZE )
Drink\Y# = Rnd( 0, MAPSIZE*GRIDSIZE )
Drink\Height = ImageHeight( Dummy )
Drink\Width = ImageWidth( Dummy )

For x = 0 To Drink\Width - 1
For y = 0 To Drink\Height - 1
Drink\ImageData[ x*Drink\Width + y ] = ReadPixelFast( x, y, ImageBuffer( Dummy ) )
Next
Next

If MapData( Drink\X# Shr GRIDSHIFTS, Drink\Y# Shr GRIDSHIFTS ) Then i = i - 1
Next
FreeImage( Dummy )

SetBuffer BackBuffer()

Restore MapData
For i = 0 To MAPSIZE - 1
For t = 0 To MAPSIZE - 1
Read MapData( t, i )
Next
Next

Timer = CreateTimer( 60 )

DisplayFPS = 0
FPS = 0
Counter = MilliSecs()

While Not KeyHit( 1 )
Cls

LockBuffer BackBuffer()
RenderScreen()
RenderSprites()
UnlockBuffer BackBuffer()

MoveCamera()

If MilliSecs() - Counter > 1000 Then
DisplayFPS = FPS
Counter = MilliSecs()
FPS = 0
EndIf

Text 0, 0, DisplayFPS

Flip 0
WaitTimer Timer

FPS = FPS + 1
Wend

End

Function MoveCamera()
XSpeed# = -Sgn( KeyDown( 208 ) - KeyDown( 200 ) )*Cos( CameraAngle )
YSpeed# = Sgn( KeyDown( 208 ) - KeyDown( 200 ) )*Sin( CameraAngle )

TileX = ( CamX# + XSpeed# + Sgn( XSpeed# ) ) Shr GRIDSHIFTS
TileY = ( CamY# + YSpeed# + Sgn( YSpeed# ) ) Shr GRIDSHIFTS
OldTileX = CamX# Shr GRIDSHIFTS
OldTileY = CamY# Shr GRIDSHIFTS

If Not MapData( OldTileX, TileY ) Then CamY# = CamY# + YSpeed#
If Not MapData( TileX, OldTileY ) Then CamX# = CamX# + XSpeed#

CameraAngle = CameraAngle - KeyDown( 203 ) + KeyDown( 205 )

PlaneDisplacement = PlaneDisplacement - KeyDown( 74 ) + KeyDown( 78 )
End Function

Function RenderScreen()
For i = 0 To GWIDTH - 2
Angle# = ( CameraAngle - ANGLEOFVIEW/2 + CASTINGSTEP#*i ) Mod 360
Angle# = ( 360 + Angle# ) Mod 360

;Wird der Strahl nach oben oder unten geschickt?
YDirection = 1 - ( Angle# < 180 )*2

;Wird der Strahl nach links oder rechts geschickt?
XDirection = -1 + ( Angle# > 270 Or Angle# < 90 )*2

;Horizontale Kollision
Ya# = CamY# Mod GRIDSIZE
If YDirection = 1 Then Ya# = GRIDSIZE - Ya#
Xa# = Ya#/Tan( Angle# )

IntersectionY# = CamY# + YDirection*Ya#
IntersectionX# = CamX# - YDirection*Xa#

TileY = ( IntersectionY# + YDirection ) Shr GRIDSHIFTS
TileX = IntersectionX# Shr GRIDSHIFTS

If TileX >= 0 And TileX < MAPSIZE And TileY >= 0 And TileY < MAPSIZE Then
If MapData( TileX, TileY ) Then
WallTile = MapData( TileX, TileY )
Else
Ya# = YDirection Shl GRIDSHIFTS
Xa# = Ya#/Tan( Angle# )
Repeat
IntersectionX# = IntersectionX# - Xa#
IntersectionY# = IntersectionY# + Ya#
TileY = ( IntersectionY# + YDirection ) Shr GRIDSHIFTS
TileX = IntersectionX# Shr GRIDSHIFTS
If TileX >= 0 And TileX < MAPSIZE And TileY >= 0 And TileY < MAPSIZE Then
If MapData( TileX, TileY ) Then
WallTile = MapData( TileX, TileY )
Exit
EndIf
Else
Exit
EndIf
Forever
EndIf
EndIf

WallX# = IntersectionX#
WallY# = IntersectionY#

;Vertikale Kollision
Xa# = CamX# Mod GRIDSIZE
If XDirection = 1 Then Xa# = GRIDSIZE - Xa#
Ya# = Xa#*Tan( Angle# )

IntersectionX# = CamX# + XDirection*Xa#
IntersectionY# = CamY# - XDirection*Ya#

TileY = IntersectionY# Shr GRIDSHIFTS
TileX = ( IntersectionX# + XDirection ) Shr GRIDSHIFTS

If TileX >= 0 And TileX < MAPSIZE And TileY >= 0 And TileY < MAPSIZE Then
If MapData( TileX, TileY ) Then
IntersectionTile = MapData( TileX, TileY )
Else
Xa# = XDirection Shl GRIDSHIFTS
Ya# = Xa#*Tan( Angle# )
Repeat
IntersectionX# = IntersectionX# + Xa#
IntersectionY# = IntersectionY# - Ya#
TileY = IntersectionY# Shr GRIDSHIFTS
TileX = ( IntersectionX# + XDirection ) Shr GRIDSHIFTS
If TileX >= 0 And TileX < MAPSIZE And TileY >= 0 And TileY < MAPSIZE Then
If MapData( TileX, TileY ) Then
IntersectionTile = MapData( TileX, TileY )
Exit
EndIf
Else
Exit
EndIf
Forever
EndIf
EndIf

DistanceVertically# = Abs( ( WallY# - CamY# )/Sin( Angle# ) )
DistanceHorizontally# = Abs( ( IntersectionX# - CamX# )/Cos( Angle# ) )

If DistanceHorizontally# < DistanceVertically# Then
SmallerDistance# = DistanceHorizontally#
If WallTile > 0 Then
If HD Then
TextureRow = Floor( ( WallX# Mod GRIDSIZE )*SCALEFACTOR# )
Else
TextureRow = Floor( WallX# ) Mod GRIDSIZE
EndIf
EndIf
If HD Then
TextureRow = Floor( ( IntersectionY# Mod GRIDSIZE )*SCALEFACTOR# )
Else
TextureRow = Floor( IntersectionY# ) Mod GRIDSIZE
EndIf
Else
SmallerDistance# = DistanceVertically#
If IntersectionTile > 0 Then
If HD Then
TextureRow = Floor( ( IntersectionY# Mod GRIDSIZE )*SCALEFACTOR# )
Else
TextureRow = Floor( IntersectionY# ) Mod GRIDSIZE
EndIf
EndIf
If HD Then
TextureRow = Floor( ( WallX# Mod GRIDSIZE )*SCALEFACTOR# )
Else
TextureRow = Floor( WallX# ) Mod GRIDSIZE
EndIf
EndIf

WallHeight = ( GRIDSIZE/( SmallerDistance#*Cos( CASTINGSTEP#*i - ANGLEOFVIEW/2 ) ) )*ProjectionDistance#
If WallTile = 0 And IntersectionTile > 0 Then WallTile = IntersectionTile

TStart = ( GHEIGHT/2 + PlaneDisplacement ) - WallHeight/2
TEnd = ( GHEIGHT/2 + PlaneDisplacement ) + WallHeight/2
If TStart < 0 Then YCorrection = Abs( TStart )
If TEnd >= GHEIGHT Then YCorrection2 = TEnd - GHEIGHT + 1

For t = TStart + YCorrection To TEnd - YCorrection2
If WallTile = 1 Then
WritePixelFast i, t, $FFFFFFFF
Else
ARGB = TextureData( ( WallTile - 2 )*TEXTURESIZE*TEXTURESIZE + ( TextureRow*TEXTURESIZE + ( t - GHEIGHT/2 + WallHeight/2 - PlaneDisplacement )*( TEXTURESIZE/Float( WallHeight ) ) ) )
WritePixelFast i, t, ARGB
EndIf
Next

;Floor - Casting
TStart = ( GHEIGHT/2 + PlaneDisplacement ) + WallHeight/2
TStart = TStart*( TStart >= 0 )
TEnd = GHEIGHT - 1
For t = TStart To TEnd
Length# = ( ( GRIDSIZE/2 )/( ( t - GHEIGHT/2 - PlaneDisplacement )/ProjectionDistance# ) )/Cos( CASTINGSTEP#*i - ANGLEOFVIEW/2 )
FloorX = CamX# + Cos( Angle# )*Length#
FloorY = CamY# - Sin( Angle# )*Length#
TextureColumn = FloorY Mod TEXTURESIZE
TextureRow = FloorX Mod TEXTURESIZE
ARGB = TextureData( ( FLOORTILE - 1 )*TEXTURESIZE*TEXTURESIZE + ( TextureRow*TEXTURESIZE + TextureColumn ) )
WritePixelFast i, t, ARGB
Next

If CEILING Then
;Ceil - Casting
TStart = 0
TEnd = ( GHEIGHT/2 + PlaneDisplacement ) - WallHeight/2
TEnd = TEnd*( TEnd < GHEIGHT ) + ( GHEIGHT - 1 )*( TEnd >= GHEIGHT )
For t = TStart To TEnd
Length# = ( ( GRIDSIZE/2 )/( ( GHEIGHT/2 - t + PlaneDisplacement )/ProjectionDistance# ) )/Cos( CASTINGSTEP#*i - ANGLEOFVIEW/2 )
CeilingX = CamX# + Cos( Angle# )*Length#
CeilingY = CamY# - Sin( Angle# )*Length#
TextureRow = CeilingX Mod TEXTURESIZE
TextureColumn = CeilingY Mod TEXTURESIZE
ARGB = TextureData( ( CEILINGTILE - 1 )*TEXTURESIZE*TEXTURESIZE + ( TextureRow*TEXTURESIZE + TextureColumn ) )
WritePixelFast i, t, ARGB
Next
EndIf

Distances#( i ) = SmallerDistance#

TextureRow = 0
IntersectionTile = 0
WallTile = 0
Saviour = 0
YCorrection = 0
YCorrection2 = 0
Next
End Function

Function RenderSprites()
;Sprites
For Drink.Sprite = Each Sprite
Distance# = Sqr( ( CamX# - Drink\X# )*( CamX# - Drink\X# ) + ( CamY# - Drink\Y# )*( CamY# - Drink\Y# ) )
Height = Drink\Height - 1
Width = Drink\Width
SpriteHeight = ( Height/Distance# )*ProjectionDistance#
SpriteWidth = Width*( SpriteHeight/Float( Height ) )

Difference# = ATan( ( Drink\Y# - CamY# )/( Drink\X# - CamX# ) )
If Drink\X# - CamX# < 0 Then Difference# = 180 + Difference#
Angle# = ( -Difference# - CameraAngle + 360 ) Mod 360
StartSlice = ( Angle# + ANGLEOFVIEW/2 )/CASTINGSTEP# - SpriteWidth/2
If ( StartSlice < 0 Or StartSlice > GWIDTH ) And Abs( Angle# ) > 360 - ANGLEOFVIEW/2 - SpriteWidth/2 Then
Angle# = Angle# - Sgn( Angle# )*360
StartSlice = ( Angle# + ANGLEOFVIEW/2 )/CASTINGSTEP# - SpriteWidth/2
EndIf

XStart = StartSlice*( StartSlice >= 0 )
XEnd = StartSlice + SpriteWidth - 1
XEnd = XEnd*( XEnd < GWIDTH ) + ( GWIDTH - 1 )*( XEnd > GWIDTH )
YStart = ( GHEIGHT/2 - Spriteheight/2 + PlaneDisplacement )*( GHEIGHT/2 - SpriteHeight/2 + PlaneDisplacement >= 0 )
YEnd = GHEIGHT/2 + SpriteHeight/2 - 1 + PlaneDisplacement
YEnd = YEnd*( YEnd < GHEIGHT ) + ( GHEIGHT - 1)*( YEnd >= GHEIGHT )

For x = XStart To XEnd
For y = YStart To YEnd
If Distances#( x ) > Distance# Then
ARGB = Drink\ImageData[ Floor( ( x - StartSlice )*( Width/Float( SpriteWidth ) ) )*Drink\Width + ( y - GHEIGHT/2 + SpriteHeight/2 - PlaneDisplacement )*( Height/Float( SpriteHeight ) ) ]
If ARGB - $FF000000 <> 0 Then
WritePixelFast x, y, ARGB
EndIf
EndIf
Next
Next
Next
End Function

.MapData
Data 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
Data 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2
Data 1, 0, 2, 0, 2, 0, 2, 0, 2, 2, 2, 2, 2, 2, 0, 2
Data 2, 2, 2, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 2
Data 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2
Data 2, 2, 2, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 2, 0, 2
Data 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 0, 2
Data 2, 2, 2, 0, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 0, 2
Data 2, 2, 2, 0, 2, 2, 0, 2, 0, 0, 0, 2, 0, 2, 0, 2
Data 2, 2, 2, 0, 0, 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 2
Data 2, 0, 2, 0, 0, 0, 0, 2, 0, 2, 0, 2, 2, 2, 0, 2
Data 2, 0, 2, 0, 0, 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 2
Data 2, 0, 2, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 0, 2
Data 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2
Data 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2
Data 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2


Edit:
Jetzt habe ich doch tatsächlich vergessen, die bekannten Bugs aufzuzählen Razz
Es kann manchmal vorkommen, dass Strahlen durch die Wände 'durchsausen'.
Das macht sich dadurch bemerkbar, dass Streifen der Textur einer dahinterliegenden Wand auf der vorderen sichtbar werden, oder dass an einer Ecke plötzlich der Eckpunkt fehlt und man das dahinter sieht.
Sollte ich den Fehler finden, werde ich ihn nachbessern - euch steht es selbstverständlich frei, den Code selbst auszubessern.
  • Zuletzt bearbeitet von Noobody am So, Apr 19, 2009 19:08, insgesamt 2-mal bearbeitet

hectic

Sieger des IS Talentwettbewerb 2006

BeitragMo, März 31, 2008 19:46
Antworten mit Zitat
Benutzer-Profile anzeigen
*respektzeuge* Ein echt gutes stück Code. Leider bekomme ich in Zeile 266 und 326 ein MAV, wenn ich nicht zuvor auf WritePixel stelle. Da sollte man also noch nachbessern. Auf die Schnelle konnte ich das Problem nicht finden.
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D

The_Nici

BeitragMo, März 31, 2008 19:52
Antworten mit Zitat
Benutzer-Profile anzeigen
Geniales Ding.

Erinnert an TES: I xD

Noobody

BeitragMo, März 31, 2008 21:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Das mit dem WritePixelFast ist nun wirklich seltsam - ich habe es auf 2 PCs ausgetestet und es lief immer ohne Probleme.
Was ich noch vergass zu erwähnen, mit + und - auf dem Numpad kann man nach oben oder unten schauen.
Es ist nur eine simulierte Rotation; innerhalb gewisser Grenzen sieht es dennoch relativ realistisch aus.
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

Silver_Knee

BeitragDi, Apr 01, 2008 0:17
Antworten mit Zitat
Benutzer-Profile anzeigen
hat was von dem WinME Bildschirmschoner "Labyrinth"

peacemaker

BeitragDi, Apr 01, 2008 12:01
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich find das Teil sehr cool! Ist ziemlich schnell, wenn man bedenkt das da in Echtzeit herumskaliert wird. Sehr schön!

mfG
~Tehadon~
www.tehadon.de
http://www.blitzforum.de/worklogs/14/

TimBo

BeitragDi, Apr 01, 2008 12:11
Antworten mit Zitat
Benutzer-Profile anzeigen
jeah stimmt hat schon was von Win MoreErrors

Gutes Teil !!

Viele Grüße
Intel ViiV Quad-Core
mfg Tim Borowski // CPU: Ryzen 2700x GPU: Nvidia RTX 2070 OC (Gigabyte) Ram: 16GB DDR4 @ 3000MHz OS: Windows 10
Stolzer Gewinner des BCC 25 & BCC 31
hat einen ersten Preis in der 1. Runde beim BWInf 2010/2011 & 2011/12 mit BlitzBasic erreicht.

Neue Antwort erstellen


Übersicht BlitzBasic Codearchiv

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group