Question

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;

            }
            }
        );
Était-ce utile?

La solution

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top