Seite 3 von 3

Re: dynamic Lightning

Verfasst: 10.12.2011 00:44
von STARGÅTE
Sry für Doppelpost, aber hier mal die Variante mit X,Y und Liste:

Die Liste enthält nun die relativen Koordinaten zur Lichtquelle wo eine Ecke ist.
Ich weiß leider nicht genau wie du die "Ecken hinter den Ecken" bestimmst, sodass alles glatt liegt, aber ich denke mal mit dem neuen Code kannst du mehr anfangen:

DisplayLight() nimmt nun die Ecken-Liste und sortiert sie nach Winkeln.
Damit alles gedeckt ist, sollten dann immer zwei gleiche Winkel als doppelpack kommen, sodass dann die Liste um 1 verschoben wird sodass die Dreicke entstehen.
Was noch zu beachten wäre, wäre wenn es zu wenige Ecken gibt, dass dann die Dreicke zu "flach" sind, sodass du selbst noch Ecken "im Unendlichen" hinzufügen musst. Ich vermute mal, auf dieses Problem bist du auch bei deinen Schatten schon gestoßen, wenn die Lichtquelle zu dicht am Objekt liegt richtig ?^^

Code: Alles auswählen

Structure DX9Vertex
	X.f
	Y.f
	Z.f
	Rhw.f
	Color.l
	Tu.f
	Tv.f
EndStructure  

Structure DX9
	TexRes.i
	Vertice.DX9Vertex[4]
	TmpVertice.DX9Vertex[4]
	Width.l
	Height.l
	RealWidth.l
	RealHeight.l
	Angle.f
	Transformed.l
EndStructure

Structure Corner
	X.f
	Y.f
EndStructure

Structure CornerSort
	*Corner.Corner
	Angle.f
EndStructure

Procedure DisplayLightCone(Sprite3D.i, X.f, Y.f, X1.f, Y1.f, X2.f, Y2.f, MaxLength.f=386.0)
	Protected *DX9.DX9 = IsSprite3D(Sprite3D)
	With *DX9
		\Transformed = 1
		\Vertice[0]\X = X
		\Vertice[0]\Y = Y
		\Vertice[0]\Tu = 0.5
		\Vertice[0]\Tv = 0.5
		\Vertice[3]\X = X
		\Vertice[3]\Y = Y
		\Vertice[3]\Tu = 0.5
		\Vertice[3]\Tv = 0.5
		\Vertice[1]\X = X+X1
		\Vertice[1]\Y = Y+Y1
		\Vertice[2]\X = X+X2
		\Vertice[2]\Y = Y+Y2
		\Vertice[1]\Tu = 0.5+X1/MaxLength*0.5
		\Vertice[1]\Tv = 0.5+Y1/MaxLength*0.5
		\Vertice[2]\Tu = 0.5+X2/MaxLength*0.5
		\Vertice[2]\Tv = 0.5+Y2/MaxLength*0.5
		DisplaySprite3D(Sprite3D, 0, 0)
	EndWith
EndProcedure

Procedure DisplayLight(Sprite3D.i, X.f, Y.f, List Corner.Corner(), MaxLength.f=386.0)
	Protected *Corner1.Corner, *Corner2.Corner
	Protected NewList CornerSort.CornerSort()
	; Allen Ecken einen Winkel geben
	ForEach Corner()
		AddElement(CornerSort())
		CornerSort()\Corner = @Corner()
		CornerSort()\Angle = ATan2(Corner()\X, Corner()\Y)
	Next
	; Sortieren
	SortStructuredList(CornerSort(), #PB_Sort_Ascending, OffsetOf(CornerSort\Angle), #PB_Sort_Float)
	; Verschieben und Anzeigen
	LastElement(CornerSort())
	*Corner1 = CornerSort()\Corner
	ResetList(CornerSort())
	While NextElement(CornerSort())
		*Corner2 = CornerSort()\Corner
		DisplayLightCone(Sprite3D, X, Y, *Corner1\X, *Corner1\Y, *Corner2\X, *Corner2\Y, MaxLength)
		NextElement(CornerSort())
		*Corner1 = CornerSort()\Corner
	Wend
EndProcedure



InitSprite()
InitSprite3D()

Enumeration
	#Window
	#Sprite
	#Sprite3D
EndEnumeration

OpenWindow(#Window, 0, 0, 800, 600, "ScreenTitle", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(#Window), 0, 0, WindowWidth(#Window), WindowHeight(#Window), 0, 0, 0)

CreateSprite(#Sprite, 256, 256, #PB_Sprite_Texture)
StartDrawing(SpriteOutput(#Sprite))
For R = 127 To 1 Step -1
	Gray = Pow(1-r/127.0, 2)*255
	Circle(128, 128, R, RGB(Gray, Gray, Gray))
Next
StopDrawing()
CreateSprite3D(#Sprite3D, #Sprite)

NewList Corner.Corner()
RandomSeed(15)
For I = 0 To 9
	Angle.f = Radian(Random(359))
	AddElement(Corner())
	Radius1.f = Random(256)+128
	Corner()\X = Cos(Angle)*Radius1
	Corner()\Y = Sin(Angle)*Radius1
	AddElement(Corner())
	Radius2.f = Random(256)+128
	Corner()\X = Cos(Angle)*Radius2
	Corner()\Y = Sin(Angle)*Radius2
Next

Repeat
	
	Repeat
		
		Select WindowEvent()
			Case #PB_Event_CloseWindow
				End
			Case #Null
				Break
		EndSelect
		
	ForEver
	
	ClearScreen(0)
	
	StartDrawing(ScreenOutput())
	For X = 0 To 799
		Line(X,0,1,600,RGB(X*128/799,0,128-X*128/799))
	Next
	StopDrawing()
	
	If Start3D()
		Sprite3DBlendingMode(5,2)
		DisplayLight(#Sprite3D, 400, 300, Corner())
		Stop3D()
	EndIf
	
	FlipBuffers()
	
Until WindowEvent() = #PB_Event_CloseWindow 
Info: SortStructuredList() ist nicht das schnellste der Welt, daher vermute ich, der Code wird mit zunahme der Lichter und Ecken schnell langsam.

Re: dynamic Lightning

Verfasst: 10.12.2011 12:22
von oh... well?!
oh... was macht die Procedure "ATan2()"? Die is bei mir irgendwie nich definiert.
Und ja, auf das Problem mit dem Ecken im Unendlichen hab ich auch und noch nicht wirklich gelöst, aber da bin ich zuversichtlich.

Re: dynamic Lightning

Verfasst: 10.12.2011 15:00
von Lord
PureBasic-Geschichte hat geschrieben:7. Juni 2010 : Version 4.50
- Hinzugefügt: Viele Mathe-Funktionen: Exp(), ATan2(), Radian(), Degree(), [A]CosH(), [A]SinH(), [A]TanH(), IsNaN(), IsInfinity(), NaN(), Infinity(), Sign()
PureBasic Hilfe hat geschrieben:ATan2()

Syntax

Ergebnis.f = ATan2(x.f, y.f)

Beschreibung

Berechnet den Winkel im Bogenmaß (Radiant) zwischen der X-Achse und einer Linie, welche in der von 'x' und 'y' definierten Richtung gezeichnet wird. Der Winkel kann zum Berechnen von Winkeln zwischen Linien in 2D verwendet werden, oder zum Umwandeln rechtwinkeliger Koordinaten in Polarkoordinaten.
Alles klar?

Re: dynamic Lightning

Verfasst: 12.12.2011 17:25
von oh... well?!
^^jop, danke. Hab die Procedure mal wie folgt implementiert:

Code: Alles auswählen

Procedure.f ATan2(x.f, y.f)
   Protected Angle.f
   Angle = ATan(y/x)
   If x < 0 : Angle + #PI : EndIf
   ProcedureReturn Angle
EndProcedure
Bis jetzt scheints zu funktionieren.

Jetzt hab ich denk ich mal alle notwendigen Informationen zusammen. Könnte aber noch bisschen dauern bis ihr was zu sehen bekommt. Muss nebenbei noch studieren.

Re: dynamic Lightning

Verfasst: 12.12.2011 18:15
von DarkDragon

Re: dynamic Lightning

Verfasst: 12.12.2011 19:03
von NicTheQuick
Doch, seine Procedure ist richtig. Lediglich für den Fall y < 0 und x < 0 hat er eine 2*Pi-Verschiebung drin, was aber ja bekanntlich kein Problem ist. Was vielleicht nicht jeder weiß ist, dass ATan() mit - und + Unendlich zurecht kommt. Fall 4 und 5, wo x = 0 ist, sind somit automatisch abgedeckt.
Man sieht sogar, dass die in PB eingebaut Funktion ATan2 für den Fall x = 0 und y = 0 falsch rechnet. Man erhält dann nämlich 0.0 statt NaN.

Hier mein Testcode dazu:

Code: Alles auswählen

Procedure.d ATan2b(x.d, y.d)
   Protected angle.d
   angle = ATan(y / x)
   If x < 0 : angle + #PI : EndIf
   ProcedureReturn angle
EndProcedure

Debug "Case 1"
Debug ATan(1. / 1.)
Debug ATan2b(1, 1)
Debug ATan2(1, 1)
Debug "Case 2a"
Debug ATan(0.0 / -1.0) + #PI
Debug ATan2b(-1, 0)
Debug ATan2(-1, 0)
Debug "Case 2b"
Debug ATan(1.0 / -1.0) + #PI
Debug ATan2b(-1, 1)
Debug ATan2(-1, 1)
Debug "Case 3 (2*Pi-Verschiebung)"
Debug ATan(-1.0 / -1.0) - #PI
Debug ATan2b(-1, -1)
Debug ATan2(-1, -1)
Debug "Case 4"
Debug #PI / 2.
Debug ATan2b(0.0, 1.0)
Debug ATan2(0.0, 1.0)
Debug "Case 5"
Debug - #PI / 2.
Debug ATan2b(0.0, -1.0)
Debug ATan2(0.0, -1.0)
Debug "Case 6"
Debug "NaN"
Debug ATan2b(0, 0)
Debug ATan2(0, 0)