0

在我想用来演示我的问题的示例中,我有一个涡轮机模型和一个小电网,如下图所示。模型的边界框显示为红色框。我尝试检查绿色网格中的哪些节点位于涡轮机边界框上方。如果一个节点位于边界框之上,我将它向下移动一点,这样我就可以清楚地看到哪些节点在边界框之上,哪些不在边界框之上。

正如您在第一张图片中看到的那样,它非常适合我的非旋转模型。但是,如果我将模型旋转 -90°,所有命中测试都会失败。我不明白为什么会这样!在为“挑选”进行命中测试时,我遇到了同样的问题。

在此处输入图像描述

在此处输入图像描述

这是我用来检查节点是否在任何边界框上方的小函数。对于这个任务,我为每个节点创建了一条指向底部的射线。然后,我检查这条射线与我所有模型的所有位置的交点。(如果我有多个涡轮机,我只会有涡轮机模型,但它有多个位置。这使得在 GPU 上渲染速度更快。)

foreach (var node in level.VisualGraph.Nodes)
{
    SharpDX.Vector3 upperVector = new SharpDX.Vector3(node.Position.X, 1.0f, node.Position.Z);

    SharpDX.Ray ray = new SharpDX.Ray(upperVector, new SharpDX.Vector3(0.0f, -1.0f, 0.0f));
    foreach (var model in level.Models)
    {
        foreach (var position in model.Positions)
        {
            if (position.BoundingBox.GeometricBoundingBox.Intersects(ref ray))
            {
                node.Position = new SharpDX.Vector3(node.Position.X, 0.6f, node.Position.Z);
                break;
            }
        }
    }
}

如前所述,每个模型可以在场景中出现多次,因此我只存储每个模型一次并计算其每个位置的变换。因此,模型的每个位置都有一个边界框。

我用于命中测试的“GeometricBoundingBox”是SharpDX.BoundingBox类型。当我向我的模型添加一个新位置时,我通过检查模型的所有顶点的最小值和最大值来创建一个新的边界框。

bool isFirst = true;
foreach (var vertex in vertices)
{
    if (isFirst)
    {
        _min = new SharpDX.Vector3(vertex.GetPosition().X, vertex.GetPosition().Y, vertex.GetPosition().Z);
        _max = new SharpDX.Vector3(vertex.GetPosition().X, vertex.GetPosition().Y, vertex.GetPosition().Z);

        isFirst = false;
    }
    else
    {
        _min.X = Math.Min(_min.X, vertex.GetPosition().X);
        _min.Y = Math.Min(_min.Y, vertex.GetPosition().Y);
        _min.Z = Math.Min(_min.Z, vertex.GetPosition().Z);

        _max.X = Math.Max(_max.X, vertex.GetPosition().X);
        _max.Y = Math.Max(_max.Y, vertex.GetPosition().Y);
        _max.Z = Math.Max(_max.Z, vertex.GetPosition().Z);
    }
}

当第一次创建边界框或父位置的世界矩阵发生变化时,我计算我的“GeometricBoundingBox”如下:

SharpDX.Vector4 testMin = Helper.Math.Multiply(new SharpDX.Vector4(_min, 1.0f), worldMatrix);
SharpDX.Vector4 testMax = Helper.Math.Multiply(new SharpDX.Vector4(_max, 1.0f), worldMatrix);

GeometricBoundingBox = new SharpDX.BoundingBox(new SharpDX.Vector3(testMin.X, testMin.Y, testMin.Z), new SharpDX.Vector3(testMax.X, testMax.Y, testMax.Z));

用于将模型转换为位置的世界矩阵也用于计算边界框,如上所示。我这样计算:

public void UpdateWorldMatrix()
{
    SharpDX.Matrix rotationMatrix = SharpDX.Matrix.RotationYawPitchRoll(RotationY, RotationX, RotationZ);

    // We need to calculate the transformation matrix once and apply it for the initial offset before we can calculate the final matrix.
    SharpDX.Matrix initialMatrix = SharpDX.Matrix.Scaling(Scaling * _parentModel.InitialScaling) * rotationMatrix;
    SharpDX.Vector3 initialTranslation = Helper.Converters.ToVector(Helper.Math.Multiply2(_parentModel.InitialTranslation, initialMatrix));

    // Calculate world matrix and update bounding box.
    WorldMatrix = SharpDX.Matrix.Scaling(Scaling * _parentModel.InitialScaling) * rotationMatrix * SharpDX.Matrix.Translation(Position + Translation + initialTranslation);

    if (ParentStaticPosition != null)
        WorldMatrix = SharpDX.Matrix.Multiply(WorldMatrix, ParentStaticPosition.WorldMatrix);

    BoundingBox.ReBuild(WorldMatrix);
}

在两个模型中,边界框都非常适合我的涡轮机模型。虽然模型在 GPU 上针对每个位置进行转换,但边界框由上面显示的代码进行转换。由于模型和边界拟合,我相信计算它们是有效的。

但我不明白为什么我的命中测试适用于非旋转对象,但我不适用于旋转对象。

你有什么想法?

4

1 回答 1

1

您可以为光线投射做的一件事是将光线转换为模型空间,而不是将边界框转换为您的方向。这是通过采用模型方向矩阵的逆矩阵并将向量的起点和终点乘以逆矩阵来完成的。然后在模型空间中创建射线并将其投射到模型空间 aabb。

如果您通过矩阵定位您的 aabb,这将不起作用。您需要通过将模型中的每个顶点与方向矩阵相乘来重新计算新的 aabb,然后重新计算 aabb。我相信这就是您正在做的事情,但我相信您正在转换的边界框可能没有正确的最大最小范围。

于 2017-02-14T15:21:44.157 回答