TransWikia.com

Problem with per-triangle collision detection when geometry is rotated

Stack Overflow Asked on November 15, 2021

For my game, I am attempting to implement per-triangle collision detection with the camera. It appears as though the code is mostly working, in that non-rotated geometry is correctly hit-tested, and stops the camera. However, the problem arises when I attempt to move the camera into any piece of rotated geometry. I’m going to provide a few pictures to help illustrate my problem, as well as the code that I’m currently using for collision detection. It should be noted that I’m using SharpDX as a 3D library.

In this picture, I am correctly hit-testing the wall beside me. I cannot penetrate it from any direction. This piece of geometry is not rotated.
enter image description here

In this picture I am correctly hit-testing the floor below me. Again, it is not rotated.
enter image description here

In this picture, I circle a series of pieces of geometry, all of which are rotated by 270 degrees on the Y axis. I can pass right through these pieces.
enter image description here

In this picture I am hitting something head-on, which is causing my hit-detection to trigger. You will see in the next picture what this "something" is.
enter image description here

Finally, here is a picture of those pieces of rotated geometry without rotation. I correctly hit-detect them in this state. When they’re rotated, the hitboxes remain in the same location as you visually see them in this picture, which is why I hit "something" in front of them.
enter image description here

Here is my current code for camera hit detection (Updated for better readability):

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;
                        }
                    }
                }
            }

And my code for creating a rotation matrix. I’m positive this code works as intended, because it’s the same function I use for rotating my geometry.

/// <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);
        }

And here is my Vertex class. If you guys need anything else, just let me know.

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();
        }

    }
}

I am clearly doing something wrong, but I don’t know what it could be. I’m rotating the vertices first, then translating them. Am I missing something here?

One Answer

So it turns out I was just being dumb. The way that you actually rotate a vertex is with Vector3.TransformCoordinate(); and feed it the rotation matrix of the model. Here is the updated and working code (Which is pretty glorious to see working in person).

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

Answered by Krythic on November 15, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP