Page 1 of 1

Updatable Mesh

Posted: Sat Mar 01, 2014 12:34 pm
by stino
Hi,

I'm currently trying to add physics to a voxel-generated asteroid. But since the asteroid is destructible i need to be able to remove and modify mesh shapes from the compound body, but this compound body seems to be immutable. I could remove the compound body and create a new one each time the asteroid is modified, but this would remove the physics state, so it would stop rotating/moving?

The asteroid exist out of a 3d grid, each grid cell (that has a low res isosurface geometry in it) will get MobileMesh shape to represent that part of the asteroid.

When the asteroid is modified by destruction, the mobileMesh will need to be updated, or even removed. So i'm wondering, within bepu physics, what would be the best way to achieve this? If i have to recreate the entire entity, would it be beneficial to create a mobile mesh for the entire thing?

Re: Updatable Mesh

Posted: Sat Mar 01, 2014 7:18 pm
by Norbo
I could remove the compound body and create a new one each time the asteroid is modified, but this would remove the physics state, so it would stop rotating/moving?
Caching and reapplying the velocities before the modification would solve that particular issue.
If i have to recreate the entire entity, would it be beneficial to create a mobile mesh for the entire thing?
Probably not- recreating the acceleration structure for an entire mesh is pretty heavy. Having submeshes which limit the need for mesh reconstruction would probably be a win, since the upper level compound tree has less leaves to deal with.

For modifications which do not change the topology of the compound tree, there is no fundamental need for a rebuild of the whole object. With some hacking, the operation could be limited to a refit- which the compound does every frame anyway. This would be an option if performance is a big enough concern to warrant diving into the source.

You might also find some use for the "CompoundHelper" class. They were built for a dynamic fracture prototype and can reduce the amount of effort spent on recreating objects. They don't help directly with adding to or modifying the compound, but they do show the kinds of things that need to be adjusted internally to handle that sort of thing.

Re: Updatable Mesh

Posted: Sat Mar 01, 2014 7:36 pm
by Norbo
Another note: you can recreate the collidable for an entity separately from the entity itself. The MorphableEntity's CollisionInformation property is settable.

Re: Updatable Mesh

Posted: Sat Mar 01, 2014 8:02 pm
by stino
Performance of recreating the acceleration structure is a concern of course., but it's a one time cost. If it takes less then +- 600ms, then it's even cheap enough. The explosion will mask much of the transformation (which is running on a separate thread until it's done) and won't happen for a while again until something else hits the asteroid.

Currently i'm still in the stage of optimizing the iso-surface generation because that takes way more then my targeted 600ms unless i run it on 5x5x5 volumes :(.
But I've noticed that I can't fly into caverns of the asteroid, might the MobileMesh be generating a ConvexHull instead of a triangle mesh?

EDIT: hehe, on larger asteroids (say, 33k triangles) calling the constructor of MobileMesh takes a while :p

Re: Updatable Mesh

Posted: Sat Mar 01, 2014 8:14 pm
by Norbo
But I've noticed that I can't fly into caverns of the asteroid, might the MobileMesh be generating a ConvexHull instead of a triangle mesh?
MobileMesh can represent concavity; it doesn't use a convex hull.

If the MobileMeshSolidity is set to Solid, make sure the mesh is closed. I can't remember if I included verification for closedness off the top of my head, but a Solid open mesh could do all sorts of weird things if it existed.

Re: Updatable Mesh

Posted: Sat Mar 01, 2014 8:50 pm
by stino
The mesh is an isosurface from metabals, so it should be closed, and it renders closed. But i might be feeding it wrong data, need to check on that, although the outside feels like it collides the way it looks.

Setting the collision information of a morph-able entity would be this:

Code: Select all

 
this.physicsEntity.SetCollisionInformation(new CompoundCollidable(new CompoundShape(this.cellShapes.Values.ToList())));
where the shapes are made like this:

Code: Select all

var shape = new MobileMeshShape(vertices, indices, AffineTransform.Identity, MobileMeshSolidity.Clockwise);
this.cellShapes.Add(cell, new CompoundShapeEntry(shape));
is this the way you designed it?
Because I get that the Shape contains the actual shape data, but i'm not entirely sure yet as to what the Collidable exactly does?

Re: Updatable Mesh

Posted: Sat Mar 01, 2014 9:41 pm
by stino
Norbo wrote:MobileMesh can represent concavity; it doesn't use a convex hull.d.
Why is the constructor of MobileMeshShape calling ConvexHullHelper.GetConvexHull then?
It just threw an exception about a degenerate triangle.

Code: Select all

var shape = new MobileMeshShape(vertices, indices, AffineTransform.Identity, MobileMeshSolidity.Clockwise);
With vertices:

Code: Select all

{BEPUutilities.Vector3[3]}
  {-12, -13,342, 12}
  {-12, -12, 12,458}
  {-12,71, -12, 12}
and indices just 0 1 2.

This is now happening because I've split up the asteroid into the multiple parts, and this part seems to exist out of a single triangle.
I could check if index count = 3 to use a TriangleShape instead of MobileMeshShape to fix this, but that doesn't explain why the ConvexHullHelper is throwing the exception :D

Re: Updatable Mesh

Posted: Sat Mar 01, 2014 9:56 pm
by Norbo
is this the way you designed it?
Because I get that the Shape contains the actual shape data, but i'm not entirely sure yet as to what the Collidable exactly does?
There are three levels:
1) Entity: an object capable of motion (dynamic or kinematic). Has an EntityCollidable that acts as its proxy in the collision pipeline.
2) Collidable: an object which can collide with other collidables to generate contacts (a subclass of BroadPhaseEntry, which covers all objects which live in the broad phase). Has a collision shape.
3) CollisionShape: contains local collision geometry.

The reasons for the separation are:
-Because CollisionShapes contain strictly local information, they can be shared between multiple collidables. For example, one MobileMeshShape could be used by a hundred different MobileMeshCollidables. (There's one exception to this: the StaticGroup. But I wouldn't worry about that detail too much, since the StaticGroup is likely going to get deleted completely when the broad phase gets rewritten soon.)
-Not all Collidables are EntityCollidables (that is, used by entities). The StaticMesh, InstancedMesh, Terrain, and StaticGroup are all Collidables, but since they're designed to be totally stationary, they can't be used by entities.
-The Entity class focuses on the general physical properties of an object and not collision detection representation. The Collidable isolates that logic.

More information and examples can be found in the EntityConstructionDemo in the BEPUphysicsDemos project.
Why is the constructor of MobileMeshShape calling ConvexHullHelper.GetConvexHull then?
The hull is computed and cached to accelerate the computation of a tight bounding box each frame. The convex hull operation prunes out all redundant or internal points leaving only extreme points capable of contributing to the bounding box.
I could check if index count = 3 to use a TriangleShape instead of MobileMeshShape to fix this, but that doesn't explain why the ConvexHullHelper is throwing the exception
Is this in the most recent version? I can't reproduce an exception with that data in the latest changeset. There were some fixes made in v1.3.0 that might be relevant.

Re: Updatable Mesh

Posted: Sun Mar 09, 2014 7:26 pm
by stino
Ye sorry, forgot to mention that I didn't update to the latest version, so yes, it could be fixed. Though it kind of made sense that degenerate triangles make problems for a convex hull.
Updating is rather difficult because I added implicit & explicit casts between Bepu Vector3 and SlimDX Vector3 and other structures and i would have to update all those casts.

but now i'm seeing some other issue, I hope i'm just forgetting to do something, or doing something wrong.
First the entity is created with a sphere shape as collider, since no geometry is generated at this point.

Code: Select all

            this.physicsEntity = new MorphableEntity(new SphereShape(radius), mass);
            this.physicsEntity.PositionUpdated+=physicsEntity_PositionUpdated;
When the iso surfaces are computed, i update the entity.
I'm extracting the vertex and index data from the isosurface's mesh:

Code: Select all

                var vertices = cell.Mesh.VertexStreams.GetStream<SlimDX.Vector3>("POSITION", 0).GetData().Select(i => (BEPUutilities.Vector3)i).ToArray();
                var indices = cell.Mesh.IndexStream.EnumerateIndices().Select(i => (int)i).ToArray();
                EntityShape shape;
                if (indices.Length > 3)
                {
                    shape = new MobileMeshShape(vertices, indices, AffineTransform.Identity, MobileMeshSolidity.Clockwise, out distributionInfo);
                }
                else if (indices.Length == 3)
                {  // use a triangle shape if only a triangle exists in this cell
                    shape = new TriangleShape(vertices[indices[0]], vertices[indices[1]], vertices[indices[2]]);
                }
                else return; // indices == 0? nothing to collide against.

                // vertices are relative to the center of the asteroid, not to the origin of the Cell. No translation required
                this.cellShapes.Add(cell, new CompoundShapeEntry(shape, RigidTransform.Identity, 1));
                this.physicsEntity.SetCollisionInformation(new CompoundCollidable(new CompoundShape(this.cellShapes.Values.ToList())));
cellshapes is just something so i can keep track of the collision shapes

Code: Select all

        private readonly Dictionary<TerrainCell, CompoundShapeEntry> cellShapes = new Dictionary<TerrainCell, CompoundShapeEntry>();
[code]

But when i do this and extract the vertices from the TriangleMesh again and render those, it matches exactly with the geometry.
[code]
                    //Temp Debug:
                    CompoundCollidable colinf = asteroid.Entity.CollisionInformation as CompoundCollidable;
                    CompoundShape cshape = colinf .Shape as CompoundShape;
                    foreach (var shape in cshape.Shapes)
                    {
                        MobileMeshShape mmshape = shape.Shape as MobileMeshShape;
                        if (mmshape != null)
                        { 
                            foreach (var vertex in mmshape.TriangleMesh.Data.Vertices)
                            {  
                                var instance = this.geometryInstances.Add(gizmoMesh, gizmoMaterial);
                                instance.Parameters.Matrix = Matrix.Translation(vertex) * asteroid.Transform;
                            }
                        }
                    }
The black ticks are XYZ axis arrows originating at the vertices.
Image
So i'd guess everything works, right?
But it doesn't.
I fly as your unmodified playerController from the demos (so, capsule shape?) with an added jetpack (applyImpulse) to the asteroid and i fly straight through the surface and hit something i'm not sure what it is.

I've also added raycasts from the player to the center of the asteroid in every frame, and they do seem to hit something, inside the asteroid:
Image

Am I skipping a step in the collision/entity code?

Re: Updatable Mesh

Posted: Mon Mar 10, 2014 1:19 am
by Norbo
The MobileMeshShape (and other shapes which have constructors which take potentially offset data) recenters the input onto the shape's center of mass. If the mesh is rendered assuming that the physics mesh has the same origin as the graphical mesh, the graphics and physics might not match.

Shapes which perform recentering output the center of mass from the constructor. For more information, check the shape recentering documentation and the GraphicMatchingDemo.

Re: Updatable Mesh

Posted: Mon Mar 10, 2014 10:15 am
by stino
Oh, i see, when the triangle mesh is created from all vertices in one quadrant, it still re-centers the entire mesh so that it's center is at 0 0 0?

Code: Select all

                BEPUutilities.Vector3 center = BEPUutilities.Vector3.Zero;
                EntityShape shape;
                if (indices.Length > 3)
                {
                    ShapeDistributionInformation distributionInfo;
                    shape = new MobileMeshShape(vertices, indices, AffineTransform.Identity, MobileMeshSolidity.Clockwise, out distributionInfo);
                    center = distributionInfo.Center;
                }
                else if (indices.Length == 3)
                {
                    shape = new TriangleShape(vertices[indices[0]], vertices[indices[1]], vertices[indices[2]], out center);
                }
                else return;


                this.cellShapes.Add(cell, new CompoundShapeEntry(shape, new RigidTransform(-center), 1));
That did it, yay!

EDIT: there still is a small offset, I'd guess the CompoundShape recenters again?
Yep, it does.

Re: Updatable Mesh

Posted: Thu Mar 13, 2014 12:37 pm
by stino
the SetCollisionInformation on the physics entity seems to be rather expensive. The shapes and collidable are created in a separate thread and then in the main update thread i call SetCollisionInformation with the collidable, and I get a very noticeable spike when updating the asteroids.

And calling SetCollisionInformation from the seperate thread seems to be not done.

Is there any way i can speed up the process of swapping the collision information? Or at least let it run outside of the main game loop?

Re: Updatable Mesh

Posted: Thu Mar 13, 2014 7:33 pm
by Norbo
The cost is probably from some entity property reinitialization. Specifically, if they aren't provided, it recomputes the inertia tensor and volume in v1.2.0 and before. If you pass in all the precomputed physical properties to the SetCollisionInformation function, most of the cost should be eliminated.

In v1.3.0 or above, these initialization costs are reduced and only occur during shape construction instead of on entity usage.

(You could also use SetCollisionInformation on another thread if the entity does not belong to the Space or if the Space is not updating, but it's generally nicer to just have an instant swap.)

Re: Updatable Mesh

Posted: Sat Mar 15, 2014 10:30 pm
by stino
if IgnoreShapeChanges is true, will SetCollisionInformation also recalculate the inertia tensor, I assumed it wouldn't.

Re: Updatable Mesh

Posted: Sat Mar 15, 2014 11:43 pm
by Norbo
It would indeed- the IgnoreShapeChanges property can be a little misleading when it comes to MorphableEntity. IgnoreShapeChanges is only checked when changes are made to the properties of the shape, not to the shape reference itself. In other words, changing the shape reference is considered a change to the entity, not to the shape.

The reason for this behavior is:
IgnoreShapeChanges exists to help with the case where a CollisionShape is shared among many Entity objects. Not every entity always needs to be updated in this case.

That behavior does not extend to the MorphableEntity since 1) changing a MorphableEntity's collidable affects only a single MorphableEntity, making the choice of whether or not to update properties extremely direct, and 2) MorphableEntity is a rarely used advanced feature where greater familiarity and control is assumed.