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.
In this picture I am correctly hit-testing the floor below me. Again, it is not rotated.
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.
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.
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.
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?
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;
}
}
}
}
Answered by Krythic on November 15, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP