Mesh/Box collisions...

Oct 20, 2010 at 1:07 AM
Edited Oct 20, 2010 at 4:08 AM

I am trying to resolve the mesh/box collisions issues I am having.  My bigger boxes seem to do collision alright.  My smaller boxes, such as the ones I use for arms and legs, will fall through my mesh if they are not aligned with the normal of the floor they're colliding with.  This should be something you could test in your holodeck example:

My CRigidBody inherits your RigidBody class.  All it really does is requires me to do things in a particular order, to make sure I don't make any boo-boos.  It helped me catch a few hard-to-find mistakes that evolved from over non-stop tweaking over weeks.

public CRigidBody(Part part, Material material)
{
    Skin.Add(part, material);

    CompleteConstruction();
}

private void CompleteConstruction()
{
    //Applies a default transform of no scaling, at the origin, no rotation.
    Transform identity = new Transform(1f, Vector3.Zero, Quaternion.Identity);
    Skin.ApplyTransform(ref identity);
    
    //Sets the MassProperties based on the shape.  If a cube, uses MassProperties.FromCuboid, etc.
    AssignedMass = DefaultMass; //DefaultMass is just a floating point number comparable to the object's size.  It is often changed after construction to be the item's mass.

    //Sets the world to be at the origin.
    SetWorld(Vector3.Zero, Quaternion.Identity);
}

This is how I am creating the box part.  That returned part is added to a RigidBody's skin, as shown in the constructor above.  I have the material to be 0 for elasticity and roughness (I assume that's okay, right?).

private static PolyhedronPart CreateBoxPart(Vector3[] vertices)
{
    ConvexHull3D hull = new ConvexHull3D(vertices);
    CompiledPolyhedron compiled = hull.ToPolyhedron();
    PolyhedronPart part = new PolyhedronPart(compiled);
    return part;
}

And I use the following to assign the mass:

MassProperties = MassProperties.FromCuboid(value, myModelSpaceBox.Max - myModelSpaceBox.Min);

My mesh parts are even more simple:

private static MeshPart CreateMeshPart(Vector3[] vertexPositions, int[] indices)
{
    return new MeshPart(vertexPositions, indices);
}

I did have to reverse the winding of my triangles for collisions to work at all.

Originally, I was setting my MassProperties to be MassProperties.Immovable, but that did not work at all.  I had to use Freeze() instead, and use:

MassProperties = MassProperties.FromTriMesh(value, myVertexPositions, myIndices, out centerOfMass);   

And this is how I am throwing my box at my mesh, just for clarity's sake:

Vector3 impulse = myCamera.Forward * 10f;
Vector3 offset = Vector3.Zero;
arrow.Body.ApplyImpulse(ref impulse, ref offset);

Box on box collision is darn near perfect.  My mesh on box is iffy then the box isn't axis-aligned, particularly the smaller they are (mass and size), like arms and legs.

Ideas, suggestions?

Cheers, and thank you for all your help!

private static MeshPart CreateMeshPart(Vector3[] vertexPositions, int[] indices)
{
    return new MeshPart(vertexPositions, indices);
}
Coordinator
Oct 21, 2010 at 2:55 PM
Edited Oct 21, 2010 at 2:56 PM

Thanks for that info; I plan to spend time this weekend working on the mesh collision issue (and the exception you reported earlier). I'll let you know what I find.

Oct 25, 2010 at 4:05 AM
Edited Oct 25, 2010 at 4:50 AM

Something I have noticed is that mesh collision detection is rather slow.  With 1 ragdoll (8 bodies, 1 world constraint, 7 joints) versus a mesh, no problem.  10 ragdolls versus a mesh... ouch, 2 FPS.  They were speedy until they got close to the mesh, which proves that your partitioning is working (I'd hope so! :-P).  My environment is already partitioned, but I could partition it smaller yet.  I haven't looked at your code, but facing a similar problem in my past, I had to partition the triangles in my environmental meshes.  How are you doing your mesh collision detection once things get close?

Here's an odd issue: I have turned off collisions between my terrain and my ragdolls, via your OnCollision function, but it is still slow.  I am presuming that OnCollision only checks if there is a collision.  Perhaps we need a way to decide if we need to check at all?  Collision groups, or another delegate.  I'll add my own for now and see what happens.

EDIT: great success.  Here are my changes.  (I prefixed all my stuff with ZOOP_ so it is easy to find.)

In RigidBody class file:

/// <summary>
/// Determines whether a collision is possible between the two bodies.  Return true to test for collisions.
/// </summary>
/// <param name="sender"></param>
/// <param name="other"></param>
public delegate bool ZOOP_CollisionPossibleEventHandler(RigidBody sender, RigidBody other);

In RigidBody class:

/// <summary>
/// Return true to check for collisions at all between the two given bodies.  Return false to not check for collisions.
/// </summary>
public ZOOP_CollisionPossibleEventHandler ZOOP_CollisionPossible;

internal bool ZOOP_IsCollisionPossible(RigidBody other)
{
    if (ZOOP_CollisionPossible != null)
    {
        return ZOOP_CollisionPossible(this, other);
    }

    return true;
}

In the BodyCollisionFunctor class, I updated the WritePair function below, adding a call to IsCollisionPossible just before calling base.WritePair.  I am not sure if this is the best place to put it, but it does seem to work.

public override void WritePair(Composition a, Composition b)
{
    RigidBody ba = ((BodySkin)a).Owner, bb = ((BodySkin)b).Owner;

    // only process collisions if:
    // - at least one body is active
    // - bodies do not share any constraints on which collisions are disabled
    for (int i = 0; i < bb.Constraints.Count; i++)
    {
        var c = bb.Constraints[i];
        if (!c.IsCollisionEnabled && (c.BodyA == ba || c.BodyB == ba))
	        return;
    }

    if (ba.IsActive || bb.IsActive)
    {
        //ZOOP_EDIT:
        if (ba.ZOOP_IsCollisionPossible(bb) && bb.ZOOP_IsCollisionPossible(ba))
        {
            base.WritePair(a, b);
        }
    }
}

Cheers.

Coordinator
Oct 25, 2010 at 8:58 PM
Edited Oct 25, 2010 at 9:01 PM

Been working on this one and I think I've come up with a fix for the exception problem. The poly/mesh problem is turning out to be a little more difficult. I've tried a lot of poly/mesh collisions with meshes that I already have and they all seem to be working well, but it's very possible that there are collision cases that I'm not fully exercising.

Any chance you can share one of the world meshes you're using? Maybe throw it up on rapidshare or something. I'm completely useless with modeling software and the only sample meshes I can find on the web are very high density models that are unsuitable for physics. Since you mention a performance issue, how dense are your meshes? In addition to the sweep-and-prune culling, each mesh is processed into an octree, which the bounded box is then tested against. Only triangles that intersect the bounding box of the colliding object should be tested. If this ends up being too many triangles, two things can happen: 1) things get very slow, especially with polyhedra, and especially on the xbox, and 2) the maximum number of collision points can be exceeded, causing collisions with some triangles to be dropped completely. It's entirely possible that there is some problem with the octree causing too many triangles to be checked. Perhaps a larger mesh will expose that issue.

Also, I was curious if there was a reason you're constructing ragdolls from polyhedra? Poly/mesh collisions are the most expensive, so I'm not surprised that it would be fairly slow; this is why I chose capsules for the example.  However, I'm not sure I'd expect it to go all the way down to 2fps, so maybe something else is going on. 

To the suppression of collisions between objects, I think I'd rather stick with the mechanism already in place (the IsCollisionEnabled propery of constraints). A dummy constraint between two objects could be created that does nothing except suppress collisions.