3D-Koordinaten in 2D-Koordinaten umrechnen
-
- Beiträge: 26
- Registriert: 05.11.2006 22:01
- Kontaktdaten:
Ich hatte PureBasic schon einmal über einen längeren Zeitraum hinweg verwendet und bin damit soweit auch gut klar gekommen. Nun beschäftige ich mich aber erstmal mehr mit GLBasic, weil ich damit für eine spezielle Plattform compilieren kann, die mich interessiert.
Also Strukturen und Listen habe ich in PureBasic natürlich schon verwendet aber Pointer nicht. Nun, dann müsste ich mich wohl erstmal mit Pointern auseinandersetzen, vielleicht verstehe ich dann mehr. Allerdings verwendest du in deinem Code unglaublich viele Variablen und da muss man sich erstmal eine Übersicht verschaffen.
Also Strukturen und Listen habe ich in PureBasic natürlich schon verwendet aber Pointer nicht. Nun, dann müsste ich mich wohl erstmal mit Pointern auseinandersetzen, vielleicht verstehe ich dann mehr. Allerdings verwendest du in deinem Code unglaublich viele Variablen und da muss man sich erstmal eine Übersicht verschaffen.
-
- Beiträge: 26
- Registriert: 05.11.2006 22:01
- Kontaktdaten:
Inzwischen habe ich mich dazu entschieden lieber einen eigenen Code, der stark vereinfacht ist, zu schreiben. Diesen hier für GLBasic umzusetzen ist mir doch zu mühevoll. Pointer gibt es dort nämlich nicht. Nun hätte ich aber eine Bitte. Und zwar gibt es doch folgende allgemein bekannte einfache Formel, um 3D-Koordinaten in 2D umzurechnen:
Das funktioniert auch alles schon wunderbar aber nun gibt es ein Problem, wenn sich ein Punkt hinter dem Betrachtungspunkt befindet, wenn Z also kleiner 0 ist. Dann kehrt sich die ganze Berechnung um und der Punkt wandert wieder in das Bild hinein.
(Um kurz am Rande noch etwas Wichtiges zu erwähnen: ich mache mir es ganz einfach, indem ich keine virtuelle Kamera erstelle, wo ich ständig aus einem anderen Blickwinkel berechnen muss, sondern die Berechnung für den Blickwinkel bleibt immer die selbe und ich bewege oder rotiere nur die gesamte Welt! Ich rotiere dann entsprechend, so dass es so aussieht, als wenn die Kamera schwenken würde.)
Könntest du mir verraten, wie ich nun einen Punkt "hinter dem Bildschirm" berechnen könnte? Ich habe schon viel rumprobiert aber es klappt einfach nicht.
Nun, warum berechnen, wenn "hinter dem Bildschirm"? Ganz einfach: ich definiere auch Linienverbindungen zwischen den Punkten meines Drahtgittermodells und längere Linien, die entlang der Z-Achse verlaufen, müssen solange korrekt dargestellt werden, bis sich beide Punkte der Linie hinter dem Betrachter befinden. Deshalb brauche ich das. Momentan habe ich es halt so gemacht, dass der Punkt dann eben nicht mehr berechnet wird und nur Linien dargestellt werden, von denen beide Punkte noch im Bereich Z>0 sind.
Könntest du mir da helfen, Nic?
Code: Alles auswählen
x2D = ScreenW / 2 + x3D * Zoom / z3D
y2D = ScreenH / 2 + y3D * Zoom / z3D
(Um kurz am Rande noch etwas Wichtiges zu erwähnen: ich mache mir es ganz einfach, indem ich keine virtuelle Kamera erstelle, wo ich ständig aus einem anderen Blickwinkel berechnen muss, sondern die Berechnung für den Blickwinkel bleibt immer die selbe und ich bewege oder rotiere nur die gesamte Welt! Ich rotiere dann entsprechend, so dass es so aussieht, als wenn die Kamera schwenken würde.)
Könntest du mir verraten, wie ich nun einen Punkt "hinter dem Bildschirm" berechnen könnte? Ich habe schon viel rumprobiert aber es klappt einfach nicht.
Nun, warum berechnen, wenn "hinter dem Bildschirm"? Ganz einfach: ich definiere auch Linienverbindungen zwischen den Punkten meines Drahtgittermodells und längere Linien, die entlang der Z-Achse verlaufen, müssen solange korrekt dargestellt werden, bis sich beide Punkte der Linie hinter dem Betrachter befinden. Deshalb brauche ich das. Momentan habe ich es halt so gemacht, dass der Punkt dann eben nicht mehr berechnet wird und nur Linien dargestellt werden, von denen beide Punkte noch im Bereich Z>0 sind.
Könntest du mir da helfen, Nic?
- 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
-
- Beiträge: 26
- Registriert: 05.11.2006 22:01
- Kontaktdaten:
- 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
Hier wäre der richtige Code:
Code: Alles auswählen
Structure V3D
x.d
y.d
z.d
EndStructure
Procedure GetEndpoint(*p1.V3D, *p2.V3D, *p_out.V3D)
Protected u.V3D, mue.d
u\x = *p2\x - *p1\x
u\y = *p2\y - *p1\y
u\z = *p2\z - *p1\z
If u\z = 0.0
mue = 0.0
Else
mue = - *p1\z / u\z
EndIf
*p_out\x = *p1\x + mue * u\x
*p_out\y = *p1\y + mue * u\y
*p_out\z = *p1\z + mue * u\z
EndProcedure
Define p1.V3D, p2.V3D
p1\x = 1
p1\y = 2
p1\z = 3
p2\x = -3
p2\y = -2
p2\z = -1
;Da bei p2 Z im Negativen liegt, müssen wir p2 neu berechnen
GetEndpoint(@p1, @p2, @p2)
;Neue Koordinaten von Z
Debug p2\x
Debug p2\y
Debug p2\z
-
- Beiträge: 26
- Registriert: 05.11.2006 22:01
- Kontaktdaten:
Der Code erschlägt mich ja glatt, trotzdem besten Dank für deine Bemühung. Naja im Vergleich jetzt mal zu der Formel, wie ich sie gegeben habe, ist dies hier echt umständlich.
Nun gut, ich kann nur versuchen, es irgendwie in meinen Code zu übertragen. Aber ich bin überzeugt, es ginge sehr viel einfacher. Denn es wiederspricht irgendwie sehr meiner Logik, dass so viel mehr Rechenaufwand nötig ist, nur weil Z negativ wird.
Möglicherweise aber konnte ich nicht genau rüberbringen, was ich gerne wollte oder das Problem liegt ganz einfach daran, dass du in PureBasic denkst und ich in GLBasic. Wenn ich meinen Code mal gebe, würde das sicher wenig nützen, denn der würde in PureBasic ja nicht laufen. Müsste ich vorher umschreiben...
Nun gut, ich kann nur versuchen, es irgendwie in meinen Code zu übertragen. Aber ich bin überzeugt, es ginge sehr viel einfacher. Denn es wiederspricht irgendwie sehr meiner Logik, dass so viel mehr Rechenaufwand nötig ist, nur weil Z negativ wird.
Möglicherweise aber konnte ich nicht genau rüberbringen, was ich gerne wollte oder das Problem liegt ganz einfach daran, dass du in PureBasic denkst und ich in GLBasic. Wenn ich meinen Code mal gebe, würde das sicher wenig nützen, denn der würde in PureBasic ja nicht laufen. Müsste ich vorher umschreiben...
Dein Problem ist einfach das du die Ergebnisse filtern musst, so oder so musst du erst alle Berechnen und dann filtern, welche sind außerhalb des Bildschirms...
Dieses Filtern kann man nicht einfacher machen...
Gruß
Scarabol
Dieses Filtern kann man nicht einfacher machen...
Gruß
Scarabol
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea
PB-V: 4
WinXP
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea
PB-V: 4
WinXP
- 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
-
- Beiträge: 26
- Registriert: 05.11.2006 22:01
- Kontaktdaten:
Um vielleicht doch ein eventuelles Missverständnis auszuschließen, habe ich nun meinen Code für PureBasic umgeschrieben:
Leider funktionieren die Rotationen hier in PureBasic nicht, da die Funktionen ATAN(), SIN() und COS() anders arbeiten als bei GLBasic. Da konnte der Winkel im DEG-Format angegeben werden und ATAN() akzeptierte die Angabe des X- und Y-Anstiegs. Ich habe zwar schon probiert in Radiant umzurechnen aber das klappte dann alles vorne und hinten nicht.
Aber egal, es geht ja hier nur mal darum, wie ich das gemacht habe. Wie schon erwähnt, verschiebe ich immer die 3D-Punkte und erreiche damit denselben Effekt.
So, und jetzt habe ich bei obigem Code die Stelle kommentiert, wo die Formel rein müsste für Z<=0. Da muss jetzt nichts gefiltert werden, es geht immer nur um die Berechnung eines einzigen 2D-Punktes bei jedem Schleifendurchlauf. Es muss ganz einfach sein - irgendwie muss die Formal nur umgekehrt werden aber ich weiß eben nicht, wie. Momentan werden eben die Linien einfach ausgeblendet, so bald einer der beiden Endpunkte nicht mehr korrekt berechnet werden kann.
Code: Alles auswählen
Structure Dots3D
dx.f
dy.f
dz.f
EndStructure
Structure Dots2D
da.l
dx.l
dy.l
EndStructure
Structure Lines
d1.l
d2.l
cl.l
EndStructure
Global Dim Dots3D.Dots3D(0)
Global Dim Dots2D.Dots2D(0)
Global Dim Lines.Lines(0)
Global CamDist, ScreenW, ScreenH, Zoom, NrOfDots, NrOfLines
Procedure Convert3Dto2D()
For i = 0 To NrOfDots
Dots2D(i)\da = 0
If Dots3D(i)\dz - CamDist > -200
Dots2D(i)\da = 1
Dots2D(i)\dx = ScreenW / 2 + Dots3D(i)\dx * Zoom / (-Dots3D(i)\dz - CamDist)
Dots2D(i)\dy = ScreenH / 2 + Dots3D(i)\dy * Zoom / (-Dots3D(i)\dz - CamDist)
Else
;Hier muss die Formel für die Berechnung des 2D Punktes hinter dem Betrachter rein!
EndIf
Next
EndProcedure
Procedure DrawObject(Mode)
StartDrawing(ScreenOutput())
If Mode = 1 Or Mode = 3
For i = 0 To NrOfLines
If Dots2D(Lines(i)\d1)\da And Dots2D(Lines(i)\d2)\da
LineXY(Dots2D(Lines(i)\d1)\dx, Dots2D(Lines(i)\d1)\dy, Dots2D(Lines(i)\d2)\dx, Dots2D(Lines(i)\d2)\dy, Lines(i)\cl)
EndIf
Next
EndIf
If Mode > 1
For i = 0 To NrOfDots
If Dots2D(i)\da
If Dots2D(i)\dx > 0 And Dots2D(i)\dx < ScreenW And Dots2D(i)\dy > 0 And Dots2D(i)\dy < ScreenH
Plot(Dots2D(i)\dx, Dots2D(i)\dy, $ffffff)
EndIf
EndIf
Next
EndIf
StopDrawing()
EndProcedure
Procedure MoveObject(mx, my, mz)
For i = 0 To NrOfDots
With Dots3D(i)
\dx + mx
\dy + my
\dz + mz
EndWith
Next
EndProcedure
Procedure RotateObject(rx, ry, rz)
Protected dist, angle
For i = 0 To NrOfDots
; If rx
; dist = Sqr(Pow(Dots3D(i)\dy, 2) + Pow(Dots3D(i)\dz + CamDist, 2))
; angle = ATan(Dots3D(i)\dy, Dots3D(i)\dz + CamDist)
; angle - rx
; Dots3D(i)\dy = Sin(angle) * dist
; Dots3D(i)\dz = Cos(angle) * dist - CamDist
; EndIf
;
; If ry
; dist = Sqr(Pow(Dots3D(i)\dx, 2) + Pow(Dots3D(i)\dz + CamDist, 2))
; angle = ATan(Dots3D(i)\dz + CamDist, Dots3D(i)\dx)
; EndIf
; angle + ry
; Dots3D(i)\dx = Sin(angle) * dist
; Dots3D(i)\dz = Cos(angle) * dist - CamDist
; EndIf
;
; If rz
; dist = Sqr(Pow(Dots3D(i)\dx, 2) + Pow(Dots3D(i)\dy, 2))
; If Dots3D(i)\dx < Dots3D(i)\dy
; angle = ATan(Dots3D(i)\dx, Dots3D(i)\dy)
; angle + rz
; Dots3D(i)\dx = Sin(angle) * dist
; Dots3D(i)\dy = Cos(angle) * dist
; EndIf
Next
EndProcedure
;Set initial values
ScreenW = 640
ScreenH = 480
CamDist = 100
Zoom = 512
;Create object
NrOfDots = 120
NrOfLines = 21
ReDim Dots3D.Dots3D(NrOfDots)
ReDim Dots2D.Dots2D(NrOfDots)
ReDim Lines.Lines(NrOfLines)
i = 0
For z = -50 To 50 Step 10
For x = -50 To 50 Step 10
With Dots3D(i)
\dx = x
\dy = -20
\dz = z
EndWith
i + 1
Next
Next
For i = 0 To 10
Lines(i)\d1 = i
Lines(i)\d2 = i + 1 * 110
Lines(i)\cl = $ff0000
Lines(i + 11)\d1 = i * 11
Lines(i + 11)\d2 = i * 11 + 10
Lines(i + 11)\cl = $ff0000
Next
InitKeyboard()
InitSprite()
If OpenWindow(0, 0, 0, ScreenW, ScreenH, "3D Wireframe")
If OpenWindowedScreen(WindowID(0), 0, 0, ScreenW, ScreenH, 0, 0, 0)
Repeat
Event = WindowEvent()
ClearScreen(0)
ExamineKeyboard()
If KeyboardPushed(#PB_Key_W): RotateObject(1, 0, 0): EndIf
If KeyboardPushed(#PB_Key_S): RotateObject(-1, 0, 0): EndIf
If KeyboardPushed(#PB_Key_Left): MoveObject(-1, 0, 0): EndIf
If KeyboardPushed(#PB_Key_Right): MoveObject(1, 0, 0): EndIf
If KeyboardPushed(#PB_Key_LeftControl) Or KeyboardPushed(#PB_Key_RightControl)
If KeyboardPushed(#PB_Key_A): RotateObject(0, 0, -1): EndIf
If KeyboardPushed(#PB_Key_D): RotateObject(0, 0, 1): EndIf
If KeyboardPushed(#PB_Key_Up): MoveObject(0, -1, 0): EndIf
If KeyboardPushed(#PB_Key_Down): MoveObject(0, 1, 0): EndIf
Else
If KeyboardPushed(#PB_Key_A): RotateObject(0, -1, 0): EndIf
If KeyboardPushed(#PB_Key_D): RotateObject(0, 1, 0): EndIf
If KeyboardPushed(#PB_Key_Up): MoveObject(0, 0, -1): EndIf
If KeyboardPushed(#PB_Key_Down): MoveObject(0, 0, 1): EndIf
EndIf
Convert3Dto2D()
DrawObject(1)
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
EndIf
EndIf
Aber egal, es geht ja hier nur mal darum, wie ich das gemacht habe. Wie schon erwähnt, verschiebe ich immer die 3D-Punkte und erreiche damit denselben Effekt.
So, und jetzt habe ich bei obigem Code die Stelle kommentiert, wo die Formel rein müsste für Z<=0. Da muss jetzt nichts gefiltert werden, es geht immer nur um die Berechnung eines einzigen 2D-Punktes bei jedem Schleifendurchlauf. Es muss ganz einfach sein - irgendwie muss die Formal nur umgekehrt werden aber ich weiß eben nicht, wie. Momentan werden eben die Linien einfach ausgeblendet, so bald einer der beiden Endpunkte nicht mehr korrekt berechnet werden kann.
Hi Leute,
hier noch eine Ergänzung:
Gruß
Scarabol
hier noch eine Ergänzung:
Code: Alles auswählen
Procedure Camera_LookAt(*Camera.Camera, x, y, z)
Protected temp.V3D, dx, dy, dz, d.f
temp\x = *Camera\p\x
temp\y = *Camera\p\y
temp\z = *Camera\p\z
dx = *Camera\p\x-x
dy = *Camera\p\y-y
dz = *Camera\p\z-z
d = Sqr(dx*dx+dy*dy+dz*dz)
; links rechts
temp\y = ATan(dx/dz)*#rad2deg
; hoch runter
temp\x = ASin(dy/d)*#rad2deg
Camera_Set(*Camera, 0, temp)
EndProcedure
Scarabol
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea
PB-V: 4
WinXP
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea
PB-V: 4
WinXP