Drawing3D - Draw-Befehle für 3D-Szenen

Du brauchst Grafiken, gute Programme oder Leute die dir helfen? Frag hier.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: Drawing3D - Draw-Befehle für 3D-Szenen

Beitrag von NicTheQuick »

Ich habe es jetzt nicht überprüft, aber kann es sein, dass einer von euch von einer globalen Rotation spricht und der andere von einer lokalen?
Bild
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Drawing3D - Draw-Befehle für 3D-Szenen

Beitrag von STARGÅTE »

silbersurfer hat geschrieben:ja aber was genau mache Ich da Falsch?
Die zusammensetzung ist einfach falsch. Die Rotation um alle 3 möglichen Achsen ist nicht nur die Multiplikation der einzelnen Komponenten.
silbersurfer hat geschrieben:Mir ist auch aufgefallen das es nur zu fehlern kommt wenn Ich X und Y Achse Rotiere X-Z oder Y-Z ergeben in meinen Augen keine fehler zumindest Rotieren Sie wie Ich mir das gedacht hatte
Da der Fehler ja schon in der Matrix liegt, will ich deine falsche Matrix ungern analysieren.

Hier mal ein anschauliches Beispiel im 2D-Raum:
Ein Vektor wäre hier v=(x,y)
Eine Rotationsmatrix: M=((Cos(φ),-Sin(φ)),(Sin(φ), Cos(φ)))

Wenn ich nun um zB 90° drehen möchte ergibt das die Matrix: M = ((0, -1), (1, 0))
Wenn ich nun diese Drehung zwei mal durchführe, müsste mein Vektor ja umgeklappt sein.

Mathematisch wäre das M*M*v (also zwei mal um 90° drehen)
Du hast bei deiner matrix jetzt den Fehler gemacht:
((0, -1), (1, 0)) * ((0, -1), (1, 0)) = ((0, 1), (1, 0)) FALSCH
Richtig wäre hier eine Matrixmultiplikation also:
((0, -1), (1, 0)) * ((0, -1), (1, 0)) = ((0-1, 0+0), (0+0, -1+0)) = ((-1, 0), (0, -1))
Denn jetzt erhalte ich wirklich die Drehung um 180 grad.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
dige
Beiträge: 1182
Registriert: 08.09.2004 08:53

Re: Drawing3D - Draw-Befehle für 3D-Szenen

Beitrag von dige »

Hallo STARGÅTE, Danke für die tolle Include. Ich wollte die gerade ausprobieren um damit einen
Collagen Effekt ( Mehrere Bilder, leicht verdreht zum Teil überlagert in einem Bild zusammengefasst)
erstellen.

Dabei ist mir aufgefallen, wenn man das Beispiel 04 dafür nimmt (DrawImage3D()) und Bilder
gedreht übereinander zeichnet, dass dann Pixel vom unteren Bild durchscheinen...

Code: Alles auswählen


; Image3D
;---------
; Disable the debugger !


XIncludeFile "Drawing3D.pbi"

Enumeration
	#Window
	#Gadget
	#Image
	#Image3D
EndEnumeration

UsePNGImageDecoder()
UseJPEGImageDecoder()

LoadImage(#Image, "Image.png")
CreateImage3D(#Image3D, #Image)

OpenWindow(#Window, 0, 0, 500, 500, "Image3D", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
CanvasGadget(#Gadget, 0, 0, WindowWidth(#Window), WindowHeight(#Window))

If StartDrawing3D(CanvasOutput(#Gadget))
	Drawing3DMode(#Drawing3D_Outline)
	DrawImage3D(#Image3D, 0, 0, 0, 400, 400, 0, 0, -30)
  DrawImage3D(#Image3D, 0, 0, 0, 400, 400, 0, 0, 15)
  DrawImage3D(#Image3D, 0, 0, 0, 400, 400, 0, 0, 45)
	StopDrawing3D()
EndIf

Repeat
	
	Select WaitWindowEvent()
			
		Case #PB_Event_CloseWindow
			End
			
	EndSelect
	
ForEver
"Papa, mein Wecker funktioniert nicht! Der weckert immer zu früh."
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Drawing3D - Draw-Befehle für 3D-Szenen

Beitrag von STARGÅTE »

Das ist der ganz normale Z-fighting-Effekt wie es bei allen 3D-Anwendungen zu sehen ist, wenn zwei Dreicke parallel und in der selben Ebene liegen.

Diesen Effekt kannst du umgehen, wenn du die Bilder (die übereinander liegen sollen) auch leicht in der z-Achse anhebst.
Mit leicht meine ich wirklich nur 0.001 oder gar noch weniger. Sie dürfen halt nur nicht ale den selben z-Wert haben.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
dige
Beiträge: 1182
Registriert: 08.09.2004 08:53

Re: Drawing3D - Draw-Befehle für 3D-Szenen

Beitrag von dige »

Wow, das ist ja simple :shock:

Danke STARGÅTE :D

Wenn du jetzt noch eine Idee hast, wie ich etwas gegen die Treppeneffekte an den
gedrehten Bildkanten machen kann? Dann ist deine Include für mich perfekt.

Ciao Dige
"Papa, mein Wecker funktioniert nicht! Der weckert immer zu früh."
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Drawing3D - Draw-Befehle für 3D-Szenen

Beitrag von STARGÅTE »

Meine "mini"-Engine hat kein Antialiasing (Kantenglättung), somit werden die "Faces" in ganzen Pixel gerendert.
Allerdings nutzt ich ich beim rendern der Bilder einen linearen Fit über 4 Pixel.
Du könntest nun also einfach ein Rand mit einem transparentem Pixel hinzufügen.

Ansonsten müsste ich halt den Renderprozess etwas umschreiben...
Wenn die die Imagegröße nicht ganz genau sein soll, kannst du auch diese Procedure mal ersetzen:

ca. Zeile 250 im Include

Code: Alles auswählen

Procedure.i Drawing3D_ImageColor(*Color.Drawing3D_Color, X.f, Y.f)
	Protected *Image3D.Drawing3D_Image = Drawing3DInclude\CurrentImage3D
	Protected Null.Drawing3D_Color
	Protected FX.f = Mod(X**Image3D\Width+0.5, 1.0)
	Protected FY.f = Mod(Y**Image3D\Height+0.5, 1.0)
	Protected PixelX0.i = X * (*Image3D\Width+2)  - 1.5 - FX
	Protected PixelY0.i = Y * (*Image3D\Height+2) - 1.5 - FY
	Protected PixelX1.i = X * (*Image3D\Width+2)  - 0.5 - FX
	Protected PixelY1.i = Y * (*Image3D\Height+2) - 0.5 - FY
; 	If PixelX0 < 0 : PixelX0 = 0 : EndIf
; 	If PixelY0 < 0 : PixelY0 = 0 : EndIf
; 	If PixelX1 > *Image3D\Width-1 : PixelX1 = *Image3D\Width-1 : EndIf
; 	If PixelY1 > *Image3D\Height-1 : PixelY1 = *Image3D\Height-1 : EndIf
; 	Protected *C00.Drawing3D_Color = *Image3D\Pixel(PixelX0, PixelY0)
; 	Protected *C10.Drawing3D_Color = *Image3D\Pixel(PixelX1, PixelY0)
; 	Protected *C01.Drawing3D_Color = *Image3D\Pixel(PixelX0, PixelY1)
; 	Protected *C11.Drawing3D_Color = *Image3D\Pixel(PixelX1, PixelY1)
	Protected.Drawing3D_Color *C00 = @Null, *C10 = @Null, *C01 = @Null, *C11 = @Null
	If PixelX0 >= 0 And PixelX0 < *Image3D\Width And PixelY0 >= 0 And PixelY0 < *Image3D\Height : *C00 = *Image3D\Pixel(PixelX0, PixelY0) : EndIf
	If PixelX1 >= 0 And PixelX1 < *Image3D\Width And PixelY0 >= 0 And PixelY0 < *Image3D\Height : *C10 = *Image3D\Pixel(PixelX1, PixelY0) : EndIf
	If PixelX0 >= 0 And PixelX0 < *Image3D\Width And PixelY1 >= 0 And PixelY1 < *Image3D\Height : *C01 = *Image3D\Pixel(PixelX0, PixelY1) : EndIf
	If PixelX1 >= 0 And PixelX1 < *Image3D\Width And PixelY1 >= 0 And PixelY1 < *Image3D\Height : *C11 = *Image3D\Pixel(PixelX1, PixelY1) : EndIf
	*Color\Alpha = *C00\Alpha*(1-FX)*(1-FY) + *C10\Alpha*(FX)*(1-FY) + *C01\Alpha*(1-FX)*(FY) + *C11\Alpha*(FX)*(FY)
	*Color\Red   = *C00\Red  *(1-FX)*(1-FY) + *C10\Red  *(FX)*(1-FY) + *C01\Red  *(1-FX)*(FY) + *C11\Red  *(FX)*(FY)
	*Color\Green = *C00\Green*(1-FX)*(1-FY) + *C10\Green*(FX)*(1-FY) + *C01\Green*(1-FX)*(FY) + *C11\Green*(FX)*(FY)
	*Color\Blue  = *C00\Blue *(1-FX)*(1-FY) + *C10\Blue *(FX)*(1-FY) + *C01\Blue *(1-FX)*(FY) + *C11\Blue *(FX)*(FY)
EndProcedure
Damit ist das Image zwei 2 Pixel kleiner aber dafür am Rand glatter.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
dige
Beiträge: 1182
Registriert: 08.09.2004 08:53

Re: Drawing3D - Draw-Befehle für 3D-Szenen

Beitrag von dige »

Danke und sorry, ein kleines Problem habe ich noch.
Mittels Drawing3DBackground($FFFFFFFF) lege ich doch fest, welchen Hintergrund
das zu drehende Bild hat, oder? Wenn ich das nicht verwende, wird Schwarz genommen
und es wird ein Rand um das Bild sichtbar.

Leider funktioniert dann folgende Vorgehensweise nicht, weil durch
Drawing3DBackground($FFFFFFFF) das komplette Bild weiss gezeichnet wird und
vorherige Drawings verloren gehen.

Code: Alles auswählen

XIncludeFile "Drawing3D.pbi"

Enumeration
  #Window
  #Gadget
  #Image
  #Image3D
EndEnumeration

UsePNGImageDecoder()

OpenWindow(#Window, 0, 0, 500, 500, "Image3D", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
CanvasGadget(#Gadget, 0, 0, WindowWidth(#Window), WindowHeight(#Window))

For n = 1 To 10

  ; Nächstes Bild laden
  LoadImage(#Image, "Image.png")
  CreateImage3D(#Image3D, #Image)

  If StartDrawing3D(CanvasOutput(#Gadget))
    Drawing3DMode(#Drawing3D_Default)
    Drawing3DBackground($FFFFFFFF)
    DrawImage3D(#Image3D, Random(20), Random(20), 0, ImageWidth(#Image), ImageHeight(#Image), 0, 0, Random(60)-30)
    StopDrawing3D()
  EndIf
  FreeImage3D(#Image3D)
Next
Repeat
  
  Select WaitWindowEvent()
      
    Case #PB_Event_CloseWindow
      End
      
  EndSelect
  
ForEver

Ich Danke dir schon mal im voraus!! :D
"Papa, mein Wecker funktioniert nicht! Der weckert immer zu früh."
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Drawing3D - Draw-Befehle für 3D-Szenen

Beitrag von STARGÅTE »

Ne sry (muss wohl mal n Docu schreiben ^^).

Drawing3DBackground() legt fest, mit welcher Farbe der Puffer gefüllt werden soll.
So erzeugt zB Drawing3DBackground(0) ein komplett transparenten Hintergrund wie bei Images mit #PB_Image_Transparent.

Damit die Drawing nicht verloren gehen, darfst du Drawing3DBackground() beim 2. Aufruch keine Farbe geben.

Allerdings hatte ich in der aktuellen Version hier im Forum n Fehlerdrin, der das alte gemalte überschreibt, hier mal die neue Prozedur, die jetzt kein Drawing3DBackground() mehr verwenden, sondern die Pixel des letzten Outputs.
Dann aber auch kein Drawing3DBackground() mehr verwenden, da dort eine Box gemalt wird.
Lieber selber den Background setzen mit normalen 2D-Drawing am anfang.

Code: Alles auswählen

; Schließt eine Drawing3D-Umgebung und rendert die Szene
Procedure StopDrawing3D()
	
	Protected *Pixel.Drawing3D_Pixel, *PreviousPixel.Drawing3D_Pixel
	Protected Color.Drawing3D_Color
	Protected X.i, Y.i
	
	;DrawingMode(#PB_2DDrawing_AllChannels)
	DrawingMode(#PB_2DDrawing_AlphaBlend)
	
	For Y = 0 To Drawing3DInclude\MaxY
		For X = 0 To Drawing3DInclude\MaxX
			*Pixel = Drawing3DInclude\PixelIndex(X, Y)
			If *Pixel
				While *Pixel\PreviousPixel
					Drawing3D_AlphaBlend(*Pixel\PreviousPixel\Color, *Pixel\Color)
					*Pixel = *Pixel\PreviousPixel
				Wend
				;Color = Drawing3DInclude\Background
				;Plot(X, Y, Drawing3D_GetColor(Drawing3D_AlphaBlend(Color, *Pixel)))
				Plot(X, Y, Drawing3D_GetColor(*Pixel\Color))
			EndIf
		Next
	Next
	
	StopDrawing()
	
EndProcedure
Edit: Da es scheinbar interesse gibt, werde ich wohl das Projekt wieder aufnehmen.
Ich hatte damals Ideen zu "Cluster3D" eine Art Container für Drawing3D in dem ich Sachen reinrändern kann. Dieser Cluster bleibt gespeichert und dann dann selbst gerändert werden DrawCuster3D().
So könnte mal Geometrien erzeugen und dann beliebig rotierung und mehrfach anzeigen.
Auch habe ich in meiner inoffiziennen Version DrawText3D() drin, wo normaler 2D-Text in die 3D-Welt gerendert wird.
Außerdem gibs DrawCylinder3D und DrawDisk3D().

Wenn ich zeit habe versuche ich n Update zu veröffentlichen.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
alter Mann
Beiträge: 201
Registriert: 29.08.2008 09:13
Wohnort: hinterm Mond

Re: Drawing3D - Draw-Befehle für 3D-Szenen

Beitrag von alter Mann »

@Silbersurfer:
Ich vergesse meist, das auch Programmierer Mathe nicht mögen deshalb hier mal den Versuch einer Erklärung.

Code: Alles auswählen

; wenn Deine Drehmatrix nicht stimmt, so setze Deine Matrix doch einfach aus den Einzelmatrizen (die ja stimmen) zusammen,
; indem Du sie nacheinander durchmultiplizierst:

Procedure MatrixMult3x3(*m1.Matrix3D,*m2.Matrix3D,*m3.Matrix3D)
 *m3\p11 = *m1\p11 * *m2\p11 + *m1\p21 * *m2\p12 + *m1\p31 * *m2\p13
 *m3\p12 = *m1\p11 * *m2\p21 + *m1\p21 * *m2\p22 + *m1\p31 * *m2\p23
 *m3\p13 = *m1\p11 * *m2\p31 + *m1\p21 * *m2\p32 + *m1\p31 * *m2\p33

 *m3\p21 = *m1\p12 * *m2\p11 + *m1\p22 * *m2\p12 + *m1\p32 * *m2\p13
 *m3\p22 = *m1\p12 * *m2\p21 + *m1\p22 * *m2\p22 + *m1\p32 * *m2\p23
 *m3\p23 = *m1\p12 * *m2\p31 + *m1\p22 * *m2\p32 + *m1\p32 * *m2\p33

 *m3\p31 = *m1\p13 * *m2\p11 + *m1\p23 * *m2\p12 + *m1\p33 * *m2\p13
 *m3\p32 = *m1\p13 * *m2\p21 + *m1\p23 * *m2\p22 + *m1\p33 * *m2\p23
 *m3\p33 = *m1\p13 * *m2\p31 + *m1\p23 * *m2\p32 + *m1\p33 * *m2\p33
EndProcedure

; Du kannst natürlich auch die von Stargate erwähnten Quaternions benutzen. Der Vorteil : alle Transformationen
; können durch eine Matrixform dargestellt werden z.B. :

Structure Matrix4                 ; Drehmatrix  Verschiebematrix Skalierungsmatrix
  p11.f : p21.f : p31.f : p41.f   ; d d d 0     1 0 0 v          s 0 0 0
  p12.f : p22.f : p32.f : p42.f   ; d d d 0     0 1 0 v          0 s 0 0
  p13.f : p23.f : p33.f : p43.f   ; d d d 0     0 0 1 v          0 0 s 0
  p14.f : p24.f : p34.f : p44.f   ; 0 0 0 1     0 0 0 1          0 0 0 1
EndStructure

; die gesamte Transformation mit verdrehen, verschieben, skalieren kann durch Multiplizieren der entsprechenden
; Matrizen auf eine Matrix-Vektor-Multiplikation zurückgeführt werden, was bei großen Datenmengen natürlich von
; Vorteil ist (z.B. OpenGL arbeitet so)
; Punkte und Vektoren werden dabei so dargestellt:

Structure Vector4                 ; Punkt     Vektor
  p1.f : p2.f : p3.f : p4.f       ; x y z 1   x y z 0
EndStructure

; orthogonal :
; Eine Drehmatrix ist immer orthogonal d.h. die Determinante ist 1.
; Wenn orthogonale Matrizen multipliziert werden, ist das Ergebnis wieder orthogonal.
; Die Drehmatrix kann man sich als Koordinatensystemachsen vorstellen (jede Achse steht senkrecht auf den anderen
; beiden Achsen -> deswegen orthogonal). Wenn Matrizen sehr oft miteinander multipliziert werden, (und nicht immer
; wieder initialisiert werden z.B. durch Neuberechnung aus Winkeln) kann durch die Fehlerfortpflanzung die
; Drehmatrix nicht mehr orthogonal sein. Das kann man durch die Berechnung der Determinante der Drehmatrix
; prüfen (der Skalierungsfaktor ist hierbei zu beachten!!!). Wenn die Determinante sehr von 1 abweicht, dann
; sollte man die Drehmatrix wieder orthogonalisieren, sonst ist die Darstellung verzerrt.

Structure Vector3
  p1.f : p2.f : p3.f
EndStructure

Procedure.f Determinante(*m.Matrix3D)
  Protected D.f = *m\p11 * *m\p22 * *m\p33 + *m\p21 * *m\p32 * *m\p13 + *m\p31 * *m\p12 * *m\p23
  D - *m\p11 * *m\p32 * *m\p23 + *m\p21 * *m\p12 * *m\p33 + *m\p31 * *m\p22 * *m\p13
  ProcedureReturn D
EndProcedure

Procedure VektorProduct(*v1.Vektor3,*v2.Vector3,*v3.Vector3)
  *v3\p1 = *v1\p2 * *v2\p3 - *v1\p3 * *v2\p2
  *v3\p2 = *v1\p3 * *v2\p1 - *v1\p1 * *v2\p3
  *v3\p3 = *v1\p1 * *v2\p2 - *v1\p2 * *v2\p1
EndProcedure

Procedure VektorNorm(*v.Vector3)
  Protected L.f = *v\p1 * *v\p1 + *v\p2 * *v\p2 + *v\p3 * *v\p3
  L = Sqr(L)
  *v\p1 * L
  *v\p2 * L
  *v\p3 * L
EndProcedure

Procedure OrthoMatrix(*m.Matrix3D)
  Protected v1.Vector3,v2.Vektor3,v3.Vektor3,vh2.Vector3,vh3.Vector3
   
  v1\p1 = *m\p11 : v1\p2 = *m\p12 : v1\p3 = *m\p13
  v2\p1 = *m\p21 : v2\p2 = *m\p22 : v2\p3 = *m\p23
  v3\p1 = *m\p31 : v3\p2 = *m\p32 : v3\p3 = *m\p33
  
  VectorProduct(@v1,@v2,@vh3)
  VectorProduct(@vh3,@v1,@vh2)
  
  VectorNorm(@v1)
  VectorNorm(@vh2)
  VectorNorm(@vh3)
  
  *m\p11 = v1\p1  : *m\p12 = v1\p2  : *m\p13 = v1\p3
  *m\p21 = vh2\p1 : *m\p22 = vh2\p2 : *m\p23 = vh2\p3
  *m\p31 = vh3\p1 : *m\p32 = vh3\p2 : *m\p33 = vh3\p3

EndProcedure 
(der Code ist nicht geprüft!!)
Win11 64Bit / PB 6.0
Benutzeravatar
dige
Beiträge: 1182
Registriert: 08.09.2004 08:53

Re: Drawing3D - Draw-Befehle für 3D-Szenen

Beitrag von dige »

STARGÅTE hat geschrieben: Lieber selber den Background setzen mit normalen 2D-Drawing am anfang.
Yap, sieht gut aus! Danke!

Jetzt wollte ich die Bilder zufällig gedreht und zufällig platziert zeichnen lassen. Aber da
stimmt was mit den Koordinatenangaben bei DrawImage3D() nicht...
Als ob sich da was aufsummiert...

Code: Alles auswählen

XIncludeFile "Drawing3D.pbi"

Enumeration
  #Window
  #Gadget
  #Image
  #Image3D
EndEnumeration

UsePNGImageDecoder()

OpenWindow(#Window, 0, 0, 1024, 768, "Image3D", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
CanvasGadget(#Gadget, 0, 0, WindowWidth(#Window), WindowHeight(#Window))

For n = 1 To 10

  ; Nächstes Bild laden
  CreateImage(#Image, 160, 120, 32, #PB_Image_Transparent )
  If StartDrawing(ImageOutput(#Image))
      DrawingMode(#PB_2DDrawing_AllChannels )
      RoundBox(0, 0, ImageWidth(#Image), ImageHeight(#Image), 3, 3, RGBA(128, 128, 128, 100)) ; Schatten
      RoundBox(4, 4, ImageWidth(#Image) - 8, ImageHeight(#Image) - 8, 3, 3, RGBA(255, 255, 255, 255)) ; BildRahmen
      DrawText(20, 20, Str(n))
    StopDrawing()
  EndIf
  ; LoadImage(#Image, "Image.png")
  CreateImage3D(#Image3D, #Image)

  If StartDrawing3D(CanvasOutput(#Gadget))
    Drawing3DMode(#Drawing3D_Default)
    x = Random(WindowWidth(#Window) - ImageWidth(#Image))
    y = Random(WindowHeight(#Window) - ImageHeight(#Image))
    
    DrawImage3D(#Image3D, x, y, 0, ImageWidth(#Image), ImageHeight(#Image), 0, 0, Random(60)-30)
    ; DrawImage(ImageID(#Image), x, y)
    DrawText( x, y, "Bild: " + Str(n) + " | " + Str(x) + ", " + Str(y))
    StopDrawing3D()
  EndIf
  FreeImage3D(#Image3D)
Next
Repeat
  
  Select WaitWindowEvent()
      
    Case #PB_Event_CloseWindow
      End
      
  EndSelect
  
ForEver
"Papa, mein Wecker funktioniert nicht! Der weckert immer zu früh."
Antworten