пересечение ориентированного блока в threeJS

Я пытаюсь узнать, пересекаются ли 2 ориентированные ограничивающие рамки с помощью threeJS.

Существует метод box3.intersect, но он работает только для неориентированных ограничивающих прямоугольников.

Что-то уже встроено или мне нужно реализовать это самому?

Я хочу знать, пересекается ли каждое синее поле с розовым в приведенном ниже примере. Я просто хочу знать, соприкасаются ли они, а не как выглядит перекресток.

введите здесь описание изображения

Спасибо


person Nicolas    schedule 13.02.2015    source источник
comment
Что вы используете для хранения своей ориентированной ограничивающей рамки? Я заметил, что box3 вообще не поддерживает ориентирование.   -  person Brendan Annable    schedule 20.02.2015


Ответы (1)


Если вы хотите создать свой собственный, я бы рекомендовал прочитать Теорема о разделяющей оси для ориентированных ограничивающих рамок, Джонни Хьюн.

Вот метод обнаружения столкновений с двумя ориентированными ограничивающими рамками, которые я сделал для игры, над которой работал. Его нет в ThreeJS, но он должен быть довольно простым для преобразования.

Примечание: он использует glMatrix для математических вычислений матрицы. Важное примечание. Я считаю, что в векторе разрешения есть ошибка, которую я не отследил. Однако обнаружение пересечения казалось точным.

/**
 * Checks if two given bounding boxes intersect with one another.
 *
 * Results an object with the following keys:
 * @property {boolean} intersects - True if the bounding boxes intersect
 * @property    {vec3} resolution - A vector specifying the shortest distance
 * and magnitude to move the boxes such that they are no longer intersecting
 *
 * Uses the Separating Axis Theorem
 * See http://en.wikipedia.org/wiki/Hyperplane_separation_theorem)
 * Looks for separating planes between the bounding boxes.
 *
 * @param {PhysJS.util.math.BoundingBox} box1 The first bounding box
 * @param {PhysJS.util.math.BoundingBox} box2 The second bounding box
 * @returns {Object} Containers two properties, 'intersects' and 'resolution'
 */
intersects: function (box1, box2) {
    // assumes the position of each box to be an orthonormal basis
    var pos1 = box1.getPosition(); // mat44
    var pos2 = box2.getPosition(); // mat44
    var center1 = vec4.transformMat4(vec4.create(), box1.getCenter(), pos1);
    var center2 = vec4.transformMat4(vec4.create(), box2.getCenter(), pos2);
    var centerDifference = vec4.subtract(vec4.create(), center2, center1);

    var results = {
        intersects: true,
        resolution: null
    };

    // broad phase
    var maxDiameter1 = vec4.length(vec4.subtract(vec4.create(), box1.getMax(), box1.getMin()));
    var maxDiameter2 = vec4.length(vec4.subtract(vec4.create(), box2.getMax(), box2.getMin()));
    if (vec4.length(centerDifference) > maxDiameter1 + maxDiameter2) {
        results.intersects = false;
        return results;
    }

    // narrow phase

    // get the axis vectors of the first box
    var ax1 = mat4.col(pos1, 0);
    var ay1 = mat4.col(pos1, 1);
    var az1 = mat4.col(pos1, 2);
    // get the axis vectors of the second box
    var ax2 = mat4.col(pos2, 0);
    var ay2 = mat4.col(pos2, 1);
    var az2 = mat4.col(pos2, 2);

    // keep them in a list
    var axes = [ax1, ay1, az1, ax2, ay2, az2];

    // get the orientated radii vectors of the first box
    var radii1 = box1.getRadii();
    var radX1 = vec4.scale(vec4.create(), ax1, radii1[0]);
    var radY1 = vec4.scale(vec4.create(), ay1, radii1[1]);
    var radZ1 = vec4.scale(vec4.create(), az1, radii1[2]);

    // get the orientated radii vectors of the second box
    var radii2 = box2.getRadii();
    var radX2 = vec4.scale(vec4.create(), ax2, radii2[0]);
    var radY2 = vec4.scale(vec4.create(), ay2, radii2[1]);
    var radZ2 = vec4.scale(vec4.create(), az2, radii2[2]);

    var smallestDifference = Infinity;
    // there are 15 axes to check, so loop through all of them until a separation plane is found
    var zeros = vec4.create();
    for (var i = 0; i < 15; i++) {
        var axis;

        // the first 6 axes are just the axes of each bounding box
        if (i < 6) {
            axis = axes[i];
        }
        // the last 9 axes are the cross product of all combinations of the first 6 axes
        else {
            var offset = i - 6;
            var j = Math.floor(offset / 3);
            var k = offset % 3;
            axis = vec4.cross(vec4.create(), axes[j], axes[k + 3]);
            if (vec4.close(axis, zeros)) {
                // axes must be collinear, ignore
                continue;
            }
        }

        // get the projections of the first half box onto the axis
        var projAx1 = Math.abs(vec4.dot(radX1, axis));
        var projAy1 = Math.abs(vec4.dot(radY1, axis));
        var projAz1 = Math.abs(vec4.dot(radZ1, axis));

        // get the projections of the second half box onto the axis
        var projAx2 = Math.abs(vec4.dot(radX2, axis));
        var projAy2 = Math.abs(vec4.dot(radY2, axis));
        var projAz2 = Math.abs(vec4.dot(radZ2, axis));

        // sum the projections
        var projectionBoxesSum = projAx1 + projAy1 + projAz1 + projAx2 + projAy2 + projAz2;

        // get the projection of the center difference onto the axis
        var projectionDifference = Math.abs(vec4.dot(centerDifference, axis));

        if (projectionDifference >= projectionBoxesSum) {
            // If the projection of the center difference onto the axis is greater
            // than the sum of the box projections, then we found a separating plane!
            // The bounding boxes therefore must not intersect
            results.intersects = false;
            break;
        }
        else {
            // keep track of the difference, the smallest gives the minimum distance
            // and direction to move the boxes such that they no longer intersect
            var difference = projectionBoxesSum - projectionDifference;
            if (difference < smallestDifference) {
                results.resolution = vec4.scale(vec4.create(), axis, difference);
                smallestDifference = difference;
            }
        }
    }

    if (results.intersects) {
        // make sure the resolution vector is in the correct direction
        var dot = vec4.dot(results.resolution, centerDifference);
        var sign = dot ? dot < 0 ? -1 : 1 : 0;
        vec4.scale(results.resolution, results.resolution, -sign);
    }

    return results;
}

Источник

person Brendan Annable    schedule 14.02.2015
comment
Спасибо, приятно читать. Мне просто интересно, было ли это уже в ThreeJS или нет. Значит, я думаю, это не реализовано в ThreeJS? - person Nicolas; 16.02.2015
comment
Бегло просмотрев, я не смог найти никаких реализаций в ThreeJS. Они, как правило, сохраняют функции, которые слишком специфичны, вне базовой библиотеки. - person Brendan Annable; 17.02.2015
comment
Да, это хорошо и плохо, я думаю :). В любом случае, спасибо. Не реализовано в ThreeJS. - person Nicolas; 17.02.2015