AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

2D-Pixel eines Control3D?

Ein Thema von laube53 · begonnen am 28. Sep 2013 · letzter Beitrag vom 20. Okt 2013
Antwort Antwort
laube53

Registriert seit: 10. Feb 2011
Ort: Berlin
10 Beiträge
 
#1

2D-Pixel eines Control3D?

  Alt 28. Sep 2013, 19:23
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?
Thomas Lauer
  Mit Zitat antworten Zitat
Thom

Registriert seit: 19. Mai 2006
570 Beiträge
 
Delphi XE3 Professional
 
#2

AW: 2D-Pixel eines Control3D?

  Alt 1. Okt 2013, 17:48
[gelöscht]

Sorry - Unfug geschrieben...

Man sollte nicht immer der Onlinehilfe vertrauen. Dort steht zwar zur Funktion TContext3D.WorldToScreen() :
Zitat:
Wandelt einen 2D-Punkt (z.B. Mauskoordinaten) in einen 3D-Punkt in einer Szene um.
Das ist aber falsch: Diese Methode macht, was sie dem Namen nach soll - sie wandelt einen Punkt aus der 3D-Welt in Bildschirmkoordinaten um.

Die Anwendung ist einfach:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  P: TPoint3D;
begin
  P:=Context.WorldToScreen(Cube.Projection,Cube.AbsolutePosition);
  [...]
end;
Thomas Nitzschke
Google Maps mit Delphi

Geändert von Thom ( 1. Okt 2013 um 23:34 Uhr) Grund: Unsinn korrigiert. ;-)
  Mit Zitat antworten Zitat
laube53

Registriert seit: 10. Feb 2011
Ort: Berlin
10 Beiträge
 
#3

AW: 2D-Pixel eines Control3D?

  Alt 15. Okt 2013, 19:01
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?
Thomas Lauer
  Mit Zitat antworten Zitat
Thom

Registriert seit: 19. Mai 2006
570 Beiträge
 
Delphi XE3 Professional
 
#4

AW: 2D-Pixel eines Control3D?

  Alt 15. Okt 2013, 19:20
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!

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.
Thomas Nitzschke
Google Maps mit Delphi

Geändert von Thom (16. Okt 2013 um 14:07 Uhr)
  Mit Zitat antworten Zitat
laube53

Registriert seit: 10. Feb 2011
Ort: Berlin
10 Beiträge
 
#5

AW: 2D-Pixel eines Control3D?

  Alt 20. Okt 2013, 20:22
Meine Erkenntnisse bis jetzt:
Ich habe begonnen mit einer FireMonkey3D-Demo namens Arrows3D, siehe http://cc.embarcadero.com/item/29148.

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.
Thomas Lauer
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:59 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz