OpenGl ES на Android тонкая настройка кода выбора лучей

Я реализовал выбор лучей, используя 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;

            }
            }
        );

person James andresakis    schedule 07.03.2012    source источник


Ответы (1)


Ошибка, которая у вас есть, звучит так, будто вы делаете ошибку при обнаружении столкновений, у меня была ошибка в функции, которая у меня была для точечных произведений, и это привело к действительно странным результатам. Можете ли вы опубликовать больше вашего алгоритма столкновения?

Я реализовал пикинг лучей здесь: http://android-raypick.blogspot.ca/ Я не вставлял код здесь, потому что его много, не стесняйтесь сравнивать свой код с этим кодом, этот код протестирован и работает.

person Gregory Beauchamp    schedule 26.04.2012
comment
Я не могу вспомнить, как на данный момент, но я смог исправить проблему, с которой я столкнулся в отношении точности моего выбора лучей. Насколько я помню, я вычитал из того, что должен был добавить, или наоборот, и это все отбрасывало. Когда у меня будет шанс, я просмотрю свой код и вернусь к вам. - person James andresakis; 26.04.2012
comment
Я подтверждаю, что код из android-raypick.blogspot.ca работает, я использую его в мое приложение. Все расчеты там правильные, однако выделения памяти огромны. Возможно, вы захотите переделать код, чтобы не выделять килобайты памяти только для проверки пересечения луча с 900 треугольниками. - person keaukraine; 21.09.2012
comment
@keaukraine: я не могу заставить это работать, разместил вопрос здесь stackoverflow.com/questions/14185279/, надеюсь, вы сможете взглянуть и убедиться, что я на правильном пути. - person Araw; 12.01.2013
comment
@Araw Если вы получаете несколько обнаружений столкновений, вы должны выбрать тот, который находится ближе всего к камере - он будет правильным. Код проверяет пересечение с лучом, поэтому он может выбирать треугольники, которые закрыты другими треугольниками. Ближайший не закрыт другими треугольниками. - person keaukraine; 15.01.2013