如何在threejs中计算3d对象的位置并将其放置在场景中,以使多个3d对象彼此不重叠

时间:2019-02-02 07:47:11

标签: javascript three.js 3d

我正在研究货物计划应用程序,并希望将货物装载到集装箱中。我正在使用threejs为它创建3d模型。我对threejs完全陌生,到目前为止,我们已经设法创建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();
}

当我在集装箱内添加多件货物时,货物彼此重叠。我注意到,确定如何摆脱这个重叠的问题。

1 个答案:

答案 0 :(得分:0)

您可以尝试一种放松方法,即在无限循环中,每个框都更改一个小位,直到所有框都满意为止。

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(边界体积层次结构,例如动态ABBB树)或其他一些数据结构可以有效地完成此操作。即使是OctTree也可以取得良好的效果。这同样适用于函数“ overlap_at_all”

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

现在,不考虑容器盒。我们可以引入它作为约束“ push_away_boxes”函数内部的框的运动。但是,鉴于该约束,无法保证该方法的收敛性。因此,我们可以为循环提供最大的迭代次数,以防止无限循环。此解决方案不能保证找到解决方案。

在我的答案中找不到范围最小的最佳布置。