ich möchte die 2D-Mauskoordinaten auf 3D-Koordinaten, die in festgelegter Entfernung auf einer Projektionsfläche liegen, abbilden. Habe da auch schon einiges ausprobiert und gerechnet, komm aber nicht so wirklich auf ein optimales Ergebnis. Irgendwo steckt der Wurm drin, vielleicht kann mir ja jemand helfen.
Ich erklär mal wie ich es probiert habe, dazu hänge ich zur Veranschaulichung meines Gedankenganges eine (wunderschöne) Skizze an . Der Einfachheit halber schreibe ich die Berechnungen nur für den X-Wert auf, für die Y-Koord. verläufts analog (und Z ist ja sowieso festlegegt)).
Die Entfernung von meiner Kamera zur gewünschten Projektionsfläche sei in der Konstante DISPLACE gespeichert. Die Breite der sichtbaren Projektionsfläche speichere ich in der Variablen d. Der Betrachtungswinkel sei in der Konstanten FOV gespeichert.
Also berechne ich d mit dem Sinus-Satz,
Code:
(d/2)/sin(FOV/2) = DISPLACE / sin(90 - FOV/2)
durch umformen erhalte ich dann die Projektionsbreite d. Als nächstes berechne ich zuerst die Mausposition mit dem Mittelpunkt der Arbeitsfläche als Ursprung.
Code:
x := P.X - ClientWidth div 2
Relativ zur Breite der Arbeitsfläche ergibt sich für x dann ein Wert zwischen -1 bis 1.
Code:
x := 2 * x / ClientWidth
Und den multipliziere ich dann mit d, um die Koordinate auf die Projektionsfläche, die in der Entfernung DISPLACE liegt und da genau meine Arbeitsfläche ausfüllen sollte, abzubilden.
Code:
x := x * d
Klappt nur leider nicht , irgendwo muss ich nen grundlegenden Fehler in meinem Modell haben. Ich liege mit meinen Berechnungen immer weiter daneben, je weiter ich von dem Ursprung wegkomme.
Naja, hier nochmal ein Code-Schnipsel, wie meine Umsetzung davon in Delphi aussieht (die Position der Kamera ist hier mal außer Acht gelassen):
Code:
// Mausposition auf OpenGL-Frame
GetCursorPos(P);
P := Self.ScreenToClient(P);
// Mauskoordinaten mit Urpsrung in der Mitte des Bildschirms
Registriert: Di Dez 27, 2005 12:44 Beiträge: 393 Wohnort: Berlin
Programmiersprache: Java, C++, Groovy
Hallo 7eddi,
müsste es in deiner letzten Zeile nicht
Code:
x := x * d / 2
heissen?
Wenn du z.B. für d 1000 berechnet hast, müsste deine Projektionsfläche im X-Bereich von -500 bis 500 gehen. Wenn x von -1 bis 1 geht, würdest du ja eine Projektionsfläche von -1000 bis 1000 erhalten, also musst du nochmal durch 2 teilen.
Viele Grüße dj3hut1
P.S. sin(90 - FovRad / 2) ist übrigens dasselbe wie cos(FovRad / 2)
Registriert: So Sep 26, 2004 05:57 Beiträge: 190 Wohnort: Linz
Gibt es einen Grund weshalb du nicht gluUnProject verwenden möchtest? Ansonnsten wäre es damit wohl einfacher. Sollte dein ClientWidth aus irgend einem Grund nicht mit deinem Viewport übereinstimmen, so kannst du ja für diese Berechnung eine andere Viewport-Matrix erstellen (geht eh recht einfach). Den Z-Wert musst du natürlich auch noch entsprechend modifizieren (wird bei gluUnProject ja im Wertebereich [0|1] benötigt), sollte aber auch nicht so das Problem sein. Oder hab ich da jetzt irgendwas falsch verstanden?
Du hast Recht! Ich hatte es sogar vorher so, hab dann aber irgendwie gedacht ich müsste das ändern.
@Lyr:
Ooooh, doch, ich möchte gluUnProject verwenden (man muss nur wissen, dass es diese Funktion gibt und wie sie heißt). Jedenfalls habe ich sie gerade ausprobiert, bekomme aber irgendwie immer die gleichen Koordinaten ausgespuckt, egal welche Fensterkoordinaten ich übergebe. Die zurückgegebenen Koordinaten entsprechen sogar genau der Position meiner Kamera!? Was mache ich falsch? Habe das Beispiel von http://wiki.delphigl.com/index.php/gluUnProject genommen und damit rumgespielt - ohne Erfolg.
Registriert: So Sep 26, 2004 05:57 Beiträge: 190 Wohnort: Linz
Ich nehme an das Problem bei dir ist der Z-Wert, welcher für gluUnProject eben wie bereits erwähnt nicht der Abstand von der Kamera ist, sondern zwischen 0 und 1 liegen muss. Wenn du den Abstand von der Kamera verwenden möchtest, musst du den Z-Wert entsprechend anpassen, und zwar folgendermaßen:
ZWindow = ( ( (-(f+n) * ZWorld - 2*f*n) / -ZWorld*(f-n) ) + 1 ) / 2
f ... Far Plane deiner View-Frustum
n ... Near Plane
ZWorld ... der negative Abstand vom Betrachter, also wenn du den Punkt 10 Einheiten vor dem Betrachter haben willst, ist ZWorld = -10
Hier sollte nun für ZWindow ein Wert zwischen 0 und 1 raus kommen. Also für
ZWorld = -n => ZWindow = 0
ZWorld = -f => ZWindow = 1
solltest vielleicht ausprobieren um zu sehen ob wir beide die Formel richtig übertragen haben :-).
Und dann so wie im gluUnProject-Artikel nur halt das Z durch ZWindow ersetzen:
Das mit dem glReadPixels kannst dir dadurch natürlich auch sparen.
Ist doch etwas länger geworden mit der Umformung als ich ursprünglich dachte, ist halt das Problem, dass du den Z-Wert praktisch in Welt-Koordinaten gegeben hast und x und y im Fenster-Koordinatensystem. Sollte aber so hin hauen ...
Und falls es dich interessiert wie man auf diese viel zu lange Formel kommt:
Man nehme den Vektor (0,0,ZWorld,1)
Multipliziere ihn mit der Projektionsmatrix (siehe glFurstum, ist in diesem speziellen Fall kein Unterschied zu gluPerspective da x und y = 0)
Dividiere ihn durch -ZWorld (siehe Wiki->Clipping Plane oder auch Wiki->Feste Funktionspipeline)
Bringe ihn von [-1|1] auf [0|1] (siehe glDepthRange)
Und das ZWorld negativ sein muss liegt daran dass die OGL-Frustum standardmäßig in die -Z - Richtung blickt, kannst aber eh einfach umformen.
Hm, es ist komisch, egal welche Werte ich für X, Y, Z wähle (Z zwischen 0 und 1), gluUnProject liefert mir immer das gleiche Ergebnis (Die Position der Kamera). Kann es sein, dass etwas mit den Matrizen Modelview, Projection oder Viewport nicht stimmt?
Registriert: So Sep 26, 2004 05:57 Beiträge: 190 Wohnort: Linz
Da hast du recht, das ist doch ziemlich komisch. Wenn du den Code aus dem gluUnProject Artikel zum auslesen der Matrizen verwendest, kann ich mir eigentlich nur noch vorstellen, dass es mit dem Zeitpunkt des Aufrufes Problem gibt, obwohl es selbst dann komisch ist ... nur wenn die Projection-Matrix die Identitäts-Matrix ist könnt ichs mir vorstellen.
Also du solltest diesen Aufruf halt mit den Matrizen machen mit denen du zeichnest. Wenn dir der Aufruf nicht in deine Zeichenroutine rein passt, kannst dir ja die Matrizen zwischenspeichern.
Natürlich sollte die Modelview-Matrix ausschließlich die Kamera-Transformation enthalten, nicht die "temporären" Transformationen zum zeichnen der Objekte. Also:
Projection Matrix sollte die Werte von glFrustum / gluPerspective oder glOrtho enthalten.
Modelview Matrix sollte die Werte von einem gluLookAt-Aufruf oder entsprechenden OpenGL-Transformationen enthalten, nicht jedoch die Transformationen mit denen du deine Objekte in der Welt positionierst.
Viewport sollte logischer Weise auch gesetzt sein.
Und welche Werte verwendest du eigentlich für die Near- und Far-Plane? Deine Zeichnung sieht diesbezüglich etwas ... komisch aus.
Registriert: Do Sep 25, 2003 15:56 Beiträge: 7810 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Ist es wirklich nötig dass die Szene 10000 tief ist? Das ist schlecht für die Tiefenpuffer auflösung. Die Far-Plane sollte so nah wie möglich an der Nearplane sein. Und nach möglichkeit sollte der Abstand der Planes eine Potenz von 2 sein (256, 512 ...)
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Naja, meine "Szene" besteht wirklich nur aus ein paar Polygonkreisen... Aber ich kann ja trotzdem mal darüber nachdenken, die Diemnsionierung etwas zurückzufahren. Ändert das denn etwas an meinem Problem?
Registriert: Mo Mai 29, 2006 21:13 Beiträge: 142 Wohnort: Ballenstedt/Sachsen-Anhalt
Unter Umständen ja, weil im Moment der Schritt von einer GL-Einheit nur 0,0001 Z-Buffer Einheiten sind(hoffe, das war jetzt verständlich).
Damit kann es schon sein, das da was verloren geht.
Obwohl, dann müsste ja bei Z=1 ein Punkt auf der Farclipping-Plane rauskommen, also bei 10000.
Jedenfalls, kleiner ist immer besser Am besten ausprobieren, so klein machen das gerade noch alles drauf ist. Wenn du nur 'n paar Kreise hast, reicht sicherlich auch 128 oder noch kleiner.
Registriert: So Sep 26, 2004 05:57 Beiträge: 190 Wohnort: Linz
Eigentlich wollte ich mit der Near- und der Far-Plane nur wissen ob du zb als Near einen negativen Wert oder 0 angegeben hast ... weiß nicht genau wie die glu mit solchen Werten verfährt, sie sollte damit auch keine Probleme haben, war nur der Vollständigkeit halber. Mit 1 und ein paar 1000 solltest du aber keine Probleme haben. Wie gesagt sind die Matrizen die du zum Zeitpunkt deines 2D->3D Aufrufes verwendest interessanter.
Mitglieder in diesem Forum: 0 Mitglieder und 7 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.