Entwickler-Ecke
Multimedia / Grafik - 3d koordinaten in 2d umwandeln
chaoslion - So 12.03.06 16:08
Titel: 3d koordinaten in 2d umwandeln
Hallo!
Wie ihr aus der Überschrift lesen könnte hab ich im moment das Problem der Umwandlung von 3 Koordinaten (x,y,z) in die Bildschirmkoordinaten (x,y).
Ich hab folgende Umwandlungen versucht:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| function x3d2d(x,z:real):real; begin result:=ZOOMFAKTOR * (x / (1 + z)); end; function y3d2d(y,z:real):real; begin result:=ZOOMFAKTOR * (y / (1 + z) ); end; |
Das erste Bild zeigt komische Werte wenn ich die 2. Formel benutze.
Das 2. Bild zeigt wie es Aussieht mit der ersten Formel jedoch ist das rotieren falsch,
den das Koorinatensystem wird schief (3. bild ein wenig um y rotiert)..
[url=
http://img59.imageshack.us/my.php?image=fehler12im.jpg]
[/URL]
[url=
http://img59.imageshack.us/my.php?image=ok17on.jpg]
[/URL]
[url=
http://img59.imageshack.us/my.php?image=ok1rotiertumy5ub.jpg]
[/URL]
F34r0fTh3D4rk - So 12.03.06 16:48
wozu schreibst du eigentlich:
wenns auch so geht:
?
chaoslion - So 12.03.06 16:53
weil 1 er teilungsfaktor ist, eigentlich war es vorher 0.5, das heisst das die z werte nur halb so groß sind wie die y oder x aber im moment steht 1 als platzhalter da.
chaoslion - So 12.03.06 17:15
so rufe ich sie auf:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| type TVek3d=record x,y,z:real; end;
procedure TMATHE.ZeichnePunkt(pkt1:TVek3d); begin CANVAS.PutPixel(VNULLX+x3d2d(pkt1.x,pkt1.z),VNULLY-y3d2d(pkt1.y,pkt1.z),RED,fxBlend); end; |
VNULLX ^ VNULLY sind konstanten = 320 und 240, da ich von 640*480 als auflösung ausgehe
desweiteren soll er alles vom zentrum ausrichten
zb hast du x=20, y=20, z=30 welcher er dann "umrechnet" in 340, 260 und z halt durch formel..
putpixel..ist von einer Grafikengine..
red ist Farbkonstante
fxblend nen Effekt
F34r0fTh3D4rk - So 12.03.06 18:03
btw da ist n highlighting fehler, das .z wird als zahl gelesen Oo
delfiphan - So 12.03.06 19:28
Siehe Projektionsmatrix und homogene Koordinaten.
Bzw. Mit was für Koordinaten hast du es zu tun? Nimm mal für Zoomfaktor 400 und anstelle von "1" ebenfalls einen Wert in dieser Grössenordnung.
chaoslion - So 12.03.06 19:45
hab ich ja schon dennoch ist das koordinatensystem bei der rotation schief..
delfiphan - So 12.03.06 21:50
Je höher du diese beiden Werte setzst, desto näher solltest du eine Parallelprojektion erhalten. Wenn das nicht der Fall ist, dann ist eventuell etwas mit deiner Drehroutine falsch.
NCortex - So 12.03.06 22:11
hey, ich hatte ein ähnliches Problem. Ich hab das mit Matrixrechnung gelöst.
Kurze Vorerklärung:
TVektor, ist ein 3D Vektor mit (x,y,z)
TProjektionsMatrix ist eine 2x3 Matrix. also:
(x1,x2,x3)
(y1,y2,y3)
Die Projektionsmatrix bestimmt die Perspektive (Militär-,Isometrie, Dimetrie... etc):
Sie standaertprojektion sieht folgendermaßen aus:
(-0.5 , 1 , 0)
(-0,5 , 0 , 1)
fVR.mal() ist skalarprodukt. fVR.Vektor() gibt einen Vektor aus.
Delphi-Quelltext
1: 2: 3: 4: 5:
| function TMatrixrechnung.Auf2DProjizieren(a:TVektor;P:TProjektionsMatrix):TPoint; begin result.X := round(fVR.mal(fVR.Vektor(P.x1,P.x2,P.x3),a)); result.Y := round(fVR.mal(fVR.Vektor(P.y1,P.y2,P.y3),a)); end; |
der obige Code ist eiglich nur da um es dynamisch zu machen, du kannst auch einfach:
Delphi-Quelltext
1: 2:
| V2d.x := -0.5 * V3d.x + V3d.y; V2d.x := -0.5 * V3d.x + V3d.z; |
benutzen.
wenn du noch fragen dazu hast, kann ich dir gern noch tiefgehender helfen.
mfg Ncortex
chaoslion - Mo 13.03.06 00:13
NCortex hat folgendes geschrieben: |
Delphi-Quelltext 1: 2:
| V2d.x := -0.5 * V3d.x + V3d.y; V2d.x := -0.5 * V3d.x + V3d.z; |
|
hey!
Ist wahrscheinlich nur nen Schreibfehler, aber wieso berechnest Du 2x den x Wert?
Ich hab ja zur Darstellung eines Punktes das "Schulkoordinatensystem" genommen.
Das heißt der Punkt(x,y,z) wird so gezeichnet:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| y | . | . | . -------.---------- x .| . | z. | |
korrekter Weise muss man doch von einer Zentralprojektion ausgehen, also das
der Benutzer in Richtung Z Achse schaut, oder?
Allesquarks - Mo 13.03.06 00:34
Wie hier schon erwähnt gibt es verschiedene Arten der Projektion Fluchtpunkt,senkrechte Projektion auf eine Ebene etc.
Aber beim Schulkoordinatensystem ist es für das Auge sowieso gewöhnungsbedürftig. Dort schaut der Benutzer keineswegs in z-Richtung. Und gerade weil dieses Darstellungssystem so zerrt auf jeden Fall immer erst die Koordinaten drehen und dann erneut abbilden. Und zum Abbildungsmaßstab:
| .
| .
| .
-----------------
|
|
|
z-Achse um die Hälfte gekürzt aber bei x-,y-Längenberechnung nochmal durch Wurzel zwei teilen.
delfiphan - Mo 13.03.06 02:15
NCortex: Deine Rechnung sieht etwas ungewöhnlich aus. Wenn man eine Projektion will muss man irgendwann mal durch die Tiefenkoordinate z teilen. Denn: Je grösser die Tiefenkoordinate z, desto kleiner soll das Objekt sichtbar sein. Wenn man durch z teilt, erhält man genau diesen Effekt: Je grösser z, desto kleiner die Abbildung.
F34r0fTh3D4rk - Mo 13.03.06 15:07
im grunde ist es auch eine 3x3 matrix, nur stehen in der letzten zeile lauter nullen, damit die z achse wegfällt.
man kann auch ebenso auf der x oder y achse projezieren.
NeoInDerMATRIX - Mo 13.03.06 20:55
Hi,
ich habe dazu mal gerade nen altes DOC auf meiner Platte gefunden! Evtl hilft es ja.
Damit habe ich das auch unter DOS mal hinbekommen.
Cu
Neo
NCortex - Mi 15.03.06 14:59
ähm... mir fällt grade auf, dass mein koordinatensystem anders ist.
bei mir ist z nach oben, y nach rechts und x die Tiefe. Daher auch 0.5 * x
das ist die standartperspektive, die man auch in der SChule benutzt. die tiefe einfach um die hälfte verkürzt dazu addieren.
hoffe das erklärt die Rechnung
NeoInDerMATRIX - Mi 15.03.06 21:44
Hi,
das mit dem Verkürtzt Rechnen ist doch aber wenn ich mich nicht irre bei der Perspektive nur so wenn der sicht winkel auf die Fläche ca. 45° sind oder irre ich mich da?
Cu
Neo
chaoslion - Do 16.03.06 15:51
jap 45°..er muss aber für ne korrekte betrachtung 90° sein
-----------------------------------------------------------
danke euch, hab mal nen bissle gegoogelt nach den begriffen die hier im thread so fielen
und hab ne lösung gefunden:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| function x3d2d(x,z:real):real; begin result:=(x*ZOOMFAKTOR)/(z+ZOOMFAKTOR); end;
function y3d2d(y,z:real):real; begin result:=(y*ZOOMFAKTOR)/(z+ZOOMFAKTOR); end; |
wobei 100 <= ZOOMFAKTOR <= 400 liegt. und bitte nicht kleiner 100 sonst ÜBELST fischaugeneffekt.. :)
ich kann ja dann mal nen screen posten, falls der rest mit den graden auch geht..
delfiphan - Do 16.03.06 21:33
Dafür hättest du nicht googeln müssen, ich hatte dir die Lösung ja schon in meinem ersten Post gegeben ;)
delfiphan hat folgendes geschrieben: |
Nimm mal für Zoomfaktor 400 und anstelle von "1" ebenfalls einen Wert in dieser Grössenordnung.
(...)
Je höher du diese beiden Werte setzst, desto näher solltest du eine Parallelprojektion erhalten. Wenn das nicht der Fall ist, dann ist eventuell etwas mit deiner Drehroutine falsch. |
chaoslion - Do 23.03.06 22:32
Die Seite sieht echt gut aus, bin noch nicht ganz fertig mit lesen..
naja ich stecke im Moment fest, ne simple Ebene zu zeichen, bzw die Fläche.
Ist noch nen bissle buggy :P
[url=
http://img119.imageshack.us/my.php?image=maddeshading3cm.jpg]
[/URL]
wenigstens klappt die rotation jetzt..
F34r0fTh3D4rk - Fr 24.03.06 21:34
ich bekomme es auch nicht hin, mein koordinatensystem steht auf dem kopf
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| function Projektion(v3d: TVektor3d): TVektor2d; var r1, r2: TVektor3d; m3x3: TMatrix3x3; begin m3x3[0, 0] := 0; m3x3[0, 1] := 0; m3x3[0, 2] := 0; m3x3[1, 0] := - (sqrt(2) / 4); m3x3[1, 1] := 1; m3x3[1, 2] := 0; m3x3[2, 0] := - (sqrt(2) / 4); m3x3[2, 1] := 0; m3x3[2, 2] := 1;
matrixrowtovektor_3x3(m3x3, r1, 1); matrixrowtovektor_3x3(m3x3, r2, 2); result.x1 := skalarprodukt_v3d(v3d, r1); result.x2 := skalarprodukt_v3d(v3d, r2); end; |
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62:
| var cube_3d: array [0..9] of TVektor3d; cube_2d: array [0..9] of TVektor2d;
procedure TForm1.Cube; var i, j: integer; begin image1.canvas.Pen.color := clblack; cube_3d[0].x1 := 0; cube_3d[0].x2 := 0; cube_3d[0].x3 := 0; cube_3d[1].x1 := 50; cube_3d[1].x2 := 0; cube_3d[1].x3 := 0; cube_3d[2].x1 := 50; cube_3d[2].x2 := 50; cube_3d[2].x3 := 0; cube_3d[3].x1 := 0; cube_3d[3].x2 := 50; cube_3d[3].x3 := 0; cube_3d[4].x1 := 0; cube_3d[4].x2 := 0; cube_3d[4].x3 := 0; cube_3d[5].x1 := 0; cube_3d[5].x2 := 0; cube_3d[5].x3 := 50; cube_3d[6].x1 := 50; cube_3d[6].x2 := 0; cube_3d[6].x3 := 50; cube_3d[7].x1 := 50; cube_3d[7].x2 := 50; cube_3d[7].x3 := 50; cube_3d[8].x1 := 0; cube_3d[8].x2 := 50; cube_3d[8].x3 := 50; cube_3d[9].x1 := 0; cube_3d[9].x2 := 0; cube_3d[9].x3 := 50; for i := 0 to 9 do cube_2d[i] := Projektion(cube_3d[i]); image1.Canvas.MoveTo(image1.Width div 2 + round(cube_2d[0].x1), image1.Height div 2 + round(cube_2d[0].x2)); for j := 1 to 9 do image1.canvas.LineTo(image1.Width div 2 + round(Cube_2d[j].x1), image1.Height div 2 + round(Cube_2d[j].x2)); end;
procedure TForm1.ODraw(x1, x2: double); begin image1.Canvas.MoveTo(image1.Width div 2, image1.Height div 2); image1.Canvas.LineTo(image1.Width div 2 + round(x1), image1.Height div 2 + round(x2)); end;
procedure TForm1.Button1Click(Sender: TObject); var v3d_x1: TVektor3d; v2d_x1: TVektor2d; v3d_x2: TVektor3d; v2d_x2: TVektor2d; v3d_x3: TVektor3d; v2d_x3: TVektor2d; begin image1.Canvas.pen.color := clred; v3d_x1.x1 := 200; v3d_x1.x2 := 0; v3d_x1.x3 := 0; v2d_x1 := Projektion(v3d_x1); ODraw(v2d_x1.x1, v2d_x1.x2);
image1.Canvas.pen.color := clblue; v3d_x2.x1 := 0; v3d_x2.x2 := 100; v3d_x2.x3 := 0; v2d_x2 := Projektion(v3d_x2); ODraw(v2d_x2.x1, v2d_x2.x2);
image1.Canvas.pen.color := clgreen; v3d_x3.x1 := 0; v3d_x3.x2 := 0; v3d_x3.x3 := 100; v2d_x3 := Projektion(v3d_x3); ODraw(v2d_x3.x1, v2d_x3.x2); end; |
die perspektive ist komisch, wie bekomme ich das korrekt ?
und wie zeichne ich den würfel einfacher, sodass ich nicht jede zeichenprozedur extra aufrufen muss, und zwar so, dass ich alle striche kriege ?
EDIT: nach langem gebastle:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| procedure TForm1.DrawCubeLine(a, b: integer); begin image1.Canvas.MoveTo(image1.Width div 2 + round(cube_2d[a].x1), image1.Height div 2 + round(cube_2d[a].x2)); image1.Canvas.LineTo(image1.Width div 2 + round(cube_2d[b].x1), image1.Height div 2 + round(cube_2d[b].x2)); end;
procedure TForm1.Cube; var i, j: integer; begin image1.canvas.Pen.color := clblack; cube_3d[0].x1 := 0; cube_3d[0].x2 := 0; cube_3d[0].x3 := 0; cube_3d[1].x1 := 0; cube_3d[1].x2 := 50; cube_3d[1].x3 := 0; cube_3d[2].x1 := 50; cube_3d[2].x2 := 0; cube_3d[2].x3 := 0; cube_3d[3].x1 := 50; cube_3d[3].x2 := 50; cube_3d[3].x3 := 0; cube_3d[4].x1 := 0; cube_3d[4].x2 := 0; cube_3d[4].x3 := 50; cube_3d[5].x1 := 0; cube_3d[5].x2 := 50; cube_3d[5].x3 := 50; cube_3d[6].x1 := 50; cube_3d[6].x2 := 0; cube_3d[6].x3 := 50; cube_3d[7].x1 := 50; cube_3d[7].x2 := 50; cube_3d[7].x3 := 50; for i := 0 to 7 do cube_2d[i] := Projektion(cube_3d[i]); DrawCubeLine(0, 1); DrawCubeLine(0, 2); DrawCubeLine(0, 4); DrawCubeLine(1, 3); DrawCubeLine(1, 5); DrawCubeLine(2, 3); DrawCubeLine(2, 6); DrawCubeLine(3, 7); DrawCubeLine(4, 5); DrawCubeLine(4, 6); DrawCubeLine(5, 7); DrawCubeLine(6, 7); end; |
aber mit der perspektive stimmt immer noch etwas nicht
chaoslion - Sa 25.03.06 08:46
also ich muss ehrlich sagen, ich hab das nicht mit ner Projektionsmatrix gemacht sondern so:
1. das koordinatensystem muss ja nach meiner berechnung ohne rotation so wie das 2d aussehen, also so:
Delphi-Quelltext
1: 2: 3: 4: 5:
| |Y | | | Z-------X |
du musst es drehen damit es nicht mehr auf dem kopf steht->meine drehrotine
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48:
| function Xrot(vek:TVek3d;winkel:real):TVek3d; begin result.x:=vek.x; result.y:=vek.y*cos(winkel)-vek.z*sin(winkel); result.z:=vek.y*sin(winkel)+vek.z*cos(winkel); end;
function Yrot(vek:TVek3d;winkel:real):TVek3d; begin result.x:=vek.z*sin(winkel)+vek.x*cos(winkel); result.y:=vek.y; result.z:=vek.z*cos(winkel)-vek.x*sin(winkel); end;
function Zrot(vek:TVek3d;winkel:real):TVek3d; begin result.x:=vek.x*cos(winkel)-vek.y*sin(winkel); result.y:=vek.x*sin(winkel)+vek.y*cos(winkel); result.z:=vek.z; end;
function Convert3d2d(vek:TVek3d):TVek3d; begin vek:=Xrot(vek,TEMPX); vek:=Yrot(vek,TEMPY); vek:=Zrot(vek,TEMPZ);
result.x:=(vek.x*ZOOM)/(vek.z+ZOOM); result.y:=(vek.y*ZOOM)/(vek.z+ZOOM); result.z:=0; end;
procedure ZeichneVektor(vek1,vek2:TVek3d;farbe:Cardinal); begin vek1:=Convert3d2d(vek1); vek2:=Convert3d2d(vek2); Canvas.Line( NULLX+vek1.x, NULLY-vek1.y, NULLX+vek2.x, NULLY-vek2.y,farbe,farbe,fxBlend); end; |
F34r0fTh3D4rk - Sa 25.03.06 10:38
ich möchte aber gerne vektoren und matrizen nehmen, da das ein mathematisches programm wird und eben alles stimmig sein muss ^^, außerdem ist dann die dynamik größer
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!