Seite 3 von 3

Verfasst: 21.09.2007 23:23
von Zaphod
Was der resultierende Wert Ausdrückt ist ja ganz alleine davon abhängig als was du ihn interpretierst. Du kannst also eine Splinelinie als Pfad und eine weitere als höhe nutzen.

Verfasst: 22.09.2007 08:54
von Scarabol
Hi Zaphod,

verstehe nicht ganz was du meinst...

Meine Frage ist: Wie muss ich die Interpolation umstellen um auch eine Z-Ebene berücksichtigen zu können, also 3D (x,y,z) statt 2D (x,y)?

Gruß
Scarabol

Verfasst: 22.09.2007 10:45
von Froggerprogger
Wenn deine Koordinaten in einem regelmäßigem Raster vorliegen, könntest du einmalig für jede Zeile und jede Spalte einen Spline berechnen. Entlang der Rasterlinien bist du somit fertig. Innerhalb der rechteckigen Zwischenbereiche könntest du dann ganz normal mit arithmetischem Mittel interpolieren. Ein Punkt innerhalb eines Rasterrechtecks hat zu jeder der 4 Seiten einen gewissen Abstand (normiert auf einen Wert zwischen 0 und 1), zu dem jeweils ein Spline einen 'Höhenwert' vorgibt. Diese vier Höhenwerte müssen lediglich gewichtet mit dem Abstand gemittelt werden. Beispiel:

Die Rasterlinien haben einen Abstand von 100 Einheiten.
Die Splines entlang aller Rasterlinien können berechnet werden.
Jetzt nehmen wir den Punkt P=(25, 10) aus dem ersten Rasterquadrat mit den Ecken:

Code: Alles auswählen

z.Achse
|

C=(0,100)    D=(100,100)

       P=(25,10)
A=(0,0)        B=(100,0)                     ---> x-Achse
Jetzt werten wir die vier Splines der Rasterlinien "auf der Höhe des Punkte" aus:
sab = SplineDurchAB(25,0)
sac = SplineDurchAC(0,10)
scd = SplineDurchCD(25,100)
sbd = SplineDurchBD(100, 10)

(Aufwand: vier Splineauswertungen)

Der Einfluss einer Seite auf den Punkt ist 1 minus der Abstand des Punktes zu den Seiten genormt auf 1:
dab = 1 - 0.1 = 0.9 zu AB
dac = 1 - 0.25 = 0.75 zu AC
dcd = 1 - 0.75 = 0.25 zu CD
dbd = 1 - 0.9 = 0.1 zu BD

(Aufwand: vier Subtraktionen und Divisionen (zzgl. ein paar weiteren Subtraktionen))

Um die Form zu beeinflussen könnte hier nun noch generell aus jedem Wert einmal die Wurzel genommen werden (würde den Einfluss der Randnähe erhöhen und damit ggf. glätten), oder quadrieren (würde entferntere Kanten mehr gewichten, also ggf. mehr krisseln).

Jetzt haben wir alles zusammen und erhalten für unseren Punkt P den y-Wert:

Code: Alles auswählen

Py = (dab*sab+dac*sac+dcd*scd+sbd*dbd) / 4
(Aufwand: vier Additionen und Multiplikationen, eine Division (oder Shift))

Das ganze in eine Funktion gepackt liefert dann eine Auswertung der Form y = f(x,z).

Das ganze geht aber auch stattdessen direkt mehrdimensional (ich weiß nur nicht wie). Es kann aber sein, dass das Erstellen und Auswerten eines mehrdimensionalen Splines länger dauert, als dieser Weg per Fuß.
Dafür wird ein echtes mehrdimensionales Spline noch rundere Verläufe innerhalb der Rasterrechtecke hervorbringen. Obige Interpolation innerhalb der Rechtecke ist schließlich keine Spline-Interpolation, sondern lediglich linear, bzw. nach dem Wurzelziehen sowas wie "pseudoquadratisch". Bei einem Terrain kann es aber sein, dass hierbei der Verlauf der Rasterlinien noch zu erahnen ist.

Wie gut/schlecht das nacher bei einem Terrain aussieht müsste mal eroiert werden :D

Verfasst: 22.09.2007 11:25
von Scarabol
Hi Froggerprogger,

der Ansatz ist gut aber wie du schon selbst erkannt hast, wird hier keine Spline Interpolation verwendet...

Ich werd trotzdem mal ein kleines Terrain Beispiel schreiben...

Gruß
Scarabol

Verfasst: 22.09.2007 16:56
von Scarabol
Hi Leute,

bevor ich das Spline auf das Terrain anwenden konnte hänge ich gerade noch an einem Problem mit dem Terrain, da es irgendwie zweimal angezeigt wird, ich weiß aber nicht was ich machen muss um dies zu verhindern, wenn ich versuche die "falschen" Koordinaten herauszufiltern fehlen auch den "richtigen" Koordinaten die Eckpunkte die aus dem Fenster ragen.
Was muss ich tun?

Code: Alles auswählen

;EnableExplicit

;Erstellt eine Kamera, die 3D-Koordinaten in 2D-Koordinaten umrechnet

CompilerIf Defined(PI, #PB_Constant) = #False
  #PI      = 3.141592653589793238
CompilerEndIf
#DEG2RAD = #PI / 180

Structure V3D
  x.d
  y.d
  z.d
EndStructure

Structure Camera
  p.V3D
  a.V3D
  x.V3D
  y.V3D
  z.V3D   ;Zeigt in Blickrichtung
  FOV.d
  tFOV.d
  MinX.d
  MaxX.d
  MinY.d
  MaxY.d
  AspX.d
  AspY.d
EndStructure

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

Procedure Camera_Calc(*Camera.Camera) ;Wird intern aufgerufen
  Protected a_1.d, a_2.d, a_3.d, a_4.d, a_5.d, a_6.d, v_x.V3D, v_y.V3D
  Static Pi2.d = #PI / 2
  
  a_1 = Sin(*Camera\a\y)
  a_2 = Cos(*Camera\a\x)
  a_3 = Cos(*Camera\a\y)
  a_4 = Sin(*Camera\a\x)
  a_5 = Cos(*Camera\a\z)
  a_6 = Sin(*Camera\a\z)
  
  ;Z-Achse
  *Camera\z\x = a_1 * a_2             ; Sin(y) * Cos(x)             0
  *Camera\z\y = a_4                   ; Sin(x)                      0
  *Camera\z\z = a_2 * a_3             ; Cos(x) * Cos(y)             1
  
  ;Y-Achse
  v_y\x = -a_1 * a_4                  ; -Sin(y) * Sin(x)            0
  v_y\y = a_2                         ; Cos(x)                      1
  v_y\z = -a_4 * a_3                  ; -Sin(x) * Cos(y)            0
  
  v_x\x = -*Camera\z\y * v_y\z + *Camera\z\z * v_y\y
  v_x\y = -*Camera\z\z * v_y\x + *Camera\z\x * v_y\z
  v_x\z = -*Camera\z\x * v_y\y + *Camera\z\y * v_y\x
  
  ;Einberechnung des Z-Winkels
  *Camera\x\x = v_x\x * a_5 + v_y\x * a_6
  *Camera\x\y = v_x\y * a_5 + v_y\y * a_6
  *Camera\x\z = v_x\z * a_5 + v_y\z * a_6
  
  *Camera\y\x = v_y\x * a_5 - v_x\x * a_6
  *Camera\y\y = v_y\y * a_5 - v_x\y * a_6
  *Camera\y\z = v_y\z * a_5 - v_x\z * a_6
EndProcedure

Procedure Camera_New() ;Erstellt eine neue Kamera
  Protected *Camera.Camera
  
  *Camera = AllocateMemory(SizeOf(Camera))
  
  If *Camera = 0 : ProcedureReturn #False : EndIf
  
  Camera_Calc(*Camera)
  With *Camera
    \MinX = -1
    \MaxX = 1
    \MinY = -1
    \MaxY = 1
    \AspX = 1
    \AspY = 1
  EndWith
  
  ProcedureReturn *Camera
EndProcedure

Procedure Camera_Set(*Camera.Camera, *Position.V3D, *Angle.V3D) ;Setzt Position und Winkel der Kamera
  If *Position
    *Camera\p\x = *Position\x
    *Camera\p\y = *Position\y
    *Camera\p\z = *Position\z
  EndIf
  
  If *Angle
    *Camera\a\x = *Angle\x * #DEG2RAD
    *Camera\a\y = *Angle\y * #DEG2RAD
    *Camera\a\z = *Angle\z * #DEG2RAD
    Camera_Calc(*Camera)
  EndIf
EndProcedure

Procedure Camera_Add(*Camera.Camera, *Position.V3D, *Angle.V3D) ;Addiert Position und Winkel zur Kamera
  If *Position
    *Camera\p\x + *Position\x
    *Camera\p\y + *Position\y
    *Camera\p\z + *Position\z
  EndIf
  
  If *Angle
    *Camera\a\x + *Angle\x * #DEG2RAD
    *Camera\a\y + *Angle\y * #DEG2RAD
    *Camera\a\z + *Angle\z * #DEG2RAD
    Camera_Calc(*Camera)
  EndIf
EndProcedure

Procedure.d Camera_FOV(*Camera.Camera, FOV.d = -1) ;Setzt "Field of view" der Kamera in Grad (0 < FOV < 180) oder gibt es zurück
  If FOV = -1
    ProcedureReturn *Camera\FOV
  ElseIf FOV > 0 And FOV < 180
    *Camera\FOV = FOV * #DEG2RAD
    *Camera\tFOV = Tan(*Camera\FOV)
  EndIf
EndProcedure
Procedure Camera_Size(*Camera.Camera, MinX.d, MaxX.d, MinY.d, MaxY.d) ;Setzt die maximalen Ausgabekoordinaten
  With *Camera
    \MinX = MinX
    \MaxX = MaxX
    \MinY = MinY
    \MaxY = MaxY
    
    If \MaxX - \MinX > \MaxY - \MinY
      \AspX = 1
      \AspY = (\MaxY - \MinY) / (\MaxX - \MinX)
    ElseIf \MaxX - \MinX = \MaxY - \MinY
      \AspX = 1
      \AspY = 1
    Else
      \AspY = 1
      \AspX = (\MaxX - \MinX) / (\MaxY - \MinY)
    EndIf
  EndWith
EndProcedure

Procedure Camera_Move(*Camera.Camera, *Position.V3D, *Angle.V3D) ;Bewegt die Kamera relativ zu Position und Drehung
  Protected CosZ.d, SinZ.d
  
  If *Position
    *Camera\p\x + *Position\x * *Camera\x\x + *Position\y * *Camera\y\x + *Position\z * *Camera\z\x
    *Camera\p\y + *Position\x * *Camera\x\y + *Position\y * *Camera\y\y + *Position\z * *Camera\z\y
    *Camera\p\z + *Position\x * *Camera\x\z + *Position\y * *Camera\y\z + *Position\z * *Camera\z\z
  EndIf
  
  If *Angle
    *Camera\a\z + *Angle\z * #DEG2RAD
    CosZ = Cos(*Camera\a\z)
    SinZ = Sin(*Camera\a\z)
    *Camera\a\x + (*Angle\x * CosZ + *Angle\y * SinZ) * #DEG2RAD
    *Camera\a\y + (*Angle\y * CosZ - *Angle\x * SinZ) * #DEG2RAD
    Camera_Calc(*Camera)
  EndIf
EndProcedure

Procedure Camera_3Dto2D(*Camera.Camera, *p3d.V3D, *p2d.V3D, *c3d.V3D = 0) ;Rechnet 3D-Punkt in 2D-Punkt um
  Protected v_x.V3D, v_y.V3D, v.V3D, cx.d, cy.d, cz.d
  
  ;Vektor von Kamera zu Punkt
  v\x = *p3d\x - *Camera\p\x
  v\y = *p3d\y - *Camera\p\y
  v\z = *p3d\z - *Camera\p\z
  
  ;Abstand von Kamera auf Z-Achse
  cz = v\x * *Camera\z\x + v\y * *Camera\z\y + v\z * *Camera\z\z
  
  If cz = 0
    cx = 0
    cy = 0
    *p2d\x = 0
    *p2d\y = 0
  Else
    ;Abstand von Kamera auf X- und Y-Achse
    cx = v\x * *Camera\x\x + v\y * *Camera\x\y + v\z * *Camera\x\z
    cy = v\x * *Camera\y\x + v\y * *Camera\y\y + v\z * *Camera\y\z
    
    ;Berechnung des 2D-Punktes auf X- und Y-Achse im Bereich -1 bis 1
    *p2d\x = cx / (cz * *Camera\tFOV) / *Camera\AspX
    *p2d\y = cy / (cz * *Camera\tFOV) / *Camera\AspY
    
    ;Umrechnung des Bereichs auf die maximalen Ausgabekoordinaten
    *p2d\x = *Camera\MinX + (*p2d\x + 1) * 0.5 * (*Camera\MaxX - *Camera\MinX)
    *p2d\y = *Camera\MinY + (*p2d\y + 1) * 0.5 * (*Camera\MaxY - *Camera\MinY)
  EndIf
  
  If *c3d
    *c3d\x = cx
    *c3d\y = cy
    *c3d\z = cz
  EndIf
  
  ;Wenn Punkt hinter Kamera war
  If cz <= 0  : ProcedureReturn #False : EndIf
  
  ;Wenn Punkt außerhalb maximalen Ausgabekoordinaten war
  If *p2d\x < *Camera\MinX Or *p2d\x > *Camera\MaxX : ProcedureReturn #False : EndIf
  If *p2d\y < *Camera\MinY Or *p2d\y > *Camera\MaxY : ProcedureReturn #False : EndIf
  
  ;Wenn Punkt im sichtbaren Bereich
  ProcedureReturn #True
EndProcedure


Structure Dots
  p.V3D
  c.l
EndStructure

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

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

Global NewList Dots.Dots()

InitSprite()
InitKeyboard()
InitMouse()

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

UsePNGImageDecoder()

If LoadImage(1, #PB_Compiler_Home+"Examples\Sources\Data\Terrain.png")
StartDrawing(ImageOutput(1))
w = ImageWidth(1)/4
h = ImageHeight(1)/4
Dim dotar.V3D(w,h)
Dim temp.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

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 = 4
#maxdif = 0

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_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
  
  a\x + MouseDeltaY() * 0.5
  a\y + MouseDeltaX() * 0.5
  
  If KeyboardReleased(#PB_Key_A)   : scaley/2 : EndIf
  If KeyboardReleased(#PB_Key_Z)   : scaley*2 : 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)     : 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-5
;  Camera_Set(*Camera, t, 0)
;  Camera_Move(*Camera, 0, a)
  Camera_Move(*Camera, p, a)
  
  StartDrawing(ScreenOutput())
    For x = 0 To w
      For y = 0 To h
        temp.V3D\x = Dotar(x,y)\x
        temp.V3D\y = Dotar(x,y)\y/scaley
        temp.V3D\z = Dotar(x,y)\z
        If Camera_3Dto2D(*Camera, temp, temp(x,y))
;          Circle(temp(x,y)\x, temp(x,y)\y, 2, #White)
;        Else
;          temp(x,y)\x = -1
;          temp(x,y)\y = -1
        EndIf
      Next
    Next
    For x = 0 To w-1
      For y = 0 To h-1
;        If temp(x,y)\x > 0-#maxdif And temp(x,y)\x < Width+#maxdif And temp(x,y)\y > 0-#maxdif And temp(x,y)\y < Height+#maxdif
;          If temp(x+1,y)\x > 0-#maxdif And temp(x+1,y)\x < Width+#maxdif And temp(x+1,y)\y > 0-#maxdif And temp(x+1,y)\y < Height+#maxdif
            LineXY(temp(x,y)\x, temp(x,y)\y, temp(x+1,y)\x, temp(x+1,y)\y, #Gray)
;          EndIf
;          If temp(x,y+1)\x > 0-#maxdif And temp(x,y+1)\x < Width+#maxdif And temp(x,y+1)\y > 0-#maxdif And temp(x,y+1)\y < Height+#maxdif
            LineXY(temp(x,y)\x, temp(x,y)\y, temp(x,y+1)\x, temp(x,y+1)\y, #Gray)
;          EndIf
;        EndIf
      Next
    Next
  StopDrawing()
  
  FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
Gruß
Scarabol

Verfasst: 22.09.2007 18:21
von NicTheQuick
Freut mich, das jemand meine 3D-to-2D-Funktionen gebrauchen kann. :allright:

Verfasst: 22.09.2007 18:23
von Scarabol
Schau auch ma in deinen Original Thread, ich hatte noch ein paar Verbesserungsvorschläge...

Gruß
Scarabol