1
\$\begingroup\$

I have been working on a reliable physics system in my code and so far it's ALMOST working. :D

I am aiming for wall "sliding" style of collision response, like you'd expect it to work in commercial games.

I have implemented a system that gets a collision geometry from an FBX model. Geometry with specific names will not be rendered, instead they'll be used to construct Oriented Bounding Boxes, further from which a set of Triangle structures will be constructed.

So far, everything went as expected. Triangles are correctly deduced from their parent bounding boxes, each Box having 12 triangles. I have used helper classes to render out the triangles alone, along with their normals, and I know for certain they are transformed and positioned correctly inside the world.

I am using a Ray-Triangle intersection math to determine which triangle is the closest to the player, and from that, grab a normal from which the Physics Vector will later be reflected.

For some reason this all works but only on surfaces of some specific orientation. I have grabbed a screenshot with walls that are successfully collided with marked in Green color: Walls

Against these walls the collision works perfectly, as expected.

Against all others, the collision somehow fails and player can simply walk through.

I have made 100% sure that my triangles are all correctly picked from mesh and positioned in the world and that their normals are correct (I can render all this as helper objects in 3D world).

The most important bits of my code are as follows:

Triangle construction:

for (int i = Part.MeshParts[0].StartIndex; i < Part.MeshParts[0].StartIndex + (Part.MeshParts[0].PrimitiveCount * 3); i += 3)
                {
                    Triangle temp = new Triangle();

                    temp.Normal = Vector3.Transform(modelVertices[modelIndices16[i]].Normal, NormalTransform);

                    temp.Normal.Normalize();

                    temp.Vertices[0] = Vector3.Transform(rawData[modelIndices16[i]], Transform);
                    temp.Vertices[1] = Vector3.Transform(rawData[modelIndices16[i + 1]], Transform);
                    temp.Vertices[2] = Vector3.Transform(rawData[modelIndices16[i + 2]], Transform);

                    Triangles.Add(temp);
                }

(also a copy for this for 32 bits, not important now),

This is a part of a function that returns Triangle[], which is a part of CollidableGeometry structure:

 public struct CollidableGeometry
        {
            public OrientedBoundingBox OrientedBox;
            public Triangle[] Triangles;
            public Vector3 TriangleNormal;

        }

Now, the most important is the collision detection part.

By this part, we know that OrientedCollisionGeometry[i] is colliding with Player's box:

for (int x = 0; x < OrientedCollisionGeometry[i].Triangles.Length; x++)
                        {
                            Ray PlayerMovement = new Ray(Player.player, -OrientedCollisionGeometry[i].Triangles[x].Normal);

                            OrientedCollisionGeometry[i].Triangles[x].Intersects(ref PlayerMovement, out tempDistance);

                            if (tempDistance != null)
                            {
                                if (Math.Abs((float)tempDistance) < Math.Abs((float)distance))
                                //if (tempDistance < distance)
                                {
                                    closestIDX = x;
                                    distance = tempDistance;
                                }
                            }
                        }

                        if (closestIDX != -1)
                        {
                            ///Final collision decision:

                            Player.CollisionReflectionVector += OrientedCollisionGeometry[i].Triangles[closestIDX].Normal;

                        }
}

This code roughly translates as:

We know there's an oriented bounding box that intersects player's bounding box. We go through all 12 triangles that make up a box: For each triangle, construct a Ray that starts at Player's position, and in the direction of that triangles normal (in negative). If the ray goes through the triangle, record the distance at which it does.

The triangle with lowest distance from the player is marked as most important one, and it's Normal is recorded as the one we need to reflect the player's direction of.

In short, what I know for 100% is NOT wrong:

-The triangles are correctly placed in the world.

-The triangle's normals are correct.

-The oriented box collisions are correct, and determining which OBB from the mesh is colliding with the player is also correct.

SOME surfaces works exactly as expected, and those are all of specific orientation.

The rest produce NO effect.

I can pack up the compiled game, or entire source code if somebody wants to play around and take a look.

I'm completely stumped over this for several days now. Worst part is that it DOES work normally as expected for some walls.

I have picked up the Ray-Triangle intersection from this resource link: http://www.discoverthat.co.uk/games/xna-triangle.htm

As far as I know, winding order of the triangles is also not the problem because you'd be stuck inside the wall (if you were already to go through the outside surface).

So, help?

\$\endgroup\$
1
\$\begingroup\$

I have figured it out.

Turns out, my logic was correct, however the imported mesh had it's normals messed up for whatever reason. Maybe I used incorrect settings when exporting FBX file from Max.

I have calculated my own normals so now everything is correct.

            Triangle temp = new Triangle();

            temp.Vertices[0] = Vector3.Transform(rawData[modelIndices16[i]], Transform);
            temp.Vertices[1] = Vector3.Transform(rawData[modelIndices16[i + 1]], Transform);
            temp.Vertices[2] = Vector3.Transform(rawData[modelIndices16[i + 2]], Transform);

            Vector3 Normal = Vector3.Cross(temp.Vertices[1] - temp.Vertices[0],
                                  temp.Vertices[1] - temp.Vertices[2]);

            Normal.Normalize();

            temp.Normal = Normal;

            Triangles.Add(temp);

Some more tweaks and playing around will be needed but it's working fine for now, I like where this is going.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.