OpenGL ES2.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パラメータは、近平面と遠平面の間のある種の補間のように見えます。それは単なる線形補間ですか?
前もって感謝します
/**
* 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;
}
アルゴリズムについてさらに説明します ここ
私見では、この関数を再実装する必要はありません...私はErolのソリューションを試しましたが、うまくいきました。Erolに感謝します。さらに、遊んだ
Matrix.orthoM(mtrxProjection, 0, left, right, bottom, top, near, far);
そしてそれは私の小さなnoobの例2DOpenGL ES2.0プロジェクトでもうまく機能します:
うまくいけば、私の質問(と答え)があなたを助けるはずです:
コードだけでなく、それを説明する図や図や図もあります:)私もそれを理解するのに何年もかかりました。