1

Ive implemented ray picking using min3d and some code I found online but when I implemented it I notice that its off a bit some times meaning that when I click on one box sometimes the wrong one is picked. Sometimes the one picked isnt even on the screen. This took quite a bit of code to get implemented in the first place but the main two methods I call are the following:

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

Now I have also tried implementing frustum culling but having done that it slows things way down because I didnt do much to optimize it and its not running natively. But if some one can look and maybe give me some pointers on how to make it more accurate that would be awesome. Heres where I call the picking methods.

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

            }
            }
        );
James andresakis
  • 5,335
  • 9
  • 53
  • 88

1 Answers1

2

The bug you have sounds like you are making a mistake in you collision detection, I had a bug in the function I had for dot products and caused some really odd results. Can you post more of your collision algorithm?

I implemented ray picking here: http://android-raypick.blogspot.ca/ I did not paste the code here because there is allot of it, feel free to compare your code to this code, this code is tested and working.

  • I cant remember how at the moment but I was able to correct the problem I was having in regards to the accuracy of my ray picking. From what I remember I was subtracting from somewhere I was supposed to be adding or vice versa and it was throwing everything off. When I get a chance Ill glance over my code and get back to you. – James andresakis Apr 26 '12 at 19:48
  • I confirm that code from http://android-raypick.blogspot.ca/ is working, I'm using it in my app. All calculations there are correct, however memory allocations are huge. You may want to redesign the code in order not to allocate kilobytes of memory just to check intersection of ray with 900 triangles. – keaukraine Sep 21 '12 at 06:37
  • @keaukraine : I can't make it work, have posted a question here http://stackoverflow.com/questions/14185279/ray-picking-in-opengl-es-2-0, hope you can take a look and see if I'm on the right track. – Araw Jan 12 '13 at 12:40
  • @Araw If you get multiple collision detections you should pick the one closest to camera - it will be correct one. The code checks for intersection with ray so it can pick triangles which are occluded by other triangles. The closest one is not occluded by other triangles. – keaukraine Jan 15 '13 at 09:33