20

OpenGL ES 2.0 を使用する Android アプリケーションを作成していますが、壁にぶつかりました。画面座標 (ユーザーが触れる場所) を世界座標に変換しようとしています。GLU.gluUnProject を読んで遊んでみましたが、間違っているか、理解していません。

これは私の試みです....

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];
}

私が得ている数字は正しくないようです。これはこの方法を利用する正しい方法ですか? OpenGL ES 2.0 で動作しますか? これらの計算 (Matrix.setIdentityM(mModelMatix, 0)) の前に、モデル マトリックスを恒等マトリックスにする必要がありますか?

フォローアップとして、これが正しい場合、出力 Z をどのように選択すればよいですか? 基本的に、ワールド座標をどのくらいの距離に配置したいかは常にわかっていますが、GLU.gluUnProject の Z パラメータは、近平面と遠平面の間のある種の補間のように見えます。それは単なる線形補間ですか?

前もって感謝します

4

3 に答える 3

23
/**
    * 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;       
   }

アルゴリズムについては、こちらで詳しく説明しています。

于 2012-07-30T07:23:09.533 に答える
1

うまくいけば、私の質問(および回答)があなたを助けるはずです:

ズームイン中にクリックの絶対位置を見つける方法

コードだけでなく、それを説明する図や図や図もあります:)私もそれを理解するのに何年もかかりました。

于 2012-08-02T07:41:50.080 に答える
1

私見では、この機能を再実装する必要はありません...私はErolのソリューションを試してみましたが、うまくいきました。Erolに感謝します。さらに、一緒に遊んだ

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

そして、私の小さな初心者の例である 2D OpenGL ES 2.0 プロジェクトでも問題なく動作します。

于 2013-10-04T15:07:52.667 に答える