C# 旋转模型后,SharpDX中的命中测试不起作用

C# 旋转模型后,SharpDX中的命中测试不起作用,c#,transform,hittest,sharpdx,ray-picking,C#,Transform,Hittest,Sharpdx,Ray Picking,在我想用来演示我的问题的示例中,我有一个涡轮机的单一模型和一个小网格,如下图所示。模型的边界框显示为红色框。我尝试检查绿色网格中的哪些节点位于涡轮机的边界框上方。如果一个节点位于边界框上方,我将其向下移动一点,以便可以清楚地看到哪些节点位于边界框上方,哪些节点未位于边界框上方 正如您在第一张图中所看到的,它对我的非旋转模型非常有效。但是,如果我将模型旋转-90°,所有命中测试都会失败。我不明白为什么会这样!在为“挑选”进行命中测试时,我也有同样的问题 这是我用来检查节点是否位于任何边界框之上的小

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

正如您在第一张图中所看到的,它对我的非旋转模型非常有效。但是,如果我将模型旋转-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上为每个位置转换时,边界框由上面显示的代码转换。由于模型和边界拟合,我相信计算它们是有效的

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


你有什么想法吗?

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


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

它。。它起作用了。但是为什么?我的意思是,我做的和以前完全一样,但只是在不同的空间,对吗?你能给我进一步的了解吗,厄尼丁戈?我很想了解为什么你的方法有效,而我的方法在一些轮换项目中失败了!我猜这只是因为最小最大范围计算不正确。仅旋转它们就意味着它们不再是最小-最大范围。你必须完全从你的方向矩阵中重新计算它们。我建议只在模型空间中进行光线投射,因为这比针对定向模型进行光线投射要快