Android的OpenGL的3D采摘 [英] Android OpenGL 3D picking

查看:330
本文介绍了Android的OpenGL的3D采摘的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Android上的OpenGL-ES 2.0毕竟随之而来的限制,我无法弄清楚如何采取2D画面触摸到3D点我。我不能得到正确的结果。

I'm on Android OpenGL-ES 2.0 and after all the limitations that come with it, I can't figure out how to take 2D screen touches to the 3D points I have. I can't get the right results.

我想实现拍摄光线进入点云,我可以再对比我点的距离的光线,发现最近点。

I'm trying to implement shooting a ray into the point cloud, which I can then compare distances of my points to the ray, finding the closest point.

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();
        }
    }
}

下面是我的拾取功能。我设置的位置在屏幕中间只是为了调试的目的:

Here is my picking function. I've set the location to the middle of the screen just for debugging purposes:

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

更改persepctive zNear和远没有预期的结果,怎么可能远点的1.0-1000.0角度是11个单位了吗?

Changing the persepctive zNear and Far doesn't have the expected results, how could the far point of a 1.0-1000.0 perspective be 11 units away?

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

寻找你在我的code看到任何建议或希望的错误。许多AP preciated。我Bountying多达我可以(这一直是一段时间的一个问题)。

Looking for any suggestions or hopefully bugs you see in my code. Much appreciated. I'm Bountying as much as I can (this has been a problem for a while).

推荐答案

我在这方面的工作,太 - 这是一个非常讨厌讨厌的问题。我有两个潜在客户:1。不知怎么的,所产生的ž取决于相机在哪里,而不是你所期望的。当相机z为0,则得到的z是-1,不管是什么winZ是。到现在为止,我主要是在看所产生的Z,所以我没有在其他任何的坐标确切的数字,但我搞砸与周围我的code和你的code,刚才和我'已经发现报道射线长度增​​加了更远的摄像机会从(0,0,0)。在(0,0,0),在光线的长度被报告为0。一个小时左右前,我聚集了一帮点(cameraZ,winZ,resultZ)的并插入到数学。结果似乎表明双曲类的事情;同的变量之一固定,其他使所得Z到线性变化,具有改变的因固定变量的速率。

I'm working on this, too - it's a very irritating irritating problem. I have two potential leads: 1. Somehow, the resulting z depend on where the camera is, and not how you'd expect. When the camera z is at 0, the resulting z is -1, no matter what winZ is. Up until now I've mainly been looking at the resulting z, so I don't have any exact figures on the other coordinates, but I messed around with my code and your code, just now, and I've discovered that the reported ray-length increases the farther the camera gets from (0,0,0). At (0,0,0), the ray-length is reported to be 0. An hour or so ago, I gathered a bunch of points (cameraZ, winZ, resultZ) and plugged them into Mathematica. The result seems to indicate a hyperbolic sort of thing; with one of the variables fixed, the other causes the resulting z to vary linearly, with the rate of change depending on the fixed variable.

我的第二引线是从<一个href="http://www.gamedev.net/topic/420427-gluunproject-question/">http://www.gamedev.net/topic/420427-gluunproject-question/;箭鱼引用公式:

My second lead is from http://www.gamedev.net/topic/420427-gluunproject-question/; swordfish quotes a formula:

WinZ =(1.0F / fNear-1.0F / fDistance)/(1.0F / fNear-1.0F / FFAR)

WinZ = (1.0f/fNear-1.0f/fDistance)/(1.0f/fNear-1.0f/fFar)

现在,这似乎并没有与我收集的数据相匹配,但它可能是值得一试。我想我会看看我是否能弄清楚如何这个东西的数学工作,并找出什么是错的。让我知道如果你弄清楚什么了。哦也,这里是安装在我收集到的数据公式:

Now, this doesn't seem to match up with the data I collected, but it's probably worth a look. I think I'm going to see if I can figure out how the math of this thing works and figure out what's wrong. Let me know if you figure anything out. Oh, also, here's the formula fitted to the data I collected:

-0.11072114015496763 - 10.000231721597817 X -  0.0003149873867479971 X ^ 2 - 0.8633277851535017 Y +  9.990256062051143 XY + 8.767260632968973 * ^ - 9 Y ^ 2

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

Wolfram Alpha的绘制它像这样: <一href="http://www.wolframalpha.com/input/?i=Plot3D%5B-0.11072114015496763%60%20-%2010.000231721597817%60%20x%20-%20%20%20%200.0003149873867479971%60%20x%5E2%20-%200.8633277851535017%60%20y%20%2b%20%20%20%209.990256062051143%60%20x%20y%20%2b%208.767260632968973%60%2a%5E-9%20y%5E2%20,%20%7Bx,%20-15,%20%20%20%2015%7D,%20%7By,%200,%201%7D%5D">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}]

Wolfram Alpha plots it like so: 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功能,这似乎真的是他们所使用的绘制到屏幕上以某种方式! code是如下:

AHA! Success! As near as I can tell, gluUnProject is just plain broken. Or, nobody understands how to use it at all. Anyway, I made a function that properly undoes the gluProject function, which appears to really be what they use to draw to the screen in some fashion! Code is as follows:

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 - 当前矩阵A MatrixGrabber 视口 - 一个float [4]与视口({X,Y,宽度,高度})

It currently assumes the following global variables: mg - a MatrixGrabber with current matrices viewport - a float[4] with the viewport ({x, y, width, height})

花费的变量是等同于那些gluUnProject应该采取。例如:

The variables it takes are equivalent to the ones that gluUnProject was supposed to take. For example:

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

这将返回该点下鼠标,就远远飞机。我还增加了一个功能,从相机和0-1 ...再presentation ......事情一个指定的距离之间进行转换。像这样:

This will return the point under the mouse, on the far plane. I also added a function to convert between a specified distance from the camera and its 0-1...representation...thing. Like so:

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

这会从相机返回该点下鼠标5个单位。 我测试了在这个问题给出的方法 - 我检查了近平面和远平面之间的距离。为0.1 fNear和100 FFAR,该距离应是99.9。我一直得到了约99.8977,无论位置或摄像头的方向,据我可以告诉。哈哈,好有想通了。让我知道如果你/没有任何问题的,或者如果你要我重写它采取的投入,而不是使用全局变量。希望这有助于一些人;我一直想知道这几天才认真努力解决它。

This will return the point under the mouse 5 units from the camera. I tested this with the method given in the question - I checked the distance between the near plane and the far plane. With fNear of 0.1 and fFar of 100, the distance should be 99.9. I have consistently gotten about 99.8977, regardless of position or orientation of the camera, as far as I can tell. Haha, good to have that figured out. Let me know if you do/don't have any problems with it, or if you want me to rewrite it to take inputs instead of using global variables. Hopefully this helps a few people; I had been wondering about this for a few days before seriously trying to fix it.

嘿,所以,已经想通了,它是如何应该是,我已经想通了什么,他们在实施gluUnProject错过。他们忘了(意不并没有告诉任何人?)用得到的载体,它还挺规范了向量或类似的东西的第四个要素来划分。 gluProject其设置为1的矩阵应用之前,所以它必须是1,当你完成对它们的撤销。长话短说,你可以实际使用gluUnProject,但你需要传递一个浮动[4],然后除以所有结果的坐标由第四之一,像这样:

Hey, so, having figured out how it's supposed to be, I've figured out what they missed in implementing gluUnProject. They forgot (intended not to and didn't tell anyone?) to divide by the fourth element of the resulting vector, which kinda normalizes the vector or something like that. gluProject sets it to 1 before applying matrices, so it needs to be 1 when you're done undoing them. Long story short, you can actually use gluUnProject, but you need to pass it a float[4], and then divide all the resulting coordinates by the 4th one, like so:

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现在应该包含有关的空间坐标。这似乎工作完全一样,一个我拼凑起来的。这可能是一个有点快;我认为,他们联合的步骤之一。

xyzw should now contain the relevant space coordinates. This seems to work exactly the same as the one I cobbled together. It might be a little bit faster; I think they combined one of the steps.

这篇关于Android的OpenGL的3D采摘的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆