Тест на столкновение сфер реагирует слишком быстро

Я пишу игру для Android, используя Java и OpenGL. Я могу идеально отобразить все на экране, но когда я пытаюсь проверить, сталкиваются ли два объекта или нет, мой алгоритм обнаруживает столкновение до того, как оно произойдет на экране.

Вот как я проверяю столкновение:

for(int i=0; i<enemies.size(); i++) {
    float enemyRadius = enemies.elementAt(i).worldSpaceBoundingSphereRadius();
    float[] enemyPosition = enemies.elementAt(i).getWorldSpaceCoordinates();

    for(int j=0; j<qubieBullets.size(); j++) {
        float bulletRadius = bullets.elementAt(j).worldSpaceBoundingSphereRadius();
        float[] bulletPosition = bullets.elementAt(j).getWorldSpaceCoordinates();

        float[] distanceVector = Vector3f.subtract(enemyPosition, bulletPosition);
        float distance = Vector3f.length(distanceVector);

        if(distance < (enemyRadius + bulletRadius)) {
            enemies.remove(i);
            qubieBullets.remove(j);

            i--;
            j--;

            // Reset enemy position
        }
    }
}

Когда вражеский куб (представленный сферой для обнаружения столкновений) приближается к игроку, игрок стреляет пулей (также кубом, представленным сферой) во врага. Я ожидаю, что враг сбрасывается, когда пуля попадает в него на экране, но это происходит гораздо раньше.

Методы расчета положения и радиуса в мировом пространстве:

public float[] getWorldSpaceCoordinates() {

    float[] modelSpaceCenter = {0.0f, 0.0f, 0.0f, 1.0f};
    float[] worldSpaceCenter = new float[4];
    Matrix.multiplyMV(worldSpaceCenter, 0, getModelMatrix(), 0, modelSpaceCenter, 0);
    return new float[] {worldSpaceCenter[0]/worldSpaceCenter[3], worldSpaceCenter[1]/worldSpaceCenter[3], worldSpaceCenter[2]/worldSpaceCenter[3]};
}

public float worldSpaceBoundingSphereRadius() {
    float[] arbitraryVertex = new float[] {1.0f, 1.0f, 1.0f, 1.0f};
    float[] worldSpaceVector = new float[4];
    Matrix.multiplyMV(worldSpaceVector, 0, getModelMatrix(), 0, arbitraryVertex, 0);
    float[] xyz = new float[] {worldSpaceVector[0]/worldSpaceVector[3], worldSpaceVector[1]/worldSpaceVector[3], worldSpaceVector[2]/worldSpaceVector[3]};
    return Vector3f.length(xyz);
}

Это мой код или математика неверны? Я не могу придумать больше ничего, чтобы попробовать, и было бы полезно, если бы кто-нибудь мог указать мне правильное направление.


person Sven G    schedule 16.12.2015    source источник
comment
Если вы используете кубы (если только getModelMatrix() не преобразует его без вращения), вы можете упростить вычисление радиуса до rad = sqrt( 3 * (x/2) * (x/2) ), где x — длина одного ребра куба. Кроме того, я предполагаю, что ранние столкновения, которые вы заметили, ОЧЕНЬ ранние, потому что при использовании сфер для обнаружения столкновений кубов это все равно произойдет.   -  person Foggzie    schedule 16.12.2015
comment
Когда вы делаете эту проверку на столкновение? Если вы сделаете это до рендеринга, может показаться, что это рано, потому что фактическое столкновение никогда не рендерится.   -  person Reigertje    schedule 16.12.2015
comment
Что значит намного раньше?   -  person philipxy    schedule 16.12.2015
comment
Обнаружение столкновений выполняется сразу после того, как кубы были обновлены (масштабированы, перемещены и повернуты) и отрисованы (с использованием матрицы модели, полученной с помощью getModelMatrix()). Столкновение обнаруживается практически мгновенно при нажатии на экран. Как видно на этой картинке: i.imgur.com/QVWYJva.png   -  person Sven G    schedule 16.12.2015


Ответы (1)


Ваш worldSpaceBoundingSphereRadius(), скорее всего, виноват. arbitraryVertex является вектором (1,1,1), поэтому ваша математика будет работать, только если модель куба имеет ребра длиной 2 * sqrt(1/3). Что вам нужно сделать, так это найти точную длину ребра модели вашего куба, использовать формулу из моего комментария (rad = sqrt( 3 * (x/2) * (x/2) )) и использовать этот радиус для вашего arbitraryVertex (rad,rad,rad,1).

Кроме того, вы делите результаты своего умножения на однородную координату (worldSpaceVector[0]/worldSpaceVector[3]). При правильном вращении, перемещении или масштабировании однородная координата всегда должна быть ровно 1 (если она начиналась как единица). Если это не так, у вас может быть матрица проекции или что-то еще, что не является базовым преобразованием.

РЕДАКТИРОВАТЬ:

Поскольку вы используете worldSpaceBoundingSphereRadius() только для получения радиуса, вам нужен только компонент масштабирования getModelMatrix(). Если это вернет масштабирование и перемещение, это перемещение будет применено к вашему радиусу и сделает его намного больше, чем он есть на самом деле.

person Foggzie    schedule 16.12.2015
comment
Спасибо, но это не имело никакого значения. Произвольная вершина (1,1,1) — это вектор от центра куба к одному из углов (куб имеет размеры 2x2x2 с центром в 0). Поправьте меня, если я ошибаюсь, но это должен быть радиус-вектор в пространстве модели? - person Sven G; 16.12.2015
comment
Кроме того, я не знал, что масштабирование, перемещение и вращение не влияют на однородную координату. Спасибо что подметил это. - person Sven G; 16.12.2015
comment
@SvenG Если это куб 2x2x2 с центром вокруг 0, радиус его ограничивающей сферы равен sqrt (3) или ~ 1,73205. - person Foggzie; 16.12.2015
comment
@SvenG Конечно, учитывая эту ошибку, если бы это была ошибка, у вас была бы противоположная проблема (столкновения обнаружены слишком поздно). Делает ли getModelMatrix() что-то помимо простых преобразований? - person Foggzie; 16.12.2015
comment
Я думаю, что моя проблема может заключаться в том, что я пытаюсь преобразовать радиус в мировое пространство, так как я думал, что длина будет отличаться от пространства модели. Если я просто возвращаю sqrt(3) * mScalingFactor, работает. Почему мне не нужно пересчитывать длину - person Sven G; 17.12.2015
comment
getModelMatrix() просто возвращает сохраненную матрицу модели, которая также используется для рендеринга. Он не делает ничего, кроме базовых преобразований. - person Sven G; 17.12.2015
comment
@SvenG Ах! Теперь это имеет смысл. Я добавил кое-что в свой ответ в разделе EDIT. - person Foggzie; 17.12.2015