Ich suche eine Möglichkeit ein Bild so zu verzerren, wie man es vielleicht von Grafikprogrammen her kennt, in dem man die Ecken des rechteckigen Objekts einfach umhercshieben kann.
Dabei ist es mir egal ob das per Spritebefehl geht, oder ob eine Datei direkt verwurstet wird (win-api, dll, irgendein ein toller mathematischer Algorithmus...)
Hier im Forum wurde auf einen Api-Befehl verwiesen (weiß nicht mehr genau wie der heißt. bitglt oder so), aber der kann nur Parallelogramm-Verzerrung. Ich brauche aber die Möglichkeit ein unregelmäßiges Rechteck zu erstellen.
Das hier schien ein vielversprechender Thread zu sein: http://purebasic.fr/german/viewtopic.php?f=4&t=14049
Daraus konnte ich wenigstens schon eine Lösung für die grässlichen Ergebnisse von Transformsprite3D() herauslesen, nämlich, dass die Z-werte ganz und gar nicht optional sind, wenn man ein unvermurkstes Ergegbnis haben will.
Leider ist es mir nicht gelungen aus Dark Dragon's Code eine Funktion zu extrahieren, die diese Z-werte berechnet.
Aber die Ergebnisse von TransformSprite3D() sind auch mit Z-werten nicht wirklich schön. Sieht nach der Resize-Funktion von Paint aus.
Ich hab die Rotationsfunktion hier mal rausgenommen:
Links im Bild das Ergebnis dieses Codes
Rechts das Ergebnis von Macromedia(Adobe) Fireworks, "von Hand" verzerrt (das mit SaveSprite() erstelle Sprite, welches auch vom Code benutzt wird).
Code: Alles auswählen
InitSprite()
InitSprite3D()
InitKeyboard()
InitMouse()
Enumeration
#PLANE_TOP
#PLANE_BOTTOM
#PLANE_LEFT
#PLANE_RIGHT
#PLANE_FRONT
#PLANE_BACK
EndEnumeration
Global Dim ProjectionMatrix.f(3, 3)
Structure SVector
x.f
y.f
z.f
EndStructure
Structure SCube
distance.f
*v.SVector[4]
sprite.l
EndStructure
Procedure.f _cos(angle)
ProcedureReturn Cos(angle * #PI / 180.0)
EndProcedure
Procedure.f _sin(angle)
ProcedureReturn Sin(angle * #PI / 180.0)
EndProcedure
Procedure ScreenWidth()
!extrn _PB_Screen_Width
!mov eax,[_PB_Screen_Width]
ProcedureReturn
EndProcedure
Procedure ScreenHeight()
!extrn _PB_Screen_Height
!mov eax,[_PB_Screen_Height]
ProcedureReturn
EndProcedure
Procedure Rotate(*v.SVector, angleX, angleY)
If angleX <> 0
KA.f = *v\y : KB.f = *v\z
*v\y = _cos(angleX) * KA + _sin(angleX) * KB
*v\z = _cos(angleX) * KB - _sin(angleX) * KA
EndIf
If angleY <> 0
KA.f = *v\z : KB.f = *v\x
*v\z = _cos(angleY) * KA + _sin(angleY) * KB
*v\x = _cos(angleY) * KB - _sin(angleY) * KA
EndIf
EndProcedure
Procedure builtFrustum(Array Matrix.f(2), Left.d, Right.d, Bottom.d, Top.d, Near.d, Far.d)
Matrix(0, 0) = (2.0 * Near)/(Right-Left)
Matrix(1, 1) = (2.0 * Near)/(Top-Bottom)
Matrix(2, 0) = (Right+Left)/(Right-Left)
Matrix(2, 1) = (Top+Bottom)/(Top-Bottom)
Matrix(2, 2) = -1.0 * ((Far+Near)/(Far-Near))
Matrix(3, 2) = -1.0 * ((2.0*Far*Near)/(Far-Near))
Matrix(2, 3) = -1.0
EndProcedure
Procedure builtPerspective(Array Matrix.f(2), Fov.d, Ratio.d, Near.d, Far.d)
Protected Left.d, Right.d, Top.d, Bottom.d
Protected L_Dummy.f
Fov * #PI / 180.0
L_Dummy = Tan(Fov * 0.5)
L_Dummy * Near
Top = L_Dummy
Bottom = -L_Dummy
Left = Bottom * Ratio
Right = Top * Ratio
builtFrustum(Matrix(), Left, Right, Bottom, Top, Near, Far)
EndProcedure
Procedure MultVectorMatrix(Array Matrix.f(2), *v.SVector)
Protected result.SVector
Protected w.f
result\x = *v\x * Matrix(0, 0) + *v\y * Matrix(1, 0) + *v\z * Matrix(2, 0) + Matrix(3, 0)
result\y = *v\x * Matrix(0, 1) + *v\y * Matrix(1, 1) + *v\z * Matrix(2, 1) + Matrix(3, 1)
; result\z = *v\x * Matrix(0, 2) + *v\y * Matrix(1, 2) + *v\z * Matrix(2, 2) + Matrix(3, 2)
w = *v\x * Matrix(0, 3) + *v\y * Matrix(1, 3) + *v\z * Matrix(2, 3) + Matrix(3, 3)
If w <> 0.0
w = 1.0 / w
*v\x = result\x * w
*v\y = result\y * w
; *v\z = result\z * w
EndIf
EndProcedure
Procedure DisplayCube(SpriteTop, SpriteBottom, SpriteLeft, SpriteRight, SpriteFront, SpriteBack, RotationX, RotationY, Scale.f, MoveX.f, MoveY.f, MoveZ.f)
Protected Dim v.SVector(7)
Protected Dim planes.SCube(5)
Protected k.l, mx.l, my.l
MoveZ + 2.0
v(0)\x =-1.0 : v(0)\y = 1.0 : v(0)\z = 1.0
v(1)\x = 1.0 : v(1)\y = 1.0 : v(1)\z = 1.0
v(2)\x = 1.0 : v(2)\y = 1.0 : v(2)\z =-1.0
v(3)\x =-1.0 : v(3)\y = 1.0 : v(3)\z =-1.0
v(4)\x =-1.0 : v(4)\y =-1.0 : v(4)\z = 1.0
v(5)\x = 1.0 : v(5)\y =-1.0 : v(5)\z = 1.0
v(6)\x = 1.0 : v(6)\y =-1.0 : v(6)\z =-1.0
v(7)\x =-1.0 : v(7)\y =-1.0 : v(7)\z =-1.0
; v0
; v3 v1
; v2
;
;
; v4
; v7 v5
; v6
mx = (MoveX / ScreenWidth ()) - 0.5
my = (MoveY / ScreenHeight()) - 0.5
For k=0 To 7
Rotate(@v(k), RotationX, RotationY)
v(k)\x + mx
v(k)\y + my
v(k)\z + MoveZ
MultVectorMatrix(ProjectionMatrix(), @v(k))
v(k)\x - mx
v(k)\y - my
v(k)\x * Scale
v(k)\y * Scale
v(k)\z * Scale
Next k
; Top
planes(0)\v[0] = @v(0)
planes(0)\v[1] = @v(1)
planes(0)\v[2] = @v(2)
planes(0)\v[3] = @v(3)
planes(0)\sprite = SpriteTop
; Back
planes(1)\v[0] = @v(3)
planes(1)\v[1] = @v(2)
planes(1)\v[2] = @v(6)
planes(1)\v[3] = @v(7)
planes(1)\sprite = SpriteBack
; Right
planes(2)\v[0] = @v(2)
planes(2)\v[1] = @v(1)
planes(2)\v[2] = @v(5)
planes(2)\v[3] = @v(6)
planes(2)\sprite = SpriteRight
; Front
planes(3)\v[0] = @v(1)
planes(3)\v[1] = @v(0)
planes(3)\v[2] = @v(4)
planes(3)\v[3] = @v(5)
planes(3)\sprite = SpriteFront
; Left
planes(4)\v[0] = @v(0)
planes(4)\v[1] = @v(3)
planes(4)\v[2] = @v(7)
planes(4)\v[3] = @v(4)
planes(4)\sprite = SpriteLeft
; Bottom
planes(5)\v[0] = @v(4)
planes(5)\v[1] = @v(7)
planes(5)\v[2] = @v(6)
planes(5)\v[3] = @v(5)
planes(5)\sprite = SpriteBottom
For k=0 To 5
planes(k)\distance = (planes(k)\v[0]\z + planes(k)\v[1]\z + planes(k)\v[2]\z + planes(k)\v[3]\z) * 0.25
Next k
SortStructuredArray(planes(), 0, OffsetOf(SCube\distance), #PB_Sort_Float)
For k=0 To 5
TransformSprite3D(planes(k)\sprite, planes(k)\v[0]\x, planes(k)\v[0]\y, planes(k)\v[0]\z, planes(k)\v[3]\x, planes(k)\v[3]\y, planes(k)\v[3]\z, planes(k)\v[2]\x, planes(k)\v[2]\y, planes(k)\v[2]\z, planes(k)\v[1]\x, planes(k)\v[1]\y, planes(k)\v[1]\z)
DisplaySprite3D(planes(k)\sprite, MoveX, MoveY)
Next k
EndProcedure
UsePNGImageDecoder()
OpenWindow(0, 50, 50, 640, 480, "Press Escape", #PB_Window_SystemMenu)
OpenWindowedScreen(WindowID(0), 0, 0, 640, 480, 1, 0, 0)
builtPerspective(ProjectionMatrix(), 45.0, ScreenWidth() / ScreenHeight(), 0.1, 10000.0)
CreateSprite(0,256,256,#PB_Sprite_Texture)
StartDrawing(SpriteOutput(0))
Box(0, 0, 256, 256, $0000FF)
Box(5, 5, 246, 246, $996600)
Circle(128,128,100,$0000FF)
LineXY(0, 0, 256, 256)
LineXY(0, 256,256,0)
StopDrawing()
CreateSprite3D(0, 0)
CreateSprite3D(1, 0)
CreateSprite3D(2, 0)
CreateSprite3D(3, 0)
CreateSprite3D(4, 0)
CreateSprite3D(5, 0)
CreateSprite3D(6, 0)
Define mdx.d
Define mdy.d
Define lastTime.l
Define currentTime.l
currentTime = ElapsedMilliseconds()
Repeat
WindowEvent()
ExamineKeyboard()
If IsImage(MyImage)
StartDrawing(SpriteOutput(0))
DrawImage(ImageID(MyImage), 0, 0, 256, 256)
StopDrawing()
EndIf
currentTime = ElapsedMilliseconds()
mdx = 50
mdy = 130
ClearScreen(0)
Start3D()
DisplayCube(0, 0, 0, 0,0, 0, mdy, mdx, 170.0, 200.0, 230.0, 1.5)
Stop3D()
FlipBuffers()
Until WindowEvent() = #PB_Event_CloseWindow Or KeyboardPushed(#PB_Key_Escape)
End
Zur Veranschaulichung: Das kann Fireworks: http://tinypic.com/r/j0ejba/6
Allerdings leider nicht als Batch.
Es geht mir auch gar nicht um das "rumfahren" mit der Maus, wenn ich die X/Y Koordinaten für jede Ecke angeben kann, reicht das vollkommen. Wie TransformSprite3D(), aber der Output sollte halt nicht ganz so hässlich sein...
Bin für jeden Tipp dankbar, wie das irgendwie klappen könnte