OpenGL ES on android 微调光线拾取代码

Posted

技术标签:

【中文标题】OpenGL ES on android 微调光线拾取代码【英文标题】:OpenGl ES on android fine tuning of ray picking code 【发布时间】:2012-03-07 06:07:28 【问题描述】:

我已经使用 min3d 和一些我在网上找到的代码实现了光线拾取,但是当我实现它时,我注意到它有时有点偏离,这意味着当我点击一个框时,有时会选择错误的那个。有时被选中的那个甚至不在屏幕上。这需要相当多的代码才能实现,但我调用的主要两种方法如下:

private void rayPicking(float x, float y)

    //intersection with near plane
    float[] near = new float[4];
    GLU.gluUnProject(x, scene.getViewport()[3] - y, 0f, scene.getGrabber().mModelView, 0, scene.getGrabber().mProjection, 0, scene.getViewport(), 0, near, 0);
    if (near[3] != 0)
    
        near[0] = near[0] / near[3];
        near[1] = near[1] / near[3];
        near[2] = near[2] / near[3];
    
    Number3d near3 = new Number3d(near[0], near[1], near[2]);

    //and far plane
    float[] far = new float[4];
    GLU.gluUnProject(x, scene.getViewport()[3] - y, 1f, scene.getGrabber().mModelView, 0, scene.getGrabber().mProjection, 0, scene.getViewport(), 0, far, 0);
    if (far[3] != 0)
    
        far[0] = far[0] / far[3];
        far[1] = far[1] / far[3];
        far[2] = far[2] / far[3];
    
    Number3d far3 = new Number3d(far[0], far[1], far[2]);

    Box firstPicked = null;
    Box currentModel = null;
    Number3d currentCoords = null;
    Number3d firstPickedCoords = new Number3d();

if (!sceneBoxes.isEmpty())

    //here we check each model if it was tapped and if several models were tapped, we take only that which is closer to the near clipping plane
    Iterator<Box> itr = sceneBoxes.iterator();
    while (itr.hasNext())
    
        currentModel = itr.next();
        currentCoords = new Number3d(currentModel.position().x, currentModel.position().y, currentModel.position().z);
        if (picked (far3, near3, currentCoords, 1.2f)) 
            if (firstPicked==null) 
                
                    firstPicked = currentModel;
                    firstPickedCoords.setAllFrom(currentCoords); 
                
            else if (Number3d.add(currentCoords, near3).length() < Number3d.add(firstPickedCoords, near3).length()) 
                
                    firstPicked = currentModel;
                    firstPickedCoords.setAllFrom(currentCoords);
                
    
   

    if (firstPicked != null) // if model picked
     
        String temp = firstPicked.getTitle();
        String temp2 = firstPicked.getLink();
        Log.w("3d touch working "+temp, "3d touch working "+temp);
        Intent intent = new Intent(CurAct.this, WebViewer.class);
        intent.putExtra("clkURL", temp2);
        intent.putExtra("clkUID", curr_uid);
        intent.putExtra("rid", curr_rid);
        startActivity(intent);

        firstPicked = null;
        temp = null;
        temp2 = null;

    


private boolean picked(Number3d a, Number3d b, Number3d q, float r)

    float ab = (float) Math.sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
    float aq = (float) Math.sqrt((a.x-q.x)*(a.x-q.x)+(a.y-q.y)*(a.y-q.y)+(a.z-q.z)*(a.z-q.z));
    float bq = (float) Math.sqrt((b.x-q.x)*(b.x-q.x)+(b.y-q.y)*(b.y-q.y)+(b.z-q.z)*(b.z-q.z));

    float p = (ab + aq + bq) / 2;

    float hh = (float) Math.sqrt(p * (p - ab) * (p - aq) * (p - bq));
    float h;
    if (ab!=0) h = 2 * hh / ab; else h = 2*hh;

    if (aq<h) h = aq;
    if (bq<h) h = bq;

    if (h<r)return true; else return false;

现在我也尝试实现截锥体剔除,但这样做会减慢速度,因为我没有做太多优化它并且它没有在本机运行。但是,如果有人可以看,也许能给我一些关于如何使它更准确的指示,那就太棒了。这里我称之为拣货方法。

 _glSurfaceView.setOnTouchListener( 
        new View.OnTouchListener() 

            @Override
            public boolean onTouch(View arg0, MotionEvent e) 

                switch (e.getAction() & MotionEvent.ACTION_MASK) 
                
                    case MotionEvent.ACTION_DOWN:
                        startX = e.getX();
                        startY = e.getY();
                        trace = 0.0f;
                        time = System.currentTimeMillis();
                        touchMode = DRAG;
                    break;

                    case MotionEvent.ACTION_UP:
                        // we use ray picking only when the tap wasn't longer than 0.5 sec and if we almost didn't move our finger
                        //Log.w("this is touch y"+e.getY()+" viewport is"+scene.getViewport()[3], "this is touch x"+e.getX());
                        if ((System.currentTimeMillis()-time < 500) && (trace<scene.getViewport()[3]*0.075)) rayPicking(e.getX(), e.getY());
                        time = 0;

                    case MotionEvent.ACTION_POINTER_UP:
                        touchMode = NONE;
                    break;
                
                return true;

            
            
        );

【问题讨论】:

【参考方案1】:

您遇到的错误听起来像是您在碰撞检测中犯了一个错误,我在点积的函数中遇到了一个错误,并导致了一些非常奇怪的结果。你能发布更多你的碰撞算法吗?

我在这里实现了光线拾取:http://android-raypick.blogspot.ca/ 我没有在此处粘贴代码,因为它有很多,请随意将您的代码与此代码进行比较,此代码已经过测试并且可以工作。

【讨论】:

我现在不记得是怎么回事了,但我能够纠正我在光线拾取准确性方面遇到的问题。根据我的记忆,我从我应该添加的某个地方减去,反之亦然,它把所有东西都扔掉了。有机会我会浏览一下我的代码并回复你。 我确认来自android-raypick.blogspot.ca 的代码正在运行,我正在我的应用程序中使用它。那里的所有计算都是正确的,但是内存分配很大。您可能需要重新设计代码,以免分配千字节的内存来检查光线与 900 个三角形的交点。 @keaukraine :我做不到,在这里发了一个问题***.com/questions/14185279/…,希望你能看看我是否走在正确的轨道上。 @Araw 如果您得到多个碰撞检测,您应该选择最接近相机的一个 - 这将是正确的一个。该代码检查与光线的交点,以便它可以选择被其他三角形遮挡的三角形。最近的一个没有被其他三角形遮挡。

以上是关于OpenGL ES on android 微调光线拾取代码的主要内容,如果未能解决你的问题,请参考以下文章

Android OpenGL ES和OpenGL一起学------理解Viewport(视口)和坐标系Android OpenGL ES篇(转帖)

基于视锥体(平截体)的OpenGL ES性能优化

iOS OpenGL ES 和 Android OpenGL ES 的区别

iOS OpenGL ES 与 Android OpenGL ES 兼容吗?

Android上OpenGL-ES游戏的教程和库[关闭]

如何在Android上使用OpenGL ES 2.0绘制点