6

私は Android OpenGL-ES 2.0 を使用していますが、それに伴うすべての制限の後、2D 画面のタッチを 3D ポイントにする方法がわかりません。正しい結果が得られません。

ポイントクラウドにレイを発射することを実装しようとしています。これにより、ポイントとレイの距離を比較して、最も近いポイントを見つけることができます。

public class OpenGLRenderer extends Activity implements GLSurfaceView.Renderer {
    public PointCloud ptCloud;
    MatrixGrabber mg = new MatrixGrabber();
...
    public void onDrawFrame(GL10 gl) {

        gl.glDisable(GL10.GL_COLOR_MATERIAL);
        gl.glDisable(GL10.GL_BLEND);
        gl.glDisable(GL10.GL_LIGHTING);

        //Background drawing
        if(customBackground)
            gl.glClearColor(backgroundRed, backgroundGreen, backgroundBlue, 1.0f);
        else
            gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

        if (PointCloud.doneParsing == true) {
            if (envDone == false)
                setupEnvironment();

            // Clears the screen and depth buffer.
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

            gl.glMatrixMode(GL10.GL_PROJECTION);
            gl.glLoadIdentity();
            GLU.gluPerspective(gl, 55.0f, (float) screenWidth / (float) screenHeight, 10.0f ,10000.0f);

            gl.glMatrixMode(GL10.GL_MODELVIEW);

            gl.glLoadIdentity();
            GLU.gluLookAt(gl, eyeX, eyeY, eyeZ, 
                              centerX, centerY, centerZ, 
                              upX, upY, upZ);

            if(pickPointTrigger)
                pickPoint(gl);


            gl.glPushMatrix();

            gl.glTranslatef(_xTranslate, _yTranslate, _zTranslate);
            gl.glTranslatef(centerX, centerY, centerZ);
            gl.glRotatef(_xAngle, 1f, 0f, 0f);
            gl.glRotatef(_yAngle, 0f, 1f, 0f);
            gl.glRotatef(_zAngle, 0f, 0f, 1f);
            gl.glTranslatef(-centerX, -centerY, -centerZ);

            ptCloud.draw(gl);

            gl.glPopMatrix();
        }
    }
}

これが私のピッキング機能です。デバッグの目的で、場所を画面の中央に設定しました。

public void pickPoint(GL10 gl){

        mg.getCurrentState(gl);

        double mvmatrix[] = new double[16];
        double projmatrix[] = new double[16];
        int viewport[] = {0,0,screenWidth, screenHeight};

        for(int i=0 ; i<16; i++){
            mvmatrix[i] = mg.mModelView[i];
            projmatrix[i] = mg.mProjection[i];
        }

        mg.getCurrentState(gl);

        float realY = ((float) (screenHeight) - pickY);
        float nearCoords[] = { 0.0f, 0.0f, 0.0f, 0.0f };
        float farCoords[] = { 0.0f, 0.0f, 0.0f, 0.0f };


        GLU.gluUnProject(screenWidth/2, screenHeight/2, 0.0f, mg.mModelView, 0, mg.mProjection, 0,
                    viewport, 0, nearCoords, 0);
        GLU.gluUnProject(screenWidth/2, screenHeight/2, 1.0f, mg.mModelView, 0, mg.mProjection, 0,
                    viewport, 0, farCoords, 0);

        System.out.println("Near: " + nearCoords[0] + "," + nearCoords[1] + "," + nearCoords[2]);
        System.out.println("Far:  " + farCoords[0] + "," + farCoords[1] + "," + farCoords[2]);



      //Plot the points in the scene
        nearMarker.set(nearCoords);
        farMarker.set(farCoords);
        markerOn = true;

        double diffX = nearCoords[0] - farCoords[0];
        double diffY = nearCoords[1] - farCoords[1];
        double diffZ = nearCoords[2] - farCoords[2];

        double rayLength = Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2) + Math.pow(diffZ, 2));
        System.out.println("rayLength: " + rayLength);

        pickPointTrigger = false;   
    }

パースペクティブ zNear と Far を変更しても、期待した結果が得られません。1.0-1000.0 パースペクティブの遠点が 11 ユニット離れているのはどうしてでしょうか?

GLU.gluPerspective(gl, 55.0f, (float) screenWidth / (float) screenHeight, 1.0f ,100.0f);
.....
07-18 11:23:50.430: INFO/System.out(31795): Near: 57.574852,-88.60514,37.272636
07-18 11:23:50.430: INFO/System.out(31795): Far:  0.57574844,0.098602295,0.2700405
07-18 11:23:50.430: INFO/System.out(31795): rayLength: 111.74275719790872

GLU.gluPerspective(gl, 55.0f, (float) width / (float) height, 10.0f , 1000.0f);
...
07-18 11:25:12.420: INFO/System.out(31847): Near: 5.7575016,-7.965394,3.6339219
07-18 11:25:12.420: INFO/System.out(31847): Far:  0.057574987,0.90500546,-0.06634784
07-18 11:25:12.420: INFO/System.out(31847): rayLength: 11.174307289026638

私のコードに見られる提案やできればバグを探しています。とても有難い。私はできる限り報奨金を出しています (これはしばらくの間問題でした)。

4

1 に答える 1

9

私もこれに取り組んでいます - それは非常にイライラするイライラする問題です. 2 つの潜在的な手がかりがあります。カメラの z が 0 の場合、winZ が何であっても、結果の z は -1 です。今まで私は主に結果の z を見てきたので、他の座標の正確な数字はわかりませんが、私のコードとあなたのコードをいじりました。 ray-length は、カメラが (0,0,0) から遠ざかるにつれて増加します。(0,0,0) では、レイの長さは 0 であると報告されています。1 時間ほど前に、多数のポイント (cameraZ、winZ、resultZ) を収集し、それらを Mathematica にプラグインしました。結果は双曲線的なものを示しているようです。変数の 1 つを固定すると、もう 1 つの変数によって、結果の z が直線的に変化します。

私の 2 番目のリードはhttp://www.gamedev.net/topic/420427-gluunproject-question/です。メカジキは式を引用します:

WinZ = (1.0f/fNear-1.0f/f距離)/(1.0f/fNear-1.0f/fFar)

さて、これは私が収集したデータと一致していないようですが、おそらく一見の価値があります. このことの数学がどのように機能するかを理解し、何が間違っているかを理解できるかどうかを確認しようと思います. 何か分かったら教えてください。ああ、また、私が収集したデータに当てはめた式は次のとおりです。

-0.11072114015496763 - 10.000231721597817x - 0.0003149873867479971 年x^2 - 0.8633277851535017+ 9.990256062051143 x y + 8.767260632968973*^-9 年^2

Wolfram Alpha は次のようにプロットします: http://www.wolframalpha.com/input/?i=Plot3D[-0.11072114015496763%60+-+10.000231721597817%60+x+-++++0.0003149873867479971%60+x^2+- +0.8633277851535017%60+y+%2B++++9.990256062051143%60+x+y+%2B+8.767260632968973%60*^-9+y^2+%2C+{x%2C+-15%2C++++15} %2C+{y%2C+0%2C+1}]


あはは!成功!私が知る限り、gluUnProject は単純に壊れています。または、誰もその使い方をまったく理解していません。とにかく、私は gluProject 関数を適切に元に戻す関数を作成しました。これは、何らかの方法で画面に描画するために実際に使用しているように見えます! コードは次のとおりです。

public float[] unproject(float rx, float ry, float rz) {//TODO Factor in projection matrix
    float[] modelInv = new float[16];
    if (!android.opengl.Matrix.invertM(modelInv, 0, mg.mModelView, 0))
        throw new IllegalArgumentException("ModelView is not invertible.");
    float[] projInv = new float[16];
    if (!android.opengl.Matrix.invertM(projInv, 0, mg.mProjection, 0))
        throw new IllegalArgumentException("Projection is not invertible.");
    float[] combo = new float[16];
    android.opengl.Matrix.multiplyMM(combo, 0, modelInv, 0, projInv, 0);
    float[] result = new float[4];
    float vx = viewport[0];
    float vy = viewport[1];
    float vw = viewport[2];
    float vh = viewport[3];
    float[] rhsVec = {((2*(rx-vx))/vw)-1,((2*(ry-vy))/vh)-1,2*rz-1,1};
    android.opengl.Matrix.multiplyMV(result, 0, combo, 0, rhsVec, 0);
    float d = 1 / result[3];
    float[] endResult = {result[0] * d, result[1] * d, result[2] * d};
    return endResult;
}

public float distanceToDepth(float distance) {
    return ((1/fNear) - (1/distance))/((1/fNear) - (1/fFar));
}

現在、次のグローバル変数を想定しています: mg - 現在のマトリックスを持つ MatrixGrabber ビューポート - ビューポート ({x, y, width, height}) を持つ float[4]

それが取る変数は、gluUnProject が取るはずだったものと同等です。例えば:

float[] xyz = {0, 0, 0};
xyz = unproject(mouseX, viewport[3] - mouseY, 1);

これにより、遠平面上のマウスの下のポイントが返されます。また、カメラからの指定された距離とその 0-1 の間で変換する関数を追加しました...表現...もの。そのようです:

unproject(mouseX, viewport[3] - mouseY, distanceToDepth(5));

これにより、カメラから 5 単位離れたマウスの下のポイントが返されます。質問に記載されている方法でこれをテストしました-近平面と遠平面の間の距離を確認しました。fNear が 0.1 で fFar が 100 の場合、距離は 99.9 になります。私が知る限り、カメラの位置や向きに関係なく、一貫して約 99.8977 を得ています。ハハ、それを理解できてよかったです。問題がある/ない場合、またはグローバル変数を使用する代わりに入力を受け取るように書き直してほしい場合はお知らせください。うまくいけば、これは何人かの人々に役立ちます。真剣に修正しようとする前に、私はこれについて数日間疑問に思っていました.


ねえ、それがどうあるべきかを理解したので、gluUnProject の実装で彼らが何を見逃していたのかを理解しました。彼らは、結果のベクトルの 4 番目の要素で割ることを忘れていました (そうするつもりはなく、誰にも言いませんでしたか?)。gluProject は、マトリックスを適用する前に 1 に設定するため、取り消しが完了したら 1 にする必要があります。簡単に言うと、実際には gluUnProject を使用できますが、float[4] を渡してから、次のようにすべての結果の座標を 4 番目の座標で除算する必要があります。

float[] xyzw = {0, 0, 0, 0};
android.opengl.GLU.gluUnProject(rx, ry, rz, mg.mModelView, 0, mg.mProjection, 0, this.viewport, 0, xyzw, 0);
xyzw[0] /= xyzw[3];
xyzw[1] /= xyzw[3];
xyzw[2] /= xyzw[3];
//xyzw[3] /= xyzw[3];
xyzw[3] = 1;
return xyzw;

xyzw には、関連する空間座標が含まれているはずです。これは、私がまとめたものとまったく同じように機能するようです。少し速いかもしれません。彼らはステップの1つを組み合わせたと思います。

于 2011-07-19T22:54:32.027 に答える