Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

23.08.2016, 09:39

OpenGL: Objekte selektieren

Zuerst: ja ich weiß dass OpenGL mit den alten glBegin()/glVertex...()/glEnd()-Aufrufen ziemlich antik ist, leider beschränken die Zielplattformen mit ziemlich lausigen OpenGL-Treibern meine Möglichkeiten.

Aktuell habe ich eine Szene, in der meine 3D-Objekte (alles Wireframes) dargestellt werden und rotiert/verschoben werden können. Dabei werden die Mausbewegungen auf dem Drawcanvas detektiert und dann als Translation/Rotation in eine Matrix übertragen. Diese Matrix wiederum beeinflusst die per glVertex...() übertragenen Koordinaten (Stimmt nicht, siehe Nachtrag unten).

Jetzt geht es in einem weiteren Schritt darum, Objekte in dieser Szene zu selektieren. D.h. der Benutzer klickt irgendwo in den Drawcanvas. Befindet sich in der Nähe dieses Clicks die Linie eines der dargestellten Objekte, so soll ermittelt werden, welches das ist.

Von Java3D kenne ich diverse Intersection-Methoden, bei denen eine Art Strahl in die Szene geschickt wird um dessen Kollision mit Objekten zu überprüfen - in OpenGL wird das vermutlich ähnlich sein!?

ABER (und jetzt kommt es): Wie stelle ich das mit meinem Antik-OpenGL am besten an, so dass ich damit gleichzeitig weitgehend zukunfskompatibel bin? Sprich wenn doch mal eine Umstellung auf OpenGL3/4 möglich sein sollte, wäre es schön, wenn dieser Selektiercode auch damit funktioniert.

Irgendwelche genialen Ideen/Tipps/Vorschläge?

Danke!

PS: Kleiner Nachtrag, die von den Mausbewegungen übernommenen Translationen/Rotationen werdne NICHT in eine Matrix übertragen sondern vor dem senden der Koordinaten per glTranslatef() und glRotatef() für die gesamte Szene gesetzt

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Elmi« (23.08.2016, 09:46)


dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

2

23.08.2016, 10:39

OpenGL (vor allem in neueren Ausführungen) ist eine low-level API, die sich um nichts anderes kümmert als das Zeichnen von Punkten, Linien und Dreiecken. Das ist alles was OpenGL macht und alles was OpenGL kann. Ergo kann deine Anwendung OpenGL verwenden, um Punkte, Linien und Dreiecke zu malen und fertig. OpenGL macht sich keine Gedanken darüber, was diese Punkte, Linien oder Dreiecke in deiner Anwendung für eine Bedeutung haben mögen. Ja sobald der letzte Pixel eines Dreiecks gemalt wurde, hat OpenGL schon längst wieder vergessen, dass es das Dreieck überhaupt jemals gegeben hat. So Konzepte wie "etwas selektieren" liegen weit jenseits von allem, worum OpenGL sich kümmern würde. Dein Problem hat also nichts mit OpenGL zu tun und ist auch nichts womit OpenGL dir direkt helfen könnte.

Die übliche Lösung hast du ja aber eh auch schon selbst genannt: Einen Strahl in die Szene schicken und schauen, mit welchem Objekt sich dieser als erstes schneidet. Die Tatsache, dass es sich bei den Objekten in deinem Fall um Linien handelt, die unendlich dünn und daher rein mathematisch praktisch unmöglich zu treffen sind, ist natürlich etwas, worüber du nachdenken solltest... ;)

Eine andere Lösung wäre, ein Bild deiner Szene zu rendern, in dem alle Pixel eines Objektes eine Farbe haben, die dieses Objekt eindeutig identifiziert. Dann kannst du einfach schauen, was für eine Farbe unter dem Mauszeiger liegt.

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »dot« (23.08.2016, 10:49)


BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

3

23.08.2016, 10:45

rein mathematisch praktisch unmöglich zu treffen
Nicht unmöglich. Nur im alltäglichen Einsatz höchst unwahrscheinlich. ;)
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

4

23.08.2016, 10:50

rein mathematisch praktisch unmöglich zu treffen
Nicht unmöglich. Nur im alltäglichen Einsatz höchst unwahrscheinlich. ;)

Naja, die Wahrscheinlichkeit ein Linie zu treffen ist mathematisch gesehen tatsächlich exakt 0 (auf jeden Punkt der Linie kommen überabzählbar unendlich viele andere Punkte). Dass man die zur Linie gehörenden Punkte natürlich ausrechnen kann, ist eine andere Sache... ;)

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

5

23.08.2016, 10:51

Nö. Ich kann dir ein wunderbares praktisches Sample konstruieren, wo die Change 100% ist diese Linie zu treffen. Nur ist das eben konstruiert.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

6

23.08.2016, 10:55

Nö. Ich kann dir ein wunderbares praktisches Sample konstruieren, wo die Change 100% ist diese Linie zu treffen.

Klar kannst du das. Ich rede natürlich von der Wahrscheinlichkeit, im Allgemeinen eine beliebige Linie zu treffen; die ist, wenn wir mal von Dingen wie der endlichen Genauigkeit von float absehen, mathematisch beweisbar 0. Ich denke nicht, dass Dinge wie eine exakt horizontale Gerade die exakt durch die Mittelpunkte aller Pixel in einem N×1 Pixel Bild geht von allgemeinem Interesse sind... ;)

Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von »dot« (23.08.2016, 11:08)


7

23.08.2016, 11:13

OK, also ist Handarbeit nötig. Vereinfacht wird das dadurch, dass die Kamera immer exakt parallel zu einer Ebene steht.

Der Zustand ist also:

- ich habe die bekannten Koordinaten meiner Wireframes
- ich habe meine OpenGL-Szene mit glTranslatef()/glScaled()/glRotatef verschoben/gezoomt/rotiert
- ich habe ein Mausklick in die Szene mit den XY-Koordinaten des Drawcanvas

Wie komme ich denn jetzt z.B. von den XY-Mauskoordinaten auf die Koordinaten, denen das in der OpenGL-Szene bei der aktuellen Verschiebung/Zoom/Rotation entspricht? Dass mir bei den Mauskoordinaten die dritte Dimension fehlt, weiß ich, aber da ich immer exakt Draufsicht oder eine Seitenansicht habe, bildet diese ja immer meinen Intersection-Strahl.

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

8

23.08.2016, 11:29

Es handelt sich dabei um ein Standardproblem-hast du schonmal google bemüht? Ich vermute es gibt einige Quellen in denen das Thema sehr anschaulich aufgearbeitet sein dürfte-viel anschaulicher als es irgendjemand von uns mal zwischendurch in einem kurzen Post zusammenschreiben könnte.
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

9

23.08.2016, 11:46

OK, also ist Handarbeit nötig. Vereinfacht wird das dadurch, dass die Kamera immer exakt parallel zu einer Ebene steht.

Von was für einer "Ebene" reden wir da genau und inwiefern vereinfacht das das Ganze? Jede Kamera, für die so etwas wie die Konzepte einer Position und Blickrichtung Sinn ergeben, steht notwendigerweise zu jedem Zeitpunkt exakt parallel zu unendlich vielen Ebenen; das allein ist also noch keine Information, die uns irgendwie helfen würde... ;)



Der Zustand ist also:

- ich habe die bekannten Koordinaten meiner Wireframes
- ich habe meine OpenGL-Szene mit glTranslatef()/glScaled()/glRotatef verschoben/gezoomt/rotiert
- ich habe ein Mausklick in die Szene mit den XY-Koordinaten des Drawcanvas

Wie komme ich denn jetzt z.B. von den XY-Mauskoordinaten auf die Koordinaten, denen das in der OpenGL-Szene bei der aktuellen Verschiebung/Zoom/Rotation entspricht? Dass mir bei den Mauskoordinaten die dritte Dimension fehlt, weiß ich, aber da ich immer exakt Draufsicht oder eine Seitenansicht habe, bildet diese ja immer meinen Intersection-Strahl.

Ich mach es normalerweise so, dass ich meine Mauskoordinaten in normalisierte Gerätekoordinaten (NDC) umrechne (Koordinatensystem wo links unten im Fenster (-1,-1) und rechts oben (1,1) entspricht), daraus dann die zwei Punkte (x, y, -1, 1)* und (x, y, 1, 1) konstruiere (x und y sind dabei die Mausposition in NDC) und dann die beiden Punkte mit der inversen View-Projection-Matrix transformiere. Die x-, y- und z-Koordinaten der resultierenden 4D Punkte dividierst du durch deren w-Koordinate. Was du dann hast sind die Weltkoordinaten der zwei 3D Punkte, die deiner Mausposition auf der near und far Plane entsprechen. Das funktioniert für jede beliebige View-Projection-Matrix. Der erste Punkt gibt dir den Start, die Differenz der zwei Punkte die Richtung deines Picking Strahls...

Falls du immer nur eine orthogonale Projektion entlang einer Hauptachse hast, geht's natürlich auch einfacher. In dem Fall solltest du ja direkt wissen, welchen Positionen links unten und rechts oben in deinem Fenster entspricht (immerhin musst du das bei der Konstruktion der Projektionsmatrix selbst angeben). Wenn du das weißt, kannst du auch einfach ausrechnen, welcher Position deine Mauskoordinaten entsprechen (liegen ja einfach irgendwo dazwischen im Fenster). Dein Strahl startet dann einfach an dieser Position und geht entlang der entsprechenden Hauptachse...

*) Im Falle von Direct3D muss es (x, y, 0, 1) sein, zumindest wenn wir die selbe Matrix verwenden wollen wie auch zum Rendern...

Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von »dot« (23.08.2016, 12:04)


10

23.08.2016, 12:24

OK, aber benötige ich nicht noch irgend einen Umrechnungsfaktor für z.B. den Zoom? Wenn ich in meiner OpenGL-Szene den Zoom (=glScaled()) auf 1 setze, dann ist nicht ein Pixelpunkt des OpenGL-Canvas gleich einem Koordinatenwert. Oder anders beschrieben: wenn ich eine Linie der Länge von 1 übergebe, dann wird mir die real mit ca. 40 Punkten Länge gezeichnet. Wie komme ich auf diesen Faktor?

Werbeanzeige