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
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

Ohh danke :oops:

Hab den Parameter glatt übersehen...

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,

überprüfe jetzt den Z-Parameter, aber irgendwie werden noch Linien gezeichnet die Quer über den Screen ragen, ich kann sie aber nicht einfach rausfiltern, weil mir sonst die Randstücke "angefressen" werden...

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 »

So Leute,

hier mal ein Beispiel wie das ganze als Terrain aussieht...

@Nic
Währ schön, wenn du den Code nochmal überarbeitest und auch auf die erste Seite als zweites Example verlinkst...

Wieso ist die Umrechnung (3D in 2D) so langsam?

Gruß
Scarabol

PS:
texturiertes Terrain folgt bald...
Zuletzt geändert von Scarabol am 24.09.2007 18:45, insgesamt 1-mal geändert.
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 »

Schneller geht die Umrechnung nicht. Es sei denn, du realisierst das ganze
noch mit SSE 1 oder höher.

Ich bin gerade dabei eine native Funktion zu schreiben, die 'LineXY()' ersetzt
und die Linien abschneidet, wenn sie aus dem Sichtbereich herausragen
würden.

Das mit den Sprites ist so nicht zu machen, weil man jeden einzelnen Pixel
umrechnen müsste und außerdem sortieren müsste, damit alles von hinten
nach vorne dargestellt wird und nicht durcheinander. Und dafür gibt es
3D-Grafikkarten.
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

Wie kann ich die Sprites Verwaltung den von der Grafikkarte erledigen lassen?

SSE1 ist aber doch Prozessor abhängig, oder?

EDIT
Terrain wird nun richtig angezeigt (vorne/hinten)

TODO
Terrain Interpolieren und präzieser Darstellen

Hier mal der aktuelle Code an dem ich gerade bastel:

Code: Alles auswählen

;EnableExplicit

XIncludeFile "3Dto2D.pb"

Structure Dots
  p.V3D
  c.l
EndStructure

Structure Szbuffer
  i.w
  j.w
  z.f
  xs.f
  ys.f
EndStructure

Structure tempdot
  p.V3D
  d.V3D
EndStructure

Procedure LimitVar(Var, Min, Max)
  If Var < Min
    Var = Min
  ElseIf Var > Max
    Var = Max
  EndIf
  ProcedureReturn Var
EndProcedure

Global Width.l = 800, Height.l = 600
Global NewList Dots.Dots()

Define x.l, y.l, z.l, i.l, d.d, m.l, n.l, o.l, R.l, c
Define scaley.f
Define temp.V3D

UsePNGImageDecoder()

InitSprite()
InitSprite3D()
InitKeyboard()
InitMouse()

If OpenWindow(0, 0, 0, Width, Height, "3D-to-2D", #PB_Window_ScreenCentered) = 0 : End : EndIf
If OpenWindowedScreen(WindowID(0), 0, 0, Width, Height, 0, 0, 0) = 0 : End : EndIf

If LoadImage(1, #PB_Compiler_Home+"Examples\Sources\Data\Terrain.png")
StartDrawing(ImageOutput(1))
Global w, h
w = ImageWidth(1)/2
h = ImageHeight(1)/2
Global Dim dotar.V3D(w,h)
Global Dim temp.tempdot(w,h)
Dim temp2.V3D(w*h)
For x = 0 To w
  For y = 0 To h
    dotar(x,y)\x = x
    dotar(x,y)\y = 255-Red(Point(x,y))
    dotar(x,y)\z = y
  Next
Next
StopDrawing()
EndIf

Procedure OnScreen(x,y)
  If temp(x,y)\p\x >= 0 And temp(x,y)\p\x < Width And temp(x,y)\p\y >= 0 And temp(x,y)\p\y < Height
    ProcedureReturn 1
  EndIf
EndProcedure

Procedure AnotherOnScreen(x,y)
  For tx = -2 To 2
    For ty = -2 To 2
      If (tx<>0 Or ty<>0)
        a = x+tx
        b = y+ty
        If a >= 0 And a < w And b >= 0 And b < h
          If OnScreen(a,b)
            ProcedureReturn 1
          EndIf
        EndIf
      EndIf
    Next
  Next
EndProcedure

Procedure Distance3D(x1,y1,z1,x2,y2,z2)
  dx = x2-x1
  dy = y2-y1
  dz = z2-z1
  ProcedureReturn dx*dx+dy*dy+dz*dz
EndProcedure

Define p.V3D, a.V3D, p2d.V3D, p2d.V3D

Define p_add.d, a_add.d, FOV.d
p_add.d = 1
a_add.d = 1
FOV.d = 45
scaley = 8
#maxdif = 0
Global MaxRange = 50

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

For i = 0 To 255
  CreateSprite(i, 32, 32, #PB_Sprite_Texture)
  StartDrawing(SpriteOutput(i))
    Box(0,0,32,32,RGB(i,i,i))
  StopDrawing()
  CreateSprite3D(i,i)
Next

Repeat
  ClearScreen(0)
  ExamineKeyboard()
  ExamineMouse()
  
  p\x = 0 : p\y = 0 : p\z = 0
  a\x + MouseDeltaY() * 0.5
  a\y + MouseDeltaX() * 0.5
  If a\x < 0 : a\x+360 : ElseIf a\x > 360 : a\x-360 : EndIf
  If a\y < 0 : a\y+360 : ElseIf a\y > 360 : a\y-360 : EndIf
  
  If KeyboardPushed(#PB_Key_Up)    : p\z + p_add*Cos(a\y*#Deg2Rad) : p\x + p_add*Sin(a\y*#Deg2Rad) : EndIf
  If KeyboardPushed(#PB_Key_Down)  : p\z - p_add*Cos(a\y*#Deg2Rad) : p\x - p_add*Sin(a\y*#Deg2Rad) : EndIf
  If KeyboardPushed(#PB_Key_Left)  : p\x - p_add*Cos(a\y*#Deg2Rad) : p\z + p_add*Sin(a\y*#Deg2Rad) : EndIf
  If KeyboardPushed(#PB_Key_Right) : p\x + p_add*Cos(a\y*#Deg2Rad) : p\z - p_add*Sin(a\y*#Deg2Rad) : EndIf
  
  If KeyboardReleased(#PB_Key_A)   : scaley/2 : EndIf
  If KeyboardReleased(#PB_Key_Z)   : scaley*2 : EndIf
  If KeyboardPushed(#PB_Key_S)     : MaxRange+1 : EndIf
  If KeyboardPushed(#PB_Key_X)     : MaxRange-1 : EndIf
  If KeyboardPushed(#PB_Key_D)     : FOV - 0.25 : EndIf
  If KeyboardPushed(#PB_Key_C)     : FOV + 0.25 : EndIf
  
  Camera_FOV(*Camera, FOV)
  t.V3D\x = LimitVar(*Camera\p\x+p\x, 0, w)
  t.V3D\z = LimitVar(*Camera\p\z+p\z, 0, h)
  t.V3D\y = Dotar(Int(*Camera\p\x),Int(*Camera\p\z))\y/scaley-8
  Camera_Set(*Camera, t, a)
  
  For x = 0 To w
    For y = 0 To h
      hy.d = Dotar(x,y)\y/scaley
      temp.V3D\x = Dotar(x,y)\x
      temp.V3D\y = hy
      temp.V3D\z = Dotar(x,y)\z
      If Camera_3Dto2D(*Camera, temp, temp(x,y)\p, temp(x,y)\d)
;        Circle(temp(x,y)\p\x, temp(x,y)\p\y, 2, #White)
      EndIf
      If x < w And y < h
        temp2(y*h+x)\x = x
        temp2(y*h+x)\y = y
        temp2(y*h+x)\z = Distance3D(Dotar(x,y)\x, hy, Dotar(x,y)\z, *Camera\p\x, *Camera\p\y, *Camera\p\z)
      EndIf
    Next
  Next
  
  SortStructuredArray(temp2(), 1, OffsetOf(V3D\z), #PB_Sort_Double)
  
  Start3D()
    For n = 0 To w*h
      x = temp2(n)\x
      y = temp2(n)\y
      If temp(x,y)\d\z > 0 And temp(x,y)\d\z < MaxRange And (OnScreen(x,y) Or AnotherOnScreen(x,y))
        x1 = temp(x,y)\p\x
        y1 = temp(x,y)\p\y
        x2 = temp(x+1,y)\p\x
        y2 = temp(x+1,y)\p\y
        x3 = temp(x+1,y+1)\p\x
        y3 = temp(x+1,y+1)\p\y
        x4 = temp(x,y+1)\p\x
        y4 = temp(x,y+1)\p\y
        TransformSprite3D(Dotar(x,y)\y,x4,y4,x3,y3,x2,y2,x1,y1)
        DisplaySprite3D(Dotar(x,y)\y,0,0,255)
      EndIf
    Next
  Stop3D()
  
  StartDrawing(ScreenOutput())
  DrawingMode(1)
  FrontColor(#White)
  DrawText(10, 10, fps$)
  DrawText(10, 30, Str(w*h))
  DrawText(10, 50, Str(a\x))
  DrawText(10, 70, Str(a\y))
  DrawText(10, 100, "CameraX:"+Str(*Camera\p\x))
  DrawText(10, 120, "CameraY:"+Str(*Camera\p\y))
  DrawText(10, 140, "CameraZ:"+Str(*Camera\p\z))
  StopDrawing()
  
  fps + 1
  If timer = 0
    timer = ElapsedMilliseconds()
  ElseIf ElapsedMilliseconds()-timer >= 1000
    fps$ = Str(fps)
    fps = 0
    timer = 0
  EndIf
  
  FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
Gruß
Scarabol

PS
@Nic
Spar die LineXY() Sache... denke das "richtige" Sprites notwendiger sind...
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 Nic,

was meinst du mit "dafür gibt es Grafikkarten"?

Wie kann ich das sortieren und darstellen von der Grafikkarte erledigen lassen?

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 »

Wenn du 3D programmieren möchtest, solltest du eine 3D-Engine nutzen und
nicht selbst versuchen, die Sprites so mit meiner 3Dto2D-Procedure zu
transformieren, dass es richtig aussieht.

Ich werde mich damit auf jeden Fall nicht auseinandersetzen, weil es viel zu
komplex ist und ich einfach keine Lust und keine Zeit dazu habe. Wenn du
sowas brauchst, dann musst du es dir selbst erarbeiten. :allright:
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

Zu deinem ersten Abschnitt:
... zu spät :D
http://uploaded.to/?id=h86vu1

zu deinem zweiten:
Schon klar, aber du hast da oben so andeutungen gemacht und die wollte ich hinterfragen wie du drauf kommst das das funktionieren sollte...
Das mit den Sprites ist so nicht zu machen, weil man jeden einzelnen Pixel
umrechnen müsste und außerdem sortieren müsste, damit alles von hinten
nach vorne dargestellt wird und nicht durcheinander. Und dafür gibt es
3D-Grafikkarten.
Gruß
Scarabol
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea

PB-V: 4
WinXP
johnnysnet
Beiträge: 26
Registriert: 05.11.2006 22:01
Kontaktdaten:

Beitrag von johnnysnet »

Nic, genau solch einen Code suche ich seit kurzem und ich kann nur sagen 'Respekt'!. Neidvoll blicke ich auf all die Leute, die in Mathe so fit sind, um so etwas zu bewerkstelligen. Von den ganzen Berechnungen verstehe ich praktisch nichts aber ungeachtet dessen sollte es dennoch möglich sein, diesen Code zu portieren. Also habe ich versucht, ihn für GLBasic umzuschreiben. Bis jetzt leider ohne Erfolg. Ich glaube es liegt daran, dass ich in deinem Code - mal abgesehen von der Mathematik - auch ein paar grundlegende Dinge noch nicht verstanden habe.

Und zwar komme ich z.B. nicht mit dem Ausdruck *Camera.Camera klar. Wird hier eine neue Struktur des Typs Camera erstellt? Wieso lassen sich eigentlich mehrere Kameras erstellen, wenn immer diese Art der Zuweisung verwendet wird? Meiner Auffassung nach würde durch den Aufruf der Prozedur Camera_New() die aktuelle Kamera zurückgesetzt.

Ebenfalls verstehe ich den Aufruf

Code: Alles auswählen

*Camera = AllocateMemory(SizeOf(Camera))
nicht, wenn danach

Code: Alles auswählen

  Camera_Calc(*Camera)
  With *Camera
    \MinX = -1
    \MaxX = 1
    \MinY = -1
    \MaxY = 1
    \AspX = 1
    \AspY = 1
  EndWith
ausgeführt wird, denn *Camera ist doch lediglich ein Zeiger auf die Speicheradresse, wenn der entsprechende Speicher reserviert werden konnte. Demnach müsste *Camera aber die gesamte Struktur von Camera enthalten und mich wundert, warum das dann als Zeiger funktioniert.

Ich wünschte wirklich, wenigstens die Grundlagen hier zu verstehen, dann könnte ein Portieren auch erfolgreich werden.
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 »

Wenn du verstehen willst, was der Code tut, dann musst du erstmal die
Grundlagen von Pointern verstehen. Kannst du denn PureBasic
programmieren?
Antworten