///<summary> /// Constructs a new InstancedMesh. ///</summary> ///<param name="meshShape">Shape to use for the instance.</param> ///<param name="worldTransform">Transform to use for the instance.</param> public InstancedMesh(InstancedMeshShape meshShape, AffineTransform worldTransform) { this.worldTransform = worldTransform; base.Shape = meshShape; Events = new ContactEventManager<InstancedMesh>(); }
/// <summary> /// Creates and instance of InstancedTriangleMesh /// Call the Static Method GetInstacedMesh to get the InstancedMeshShape obj /// </summary> /// <param name="InstancedMeshShape">The instanced mesh shape.</param> /// <param name="pos">The pos.</param> /// <param name="rotation">The rotation.</param> /// <param name="scale">The scale.</param> /// <param name="materialDescription">The material description.</param> /// <param name="TriangleSidedness">The triangle sidedness.</param> public InstancedTriangleMeshObject(InstancedMeshShape InstancedMeshShape, Vector3 pos, Matrix rotation, Vector3 scale, MaterialDescription materialDescription, TriangleSidedness TriangleSidedness = TriangleSidedness.Counterclockwise) { instancedMesh = new InstancedMesh(InstancedMeshShape,new BEPUphysics.MathExtensions.AffineTransform(scale,Quaternion.CreateFromRotationMatrix(rotation),pos)); instancedMesh.Material = new BEPUphysics.Materials.Material(materialDescription.StaticFriction, materialDescription.DynamicFriction, materialDescription.Bounciness); instancedMesh.Sidedness = TriangleSidedness; this.rotation = rotation; this.scale = scale; }
///<summary> /// Constructs a new InstancedMesh. ///</summary> ///<param name="meshShape">Shape to use for the instance.</param> ///<param name="worldTransform">Transform to use for the instance.</param> public InstancedMesh(InstancedMeshShape meshShape, AffineTransform worldTransform) { this.worldTransform = worldTransform; base.Shape = meshShape; collisionRules.group = CollisionRules.DefaultKinematicCollisionGroup; events = new ContactEventManager<InstancedMesh>(this); material = new Material(); materialChangedDelegate = OnMaterialChanged; material.MaterialChanged += materialChangedDelegate; }
/// <summary> /// Constructs a new demo. /// </summary> /// <param name="game">Game owning this demo.</param> public InstancedMeshDemo(DemosGame game) : base(game) { Vector3[] vertices; int[] indices; ModelDataExtractor.GetVerticesAndIndicesFromModel(game.Content.Load<Model>("guy"), out vertices, out indices); var meshShape = new InstancedMeshShape(vertices, indices); var random = new Random(); for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { //Create a transform and the instance of the mesh. var transform = new AffineTransform( new Vector3((float)random.NextDouble() * 6 + .5f, (float)random.NextDouble() * 6 + .5f, (float)random.NextDouble() * 6 + .5f), Quaternion.CreateFromAxisAngle(Vector3.Normalize(new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble())), (float)random.NextDouble() * 100), new Vector3(i * 2, 3, j * 2)); var mesh = new InstancedMesh(meshShape, transform); //Making the triangles one-sided makes collision detection a bit more robust, since the backsides of triangles won't try to collide with things //and 'pull' them back into the mesh. mesh.Sidedness = TriangleSidedness.Counterclockwise; Space.Add(mesh); game.ModelDrawer.Add(mesh); } } for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { //Drop a box on the mesh. Space.Add(new Box(new Vector3((i + 1) * 4, 10, (j + 1) * 4), 1, 1, 1, 10)); } } Space.Add(new Box(new Vector3(10, 0, 10), 20, 1, 20)); game.Camera.Position = new Vector3(10, 6, 30); }
/// <summary> /// Constructs a new demo. /// </summary> /// <param name="game">Game owning this demo.</param> public MutableStaticGroupTestDemo(DemosGame game) : base(game) { //Creating a bunch of separate StaticMeshes or kinematic Entity objects for an environment can pollute the broad phase. //This is because the broad phase implementation doesn't have guarantees about what elements can collide, so it has to //traverse the acceleration structure all the way down to pairs to figure it out. That can get expensive! //Individual objects, like StaticMeshes, can have very complicated geometry without hurting the broad phase because the broad phase //has no knowledge of the thousands of triangles in the mesh. The StaticMesh itself knows that the triangles within the mesh //never need to collide, so it never needs to test them against each other. //Similarly, the StaticGroup can be given a bunch of separate collidables. The broad phase doesn't directly know about these child collidables- //it only sees the StaticGroup. The StaticGroup knows that the things inside it can't ever collide with each other, so no tests are needed. //This avoids the performance problem! //To demonstrate, we'll be creating a set of static objects and giving them to a group to manage. var collidables = new List<Collidable>(); //Start with a whole bunch of boxes. These are entity collidables, but without entities! float xSpacing = 6; float ySpacing = 6; float zSpacing = 6; //NOTE: You might notice this demo takes a while to start, especially on the Xbox360. Do not fear! That's due to the creation of the graphics data, not the physics. //The physics can handle over 100,000 static objects pretty easily. The graphics, not so much :) //Try disabling the game.ModelDrawer.Add() lines and increasing the number of static objects. int xCount = 15; int yCount = 7; int zCount = 15; var random = new Random(5); for (int i = 0; i < xCount; i++) { for (int j = 0; j < yCount; j++) { for (int k = 0; k < zCount; k++) { //Create a transform and the instance of the mesh. var collidable = new ConvexCollidable<BoxShape>(new BoxShape((float)random.NextDouble() * 6 + .5f, (float)random.NextDouble() * 6 + .5f, (float)random.NextDouble() * 6 + .5f)); //This EntityCollidable isn't associated with an entity, so we must manually tell it where to sit by setting the WorldTransform. //This also updates its bounding box. collidable.WorldTransform = new RigidTransform( new Vector3(i * xSpacing - xCount * xSpacing * .5f, j * ySpacing + 3, k * zSpacing - zCount * zSpacing * .5f), Quaternion.CreateFromAxisAngle(Vector3.Normalize(new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble())), (float)random.NextDouble() * 100)); collidables.Add(collidable); } } } //Now create a bunch of instanced meshes too. xSpacing = 6; ySpacing = 6; zSpacing = 6; xCount = 10; yCount = 2; zCount = 10; Vector3[] vertices; int[] indices; ModelDataExtractor.GetVerticesAndIndicesFromModel(game.Content.Load<Model>("fish"), out vertices, out indices); var meshShape = new InstancedMeshShape(vertices, indices); for (int i = 0; i < xCount; i++) { for (int j = 0; j < yCount; j++) { for (int k = 0; k < zCount; k++) { //Create a transform and the instance of the mesh. var transform = new AffineTransform( new Vector3((float)random.NextDouble() * 6 + .5f, (float)random.NextDouble() * 6 + .5f, (float)random.NextDouble() * 6 + .5f), Quaternion.CreateFromAxisAngle(Vector3.Normalize(new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble())), (float)random.NextDouble() * 100), new Vector3(i * xSpacing - xCount * xSpacing * .5f, j * ySpacing + 50, k * zSpacing - zCount * zSpacing * .5f)); var mesh = new InstancedMesh(meshShape, transform); //Making the triangles one-sided makes collision detection a bit more robust, since the backsides of triangles won't try to collide with things //and 'pull' them back into the mesh. mesh.Sidedness = TriangleSidedness.Counterclockwise; collidables.Add(mesh); } } } var ground = new ConvexCollidable<BoxShape>(new BoxShape(200, 1, 200)); ground.WorldTransform = new RigidTransform(new Vector3(0, -3, 0), Quaternion.Identity); collidables.Add(ground); var group = new StaticGroup(collidables); var removed = new RawList<Collidable>(); var contained = new RawList<Collidable>(); group.Shape.CollidableTree.CollectLeaves(contained); for (int i = 0; i < 100000; ++i) { for (int collidableIndex = contained.Count - 1; collidableIndex >= 0; --collidableIndex) { if (random.NextDouble() < 0.6) { group.Shape.Remove(contained[collidableIndex]); removed.Add(contained[collidableIndex]); contained.FastRemoveAt(collidableIndex); } } for (int collidableIndex = removed.Count - 1; collidableIndex >= 0; --collidableIndex) { if (random.NextDouble() < 0.4) { group.Shape.Add(removed[collidableIndex]); contained.Add(removed[collidableIndex]); removed.FastRemoveAt(collidableIndex); } } } for (int i = 0; i < contained.Count; ++i) { game.ModelDrawer.Add(contained[i]); } Space.Add(group); //Create a bunch of dynamic boxes to drop on the staticswarm. xCount = 8; yCount = 3; zCount = 8; xSpacing = 3f; ySpacing = 5f; zSpacing = 3f; for (int i = 0; i < xCount; i++) for (int j = 0; j < zCount; j++) for (int k = 0; k < yCount; k++) { Space.Add(new Box(new Vector3( xSpacing * i - (xCount - 1) * xSpacing / 2f, 100 + k * (ySpacing), 2 + zSpacing * j - (zCount - 1) * zSpacing / 2f), 1, 1, 1, 10)); } game.Camera.Position = new Vector3(0, 60, 90); }
///<summary> /// Constructs a new InstancedMesh. ///</summary> ///<param name="meshShape">Shape to use for the instance.</param> public InstancedMesh(InstancedMeshShape meshShape) : this(meshShape, AffineTransform.Identity) { }
/// <summary> /// Constructs a new demo. /// </summary> /// <param name="game">Game owning this demo.</param> public CharacterStressierTestDemo(DemosGame game) : base(game) { //Load in mesh data and create the group. Vector3[] staticTriangleVertices; int[] staticTriangleIndices; var playgroundModel = game.Content.Load<Model>("playground"); //This is a little convenience method used to extract vertices and indices from a model. //It doesn't do anything special; any approach that gets valid vertices and indices will work. ModelDataExtractor.GetVerticesAndIndicesFromModel(playgroundModel, out staticTriangleVertices, out staticTriangleIndices); var meshShape = new InstancedMeshShape(staticTriangleVertices, staticTriangleIndices); var meshes = new List<Collidable>(); var xSpacing = 400; var ySpacing = 400; var xCount = 11; var yCount = 11; for (int i = 0; i < xCount; i++) { for (int j = 0; j < yCount; j++) { var staticMesh = new InstancedMesh(meshShape, new AffineTransform(Matrix3x3.Identity, new Vector3(-xSpacing * (xCount - 1) / 2 + i * xSpacing, 0, -ySpacing * (yCount - 1) / 2 + j * ySpacing))); staticMesh.Sidedness = TriangleSidedness.Counterclockwise; Space.Add(staticMesh); //meshes.Add(staticMesh); game.ModelDrawer.Add(staticMesh); } } //var group = new StaticGroup(meshes); //Space.Add(group); //To demonstrate, we'll be creating a set of static objects and giving them to a group to manage. var collidables = new List<Collidable>(); //Start with a whole bunch of boxes. These are entity collidables, but without entities! xSpacing = 25; ySpacing = 16; float zSpacing = 25; xCount = 25; yCount = 7; int zCount = 25; var random = new Random(); for (int i = 0; i < xCount; i++) { for (int j = 0; j < yCount; j++) { for (int k = 0; k < zCount; k++) { //Create a transform and the instance of the mesh. var collidable = new ConvexCollidable<BoxShape>(new BoxShape((float)random.NextDouble() * 25 + 5.5f, (float)random.NextDouble() * 25 + 5.5f, (float)random.NextDouble() * 25 + 5.5f)); //This EntityCollidable isn't associated with an entity, so we must manually tell it where to sit by setting the WorldTransform. //This also updates its bounding box. collidable.WorldTransform = new RigidTransform( new Vector3(i * xSpacing - xCount * xSpacing * .5f, j * ySpacing + -50, k * zSpacing - zCount * zSpacing * .5f), Quaternion.CreateFromAxisAngle(Vector3.Normalize(new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble())), (float)random.NextDouble() * 100)); collidables.Add(collidable); game.ModelDrawer.Add(collidable); } } } var group = new StaticGroup(collidables); Space.Add(group); //Now drop the characters on it! var numColumns = 16; var numRows = 16; var numHigh = 16; float separation = 24; for (int i = 0; i < numRows; i++) for (int j = 0; j < numColumns; j++) for (int k = 0; k < numHigh; k++) { var character = new CharacterController(); character.Body.Position = new Vector3( separation * i - numRows * separation / 2, 50f + k * separation, separation * j - numColumns * separation / 2); characters.Add(character); Space.Add(character); } game.Camera.Position = new Vector3(0, 10, 40); //Dump some boxes on top of the characters for fun. numColumns = 16; numRows = 16; numHigh = 8; separation = 24; for (int i = 0; i < numRows; i++) for (int j = 0; j < numColumns; j++) for (int k = 0; k < numHigh; k++) { var toAdd = new Box( new Vector3( separation * i - numRows * separation / 2, 52f + k * separation, separation * j - numColumns * separation / 2), 0.8f, 0.8f, 0.8f, 15); toAdd.PositionUpdateMode = BEPUphysics.PositionUpdating.PositionUpdateMode.Continuous; Space.Add(toAdd); } }
/// <summary> /// Constructs a new demo. /// </summary> /// <param name="game">Game owning this demo.</param> public CharacterStressTestDemo(DemosGame game) : base(game) { //Load in mesh data and create the group. Vector3[] staticTriangleVertices; int[] staticTriangleIndices; var playgroundModel = game.Content.Load<Model>("playground"); //This is a little convenience method used to extract vertices and indices from a model. //It doesn't do anything special; any approach that gets valid vertices and indices will work. ModelDataExtractor.GetVerticesAndIndicesFromModel(playgroundModel, out staticTriangleVertices, out staticTriangleIndices); var meshShape = new InstancedMeshShape(staticTriangleVertices, staticTriangleIndices); var meshes = new List<Collidable>(); var xSpacing = 400; var ySpacing = 400; var xCount = 11; var yCount = 11; for (int i = 0; i < xCount; i++) { for (int j = 0; j < yCount; j++) { var staticMesh = new InstancedMesh(meshShape, new AffineTransform(Matrix3x3.Identity, new Vector3(-xSpacing * (xCount - 1) / 2 + i * xSpacing, 0, -ySpacing * (yCount - 1) / 2 + j * ySpacing))); staticMesh.Sidedness = TriangleSidedness.Counterclockwise; Space.Add(staticMesh); //meshes.Add(staticMesh); game.ModelDrawer.Add(staticMesh); } } //var group = new StaticGroup(meshes); //Space.Add(group); //Now drop the characters on it! var numColumns = 16; var numRows = 16; var numHigh = 8; float separation = 64; for (int i = 0; i < numRows; i++) for (int j = 0; j < numColumns; j++) for (int k = 0; k < numHigh; k++) { var character = new CharacterController(); character.Body.Position = new Vector3( separation * i - numRows * separation / 2, 40f + k * separation, separation * j - numColumns * separation / 2); characters.Add(character); Space.Add(character); } //Now drop the ball-characters on it! numColumns = 16; numRows = 16; numHigh = 8; separation = 64; for (int i = 0; i < numRows; i++) for (int j = 0; j < numColumns; j++) for (int k = 0; k < numHigh; k++) { var character = new SphereCharacterController(); character.Body.Position = new Vector3( separation * i - numRows * separation / 2, 48f + k * separation, separation * j - numColumns * separation / 2); sphereCharacters.Add(character); Space.Add(character); } game.Camera.Position = new Vector3(0, 10, 40); //Dump some boxes on top of the characters for fun. numColumns = 16; numRows = 16; numHigh = 8; separation = 64; for (int i = 0; i < numRows; i++) for (int j = 0; j < numColumns; j++) for (int k = 0; k < numHigh; k++) { var toAdd = new Box( new Vector3( separation * i - numRows * separation / 2, 52f + k * separation, separation * j - numColumns * separation / 2), 0.8f, 0.8f, 0.8f, 15); toAdd.PositionUpdateMode = BEPUphysics.PositionUpdating.PositionUpdateMode.Continuous; Space.Add(toAdd); } }