Sergiy Krutykov

Eine der Anforderungen an die 3D-Objekte in OpenGL ist, dass sie darauf reagieren, wenn man auf sie tippt. Das schwierige ist dabei, herauszufinden, auf welchem Objekt getippt wurde, wenn überhaupt. Die einzige Angabe, die man dabei hat, sind die Koordinaten des Fingers auf dem Touchscreen. Es gibt die OpenGL-Funktion glReadPixels, die zu den Bildschirmkoordinaten die Farbe der entsprechenden Pixels auf dem Bildschirm liefert. Man kann sie insbesondere auf einen einzelnen Pixel anwenden. Die Farbe steht dann in Form von drei Bytes (jeweils eines für rot, grün und blau - alpha kann meistens nicht ausgelesen werden). Aus der folgenden Abbildung wird ersichtlich, dass dies zu keinem Erfolg führt, wenn man diese Methode direkt auf die gerenderte Szene anwenden würde:

Die Tresors haben zu viele unterschiedliche Farben, die eventuell auch im Hintergrund vorkommen und insbesondere ist es problematisch, die Tresore selbst auseinander zu halten. Allerdings wenn man die Tresore mit einem einfarbigen Shader Programm rendert und dabei unterschiedliche Farben zuweist und den Hintergrund schwarz hält, dann kann man anhand von der Ausgabe von glReadPixels die Tresore identifizieren. Wenn der Benutzer auf einem leeren Feld getippt hat, dann liefert die Funktion (R,G,B) = (0,0,0) zurück, so dass man erkennen kann, dass kein Objekt getroffen wurde. Sonst wird die entsprechende Farbe zurückgeliefert. In folgender Abbildung ist dargestellt, wie die obigen Tresore in dieser einfarbigen Fassung aussehen:

Aus Effizienzgründen wird hier nur der Körper des Tresors gezeichnet, weil es ausreichend ist, wenn nur beim Tippen darauf der Tresor reagiert. Das Rendern braucht auch nur dann stattzufinden, wenn auf dem Touchscreen getippt wird. Das alles kann man auch auf dem Framebuffer machen, der auch zum Anzeigen benutzt wird. Allerdings ist viel sauberer einen alternativen, unsichtbaren Framebuffer dafür zu nehmen. Dann kann man auch die Perfomance etwas verbessern, indem man die Auflösung dieses Framebuffer niedriger wählt, wie in der folgenden Abbildung:

Da der Buffer unsichtbar ist, stört das unschöne Aussehen niemanden, aber das Rendern geht noch schneller. Allerdings muss man dann die Bildschirmkoordinaten etwas transformieren, da der Framebuffer nicht den ganzen Bereich des Screens ausfüllt.

Diese Methode funktioniert ganz gut (sobald der Client saubere Koordinaten der Finger auf dem Touchscreen liefert), denn das Rendern von einfarbigen Objekten sehr schnell geht. Die Funktion glReadPixels ist zwar ziemlich langsam, aber, da es sich hier immer um einen einzigen Pixel handelt, fällt das auch nicht ins Gewicht. Das Identifizieren anhand von Farben ist auch sehr einfach: Man muss einfach jede Zahl, die man einem Objekt zuweisen will, in 3 Bytes Spalten z.B. nach der folgenden Formel:

int objectID = 12345;
int B = objectID/65536;
int G = (objectID-B*65536)/256;
int R = (objectID-B*65536)-G*256;

Beim Erkennen der Objekte muss man die Farbe des Objekts wieder in einen Integer konvertieren int objectID = B*65536 + G*256 + R. Zum Beispiel war die ID von dem linken (roten) Tresors von oben gleich 200 und die des rechten (grünen) gleich 30000.

Die einzige Einschränkung dieser Methode ist, dass die Anzahl der zu verwendeten Farben und entsprechenden der unterschiedlichen IDs auf 256*256*256 = 16'777'216 beschränkt ist.


Page last modified on March 21, 2011, at 11:11 PM