旋转几何体时每个三角形碰撞检测的问题

Problem with per-triangle collision detection when geometry is rotated

对于我的游戏,我试图用相机实现每个三角形的碰撞检测。看起来代码大部分都在工作,因为未旋转的几何体经过正确的命中测试,并停止了相机。然而,当我试图将相机移动到任何旋转的几何体中时,问题就出现了。我将提供一些图片来帮助说明我的问题,以及我目前用于碰撞检测的代码。需要注意的是,我使用的是 SharpDX 作为 3D 库。

在这张照片中,我正确地对我旁边的墙进行了碰撞测试。我无法从任何方向穿透它。这块几何图形没有旋转。

在这张照片中,我正确地对我下面的地板进行了撞击测试。同样,它没有旋转。

在这幅图中,我圈出一系列几何图形,所有这些图形都在 Y 轴上旋转了 270 度。我可以直接穿过这些碎片。

在这张照片中,我正面撞到了某个东西,这导致我的命中检测被触发。您将在下一张图片中看到这个“东西”是什么。

最后放一张没有旋转的旋转几何体的图片。我在这种状态下正确地命中检测了它们。当它们旋转时,碰撞框保持在与您在这张图片中看到的相同的位置,这就是为什么我点击它们前面的“东西”。

这是我当前的相机命中检测代码(已更新以提高可读性):

if (isCameraMoving)
            {
                foreach (StaticGeometry geometry in this.StaticGeometry)
                {
                    BoundingSphere cameraSphere = Camera.Bounds;
                    for (int i = 0; i < geometry.Mesh.Vertices.Length; i += 3)
                    {
                        // Get the Vertex Positions for the current Triangle
                        Vector3 position1 = geometry.Mesh.Vertices[i].Location;
                        Vector3 position2 = geometry.Mesh.Vertices[i + 1].Location;
                        Vector3 position3 = geometry.Mesh.Vertices[i + 2].Location;

                        // Create the rotation matrix using the geometry's current rotation setting.
                        Matrix rotationMatrix = VoidwalkerMath.CreateRotationMatrix(geometry.Rotation);

                        // rotate and translate each vertex
                        Matrix matrix1 = rotationMatrix * Matrix.Translation(position1 + geometry.Location);
                        Matrix matrix2 = rotationMatrix * Matrix.Translation(position2 + geometry.Location);
                        Matrix matrix3 = rotationMatrix * Matrix.Translation(position3 + geometry.Location);

                        // extract the new position from the rotated and translated Matrices.
                        Vector3 finalVertexLocation1 = matrix1.TranslationVector;
                        Vector3 finalVertexLocation2 = matrix2.TranslationVector;
                        Vector3 finalVertexLocation3 = matrix3.TranslationVector;

                        // Do hit detection for a triangle.
                        if (cameraSphere.Intersects(ref finalVertexLocation1, ref finalVertexLocation2, ref finalVertexLocation3))
                        {
                            this.Camera.Location = previousCameraPosition;
                            return;
                        }
                    }
                }
            }

还有我创建旋转矩阵的代码。我确信这段代码可以按预期工作,因为它与我用于旋转几何体的功能相同。

/// <summary>
        /// Converts degrees to radians.
        /// </summary>
        /// <param name="degrees">The angle in degrees.</param>
        public static float ToRadians(float degrees)
        {
            return degrees / 360.0f * TwoPi;
        }

        /// <summary>
        /// Creates a rotation matrix using degrees.
        /// </summary>
        /// <param name="xDegrees"></param>
        /// <param name="yDegrees"></param>
        /// <param name="zDegrees"></param>
        /// <returns></returns>
        public static Matrix CreateRotationMatrix(float xDegrees, float yDegrees, float zDegrees)
        {
            return
                Matrix.RotationX(ToRadians(xDegrees)) *
                Matrix.RotationY(ToRadians(yDegrees)) *
                Matrix.RotationZ(ToRadians(zDegrees));
        }

        /// <summary>
        /// Converts a Vector3 of Degrees to a Vector3 of Radians
        /// </summary>
        /// <param name="degrees"></param>
        /// <returns></returns>
        public static Vector3 ToRadians(Vector3 degrees)
        {
            return ToRadians(degrees.X,degrees.Y,degrees.Z);
        }

这是我的顶点 class。如果你们还需要什么,请告诉我。

using SharpDX;
using System.Runtime.InteropServices;

namespace VoidwalkerEngine.Framework.DirectX.Rendering
{
    [StructLayout(LayoutKind.Sequential)]
    public struct Vertex
    {

        public static Vertex Zero = new Vertex(Vector3.Zero,Vector2.Zero,Vector3.Zero);

        public Vector3 Location;
        public Vector2 TexCoords;
        public Vector3 Normal;

        public const int Size = 32;


        public Vertex(Vector3 position, Vector2 texCoords, Vector3 normal)
        {
            this.Location = position;
            this.Normal = normal;
            this.TexCoords = texCoords;
        }

        public Vertex(Vertex other)
        {
            this.Location = other.Location;
            this.Normal = other.Normal;
            this.TexCoords = other.TexCoords;
        }

        public override string ToString()
        {
            return
                "Location: " + Location.ToString() +
                ", TexCoords: " + TexCoords.ToString() +
                ", Normal: " + Normal.ToString();
        }

    }
}

我显然做错了什么,但我不知道它可能是什么。我先旋转顶点,然后平移它们。我在这里遗漏了什么吗?

原来我只是在装傻。实际旋转顶点的方式是使用 Vector3.TransformCoordinate(); 并将其提供给模型的旋转矩阵。这是更新后的工作代码(看到亲自工作真是太棒了)。

if (isCameraMoving)
            {
                foreach (StaticGeometry geometry in this.StaticGeometry)
                {
                    BoundingSphere cameraSphere = Camera.Bounds;
                    for (int i = 0; i < geometry.Mesh.Vertices.Length; i += 3)
                    {
                        // Get the Vertex Positions for the current Triangle
                        Vector3 position1 = geometry.Mesh.Vertices[i].Location;
                        Vector3 position2 = geometry.Mesh.Vertices[i + 1].Location;
                        Vector3 position3 = geometry.Mesh.Vertices[i + 2].Location;

                        // Create the rotation matrix using the geometry's current rotation setting.
                        Matrix rotationMatrix = VoidwalkerMath.CreateRotationMatrix(geometry.Rotation);

                        // Transform the Coordinate with the Rotation Matrix, then add the geometry's location
                        Vector3 finalVertexLocation1 = Vector3.TransformCoordinate(position1, rotationMatrix) + geometry.Location;
                        Vector3 finalVertexLocation2 = Vector3.TransformCoordinate(position2, rotationMatrix) + geometry.Location;
                        Vector3 finalVertexLocation3 = Vector3.TransformCoordinate(position3, rotationMatrix) + geometry.Location;

                        // Do hit detection for a triangle.
                        if (cameraSphere.Intersects(ref finalVertexLocation1, ref finalVertexLocation2, ref finalVertexLocation3))
                        {
                            this.Camera.Location = previousCameraPosition;
                            return;
                        }
                    }
                }
            }

https://www.youtube.com/watch?v=p1PnwVhx0Sc