3D-Koordinaten in 2D-Koordinaten umrechnen

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
Kiffi
Beiträge: 10711
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Beitrag von Kiffi »

CSprengel hat geschrieben:*grinst*
*auchgrins* OK, jetzt habe ich Deinen Text auch richtig gelesen.
Nix für ungut ;-)

Grüße ... Kiffi
a²+b²=mc²
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Re: 3D-Koordinaten in 2D-Koordinaten umrechnen

Beitrag von Kaeru Gaman »

NicTheQuick hat geschrieben:Das langsamste an der Include ist die Berechnung der Kamera-Achsen,
wenn ein oder mehrere Winkel geändert wurden. Die Umrechnungs-
Procedure selbst kommt ohne Winkelfunktionen aus und ist
daher auch recht schnell.
probier doch, precalculated tables zu benutzen...
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

@Kaeru:
Ja, das wäre natürlich eine Möglichkeit, aber für diesen Zweck schon etwas
übertrieben, wie ich finde.

@all:
Ich habe die Include etwas geändert. Fehler ausgemerzt und weniger
Winkelfunktionen benutzt. Pro Winkeländerung werden jetzt 6 mal Cos() und
Sin() auf allen drei Achsen angewandt. Weniger geht nicht. :wink:

Für Sonderwünsche einfach melden. Vielleicht krieg ich das ja hin.

Ich bin mir nicht sicher, ob meine Berechnungen stimmen, wenn man den
Würfel z.B. oben links in der Ecke sieht und dann mit der Maus so
schwenkt, dass er nach unten oder rechts wandert. Dann scheint es, als ob
er sich leicht neigen würde. Ich hab das mal realistisch mit meiner
Handy-Kamera nachgespielt: Ein weißes Blatt Papier, das den Würfel
darstellen soll, neigt sich auch etwas. Also wird es wohl stimmen, oder?
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

Falls jemand ein bisschen mit der SuperFormel herumspielen will. Weitere
Infos und Links finden sich bei Wikipedia.

Tasten:
- Numpad 1-6: Auswählen der Parameter
- Numpad 0: Wechseln der Superformel
- Bild Hoch/Runter: Ändern der Werte

Code: Alles auswählen

EnableExplicit

;Schnellerer Cos() und Sin() über Array und Macros gelöst
Global Dim RAD2CosSin.d($FFFFF)
Define _.l
#RT_RAD2CosSin = $FFFFF / (#PI * 2)
For _ = 0 To $FFFFF : RAD2CosSin(_) = Sin(_ * #PI * 2 / $FFFFF) : Next
Macro Sin(RAD)
  RAD2CosSin(Int(RAD * #RT_RAD2CosSin) & $FFFFF)
EndMacro
Macro Cos(RAD)
  RAD2CosSin(Int(RAD * #RT_RAD2CosSin + $3FFFF) & $FFFFF)
EndMacro

Macro SuperFormel(W, m, a, b, n1, n2, n3)
  Pow(Pow(Abs(Cos(m * W * 0.25) / a), n2) + Pow(Abs(Sin(m * W * 0.25) / b), n3), -1 / n1)
EndMacro
Macro SuperFormelS(W, SF)
  Pow(Pow(Abs(Cos(SF\m * W * 0.25) / SF\a), SF\n2) + Pow(Abs(Sin(SF\m * W * 0.25) / SF\b), SF\n3), -1 / SF\n1)
EndMacro

Structure Dots
  p.V3D
  c.l
EndStructure
Structure SuperFormel
  m.d
  a.d
  b.d
  n1.d
  n2.d
  n3.d
EndStructure

Procedure.l SelectedColor(Selected.l, nr.l)
  If Selected = nr
    ProcedureReturn $FF
  EndIf
  
  ProcedureReturn $FFFFFF
EndProcedure
Procedure DrawSF(x.l, y.l, *SF.SuperFormel, Selected.l = 0)
  Protected s.s
  s = "m=" + StrD(*SF\m, 3)
  DrawText(x, y, s, SelectedColor(Selected, 1))
  x + TextWidth(s) + 10
  s = "a=" + StrD(*SF\a, 3)
  DrawText(x, y, s, SelectedColor(Selected, 2))
  x + TextWidth(s) + 10
  s = "b=" + StrD(*SF\b, 3)
  DrawText(x, y, s, SelectedColor(Selected, 3))
  x + TextWidth(s) + 10
  s = "n1=" + StrD(*SF\n1, 3)
  DrawText(x, y, s, SelectedColor(Selected, 4))
  x + TextWidth(s) + 10
  s = "n2=" + StrD(*SF\n2, 3)
  DrawText(x, y, s, SelectedColor(Selected, 5))
  x + TextWidth(s) + 10
  s = "n3=" + StrD(*SF\n3, 3)
  DrawText(x, y, s, SelectedColor(Selected, 6))
EndProcedure
Procedure.d GetSFValue(*SF.SuperFormel, nr.l)
  Select nr
    Case 1 : ProcedureReturn *SF\m
    Case 2 : ProcedureReturn *SF\a
    Case 3 : ProcedureReturn *SF\b
    Case 4 : ProcedureReturn *SF\n1
    Case 5 : ProcedureReturn *SF\n2
    Case 6 : ProcedureReturn *SF\n3
  EndSelect
EndProcedure
Procedure SetSFValue(*SF.SuperFormel, nr.l, Value.d)
  Select nr
    Case 1 : *SF\m  = Value
    Case 2 : *SF\a  = Value
    Case 3 : *SF\b  = Value
    Case 4 : *SF\n1 = Value
    Case 5 : *SF\n2 = Value
    Case 6 : *SF\n3 = Value
  EndSelect
EndProcedure

Global Width.l = 800, Height.l = 600

Define SF1.SuperFormel, SF2.SuperFormel
Define d.d, e.d, R1.d, R2.d, d_add.d, e_add.d, dot.Dots
Define Selected.l
d_add = 0.025
e_add = 0.025

With SF1
  \m = 1
  \a = 1
  \b = 1
  \n1 = 1
  \n2 = 1
  \n3 = 1
EndWith

With SF2
  \m = 1
  \a = 1
  \b = 1
  \n1 = 1
  \n2 = 1
  \n3 = 1
EndWith

If Not (InitSprite() And InitKeyboard() And InitMouse()) : End : EndIf

If OpenWindow(0, 0, 0, Width, Height, "Superformel in 3D") = 0 : End : EndIf
If OpenWindowedScreen(WindowID(0), 0, 0, Width, Height, 0, 0, 0) = 0 : End : EndIf

Define p.V3D, a.V3D, p2d.V3D, SF.d

Define p_add.d, a_add.d, FOV.d, sf_add.d
p_add.d = 0.05
a_add.d = 1.5
sf_add.d = 0.1
FOV.d = 45


Selected = 1

Define *Camera.Camera
*Camera.Camera = Camera_New()
Camera_Size(*Camera, 0, Width - 1, 0, Height - 1)

Repeat
  ClearScreen(0)
  ExamineKeyboard()
  ExamineMouse()
  
  p\x = 0 : p\y = 0 : p\z = 0
  a\x = 0 : a\y = 0 : a\z = 0
  If KeyboardPushed(#PB_Key_LeftControl) Or KeyboardPushed(#PB_Key_RightControl)
    If KeyboardPushed(#PB_Key_Up)    : p\y - p_add : EndIf
    If KeyboardPushed(#PB_Key_Down)  : p\y + p_add : EndIf
    If KeyboardPushed(#PB_Key_Left)  : a\y - a_add : EndIf
    If KeyboardPushed(#PB_Key_Right) : a\y + a_add : EndIf
  Else
    If KeyboardPushed(#PB_Key_Up)    : p\z + p_add : EndIf
    If KeyboardPushed(#PB_Key_Down)  : p\z - p_add : EndIf
    If KeyboardPushed(#PB_Key_Left)  : p\x - p_add : EndIf
    If KeyboardPushed(#PB_Key_Right) : p\x + p_add : EndIf
  EndIf
  
  a\x + MouseDeltaY() * 0.5
  a\y + MouseDeltaX() * 0.5
  
  If KeyboardPushed(#PB_Key_A)     : a\x + a_add : EndIf
  If KeyboardPushed(#PB_Key_Z)     : a\x - a_add : EndIf
  If KeyboardPushed(#PB_Key_S)     : a\z + a_add : EndIf
  If KeyboardPushed(#PB_Key_X)     : a\z - a_add : EndIf
  If KeyboardPushed(#PB_Key_D) And FOV > 0.25    : FOV - 0.25 : EndIf
  If KeyboardPushed(#PB_Key_C) And FOV < 179.75  : FOV + 0.25 : EndIf
  
  If KeyboardReleased(#PB_Key_Pad1)  : Selected - (Selected - 1) % 6 + 0 : EndIf
  If KeyboardReleased(#PB_Key_Pad2)  : Selected - (Selected - 1) % 6 + 1 : EndIf
  If KeyboardReleased(#PB_Key_Pad3)  : Selected - (Selected - 1) % 6 + 2 : EndIf
  If KeyboardReleased(#PB_Key_Pad4)  : Selected - (Selected - 1) % 6 + 3 : EndIf
  If KeyboardReleased(#PB_Key_Pad5)  : Selected - (Selected - 1) % 6 + 4 : EndIf
  If KeyboardReleased(#PB_Key_Pad6)  : Selected - (Selected - 1) % 6 + 5 : EndIf
  If KeyboardReleased(#PB_Key_Pad0)  : Selected  = (Selected + 5) % 12 + 1: EndIf
  
  SF = 0
  If KeyboardPushed(#PB_Key_PageUp)   : SF + sf_add : EndIf
  If KeyboardPushed(#PB_Key_PageDown) : SF - sf_add : EndIf
  
  SetSFValue(SF1, Selected, GetSFValue(SF1, Selected) + SF)
  SetSFValue(SF2, Selected - 6, GetSFValue(SF2, Selected - 6) + SF)
  
  Camera_FOV(*Camera, FOV)
  Camera_Move(*Camera, p, a)
  
  StartDrawing(ScreenOutput())
    d = -#PI
    While d <= #PI 
      d + d_add
      R1 = SuperFormelS(d, SF1)
      
      e = -#PI * 0.5
      While e <= #PI * 0.5
        e + e_add
        R2 = SuperFormelS(e, SF2)
        
        dot\p\x = Cos(d) * R1 * Cos(e) * R2
        dot\p\y = Sin(d) * R1 * Cos(e) * R2
        dot\p\z = Sin(e) * R2
        dot\c = $FFFFFF;RGB((d + #PI) * 255 / (2 * #PI), (e + #PI * 0.5) * 255 / #PI, 255)
        
        If Camera_3Dto2D(*Camera, dot\p, p2d)
          Plot(p2d\x, p2d\y, dot\c)
        EndIf
      Wend
    Wend
    
    DrawingMode(#PB_2DDrawing_Transparent)
    DrawSF(0, 0, SF1, Selected)
    DrawSF(0, 16, SF2, Selected - 6)
  StopDrawing()
  
  FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
///Edit:
Hab die Superformel berichtigt. Sie war falsch.
Zuletzt geändert von NicTheQuick am 26.01.2008 20:31, insgesamt 1-mal geändert.
THEEX
Beiträge: 804
Registriert: 07.09.2004 03:13

Beitrag von THEEX »

Falls jemand ein bisschen mit der SuperFormel herumspielen will. Weitere
Infos und Links finden sich bei Wikipedia.
Etwas mehr Info würde die Suche deutlich vereinfachen...
Benutzeravatar
hardfalcon
Beiträge: 3447
Registriert: 29.08.2004 20:46

Beitrag von hardfalcon »

Ich wäre nie auf die Idee gekommen, nen Renderer als "Projektion von 3D-Koordinaten auf eine 2D-Fläche" zu betrachten. Da kann ich nur sagen: Faszinierend! :allright:
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

@CSprengel:
Ja, ich hatte gerade wenig Zeit um viel zu schreiben, war in Eile.
Aber im Grund finden sich unter Weblinks bei Wikipedia die besten Links
dazu. Ein schöner mit Erklärung und Beispielen ist der hier: 3D Supershape / Superformula

@hardfalcon:
Es ist kein Renderer, nur ein bisschen Rechnerei. Klingt ähnlich, aber mehr
macht die Include wirklich nicht.
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

@Nic
Falls du noch immer nen Anreiz suchst kannst du ja noch ein Beispiel mit Sprites erstellen...
Dann währste schon fast bei ner kompletten 3D Engine, naja fast eben...

Gruß
Scarabol
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea

PB-V: 4
WinXP
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

Hi Leute,

1. ich hab mal versucht ein Beispiel zu schreiben das Quadrate zwischen den einzelnen Punkten anzeigt (wie Terrain). Aber irgendwie tauchen falsche Linien auf und ich weiß nicht wie ich die Filtern soll.
http://www.purebasic.fr/german/viewtopi ... 9&start=20

2. Wie kann ich die Entfernung von Punkt zu Kamera ermitteln und die angezeigten Punkte danach begrenzen?

Gruß
Scarabol
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea

PB-V: 4
WinXP
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

zu 1.: Das passiert dann, wenn du den Rückgabewert von 'Camera_3Dto2D()'
nicht auswertest. Bei #True, liegt die 2D-Koordinate im sichtbaren Bereich,
bei #False nicht.

zu 2.: Du kannst den letzten Parameter von 'Camera_3Dto2D()' nutzen, um
herauszufinden in welcher relativen Entfernung zur Kamera der 3D-Punkt
liegt, der übergeben wurde. Wenn die Z-Koordinate von '*c3d' negativ ist,
liegt der Punkt z.B. hinter der Kamera. Wenn die X-Koordinate negativ ist,
links von der Kamera und wenn die Y-Koordinate negativ ist, unter der
Kamera.

Du solltest also die Punkte dann nicht anzeigen, wenn die Funktion #False
zurückgibt oder wenn die Z-Koordinate von '*c3d* negativ ist.
Antworten