Sprite3D um die y Achse drehen

Für allgemeine Fragen zur Programmierung mit PureBasic.
super_castle
Beiträge: 557
Registriert: 29.11.2005 15:05

Re: Sprite3D um die y Achse drehen

Beitrag von super_castle »

Der Tipp ist nett gemeint, aber nicht praktikabel. Nur, um eine Karte mit einer Drehung darzustellen lohnt es sich wohl kaum, eine komplette 3D-Enginge einzubinden. Außerdem ist es mit TransformSprite3D möglich. Die Frage ist nur: Wie?
ha...ha..., was meinst du wohl was in purebasic alles unter den sprites3d läuft usw....
da brauchst du nicht viel bauen in purebasic um 3d zu nutzen..., ha...ha...

na dann bastel mal schön....sinus...hoch...cosinus runter...die wurzel vom horizont...mal alpha...plus...z...
schwupps und schon dreht sich alles....was anderes macht 3dogre auch nicht....ha...ha...nur ist es übersichtlicher und einheitlicher ...
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Sprite3D um die y Achse drehen

Beitrag von STARGÅTE »

Sebastian hat geschrieben:Bei dem Beispiel fällt mir auf: Die recht Fläche scheint ein wenig um den Mittelpunkt zu "eiern". Woran liegt es und kann man es umgehen?
Jo da hast du recht, liegt daran, dass ich in dem Beispiel "nur" ein Beispiel für z geben wollte.
Ich habe dort jedoch die Radiusverkleinerung hinten unterschlagen.

Hier eine Version bei der die Achse stabil ist:

Code: Alles auswählen

InitSprite()
InitSprite3D()

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

  CreateSprite(1, 64, 64, #PB_Sprite_Texture)
  StartDrawing(SpriteOutput(1))
    Box(0, 0, 64, 64, $808080)
    For x = 0 To 7
    For y = 0 To 7
      If (x+y)%2 : Box(x*8, y*8, 8, 8, $FFFFFF) : EndIf
    Next
    Next
  StopDrawing()
  CreateSprite3D(1, 1)
    
Repeat

  ClearScreen(0)

  #HalfSize = 150
  #Distance = 500

  Start3D()

    a.f = ElapsedMilliseconds()/1000

    z1.f = #Distance-Sin(a)*#HalfSize : z4.f=z1
    z2.f = #Distance+Sin(a)*#HalfSize : z3.f=z2
    x1.f = -Cos(a)*#HalfSize*#Distance/z1 : x4.f=x1
    x2.f =  Cos(a)*#HalfSize*#Distance/z2 : x3.f=x2
    j.f = #HalfSize*#HalfSize
    y1.f = -#HalfSize-Sin(a)*j/z1 : y2.f=-#HalfSize+Sin(a)*j/z2
    y3.f =  #HalfSize-Sin(a)*j/z3 : y4.f= #HalfSize+Sin(a)*j/z4
  
    TransformSprite3D(1, x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4)
    DisplaySprite3D(1, 400, 300)
    TransformSprite3D(1, x2,y2,z2, x1,y1,z1, x4,y4,z4, x3,y3,z3)
    DisplaySprite3D(1, 400, 300)

  Stop3D()
 
  FlipBuffers()

Until WindowEvent() = #PB_Event_CloseWindow 
Aber wie gesagt, das ist eine recht unflexible variante ...

Man kann natürlich auch eine mit der echten RotationsMatrix rechnen, ähnlich wie hier:
http://www.purebasic.fr/german/viewtopi ... =3&t=23247
Dort dann mittels Prozedure ein Sprite mit 3 Koordinaten und 3 Rotationen anzuzeigen

Das sehe dann so aus:

Code: Alles auswählen

Structure Vector3D
  x.f : y.f : z.f
EndStructure

Structure Rotation3D
  CosX.f : SinX.f : CosY.f : SinY.f : CosZ.f : SinZ.f
EndStructure 
 
Procedure Drawing3D_UpdateRotation3D(*Rotation3D.Rotation3D, Rx.f, Ry.f, Rz.f)
  With *Rotation3D
    \CosX = Cos(Rx) : \SinX = Sin(Rx)
    \CosY = Cos(Ry) : \SinY = Sin(Ry)
    \CosZ = Cos(Rz) : \SinZ = Sin(Rz)
  EndWith 
EndProcedure

Procedure Drawing3D_MatrixTimesVector(*Result.Vector3D, *Rotation3D.Rotation3D, *Vector.Vector3D)
  With *Rotation3D
    *Result\x = *Vector\x * (\CosY*\CosZ)                   + *Vector\y * (\CosY*\SinZ)                    + *Vector\z * (-\SinY)
    *Result\y = *Vector\x * (\CosZ*\SinX*\SinY-\CosX*\SinZ) + *Vector\y * (\CosX*\CosZ+\SinX*\SinY*\SinZ)  + *Vector\z * (\CosY*\SinX)
    *Result\z = *Vector\x * (\CosX*\CosZ*\SinY+\SinX*\SinZ) + *Vector\y * (-\CosZ*\SinX+\CosX*\SinY*\SinZ) + *Vector\z * (\CosX*\CosY)
  EndWith
EndProcedure


#Distance = 800


Procedure DisplayField3D(Sprite3D, Width.f, Height.f, Px.f, Py.f, Pz.f, Rx.f, Ry.f, Rz.f)
  Protected Dim Corner.Vector3D(3), Dim NewCorner.Vector3D(3)
  Protected Dim V.Vector3D(3), Rotation3D.Rotation3D
  Corner(0)\x = -Width*0.5 : Corner(0)\y = -Height*0.5
  Corner(1)\x =  Width*0.5 : Corner(1)\y = -Height*0.5
  Corner(2)\x =  Width*0.5 : Corner(2)\y =  Height*0.5
  Corner(3)\x = -Width*0.5 : Corner(3)\y =  Height*0.5
  Drawing3D_UpdateRotation3D(Rotation3D, Rx, Ry, Rz)
  For n = 0 To 3
    Drawing3D_MatrixTimesVector(NewCorner(n), Rotation3D, Corner(n))
    NewCorner(n)\z + Pz
    V(n)\x = NewCorner(n)\x * #Distance / (NewCorner(n)\z+#Distance) + Px
    V(n)\y = NewCorner(n)\y * #Distance / (NewCorner(n)\z+#Distance) + Py
    V(n)\z = NewCorner(n)\z + #Distance
  Next 
  TransformSprite3D(Sprite3D, V(0)\x,V(0)\y,V(0)\z, V(1)\x,V(1)\y,V(1)\z, V(2)\x,V(2)\y,V(2)\z, V(3)\x,V(3)\y,V(3)\z)
  DisplaySprite3D(Sprite3D, 0, 0)
EndProcedure 
 

InitSprite()
InitSprite3D()

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

  Sprite3DQuality(1)

  Font = FontID(LoadFont(#PB_Any, "Arial", 48))
  CreateSprite(1, 64, 64, #PB_Sprite_Texture)
  StartDrawing(SpriteOutput(1))
    For x = 0 To 7
    For y = 0 To 7
      Box(x*8, y*8, 8, 8, $808080+$404040*(x+y)%2)
    Next
    Next
   DrawingFont(Font) : DrawingMode(1)
   DrawText(16,0,"F", $FF0000, 0)
  StopDrawing()
  CreateSprite3D(1, 1)
   
Define pd3d.IDirect3DDevice9

Repeat

  ClearScreen(0)

  #HalfSize = 150
 
  Start3D()

  ; Zum Rändern der "anderen" Seite
  EnableASM
    !extrn _PB_Screen_Direct3DDevice
    !MOV dword EAX, [_PB_Screen_Direct3DDevice]
    !MOV dword [v_pd3d],EAX
  DisableASM
  pd3d\SetRenderState(22,1)

  a.f = ElapsedMilliseconds()/1000
     
  DisplayField3D(1,200,200, 150,300,0, a,0,0)
  DisplayField3D(1,200,200, 400,300,0, 0,a,0)
  DisplayField3D(1,200,200, 650,300,0, a,0,a/3)

  FlipBuffers()

Until WindowEvent() = #PB_Event_CloseWindow 
Hier kannst du nun wirklich, eine beliebige Rotation durchführen ...

@super_castle: finde deins viel umständlicher, zumal ich n externe DLL brauche, und in der 3D-Engine "gefangen" bin.
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
Regenduft
Beiträge: 574
Registriert: 25.03.2008 15:07
Wohnort: THE LÄÄÄND!

Re: Sprite3D um die y Achse drehen

Beitrag von Regenduft »

@ Stargate: Ich stehe gerade auf dem Schlauch...
1. Was ist denn jetzt bei dem ersten Beispiel-Code anders als bei dem aus Deinem ersten Posting? (außer natürlich das Du nur einen Sprite und den zentriert zeichnest)
2. Wie kommst man denn auf den Assemblerteil im Rotationsmatrix-Code? Reverse Engineering oder ist das irgendwo (offiziell) dokumentiert?

@ super_contra: Wenn Dir Sebastian freundlich und sachlich antwortet, dann rückantworte doch bitte auch freundlich oder zumindest sachlich. Es ist ja erlaubt eine andere Meinung zu haben. Solltest Du jetzt losflamen wollen, dann mache es bitte per PN.
PureBasic 5.73 LTE x86/x64 | Windows 7 (x64)
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Sprite3D um die y Achse drehen

Beitrag von STARGÅTE »

Regenduft hat geschrieben: 1. Was ist denn jetzt bei dem ersten Beispiel-Code anders als bei dem aus Deinem ersten Posting? (außer natürlich das Du nur einen Sprite und den zentriert zeichnest)
Garnix, da ich inzwischen alle Codes aktuallisiert habe, (sry wenns verwirrt hat).
Ich hatte vorher falsche Berechungen drine, was dazu führte, dass das Bild "eierte".
Regenduft hat geschrieben: 2. Wie kommst man denn auf den Assemblerteil im Rotationsmatrix-Code? Reverse Engineering oder ist das irgendwo (offiziell) dokumentiert?
Nein. Dies habe ich aus dem Englischen Forum, dort wurde dieses Code-Stück gepostet, als es darum ging Sachen zu drehen bzw zu spiegeln.

Auf jeden Fall ist der "neue" Code "richtiger", da ich die Berechungen auch in meiner Drawing3D Include benutze.
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
Sebastian
Beiträge: 322
Registriert: 14.06.2006 16:46
Wohnort: Kiel

Re: Sprite3D um die y Achse drehen

Beitrag von Sebastian »

@Stargate:
Es ist beeindruckend. Es macht wirklich genau das, was ich benötige! Mit dieser kleinen Änderung habe ich nun genau meine drehende Karte. Wow. Du bist mein neuer Guru! :praise:

Code: Alles auswählen

InitSprite()
InitSprite3D()

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

CreateSprite(1, 96, 128, #PB_Sprite_Texture)
StartDrawing(SpriteOutput(1))
Box(0, 0, 96, 128, $808080)
For x = 0 To 11
For y = 0 To 15
If (x+y)%2 : Box(x*8, y*8, 8, 8, $FFFFFF) : EndIf
Next
Next
StopDrawing()
CreateSprite3D(1, 1)
       
Repeat

ClearScreen(0)

#SizeX = 96
#SizeY = 128
#Distance = 500

Start3D()

a.f = ElapsedMilliseconds()/1000

z1.f = #Distance-Sin(a)*#SizeX : z4.f=z1
z2.f = #Distance+Sin(a)*#SizeX : z3.f=z2
x1.f = -Cos(a)*#SizeX*#Distance/z1 : x4.f=x1
x2.f =  Cos(a)*#SizeX*#Distance/z2 : x3.f=x2
j.f = #SizeX*#SizeY
y1.f = -#SizeY-Sin(a)*j/z1 : y2.f=-#SizeY+Sin(a)*j/z2
y3.f =  #SizeY-Sin(a)*j/z3 : y4.f= #SizeY+Sin(a)*j/z4
     
TransformSprite3D(1, x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4)
DisplaySprite3D(1, 400, 300)
TransformSprite3D(1, x2,y2,z2, x1,y1,z1, x4,y4,z4, x3,y3,z3)
DisplaySprite3D(1, 400, 300)

Stop3D()

FlipBuffers()

Until WindowEvent() = #PB_Event_CloseWindow
(Win 11 64-bit, PB 6.04 und 6.10)
Benutzeravatar
Sebastian
Beiträge: 322
Registriert: 14.06.2006 16:46
Wohnort: Kiel

Re: Sprite3D um die y Achse drehen

Beitrag von Sebastian »

Oh wei! Ich habe mich an Deinem Beispiel in den letzten Stunden noch einmal ausgetobt. Ob nun DVD-Cover oder, wie in meinem Fall, eine Karte - das Problem ist, dass ein Rechteck und kein Quadrat zu verwenden ist. Also muss ich (da #PB_Sprite_Texture gerne einen Wert 2^x hätte) das Sprite in viele Kleine Sprites zerlegen. Ich nehme eine Ausgangskarte von 384x512 px. Nun zerlege ich das Sprite in 6x8 Sprite3D-Grafiken und rotiere diese mit Hilfe Deines (überarbeiteten) Codes. Funktioniert wunderbar (klar, die Rückseite nun nicht mehr, aber da muss später ja eh eine andere Grafik hin). Nur leider entstehen nun "Unsauberkeiten". Man sieht die Brüche zwischen den einzelnen Sprite3D-Grafiken. Muss ich da irgendwie runden, damit es klappt oder wie sieht die Lösung aus?

LG

Hmm. Mir fällt auf, dass das Problem nur bei der bilinearen Filterung auftritt...

Code: Alles auswählen

InitSprite()
InitSprite3D()
UsePNGImageDecoder()


OpenWindow(0, 0, 0, 1024, 600, "Screen", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0), 0, 0, WindowWidth(0), WindowHeight(0), 0, 0, 0)


; Vorgabe, in wie viele Teile das Sprite zerteilt wird

ElementsX= 6
ElementsY= 8


; Größe der einzelnen 3D-Sprites

SizeX = 64
SizeY = 64


LoadSprite(0,"karte.png")
Sprite3DQuality(#PB_Sprite3D_BilinearFiltering)

; Sprite in Sprite3D-Einheiten zerlegen

DisplaySprite(0,0,0)

Dim Sprite_Address (ElementsX, ElementsY)
Dim Sprite3D_Address (ElementsX, ElementsY)

For Y = 0 To ElementsY-1
  For X = 0 To ElementsX-1
    Sprite_Address(X,Y) = GrabSprite(#PB_Any,X*SizeX, Y*SizeY, SizeX, SizeY, #PB_Sprite_Texture)
    Sprite3D_Address(X,Y) = CreateSprite3D(#PB_Any, Sprite_Address(X,Y))
  Next
Next

q = 3

Repeat
  
  ClearScreen(0)
  
  
  StartpointX = (ElementsX/2) * (-SizeX)
  StartpointY = (ElementsY/2) * (-SizeY)
  
  #Distance = 500
  
  Start3D()
  
  a.f = ElapsedMilliseconds()/1000
  
  For Y = 0 To ElementsY-1
    For X = 0 To ElementsX-1
      
      Element_StartpointX = StartpointX + (X * SizeX)
      Element_EndpointX = Element_StartpointX + SizeX
      Element_StartpointY = StartpointY + (Y * SizeY)
      Element_EndpointY = Element_StartpointY + SizeY
      
      ; Z-Parameter 
      
      z1.f = #Distance + Sin(a) * Element_StartpointX /q : z4.f=z1
      z2.f = #Distance + Sin(a) * Element_EndpointX   /q : z3.f=z2
      
      ; X-Parameter 
      
      x1.f =  Cos(a) * Element_StartpointX * #Distance / z1 : x4.f=x1
      x2.f =  Cos(a) * Element_EndpointX * #Distance / z2 : x3.f=x2
      
      ; Y-Parameter 
      
      y1.f =   Element_StartpointY - Sin(a) * Element_StartpointX * Element_StartpointY /  z1  /q :  y4.f =   Element_EndpointY - Sin(a) * Element_StartpointX * Element_EndpointY / z4 /q
      y2.f =   Element_StartpointY - Sin(a) * Element_EndpointX   * Element_StartpointY /  z2  /q :  y3.f =   Element_EndpointY - Sin(a) * Element_EndpointX   * Element_EndpointY / z3 /q
      
      ; Darstellungs-Operationen
      
      TransformSprite3D(Sprite3D_Address(X,Y), x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4)
      DisplaySprite3D(Sprite3D_Address(X,Y), 400, 300)
      TransformSprite3D(Sprite3D_Address(X,Y), x2,y2,z2, x1,y1,z1, x4,y4,z4, x3,y3,z3)
      DisplaySprite3D(Sprite3D_Address(X,Y), 400, 300)
      
      
      
    Next
  Next
  
  Stop3D()
  
  FlipBuffers()
  
Until WindowEvent() = #PB_Event_CloseWindow
(Win 11 64-bit, PB 6.04 und 6.10)
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Sprite3D um die y Achse drehen

Beitrag von STARGÅTE »

Nun zerlege ich das Sprite in 6x8 Sprite3D-Grafiken und rotiere diese mit Hilfe Deines (überarbeiteten) Codes
Das ist nicht dein ernst ?
Sry, aber das halte ich für total sinnlos ...

1. kannst du ohne probleme nicht quadratische Sprite/Sprite3D nutzen ...
Hier ein Beitrag dazu: http://www.purebasic.fr/german/viewtopi ... 16&t=22224
2. selbst wenn nur Quadratische gehen würden, wäre ein transparenter Rand (links und recht) viel einfach und sauberer als diese Karte in 48 einzel-Sprite zu zerteilen.
Da entstehen nur probleme, egal wie gut die Routienen sind: Fugenlücken/Überlappungen, Mehr rechenzeit usw.

Eine lösung für die Fugen gibt es nicht, da DX9 immer nur eine Textur glättet von Pixel zu Pixel und am rand zur anderen seite des eigenen Rands.
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
super_castle
Beiträge: 557
Registriert: 29.11.2005 15:05

Re: Sprite3D um die y Achse drehen

Beitrag von super_castle »

Sauber ist die Drehung nicht, man sieht während der Drehung die Unebenheiten der Sinus/Cosinusfunktion. Die Fläche wirkt dadurch ein bisschen Pixelig während der Drehung.

Am saubersten geht es mit Ogre und Filterung, das ist dann Filmreif.

Gruss
Benutzeravatar
Sebastian
Beiträge: 322
Registriert: 14.06.2006 16:46
Wohnort: Kiel

Re: Sprite3D um die y Achse drehen

Beitrag von Sebastian »

@ Stargate: Tja. Was soll ich sagen? Vielleicht bin ich über das Ziel hinaus geschossen. Ich wollte es irgendwie durchdacht programmieren. Ich hatte das Programm mit einer Textur im rechteckigen Format getestet. Es lief nicht. Dann nahm ich eine quadratische Textur. Es lief. Es handelt sich um einen aktuellen Rechner (Aldi). Ich habe am WE Zugriff auf den Computer. Vielleicht habe ich einen anderen Fehler verursacht. Das werde ich nach diesem Hinweis überprüfen. Falls nicht, dann ist man immer noch auf der sicheren Seite, nur quadratische Texturen zu verwenden. Und falls ich mich geirrt habe, dann habe ich leider unnötige Zeit in die Überarbeitung Deines Codes gesteckt... :cry:

Und was das "Fugenglätten" angeht: Ich dachte immer, dass man mit dem einfachen Befehl "TransformSprite3D" ein Fundament hat, eine 3D-Engine selbst zu schreiben. Da habe ich die Leistung des Befehls eindeutig überschätzt, nehme ich an.

@super_castle: Sicher hast Du recht. Ogre kann eine ganze Menge. Ich möchte aber nur den winzigen Effekt haben, dass eine Karte umgedreht wird. So wie bei Win7 etwa bei dem Spiel "Hearts". Es geht zu schnell, um sich über pixeliges Aussehen zu wundern. Man könnte es natürlich auch vorberechnen, aber es handelt sich nicht um Spielkarten, sondern um Karten, die individuell gestaltet sind (Lernkarten).
(Win 11 64-bit, PB 6.04 und 6.10)
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Sprite3D um die y Achse drehen

Beitrag von STARGÅTE »

Und was das "Fugenglätten" angeht: Ich dachte immer, dass man mit dem einfachen Befehl "TransformSprite3D" ein Fundament hat, eine 3D-Engine selbst zu schreiben. Da habe ich die Leistung des Befehls eindeutig überschätzt, nehme ich an.
Nein leider nicht.
Klar kann TransformSprite3D() ein Sprite3D verformen wie man will (3-Dimensional) also deren 2 Dreiecke ...
Aber das zusammenspiel vieler TransformSprite3D() erreicht leider keine echte 3D-Engine ...
Das hauptproblem was ich dabei sehe ist nicht die Sache mit den Fugen, sonden, dass sich die Sprites nicht "durchdringen" können, was ja bei OGRE der fall ist. bei Sprite3D ist immer genau eins über dem anderen ...

Trotzdem könnte man eine 3D-Engine schrieben:
Ypser hatte mal vor Jahren seine Winterlandschaft 3D vorgestellt, welche auch sehr gut war. (Link leider down)
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
Antworten