Interpolation mit PB?
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
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
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea
PB-V: 4
WinXP
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea
PB-V: 4
WinXP
- Froggerprogger
- Badmin
- Beiträge: 855
- Registriert: 08.09.2004 20:02
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:
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:
(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
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
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
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

!UD2
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
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
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea
PB-V: 4
WinXP
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea
PB-V: 4
WinXP
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?
Gruß
Scarabol
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)
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