[B3D] Schattenberechnung in 2D

Übersicht BlitzBasic Codearchiv

Neue Antwort erstellen

Noobody

Betreff: [B3D] Schattenberechnung in 2D

BeitragMo, Mai 11, 2009 19:55
Antworten mit Zitat
Benutzer-Profile anzeigen
Nach Lektüre eines äusserst interessanten Artikels auf Gamedev habe ich ein kleines Programm geschrieben, welches den Schattenwurf für 2D - Objekte korrekt berechnet.

Der Algorithmus ist im Moment limitiert auf konvexe Objekte, ausserdem müssen die Eckpunkte jedes Objekts im Gegenuhrzeigersinn angegeben werden.
Immerhin tut er seinen Dienst, und das relativ flott dank simpler Vektorrechnung und 3D - Beschleunigung durch die Grafikkarte.

Der Code (ich habe mich sogar dazu durchgerungen, ihn ein wenig zu kommentieren Razz ) Code: [AUSKLAPPEN]
Const GWIDTH = 800
Const GHEIGHT = 600

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

Global PolygonSurf, ShadowSurf

Type TPolygon ;Ein Schattenwerfendes Polygon
   Field VertexCount ;Anzahl Vertices
   Field Vertex.TVertex[ 128 ] ;Die Vertices an sich
   
   Field CenterX# ;Koordinaten des Mittelpunkts
   Field CenterY#
End Type

Type TVertex ;Ein Eckpunkt eines Polygons
   Field Polygon.TPolygon ;Zugehöriges Polygon
   
   Field X# ;Position
   Field Y#
   
   Field Prev.TVertex ;Vorgänger und Nachfolger
   Field Succ.TVertex
   
   Field VertIndex ;Index des 3D - Vertex' auf der Surface
End Type

Init()

;Ein paar kleine Polygone zur Demonstration erstellen
CreatePolygon( 100, 100, 50, 50, 45 )
CreatePolygon( 250, 100, 50, 80, 90 )
CreatePolygon( 400, 500, 200, 50, 45 )
CreatePolygon( 400, 300, 10, 10, 36 )

Local Timer = CreateTimer( 60 ) ;Gebt 100% Auslastung keine Chance >:O

While Not KeyHit( 1 )
   LightX# = 400 + Cos( ( MilliSecs() Mod 3600 )/10. )*100 ;Das Licht ein wenig kreisen lassen
   LightY# = 300 - Sin( ( MilliSecs() Mod 3600 )/10. )*100
   CalculateShadows( LightX#, LightY# ) ;Schatten berechnen
   
   Wireframe MouseDown( 1 ) ;Wireframe je nach Wunsch
   
   RenderWorld ;Rendern
   
   Color 255, 255, 0 ;Licht einzeichnen
   Oval LightX# - 10, LightY# - 10, 20, 20
   
   ClearSurface ShadowSurf ;Und die Schattensurface aufräumen
   
   Flip 0 ;Versichtbaren und so
   WaitTimer Timer
Wend
End

Function Init()
   DrawCam = CreateCamera()
   CameraProjMode DrawCam, 2            ;Kameraprojektion auf Orthogonal stellen
   CameraZoom DrawCam, 2.0/Float( GWIDTH )   ;Zoom für 2D richtig einstellen
   CameraClsColor DrawCam, 64, 64, 64      ;Hintergrundfarbe auf dunkles Grau einstellen - sonst sieht man die Schatten nicht
   
   DrawPivot = CreatePivot( DrawCam )   ;Pivot für Schatten und Polygone erstellen
   TurnEntity DrawPivot, 180, 0, 0      ;Pivot so drehen und positionieren, dass wir das normale 2D - Koordinatensystem haben
   PositionEntity DrawPivot, -GWIDTH/2., GHEIGHT/2., 100, True
   
   PolygonMesh = CreateMesh( DrawPivot ) ;Mesh und Surface für die Polygone erstellen
   PolygonSurf = CreateSurface( PolygonMesh )
   EntityFX PolygonMesh, 1 + 2
   
   ShadowMesh = CreateMesh( DrawPivot ) ;Mesh und Surface für die Schatten erstellen
   ShadowSurf = CreateSurface( ShadowMesh )
   EntityFX ShadowMesh, 1 + 2
End Function

Function CalculateShadows( LightX#, LightY# )
   For Polygon.TPolygon = Each TPolygon
      For i = 0 To Polygon\VertexCount*2 ;Alle Vertices durchgehen
         Local Vertex.TVertex = Polygon\Vertex[ i Mod Polygon\VertexCount ] ;Momentan zu bearbeitenden Vertex rauslesen
         
         ;Skalarprodukt zwischen dem Vektor zum Licht und der Normale der Seite zwischen dem aktuellen Vertex und dem folgenden Vertex berechnen
         EdgeDP# = ( Vertex\Y# - Vertex\Succ\Y# )*( Vertex\X# - LightX# ) + ( Vertex\Succ\X# - Vertex\X# )*( Vertex\Y# - LightY# )
         
         If Triangulate Then ;Falls trianguliert werden soll, dann...
            V1 = AddVertex( ShadowSurf, Vertex\X#, Vertex\Y#, 0, 0.6, 0.9 ) ;...benötigte Vertices erstellen..
            V2 = AddVertex( ShadowSurf, Vertex\X# + ( Vertex\X# - LightX# )*100, Vertex\Y# + ( Vertex\Y# - LightY# )*100, 0, 0.6, 0.9 )
            
            VertexColor ShadowSurf, V1, 0, 0, 0 ;...einfärben...
            VertexColor ShadowSurf, V2, 0, 0, 0
            
            AddTriangle ShadowSurf, OldV1, V1, OldV2 ;...und triangulieren
            AddTriangle ShadowSurf, V1, V2, OldV2
         EndIf
         
         If i > 0 Then
            ;Wenn die aktuelle Seite auf der Schattenseite und die vorherige Seite auf der Lichtseite ist, dann fängt hier der Schatten an
            If EdgeDP# > 0 And OldEdgeDP# < 0 Then
               V1 = AddVertex( ShadowSurf, Vertex\X#, Vertex\Y#, 0, 0.6, 0.9 ) ;Die ersten beiden Vertices erstellen und einfärben
               V2 = AddVertex( ShadowSurf, Vertex\X# + ( Vertex\X# - LightX# )*100, Vertex\Y# + ( Vertex\Y# - LightY# )*100, 0, 0.6, 0.9 )
               
               VertexColor ShadowSurf, V1, 0, 0, 0
               VertexColor ShadowSurf, V2, 0, 0, 0
               
               Triangulate = True
            ;Wenn die aktuelle Seite auf der Lichtseite und die vorherige Seite auf der Schattenseite ist, hört hier der Schatten auf
            ElseIf EdgeDP# < 0 And OldEdgeDP# > 0 And Triangulate Then
               Triangulate = False ;Nix wie raus hier!
               Exit
            EndIf
         EndIf
         
         OldEdgeDP# = EdgeDP#
         OldV1 = V1
         OldV2 = V2
      Next
   Next
End Function

;Erstellt ein Polygon mit dem Zentrum X#, Y#, der Breit Width#, der Höhe#, der Genauigkeit Stepsize und der Farbe R G B
Function CreatePolygon( X#, Y#, Width#, Height#, StepSize = 10, R = 255, G = 255, B = 255 )
   Polygon.TPolygon = New TPolygon
      Polygon\CenterX# = X#
      Polygon\CenterY# = Y#
   
   For i = 0 To 360 - StepSize
      CreateVertex( Polygon, X# + Cos( i )*Width#, Y# - Sin( i )*Height# )
      
      i = i + StepSize - 1
   Next
   
   Polygon\Vertex[ Polygon\VertexCount - 1 ]\Succ = Polygon\Vertex[ 0 ]
   
   For i = 0 To Polygon\VertexCount - 1
      Polygon\Vertex[ i ]\VertIndex = AddVertex( PolygonSurf, Polygon\Vertex[ i ]\X#, Polygon\Vertex[ i ]\Y#, 0 )
      VertexColor PolygonSurf, Polygon\Vertex[ i ]\VertIndex, R, G, B
      
      If i >= 2 Then AddTriangle PolygonSurf, Polygon\Vertex[ i ]\VertIndex, Polygon\Vertex[ i - 1 ]\VertIndex, Polygon\Vertex[ 0 ]\VertIndex
   Next
End Function

Function CreateVertex( Polygon.TPolygon, X#, Y# ) ;Erstellt einen Eckpunkt an einem Polygon
   Polygon\Vertex[ Polygon\VertexCount ] = New TVertex
      Polygon\Vertex[ Polygon\VertexCount ]\X# = X#
      Polygon\Vertex[ Polygon\VertexCount ]\Y# = Y#
   
   If Polygon\VertexCount > 0 Then
      Polygon\Vertex[ Polygon\VertexCount ]\Prev = Polygon\Vertex[ Polygon\VertexCount - 1 ]
      Polygon\Vertex[ Polygon\VertexCount - 1 ]\Succ = Polygon\Vertex[ Polygon\VertexCount ]
   EndIf
   
   Polygon\VertexCount = Polygon\VertexCount + 1
End Function

Mit linker Maustaste kann man Wireframe ein- und ausschalten.

Ein kleiner Screenshot:
user posted image

Die im Artikel beschriebene Methode zur Berechnung der weichen Übergänge am Rand der Schatten hat bei mir längst nicht so gut ausgesehen, weswegen ich die Funktion wieder rausgenommen habe. Ebenfalls ist die Lichtberechnung in Blitz nicht so gut hinzubekommen, da man dort leider keinen Alpha - Buffer zur Verfügung hat (ich habe noch ein wenig damit herumprobiert, den Z - Buffer zum eigenen Nutzen zu verwenden, allerdings hat es nicht wirklich funktioniert Razz ).
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
 

aletes

BeitragMo, Mai 11, 2009 20:00
Antworten mit Zitat
Benutzer-Profile anzeigen
hmm, das sieht eigentlich ganz gut aus, kann man bestimmt noch gebrauchen Very Happy

ozzi789

BeitragMo, Mai 11, 2009 20:34
Antworten mit Zitat
Benutzer-Profile anzeigen
Mensch Noobody du bist zu gut!

Wieder mal ein sehr interessanter & nützlicher Code deinerseits, kurz thnx Very Happy
0x2B || ! 0x2B
C# | C++13 | Java 7 | PHP 5

ToeB

BeitragMo, Mai 11, 2009 21:43
Antworten mit Zitat
Benutzer-Profile anzeigen
Fast genau so geht mein Vetex2D vor ^_^'

Aber trotzdem sehr gut gemacht... vielleicht wäre es besser wenn du sowieso nur "Polygones" erstellst (die ja an sich symetrisch sind) das du statt 30 Schatten nur einen schatten zeichnest...


mfg ToeB
Religiöse Kriege sind Streitigkeiten erwachsener Männer darum, wer den besten imaginären Freund hat.
Race-Project - Das Rennspiel der etwas anderen Art
SimpleUDP3.0 - Neuste Version der Netzwerk-Bibliothek
Vielen Dank an dieser Stelle nochmal an Pummelie, welcher mir einen Teil seines VServers für das Betreiben meines Masterservers zur verfügung stellt!

Dottakopf

BeitragSa, Nov 21, 2009 0:40
Antworten mit Zitat
Benutzer-Profile anzeigen
Geiles Teil!
Genau sowas habe ich gerade gesucht ! Danke

Gruß
Dottakopf
Rechtschreibfehler gelten der allgemeinen Belustigung!

Neue Antwort erstellen


Übersicht BlitzBasic Codearchiv

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group