71. 为物体绘制立方体边界

71. 为物体绘制立方体边界

本教程翻译自官方教程Draw Bounding Boxes,各位也可以进入本站镜像站点查看

本文目录

  1. 如何绘制立方体边界
    1. 绘制单个物体的边界
    2. 绘制多个物体的边界
    3. 一个更好的方法
    4. 最后一个技巧
    5. API

如何绘制立方体边界

Babylon中,很容易在物体周围绘制边界框。你可以把一个边界框想象成一个视觉框,你的物体可以完美地嵌入其中。它包含物体的外部“边界”。

绘制单个物体的边界

我们先来为单个物体绘制边界。你可以参照下面这个默认实例

假设在你的场景中有一个球体,你把它命名为sphere

要在球体周围绘制边界框,只需将showBoundingBox属性设置为true

像这样:

sphere.showBoundingBox = true;

是不是很简单?

我们来看一下效果

绘制多个物体的边界

接下来,我们来点有难度的。让我们假设你的场景中还有一个你已经地命名为ground的地平面,你想要在包含球体和地面的区域周围画一个边界框。

为此,我们要首先获得两个物体的边界信息的最小值和最大值,我们通过特殊的方法来比较两个向量值,计算出新的最小值和最大值。然后我们将球体的边界信息设置为新的最小值和最大值。我们来试试。

我们首先声明四个新变量,它们将保存球体和地面的最小和最大边界信息。

let sphereMin = sphere.getBoundingInfo().boundingBox.minimum;
let sphereMax = sphere.getBoundingInfo().boundingBox.maximum;

let groundMin = ground.getBoundingInfo().boundingBox.minimum;
let groundMax = ground.getBoundingInfo().boundingBox.maximum;

现在让我们声明两个新的变量并使用上面提到的特殊方法来比较两个物体的最小和最大边界信息。

let newMin = BABYLON.Vector3.Minimize(sphereMin, groundMin);
let newMax = BABYLON.Vector3.Maximize(sphereMax, groundMax);

所以现在newMinnewMax是两个物体的最小和最大界限!因此,接下来我们将球体的边界信息设置为newMinnewMax

sphere.setBoundingInfo(new BABYLON.BoundingInfo(newMin, newMax));

最后,像之前一样,我们显示球体的边界框。

sphere.showBoundingBox = true;

我们看一下效果

一个更好的方法

好了,我们上面用的方法其实存在一个问题。我们实际上将球体的边界信息更改为包含球体和地面的新边界信息。实际上,有一种更好的方法可以做到这一点,那就是不去管球体的边界信息,而是引入一个父物体。

首先,让我们创建一个新的通用物体,像这样:

let parent = new BABYLON.Mesh("parent", scene);

现在我们使用这个通用物体作为球面和地面的父物体;

sphere.setParent(parent);
ground.setParent(parent);

最后,我们不设置球体边界信息和也不显示显示球体的边界框,而是设置其父物体的边界并显示边界框。

parent.setBoundingInfo(new BABYLON.BoundingInfo(newMin, newMax));

parent.showBoundingBox = true;

我们来看一下效果

注意到问题了吗?我们的边界框不再与物体的边界对齐了?原因就是,到目前为止我们使用的是局部坐标而不是世界坐标。所以从技术上讲,我们看到的边界框大小是正确的,但它是围绕父物体绘制的……在这种情况下,它的中心点是坐标系的原点。当你注释掉这行代码,就可以清楚地看到问题

sphere.position.y = 1;

现在再来看一下效果

明白了吗?但如果你想要定位物体的世界边界呢?这其实很简单。我们只需要对sphereMinsphereMaxgroundMingroundMax值做一些小的修改,如下所示:

let sphereMin = sphere.getBoundingInfo().boundingBox.minimumWorld;
let sphereMax = sphere.getBoundingInfo().boundingBox.maximumWorld;

let groundMin = ground.getBoundingInfo().boundingBox.minimumWorld;
let groundMax = ground.getBoundingInfo().boundingBox.maximumWorld;

好了!这看起来更像你所期待的,不是吗?

这里是最新示例

最后一个技巧

如果你想要得一大堆物体的边界框会发生什么?你肯定不想手动的去获取每一个物体的边界值?所以我们将在混合中引入一个循环!

像前面一样,我们首先确保我们有一个父物体,并且我们想要包含在边界框中的每个物体对象的父物体都是该物体。

这里有趣的技术是,我们可以循环遍历父元素的每个“子物体”的数组。让我们首先声明一个新变量,它将是父物体的所有子物体的数组。

let childMeshes = parent.getChildMeshes();

接下来,我们声明两个新变量,它们将包含最小值和最大值。

let min = childMeshes[0].getBoundingInfo().boundingBox.minimumWorld;
let max = childMeshes[0].getBoundingInfo().boundingBox.maximumWorld;

我们将这些最小和最大变量的初始值设置为第一个子物体的世界最小和世界最大边界信息。

现在,我们可以循环遍历所有子物体,并使用每个比较物体的新边界信息不断更新最小值和最大值。它是这样的:

for(let i=0; i<childMeshes.length; i++){
        let meshMin = childMeshes[i].getBoundingInfo().boundingBox.minimumWorld;
        let meshMax = childMeshes[i].getBoundingInfo().boundingBox.maximumWorld;

        min = BABYLON.Vector3.Minimize(min, meshMin);
        max = BABYLON.Vector3.Maximize(max, meshMax);
    }

我们做到了!非常棒!这是这些变化后的结果

要更深入地研究边界框,请仔细阅读下面的API

API

贡献者

翻译: 阿恒 cnblogs
校对: Catherine catherine__long@126.com
技术支持: 吉吉国王 jijiking@office2.cn / Dushusir github

参与贡献? 联系sevice@office2.cn