![]() |
2D-Pixel eines Control3D?
Aus den 3D-Koordinaten (Position und RotationAngle) einer Camera in Firemonkey müsste man doch die Bildschirm-Pixel eines Punkts (Point3D) berechnen können.
Weiß jemand, wie das geht? |
AW: 2D-Pixel eines Control3D?
[gelöscht]
Sorry - Unfug geschrieben... :oops: Man sollte nicht immer der ![]()
Delphi-Quellcode:
:
TContext3D.WorldToScreen()
Zitat:
Die Anwendung ist einfach:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var P: TPoint3D; begin P:=Context.WorldToScreen(Cube.Projection,Cube.AbsolutePosition); [...] end; |
AW: 2D-Pixel eines Control3D?
Vielen Dank (nachträglich; war verreist).
Ich versuche, 3D-Objekte mit der Maus zu verschieben. Dazu muss die Zugrichtung der Maus analysiert werden und herausgefunden werden, ob sie in eine Achsenrichtung zieht. Mit WorldToScreen geht das schon. Aber die Ereignisbehandlung (MouseDown etc.) von 3D-Objekten scheint ziemlich langsam zu sein (oder ich mache etwas falsch); jedenfalls kann ich nur sehr langsam ziehen. Allerdings wurmt es mich (als Mathematiker), dass ich die Mathematik hinter der Projektion noch nicht genau verstehe. Gibt es schon etwas gründliches zu FireMonkey-3D, oder muss man sich durch die Quellen arbeiten? |
AW: 2D-Pixel eines Control3D?
Ich habe auch etliche Semester Mathematik hinter mir - aber wenn ich mir die FMX-Quelltexte anschaue, bin ich ständig am Überlegen, ob ich nur zu dumm dafür bin, die Genialität dahinter zu verstehen oder ob da einfach (Entschuldigung) nur Stümper am Werk waren/sind. Ich hatte bisher etliche Wochen damit zugebracht, Teile von FMX (u.a. 3D und Filter) zu verstehen und muß gestehen, daß ich an vielen Stellen noch ratlos bin.
Die Bewegung von Objekten ist ebenfalls ein Thema für mich, da ich die dumme Idee hatte, einen brauchbaren Editor für FMX 3D zu programmieren. Die IDE ignoriert ja bekanntlich in 3D-Formularen die zugewiesenen Kamera zur Design-Time und in TViewport3D ist die Nutzung auch nur unsagbar mühsam. Aber es freut mich sehr, daß es noch mehr Leute gibt, die genügend Optimismus aufbringen, es mit dem Feueraffen aufzunehmen. Vielleicht bekommen wir es gemeinsam hin! :-D P.S.: Ja - ohne die Quellen geht meiner Meinung nach gar nichts (außer dem Zusammenklicken der Oberfläche). Sobald eine halbwegs ernsthafte Anwendung daraus werden soll, führt kein Weg daran vorbei. |
AW: 2D-Pixel eines Control3D?
Meine Erkenntnisse bis jetzt:
Ich habe begonnen mit einer FireMonkey3D-Demo namens Arrows3D, siehe ![]() Bei einer Projektion vom 3-dimensionalen Raum auf einen Bildschirm kann man sich zwischen einr Parallelprojektion und einer Zentralprojektion entscheiden. FireMonkey3D benutzt eine Zentralprojektion: Der Bildpunkt P' von P ist der Schnittpunkt der Gerade OZ mit der Bildebene E: P' = OZ geschnitten E. Z ist das Projektionszentrum, bei Firemonkey die (absolute) Position der Camera. Die Bildebene E ist die Senkrechte zur Camera-Richtung und geht durch den Nullpunkt. In der Bildebene E legt man einen "Ursprung" VP und zwei Basisvektoren VH (horizontal) und VV (vertikal) fest. Die Koordinaten des Bildpunkts P' sind dann s und t, wenn der Ortsvektor von P' gleich dem von VP + r*VH + s*VV ist. Die Umwandlung von P' in Bildschirmpixel geschieht dann anhand einer "Karte": Sie legt ein reelles Intervall [a,b] für die s-Koordinate und [c,d] für die t-Koordinate fest, Randpixel pa (linker Rand) und Pd (oberer Rand) und es bzw. es (Pixel pro s-Einheit bzw. Pixel pro t-Einheit). Sei [XVon, XBis] x [YVon, YBis] x [ZVon, ZBis] der sichtbare Bereich der x- y- und z-Achse. Das kann man folgendermaßen in Delphi aufschreiben: type TKarte = record {Daten zur Transf.von xy-Koordinaten in Pixel} a,b,c,d :Single; {sichtbares Rechteck} pa,pd :integer; {Pixel von (a,d) = linke obere Ecke} es,et :LongInt; {Pixel pro Einheit} end; TProjTyp=(parallel,zentral); {Parallel- oder Zentralprojektion } TProjDaten=record {Proj.ebene: VX = VP+tVH+sVV } PT:TProjTyp; VS,VP,VH,VV:TVector3D; {VS: Proj.richtung bzw. -zentrum } end; var Projektion: TProjDaten; Karte:TKarte; function XPix(s:Single):Single; {Umrechnung von s,t in Pixel} begin with Karte do XPix:=pa+ex*(s-a); end; function YPix(t:Single):Single; begin with Karte do YPix:=pd+ey*(d-t); end; procedure normiere(var v:TVector3D); var t:Single; begin t:=sqrt(v.X*v.X+v.Y*v.Y+v.Z*v.Z); if t<>0 then begin v.X:=v.X/t; v.Y:=v.Y/t; v.Z:=v.Z/t; end else raise Exception.Create('Versuch,Nullvektor zu normieren!'); end; procedure SetPDC(Camera:TCamera; w,h:Single); {setzt Projektion gemäß Camera} var N,V : TVector3D; PD : TProjDaten; begin Karte.a:=XVon*1.25; // ist der tatsächlich in Viewport3D sichtbare Bereich Karte.b:=XBis*1.25; Karte.c:=YVon*1.1; Karte.d:=YBis*1.1; Karte.pa:=0; Karte.pd:=0; Karte.ex:=Round(w/(Karte.b-Karte.a)); //w=Viewport3D1.Width); Karte.ey:=Round(h/(1*(YBis-YVon))); //h=Viewport3D1.Height); PD.PT:=zentral; PD.VS:=Camera.AbsolutePosition; {Projektions-Zentrum Z} PD.VP.X:=0; {Ursprung des Koordinatensystems der Bildebene} PD.VP.Y:=0; PD.VP.Z:=0; N:=Camera.AbsoluteDirection; Normiere(N); V.X:=-N.Y*N.X; V.Y:=1-N.Y*N.Y; V.Z:=-N.Y*N.Z; Normiere(V); PD.VV:=V; PD.VH:=N.CrossProduct(V); Projektion:=PD; end; procedure project(x,y,z:Single; var s,t:Single); var d,dx,dy:Single; U1,U2,VH0,VV0:TVector3D; k:integer; begin with Projektion do begin {Berechnung d.Schnittpunkts} if PT=zentral then begin U1.X:=VS.X-w.X; U1.Y:=VS.Y-w.Y; U1.Z:=VS.Z-w.Z; end else begin U1.X:=VS.X; {U1=RichtungsTVector3D} U1.Y:=VS.Y; U1.Z:=VS.Z; end; U2.X:=w.X-VP.X; {U2=rechte Seite des LGS} U2.Y:=w.Y-VP.Y; U2.Z:=w.Z-VP.Z; VH0:=VH; VV0:=VV; normiere(VH0); normiere(VV0); d:=det(U1,VH0,VV0); {Determinate} dx:=det(U1,U2,VV0); dy:=det(U1,VH0,U2); if d=0 then raise Exception.Create('Projektionsgerade parallel zur Ebene! Prozedur abgebrochen') else begin s:=dx/d; t:=dy/d; end; end; end; Der letzte Schritt (Umrechnung von s,t in Pixel) ist aber noch verbesserungsbedürftig. WorldToScreen ist da genauer. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:39 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz