2012-04-03 12 views
0

Ich arbeite an einer Android-Anwendung, in der eine 3D-Szene angezeigt wird und der Benutzer in der Lage sein sollte, einen Bereich durch Klicken/Tippen auf den Bildschirm auszuwählen. Die Szene ist so ziemlich ein planares (Spiel) Board auf dem verschiedene Objekte platziert werden.
Jetzt ist das Problem, wie bekomme ich den angeklickten Bereich auf der Platine von den tatsächlichen Bildschirm-Raum-Koordinaten?Umgekehrte Projektionsflächenkoordinate zu Modellraumkoordinaten

Ich hatte geplant, gluUnProject() zu verwenden, da ich Zugriff auf (fast) alle notwendigen Parameter habe. Leider fehlt mir der Parameter winZ param, und kann nicht die aktuelle Tiefe erhalten, da das Berührungsereignis in einem anderen Thread als der GL-Thread auftritt.
Mein neuer Plan ist immer noch gluUnProject, aber mit einem winZ von 0, und projizieren Sie den resultierenden Punkt auf die Platine (die Platine reicht von 0,0,0 bis 10,0,10 im Modellbereich), aber ich kann nicht scheinen, herauszufinden Wie macht man das?

Ich würde mich sehr freuen, wenn mir jemand mit der nötigen Mathematik helfen könnte (Matrizen waren nie meine stärkste Seite), oder vielleicht eine bessere Lösung finden.

Um zu klären; Hier ist ein Bild von dem, was ich tun möchte:
Das rote Rechteck repräsentiert den Gerätebildschirm, das grüne x ist das Berührungsereignis und das schwarze Quadrat ist das Brett (graue Unterteilungen repräsentieren ein Quadrat von einer Einheit). Ich muss herausfinden, wo auf dem Brett die Berührung passiert ist (in diesem Fall ist es in Quadrat 1,1).

Antwort

0

So gelang es mir, dies zu lösen, indem Sie folgendermaßen vorgehen:

float[] clipPoint = new float[4]; 
int[] viewport = new int[]{0, 0, width, height}; 

//screenY/screenX are the screen-coordinates, y should be flipped: 
screenY = viewport[3] - screenY; 

//Calculate a z-value appropriate for the far clip: 
float dist = 1.0f; 
float z = (1.0f/clip[0] - 1.0f/dist)/(1.0f/clip[0]-1.0f/clip[1]); 

//Use gluUnProject to create a 3d point in the far clip plane: 
GLU.gluUnProject(screenX, screenY, z, vMatrix, 0, pMatrix, 0, viewport, 0, clipPoint, 0); 

//Get a point representing the 'camera': 
float eyeX = lookat[0] + eyeOffset[0]; 
float eyeY = lookat[1] + eyeOffset[1]; 
float eyeZ = lookat[2] + eyeOffset[2]; 

//Do some magic to calculate where the line between clipPoint and eye/camera would intersect the y-plane: 
float dX = eyeX - clipPoint[0]; 
float dY = eyeY - clipPoint[1]; 
float dZ = eyeZ - clipPoint[2]; 

float resX = glu[0] - (dX/dY)*glu[1]; 
float resZ = glu[2] - (dZ/dY)*glu[1]; 
//resX and resZ is the wanted result. 
1

Da Sie in 2D grundsätzlich schon arbeiten, (ich nehme an, Sie meinen, dass Ihre 3D-Karte von 0,0,0 bis 10,10,0 (x, y, z) reicht.) Sie könnten übersetzen und interpolieren/extrapolieren Der 2D/3D-Raumkoordinaten aus Ihren Bildschirmkoordinaten ohne das gluUnProject(). Sie benötigen Ihre Bildschirmauflösung und wählen die Auflösung des 3D-Raumrasters, in das Sie konvertieren möchten. Wenn sowohl der Bildschirm als auch der 3D-Raum ausgerichtet sind (0,0 Bildschirmabstand beträgt 0,0,0 3D-Raum) und Ihre Bildschirmabmessungen 320x240 sind, verwenden Sie Ihr vorhandenes 10x10-3D-Raster, dann 320/10 = 32 und 240/10 = 24, daher beträgt die Bildschirmgröße eines einzelnen 1x1-Bereichs 32x24. Wenn der Benutzer auf 162, 40 drückt, drückt der Benutzer innerhalb von (5, 1, 0) (162/32> = 5, aber < 6, 40/24> = 1, aber < 2) im 3D-Raum. Wenn Sie eine höhere Auflösung als diese benötigen, können Sie eine höhere 3D-Rasterauflösung wählen (d. H. 20 anstelle von 10 verwenden). Sie müssen die GL-Matrix nicht aktualisieren, um diesen Faktor zu verwenden. Obwohl es in gewisser Hinsicht einfacher sein könnte, bin ich sicher, dass Sie aus einer Modellierungsperspektive zusätzliche Arbeit erledigen müssten. Achten Sie nur auf einen Faktor von 20, 1,3 wäre bei (0,5, 1,5, 0). Wenn Ihre Bildschirm- und 3D-Raumursprünge nicht bereits ausgerichtet sind, müssen Sie zuvor die Bildschirmkoordinaten übersetzen. Wenn der Bildschirm auf 10, 10, 0 gesetzt ist, müssen Sie Ihre Bildschirmauflösung nehmen und den aktuellen Punkt von diesem abziehen, wodurch 0,0 in 320, 240 in diesem Beispiel, unserem Beispielpunkt von 162, 40, würde sei 158 (320-158 == 162), 200 (240-200 == 40).

Wenn Sie einen Überblick über die Projektionsmatrix und wie das alles funktioniert, was Ihnen helfen könnte zu verstehen, wo die Bildschirmraumdimensionen in die unproject-Matrix gesetzt werden, lesen Sie dieses Kapitel des OpenGL-Red Book. http://www.glprogramming.com/red/chapter03.html

Hoffe das hilft, und viel Glück!

+0

Vielen Dank für Ihre Antwort, aber leider ist es nicht so einfach, die Platte zur Blickrichtung nicht senkrecht ist, so dass ein einfaches Lösung wie diese wird nicht funktionieren. Ich aktualisierte die Frage mit einer einfachen Grafik, um das Problem zu visualisieren. – Jave

+0

Oh, und ich meinte, dass das Flugzeug/Board im MODELL-Raum beschrieben wird, nicht in der Welt (kann gerade nicht bearbeitet werden, schreibt auf ein Telefon) – Jave