Javascript 如何计算三维对象在threejs中的位置,并将对象放置在场景中,以便多个三维对象不会彼此重叠

Javascript 如何计算三维对象在threejs中的位置,并将对象放置在场景中,以便多个三维对象不会彼此重叠,javascript,three.js,3d,Javascript,Three.js,3d,我正在处理货物计划应用程序,希望将货物装载到集装箱中。我正在使用threejs为它创建3d模型。我对threejs完全陌生,到目前为止,我已经成功地创建了3d对象(货物)并将其放置在容器中(另一个3d对象)。我面临的问题是,当我在容器中添加多个3d对象时,这些对象彼此重叠。 我无法计算应设置的正确对象位置,以防止此重叠问题 我刚刚试着用基本的数学来计算物体的位置和它在场景中的位置 这里是它的js小提琴 计算对象位置的逻辑写在addCargo函数中,该函数只使用基本数学。这是它的代码 funct

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

我刚刚试着用基本的数学来计算物体的位置和它在场景中的位置

这里是它的js小提琴

计算对象位置的逻辑写在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();
}
功能添加货物(尺寸、颜色、标签){
var dimensionexceper=false;//检查货物尺寸是否超过containerdimension的布尔值
如果(objects.length==0){
var geometry=新的三个.BoxGeometry(dimension.width、dimension.height、dimension.length);
var材料=新的三网格基本材料({
颜色:颜色
});
货物=新的三个网格(几何形状、材料);
线框=生成重构(几何体);
默认\u框\u位置={
x:容器_dimension.width/2-dimension.width/2,
y:dimension.height/2-容器_dimension.height/2,
z:容器_dimension.length/2-dimension.length/2
}
cargo.position.set(默认位置x,默认位置y,默认位置z);
}否则{
var geometry=新的三个.BoxGeometry(dimension.width、dimension.height、dimension.length);
var材料=新的三网格基本材料({
颜色:颜色,
线框:错误
});
货物=新的三个网格(几何形状、材料);
线框=生成重构(几何体);
货物。添加(线框);
var firstObject=objects[0];
var xUpdated=false;
职位={
x:0,,
y:0,
z:0
}
var startIndex=0;
if(托盘张力.isSet){
位置y=托盘高度;
startIndex=1;
}
对于(var i=startIndex;i=容器尺寸长度){
if(position.z-parseFloat(objects[i].geometry.parameters.depth)+parseFloat(dimension.length)容器_dimension.length){
xUpdated=true;
位置.x+=parseFloat(尺寸.宽度);
位置z=0;
}
if(位置x>=容器尺寸宽度){
position.y+=parseFloat(objects[i].geometry.parameters.height);
位置x=0;
位置z=0;
}else if(position.x+parseFloat(dimension.width)>container\u dimension.width){
位置.y+=parseFloat(尺寸.高度);
位置x=0;
位置z=0;
}
}
var z_pos=容器尺寸.length/2-位置.z-(尺寸.length/2);
变量y_pos=位置.y-容器尺寸.高度/2+(尺寸.高度/2);
变量x_pos=容器尺寸.width/2-位置x-(尺寸.width/2);

如果(Math.abs(z_pos),你可以尝试一种放松方法,即在一个无限循环中,对每个盒子稍微改变一点,直到所有盒子都满意为止

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树等边界卷层次结构)或其他一些数据结构有效地完成。即使是八叉树也可以获得良好的结果。这同样适用于函数“overlap_at_”

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

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


在我的回答中,用最小的空间来寻找最佳的布局是不可能的。

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

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树等边界卷层次结构)或其他一些数据结构有效地完成。即使是八叉树也可以获得良好的结果。这同样适用于函数“overlap_at_”

函数“push_away_boxes”只会将两个盒子朝相反方向移动一小段距离dx(比如0.1或10或其他相对于盒子大小而言被视为“小”的数字)。因此,将“push_away_boxes”累积应用到给定的一对重叠盒子上,最终将使它们成为非OV