【问题标题】:How to calculate 3d objects position in threejs and place the objects on scene such that multiple 3d objects do not overlap with each other如何在threejs中计算3d对象位置并将对象放置在场景中以使多个3d对象不相互重叠
【发布时间】:2019-06-26 17:10:48
【问题描述】:

我正在开发货物计划应用程序,并希望将货物装入集装箱。我正在使用threejs为其创建3d模型。我对 threejs 完全陌生,到目前为止,我已经成功地创建了 3d 对象(货物)并将它们放在一个容器(另一个 3d 对象)中。我面临的问题是当我在容器内添加多个 3d 对象时,这些对象相互重叠。 我无法计算应设置的正确对象位置以防止出现此重叠问题。

我刚刚尝试使用基本数学计算对象位置及其在场景中的位置。

这是它的 js 小提琴

https://jsfiddle.net/nro48e6u/1/

计算对象位置的逻辑写在 addCargo 函数中,它只使用基本的数学。这是它的代码

function addCargo(dimension, color, isPallete) {
var dimensionExceed = false; // boolean value that checksifthe cargo dimensions exceed the containerdimension               
if (objects.length == 0) {
    var geometry = new THREE.BoxGeometry(dimension.width, dimension.height, dimension.length);
    var material = new THREE.MeshBasicMaterial({
        color: color
    });
    cargo = new THREE.Mesh(geometry, material);
    wireframe = generateWireframe(geometry);
    default_box_position = {
        x: container_dimension.width / 2 - dimension.width / 2,
        y: dimension.height / 2 - container_dimension.height / 2,
        z: container_dimension.length / 2 - dimension.length / 2
    }
    cargo.position.set(default_box_position.x, default_box_position.y, default_box_position.z);

} else {
    var geometry = new THREE.BoxGeometry(dimension.width, dimension.height, dimension.length);
    var material = new THREE.MeshBasicMaterial({
        color: color,
        wireframe: false
    });
    cargo = new THREE.Mesh(geometry, material);
    wireframe = generateWireframe(geometry);
    cargo.add(wireframe);
    var firstObject = objects[0];
    var xUpdated = false;

    position = {
        x: 0,
        y: 0,
        z: 0
    }
    var startIndex = 0;
    if (palleteDeimension.isSet) {
        position.y = palleteDeimension.height;
        startIndex = 1;
    }
    for (var i = startIndex; i < objects.length; i++) {
        if (!xUpdated || i == objects.length - 1) {
            position.z += parseFloat(objects[i].geometry.parameters.depth);
            xUpdated = false;
        } else {
            xUpdated = false;
            position.z += parseFloat(objects[i].geometry.parameters.depth);
        }
        if (position.z >= container_dimension.length) {
            if (position.z - parseFloat(objects[i].geometry.parameters.depth) + parseFloat(dimension.length) <= container_dimension.length) {
                position.z -= parseFloat(objects[i].geometry.parameters.depth);
            } else {
                position.x += parseFloat(objects[i].geometry.parameters.width);
                position.z = 0;
            }

        } else if (position.z + parseFloat(dimension.length) > container_dimension.length) {
            xUpdated = true;
            position.x += parseFloat(dimension.width);
            position.z = 0;
        }

        if (position.x >= container_dimension.width) {
            position.y += parseFloat(objects[i].geometry.parameters.height);
            position.x = 0;
            position.z = 0;
        } else if (position.x + parseFloat(dimension.width) > container_dimension.width) {
            position.y += parseFloat(dimension.height);
            position.x = 0;
            position.z = 0;
        }
    }
    var z_pos = container_dimension.length / 2 - position.z - (dimension.length / 2);
    var y_pos = position.y - container_dimension.height / 2 + (dimension.height / 2);
    var x_pos = container_dimension.width / 2 - position.x - (dimension.width / 2);
    if (Math.abs(z_pos) <= container_dimension.length / 2 && position.x == 0 && position.y == 0) {
        cargo.position.set(default_box_position.x, default_box_position.y, z_pos);

        if (firstObject.geometry.parameters.width != dimension.width)
            cargo.position.x = x_pos;
        if (firstObject.geometry.parameters.height != dimension.height)
            cargo.position.y = y_pos;
    } else if (Math.abs(y_pos) <= container_dimension.height / 2 && position.x == 0) {
        cargo.position.set(default_box_position.x, y_pos, z_pos);
        if (firstObject.geometry.parameters.width != dimension.width)
            cargo.position.x = x_pos;
    } else
        cargo.position.set(x_pos, y_pos, z_pos);
}
scene.add(cargo);
objects.push(cargo);
initDragCargo();
}

当我在集装箱内添加多个货物时,货物相互重叠。我很清楚如何摆脱这个重叠的问题。

【问题讨论】:

标签: javascript three.js 3d


【解决方案1】:

您可以尝试一种放松的方法,即在无限循环中,每个盒子稍微改变一点,直到所有盒子都满意为止。

dx = 0.1;
while(overlap_at_all(boxes)) {
    foreach(var box in boxes) {
        var overlapping_boxes = get_overlapping_boxes(box, boxes);
        foreach(var overlapping_box : overlapping_boxes)
            push_away_boxes(box, overlapping_box, dx);
    }
}

函数“get_overlapping_boxes”进行碰撞检测检查并返回与当前盒子碰撞的盒子。这可以使用 BVH(边界体积层次结构,例如动态 AABB 树)或其他一些数据结构来有效地完成。即使是 OctTree 也可以获得很好的结果。这同样适用于函数“overlap_at_all”

函数“push_away_boxes”只是将两个盒子朝相反的方向移动一小段距离 dx(比如说 0.1 或 10 或其他可以被认为相对于盒子大小“小”的数字)。因此,“push_away_boxes”对给定的一对重叠框的累积应用最终将使它们不重叠。一旦没有更多的重叠框,就达到了“收敛”。可以通过增大“dx”距离来提高收敛速度,但是会影响精度,dx越大性能越好,但代价是精度越差。

现在,不考虑容器箱。我们可以将其引入“push_away_boxes”函数内作为对盒子移动的约束。然而,鉴于该约束,不能保证该方法的收敛性。所以我们可以给循环最大的迭代次数,以防止无限循环。此解决方案不保证如果有解决方案就会找到。

在我的回答中,以最小的腰部空间找到最佳布置超出了范围。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-18
  • 2015-09-14
  • 2018-02-06
  • 1970-01-01
  • 2016-09-07
  • 1970-01-01
相关资源
最近更新 更多