2012-06-11 9 views
20

Buduję aplikację dla systemu Android, która korzysta z OpenGL ES 2.0, a ja natknąłem się na ścianę. Próbuję przekształcić współrzędne ekranu (gdzie użytkownik dotyka) na współrzędne globalne. Próbowałem czytać i bawić się z GLU.gluUnProject, ale robię to źle lub po prostu nie rozumiem tego.Współrzędne ekranu Android OpenGL ES 2.0 do współrzędnych światowych

To moja próba ....

public void getWorldFromScreen(float x, float y) { 
    int viewport[] = { 0, 0, width , height}; 

    float startY = ((float) (height) - y); 
    float[] near = { 0.0f, 0.0f, 0.0f, 0.0f }; 
    float[] far = { 0.0f, 0.0f, 0.0f, 0.0f }; 

    float[] mv = new float[16]; 
    Matrix.multiplyMM(mv, 0, mViewMatrix, 0, mModelMatrix, 0); 

    GLU.gluUnProject(x, startY, 0, mv, 0, mProjectionMatrix, 0, viewport, 0, near, 0); 
    GLU.gluUnProject(x, startY, 1, mv, 0, mProjectionMatrix, 0, viewport, 0, far, 0); 

    float nearX = near[0]/near[3]; 
    float nearY = near[1]/near[3]; 
    float nearZ = near[2]/near[3]; 

    float farX = far[0]/far[3]; 
    float farY = far[1]/far[3]; 
    float farZ = far[2]/far[3]; 
} 

Numery Dostaję nie wydaje się słuszne, jest to dobry sposób, żeby wykorzystać tę metodę? Czy działa w OpenGL ES 2.0? Czy przed obliczeniami należy wykonać macierz modelu macierzy tożsamości (Matrix.setIdentityM (mModelMatix, 0))?

Jako kontynuację, jeśli to prawda, w jaki sposób wybrać wyjście Z? Zasadniczo zawsze wiem, w jakiej odległości chcę współrzędne świata, ale parametr Z w GLU.gluUnProject wydaje się być rodzajem interpolacji między bliską a daleką płaszczyzną. Czy to tylko liniowa interpolacja?

góry dzięki

Odpowiedz

21
/** 
    * Calculates the transform from screen coordinate 
    * system to world coordinate system coordinates 
    * for a specific point, given a camera position. 
    * 
    * @param touch Vec2 point of screen touch, the 
     actual position on physical screen (ej: 160, 240) 
    * @param cam camera object with x,y,z of the 
     camera and screenWidth and screenHeight of 
     the device. 
    * @return position in WCS. 
    */ 
    public Vec2 GetWorldCoords(Vec2 touch, Camera cam) 
    { 
     // Initialize auxiliary variables. 
     Vec2 worldPos = new Vec2(); 

     // SCREEN height & width (ej: 320 x 480) 
     float screenW = cam.GetScreenWidth(); 
     float screenH = cam.GetScreenHeight(); 

     // Auxiliary matrix and vectors 
     // to deal with ogl. 
     float[] invertedMatrix, transformMatrix, 
      normalizedInPoint, outPoint; 
     invertedMatrix = new float[16]; 
     transformMatrix = new float[16]; 
     normalizedInPoint = new float[4]; 
     outPoint = new float[4]; 

     // Invert y coordinate, as android uses 
     // top-left, and ogl bottom-left. 
     int oglTouchY = (int) (screenH - touch.Y()); 

     /* Transform the screen point to clip 
     space in ogl (-1,1) */  
     normalizedInPoint[0] = 
     (float) ((touch.X()) * 2.0f/screenW - 1.0); 
     normalizedInPoint[1] = 
     (float) ((oglTouchY) * 2.0f/screenH - 1.0); 
     normalizedInPoint[2] = - 1.0f; 
     normalizedInPoint[3] = 1.0f; 

     /* Obtain the transform matrix and 
     then the inverse. */ 
     Print("Proj", getCurrentProjection(gl)); 
     Print("Model", getCurrentModelView(gl)); 
     Matrix.multiplyMM(
      transformMatrix, 0, 
      getCurrentProjection(gl), 0, 
      getCurrentModelView(gl), 0); 
     Matrix.invertM(invertedMatrix, 0, 
      transformMatrix, 0);  

     /* Apply the inverse to the point 
     in clip space */ 
     Matrix.multiplyMV(
      outPoint, 0, 
      invertedMatrix, 0, 
      normalizedInPoint, 0); 

     if (outPoint[3] == 0.0) 
     { 
      // Avoid /0 error. 
      Log.e("World coords", "ERROR!"); 
      return worldPos; 
     } 

     // Divide by the 3rd component to find 
     // out the real position. 
     worldPos.Set(
      outPoint[0]/outPoint[3], 
      outPoint[1]/outPoint[3]); 

     return worldPos;  
    } 

algorytm jest wyjaśnione here.

+2

Moi rozwiązania są w C++. Po zeskanowaniu tej odpowiedzi wygląda mi to dobrze. Tak więc nie będę publikować odpowiedzi. :] – TheBuzzSaw

1

IMHO nie trzeba ponownie wdrażać tej funkcji ... Eksperymentowałem z rozwiązaniem Erola i zadziałało, więc bardzo dziękuję za to Erol. Ponadto, grałem z

 Matrix.orthoM(mtrxProjection, 0, left, right, bottom, top, near, far); 

i to działa dobrze również w moim maleńkim przykład noob 2D OpenGL ES 2.0 projektu: