protected virtual void Remove(int contactIndex)
 {
     Contact removing = contacts.Elements[contactIndex];
     contacts.FastRemoveAt(contactIndex);
     OnRemoved(removing);
     unusedContacts.GiveBack(removing);
 }
        private static void MaintainEdge(int a, int b, RawList <int> edges)
        {
            bool contained = false;
            int  index     = 0;

            for (int k = 0; k < edges.Count; k += 2)
            {
                if ((edges[k] == a && edges[k + 1] == b) || (edges[k] == b && edges[k + 1] == a))
                {
                    contained = true;
                    index     = k;
                }
            }
            //If it isn't present, add it to the edge list.
            if (!contained)
            {
                edges.Add(a);
                edges.Add(b);
            }
            else
            {
                //If it is present, that means both edge-connected triangles were deleted now, so get rid of it.
                edges.FastRemoveAt(index + 1);
                edges.FastRemoveAt(index);
            }
        }
Exemple #3
0
        /// <summary>
        /// Removes redundant points.  Two points are redundant if they occupy the same hash grid cell.
        /// </summary>
        /// <param name="points">List of points to prune.</param>
        /// <param name="cellSize">Size of cells to determine redundancy.</param>
        public static void RemoveRedundantPoints(RawList <Vector3> points, double cellSize)
        {
            var set = BlockedCellSets.Take();

            for (int i = points.Count - 1; i >= 0; --i)
            {
                var element = points.Elements[i];
                var cell    = new BlockedCell
                {
                    X = (int)Math.Floor(element.X / cellSize),
                    Y = (int)Math.Floor(element.Y / cellSize),
                    Z = (int)Math.Floor(element.Z / cellSize)
                };
                if (set.Contains(cell))
                {
                    points.FastRemoveAt(i);
                }
                else
                {
                    set.Add(cell);
                    //TODO: Consider adding adjacent cells to guarantee that a point on the border between two cells will still detect the presence
                    //of a point on the opposite side of that border.
                }
            }
            set.Clear();
            BlockedCellSets.GiveBack(set);
        }
Exemple #4
0
        void DeactivateObjects()
        {
            //Deactivate only some objects each frame.
            int numberOfEntitiesDeactivated = 0;
            int numberOfIslandsChecked      = 0;
            int originalIslandCount         = simulationIslands.Count;



            while (numberOfEntitiesDeactivated < maximumDeactivationAttemptsPerFrame && simulationIslands.Count > 0 && numberOfIslandsChecked < originalIslandCount)
            {
                deactivationIslandIndex = (deactivationIslandIndex + 1) % simulationIslands.Count;
                var island = simulationIslands.Elements[deactivationIslandIndex];
                if (island.memberCount == 0)
                {
                    //Found an orphan island left over from merge procedures or removal procedures.
                    //Shoo it on out.
                    simulationIslands.FastRemoveAt(deactivationIslandIndex);
                    GiveBackIsland(island);
                }
                else
                {
                    island.TryToDeactivate();
                    numberOfEntitiesDeactivated += island.memberCount;
                }
                ++numberOfIslandsChecked;
            }
        }
Exemple #5
0
        void RemoveStaleOverlaps()
        {
            //We don't need to do any synchronization or queueing here; just remove everything directly.
            ApplySolverUpdateableChangesDirectly = true;

            //Remove stale objects.
            for (int i = narrowPhasePairs.count - 1; i >= 0; i--)
            {
                var pair = narrowPhasePairs.Elements[i];

                //A stale overlap is a pair which has not been updated, but not because of inactivity.

                //Pairs between two inactive shapes are not updated because the broad phase does not output overlaps
                //between inactive entries.  We need to keep such pairs around, otherwise when they wake up, lots of extra work
                //will be needed and quality will suffer.

                //The classic stale overlap is two objects which have moved apart.  Because the bounding boxes no longer overlap,
                //the broad phase does not generate an overlap for them.  Obviously, we should get rid of such a pair.  
                //Any such pair will have at least one active member.  Having velocity requires activity and teleportation will activate the object.

                //There's another sneaky kind of stale overlap.  Consider a sleeping dynamic object on a Terrain.  The Terrain, being a static object,
                //is considered inactive.  The sleeping dynamic object is also inactive.  Now, remove the sleeping dynamic object.
                //Both objects are still considered inactive.  But the pair is clearly stale- one of its members doesn't even exist anymore!
                //This has nasty side effects, like retaining memory.  To solve this, also check to see if either member does not belong to the simulation.


                if (pair.NeedsUpdate && //If we didn't receive an update in the previous narrow phase run and...
                    (pair.broadPhaseOverlap.entryA.IsActive || pair.broadPhaseOverlap.entryB.IsActive || //one of us is active or..
                    pair.broadPhaseOverlap.entryA.BroadPhase == null || pair.broadPhaseOverlap.entryB.BroadPhase == null)) //one of us doesn't exist anymore...
                {
                    //Get rid of the pair!
                    if (RemovingPair != null)
                        RemovingPair(pair);
                    narrowPhasePairs.FastRemoveAt(i);
                    overlapMapping.Remove(pair.BroadPhaseOverlap);
                    //The clean up will issue an order to get rid of the solver updateable if it is active.
                    //To avoid a situation where the solver updateable outlives the pair but is available for re-use
                    //because of the factory giveback here, the updateable is removed directly (ApplySolverUpdateableChangesDirectly = true).
                    pair.CleanUp();
                    pair.Factory.GiveBack(pair);


                }
                else
                {
                    pair.NeedsUpdate = true;

                }

            }

            ApplySolverUpdateableChangesDirectly = false;


        }
 ///<summary>
 /// Removes a connection reference from the member.
 ///</summary>
 ///<param name="connection">Reference to remove.</param>
 ///<param name="index">Index of the connection in this member's list</param>
 internal void RemoveConnectionReference(SimulationIslandConnection connection, int index)
 {
     if (connections.Count > index)
     {
         connections.FastRemoveAt(index);
         if (connections.Count > index)
         {
             connections.Elements[index].SetListIndex(this, index);
         }
     }
 }
Exemple #7
0
 void RemoveStaleOverlaps()
 {
     //Remove stale objects.
     for (int i = narrowPhasePairs.count - 1; i >= 0; i--)
     {
         var pair = narrowPhasePairs.Elements[i];
         if (pair.NeedsUpdate &&
             //Overlap will not be refreshed if entries are inactive, but shouldn't remove narrow phase pair.
             (pair.BroadPhaseOverlap.entryA.IsActive || pair.BroadPhaseOverlap.entryB.IsActive))
         {
             narrowPhasePairs.FastRemoveAt(i);
             OnRemovePair(pair);
         }
         else
         {
             pair.NeedsUpdate = true;
         }
     }
 }
 internal void RemovePair(CollidablePairHandler pair, ref int index)
 {
     if (pairs.count > index)
     {
         pairs.FastRemoveAt(index);
         if (pairs.count > index)
         {
             var endPair = pairs.Elements[index];
             if (endPair.CollidableA == this)
             {
                 endPair.listIndexA = index;
             }
             else
             {
                 endPair.listIndexB = index;
             }
         }
     }
     index = -1;
 }
        public override void Update(float dt)
        {
            for (int i = removedEntities.Count - 1; i >= 0; --i)
            {
                if (random.NextDouble() < 0.2)
                {
                    var entity = removedEntities[i];
                    addedEntities.Add(entity);
                    Space.Add(entity);
                    removedEntities.FastRemoveAt(i);
                }
            }
            for (int i = addedEntities.Count - 1; i >= 0; --i)
            {
                if (random.NextDouble() < 0.02)
                {
                    var entity = addedEntities[i];
                    removedEntities.Add(entity);
                    Space.Remove(entity);
                    addedEntities.FastRemoveAt(i);
                }
            }

            if (Game.MouseInput.MiddleButton != Microsoft.Xna.Framework.Input.ButtonState.Pressed)
            {
                for (int i = 0; i < 20; i++)
                {
                    var entity = addedEntities[random.Next(addedEntities.Count)];
                    entity.Position = new Vector3(
                        (float)(random.NextDouble() - 0.5f) * width,
                        (float)(random.NextDouble() - 0.5f) * height,
                        (float)(random.NextDouble() - 0.5f) * length);
                }
            }
            base.Update(dt);
        }
Exemple #10
0
        private static void RemoveInsidePoints(RawList <Vector3> points, RawList <int> triangleIndices,
                                               RawList <int> outsidePoints)
        {
            RawList <int> insidePoints = CommonResources.GetIntList();

            //We're going to remove points from this list as we go to prune it down to the truly inner points.
            insidePoints.AddRange(outsidePoints);
            outsidePoints.Clear();

            for (int i = 0; i < triangleIndices.Count && insidePoints.Count > 0; i += 3)
            {
                //Compute the triangle's plane in point-normal representation to test other points against.
                Vector3 normal;
                FindNormal(triangleIndices, points, i, out normal);
                Vector3 p = points.Elements[triangleIndices.Elements[i]];

                for (int j = insidePoints.Count - 1; j >= 0; --j)
                {
                    //Offset from the triangle to the current point, tested against the normal, determines if the current point is visible
                    //from the triangle face.
                    Vector3 offset;
                    Vector3.Subtract(ref points.Elements[insidePoints.Elements[j]], ref p, out offset);
                    float dot;
                    Vector3.Dot(ref offset, ref normal, out dot);
                    //If it's visible, then it's outside!
                    if (dot > 0)
                    {
                        //This point is known to be on the outside; put it on the outside!
                        outsidePoints.Add(insidePoints.Elements[j]);
                        insidePoints.FastRemoveAt(j);
                    }
                }
            }

            CommonResources.GiveBack(insidePoints);
        }
        /// <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>
        /// Identifies the indices of points in a set which are on the outer convex hull of the set.
        /// </summary>
        /// <param name="points">List of points in the set.</param>
        /// <param name="outputTriangleIndices">List of indices into the input point set composing the triangulated surface of the convex hull.
        /// Each group of 3 indices represents a triangle on the surface of the hull.</param>
        public static void GetConvexHull(RawList <Vector3> points, RawList <int> outputTriangleIndices)
        {
            if (points.Count == 0)
            {
                throw new ArgumentException("Point set must have volume.");
            }
            RawList <int> outsidePoints = CommonResources.GetIntList();

            if (outsidePoints.Capacity < points.Count - 4)
            {
                outsidePoints.Capacity = points.Count - 4;
            }

            //Build the initial tetrahedron.
            //It will also give us the location of a point which is guaranteed to be within the
            //final convex hull.  We can use this point to calibrate the winding of triangles.
            //A set of outside point candidates (all points other than those composing the tetrahedron) will be returned in the outsidePoints list.
            //That list will then be further pruned by the RemoveInsidePoints call.
            Vector3 insidePoint;

            ComputeInitialTetrahedron(points, outsidePoints, outputTriangleIndices, out insidePoint);

            //Compute outside points.
            RemoveInsidePoints(points, outputTriangleIndices, outsidePoints);

            var edges        = CommonResources.GetIntList();
            var toRemove     = CommonResources.GetIntList();
            var newTriangles = CommonResources.GetIntList();

            //We're now ready to begin the main loop.
            while (outsidePoints.Count > 0)
            {
                //While the convex hull is incomplete...
                for (int k = 0; k < outputTriangleIndices.Count; k += 3)
                {
                    //Find the normal of the triangle
                    Vector3 normal;
                    FindNormal(outputTriangleIndices, points, k, out normal);

                    //Get the furthest point in the direction of the normal.
                    int     maxIndexInOutsideList = GetExtremePoint(ref normal, points, outsidePoints);
                    int     maxIndex = outsidePoints.Elements[maxIndexInOutsideList];
                    Vector3 maximum  = points.Elements[maxIndex];

                    //If the point is beyond the current triangle, continue.
                    Vector3 offset;
                    Vector3.Subtract(ref maximum, ref points.Elements[outputTriangleIndices.Elements[k]], out offset);
                    float dot;
                    Vector3.Dot(ref normal, ref offset, out dot);
                    if (dot > 0)
                    {
                        //It's been picked! Remove the maximum point from the outside.
                        outsidePoints.FastRemoveAt(maxIndexInOutsideList);
                        //Remove any triangles that can see the point, including itself!
                        edges.Clear();
                        toRemove.Clear();
                        for (int n = outputTriangleIndices.Count - 3; n >= 0; n -= 3)
                        {
                            //Go through each triangle, if it can be seen, delete it and use maintainEdge on its edges.
                            if (IsTriangleVisibleFromPoint(outputTriangleIndices, points, n, ref maximum))
                            {
                                //This triangle can see it!
                                //TODO: CONSIDER CONSISTENT WINDING HAPPYTIMES
                                MaintainEdge(outputTriangleIndices[n], outputTriangleIndices[n + 1], edges);
                                MaintainEdge(outputTriangleIndices[n], outputTriangleIndices[n + 2], edges);
                                MaintainEdge(outputTriangleIndices[n + 1], outputTriangleIndices[n + 2], edges);
                                //Because fast removals are being used, the order is very important.
                                //It's pulling indices in from the end of the list in order, and also ensuring
                                //that we never issue a removal order beyond the end of the list.
                                outputTriangleIndices.FastRemoveAt(n + 2);
                                outputTriangleIndices.FastRemoveAt(n + 1);
                                outputTriangleIndices.FastRemoveAt(n);
                            }
                        }
                        //Create new triangles.
                        for (int n = 0; n < edges.Count; n += 2)
                        {
                            //For each edge, create a triangle with the extreme point.
                            newTriangles.Add(edges[n]);
                            newTriangles.Add(edges[n + 1]);
                            newTriangles.Add(maxIndex);
                        }
                        //Only verify the windings of the new triangles.
                        VerifyWindings(newTriangles, points, ref insidePoint);
                        outputTriangleIndices.AddRange(newTriangles);
                        newTriangles.Clear();

                        //Remove all points from the outsidePoints if they are inside the polyhedron
                        RemoveInsidePoints(points, outputTriangleIndices, outsidePoints);

                        //The list has been significantly messed with, so restart the loop.
                        break;
                    }
                }
            }


            CommonResources.GiveBack(outsidePoints);
            CommonResources.GiveBack(edges);
            CommonResources.GiveBack(toRemove);
            CommonResources.GiveBack(newTriangles);
        }
        public override void Update(float dt)
        {
            //Add previously removed characters.
            for (int i = removedCharacters.Count - 1; i >= 0; --i)
            {
                if (random.NextDouble() < 0.2)
                {
                    Space.Add(removedCharacters[i]);
                    removedCharacters.FastRemoveAt(i);
                }
            }

            for (int i = removedSphereCharacters.Count - 1; i >= 0; --i)
            {
                if (random.NextDouble() < 0.2)
                {
                    Space.Add(removedSphereCharacters[i]);
                    removedSphereCharacters.FastRemoveAt(i);
                }
            }

            //Tell all the characters to run around randomly.
            for (int i = 0; i < characters.Count; i++)
            {
                if (characters[i].Space != null)
                {
                    if (random.NextDouble() < 0.02)
                    {
                        removedCharacters.Add(characters[i]);
                        Space.Remove(characters[i]);
                    }
                    else
                    {
                        characters[i].HorizontalMotionConstraint.MovementDirection = new Vector2((float)(random.NextDouble() * 2 - 1), (float)(random.NextDouble() * 2 - 1));
                        if (random.NextDouble() < .01f)
                        {
                            characters[i].Jump();
                        }

                        var next = random.NextDouble();
                        if (next < .01)
                        {
                            //Note: The character's graphic won't represent the crouching process properly since we're not remove/readding it.
                            if (next < .005f && characters[i].StanceManager.CurrentStance == Stance.Standing)
                            {
                                characters[i].StanceManager.DesiredStance = Stance.Crouching;
                            }
                            else
                            {
                                characters[i].StanceManager.DesiredStance = Stance.Standing;
                            }
                        }
                    }
                }
            }

            //Tell the sphere characters to run around too.
            for (int i = 0; i < sphereCharacters.Count; i++)
            {
                if (sphereCharacters[i].Space != null)
                {
                    if (random.NextDouble() < 0.02)
                    {
                        removedSphereCharacters.Add(sphereCharacters[i]);
                        Space.Remove(sphereCharacters[i]);
                    }
                    else
                    {
                        sphereCharacters[i].HorizontalMotionConstraint.MovementDirection = new Vector2((float)(random.NextDouble() * 2 - 1), (float)(random.NextDouble() * 2 - 1));
                        if (random.NextDouble() < .01f)
                        {
                            sphereCharacters[i].Jump();
                        }
                    }
                }
            }


            base.Update(dt);
        }
Exemple #14
0
 private static void MaintainEdge(int a, int b, RawList<int> edges)
 {
     bool contained = false;
     int index = 0;
     for (int k = 0; k < edges.Count; k += 2)
     {
         if ((edges[k] == a && edges[k + 1] == b) || (edges[k] == b && edges[k + 1] == a))
         {
             contained = true;
             index = k;
         }
     }
     //If it isn't present, add it to the edge list.
     if (!contained)
     {
         edges.Add(a);
         edges.Add(b);
     }
     else
     {
         //If it is present, that means both edge-connected triangles were deleted now, so get rid of it.
         edges.FastRemoveAt(index + 1);
         edges.FastRemoveAt(index);
     }
 }
Exemple #15
0
        /// <summary>
        /// Identifies the indices of points in a set which are on the outer convex hull of the set.
        /// </summary>
        /// <param name="points">List of points in the set.</param>
        /// <param name="outputTriangleIndices">List of indices composing the triangulated surface of the convex hull.
        /// Each group of 3 indices represents a triangle on the surface of the hull.</param>
        public static void GetConvexHull(RawList<Vector3> points, RawList<int> outputTriangleIndices)
        {
            if (points.Count == 0)
            {
                throw new ArgumentException("Point set must have volume.");
            }
            RawList<int> outsidePoints = CommonResources.GetIntList();
            if (outsidePoints.Capacity < points.Count - 4)
                outsidePoints.Capacity = points.Count - 4;

            //Build the initial tetrahedron.
            //It will also give us the location of a point which is guaranteed to be within the
            //final convex hull.  We can use this point to calibrate the winding of triangles.
            //A set of outside point candidates (all points other than those composing the tetrahedron) will be returned in the outsidePoints list.
            //That list will then be further pruned by the RemoveInsidePoints call.
            Vector3 insidePoint;
            ComputeInitialTetrahedron(points, outsidePoints, outputTriangleIndices, out insidePoint);

            //Compute outside points.
            RemoveInsidePoints(points, outputTriangleIndices, outsidePoints);

            var edges = CommonResources.GetIntList();
            var toRemove = CommonResources.GetIntList();
            var newTriangles = CommonResources.GetIntList();

            //We're now ready to begin the main loop.
            while (outsidePoints.Count > 0)
            {
                //While the convex hull is incomplete...
                for (int k = 0; k < outputTriangleIndices.Count; k += 3)
                {
                    //Find the normal of the triangle
                    Vector3 normal;
                    FindNormal(outputTriangleIndices, points, k, out normal);

                    //Get the furthest point in the direction of the normal.
                    int maxIndexInOutsideList = GetExtremePoint(ref normal, points, outsidePoints);
                    int maxIndex = outsidePoints.Elements[maxIndexInOutsideList];
                    Vector3 maximum = points.Elements[maxIndex];

                    //If the point is beyond the current triangle, continue.
                    Vector3 offset;
                    Vector3.Subtract(ref maximum, ref points.Elements[outputTriangleIndices.Elements[k]], out offset);
                    float dot;
                    Vector3.Dot(ref normal, ref offset, out dot);
                    if (dot > 0)
                    {
                        //It's been picked! Remove the maximum point from the outside.
                        outsidePoints.FastRemoveAt(maxIndexInOutsideList);
                        //Remove any triangles that can see the point, including itself!
                        edges.Clear();
                        toRemove.Clear();
                        for (int n = outputTriangleIndices.Count - 3; n >= 0; n -= 3)
                        {
                            //Go through each triangle, if it can be seen, delete it and use maintainEdge on its edges.
                            if (IsTriangleVisibleFromPoint(outputTriangleIndices, points, n, ref maximum))
                            {
                                //This triangle can see it!
                                //TODO: CONSIDER CONSISTENT WINDING HAPPYTIMES
                                MaintainEdge(outputTriangleIndices[n], outputTriangleIndices[n + 1], edges);
                                MaintainEdge(outputTriangleIndices[n], outputTriangleIndices[n + 2], edges);
                                MaintainEdge(outputTriangleIndices[n + 1], outputTriangleIndices[n + 2], edges);
                                //Because fast removals are being used, the order is very important.
                                //It's pulling indices in from the end of the list in order, and also ensuring
                                //that we never issue a removal order beyond the end of the list.
                                outputTriangleIndices.FastRemoveAt(n + 2);
                                outputTriangleIndices.FastRemoveAt(n + 1);
                                outputTriangleIndices.FastRemoveAt(n);

                            }
                        }
                        //Create new triangles.
                        for (int n = 0; n < edges.Count; n += 2)
                        {
                            //For each edge, create a triangle with the extreme point.
                            newTriangles.Add(edges[n]);
                            newTriangles.Add(edges[n + 1]);
                            newTriangles.Add(maxIndex);
                        }
                        //Only verify the windings of the new triangles.
                        VerifyWindings(newTriangles, points, ref insidePoint);
                        outputTriangleIndices.AddRange(newTriangles);
                        newTriangles.Clear();

                        //Remove all points from the outsidePoints if they are inside the polyhedron
                        RemoveInsidePoints(points, outputTriangleIndices, outsidePoints);

                        //The list has been significantly messed with, so restart the loop.
                        break;
                    }
                }
            }


            CommonResources.GiveBack(outsidePoints);
            CommonResources.GiveBack(edges);
            CommonResources.GiveBack(toRemove);
            CommonResources.GiveBack(newTriangles);
        }
Exemple #16
0
        /// <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!
            Fix64 xSpacing = 6;
            Fix64 ySpacing = 6;
            Fix64 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((Fix64)random.NextDouble() * 6 + .5m, (Fix64)random.NextDouble() * 6 + .5m, (Fix64)random.NextDouble() * 6 + .5m));

                        //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 * .5m, j * ySpacing + 3, k * zSpacing - zCount * zSpacing * .5m),
                            Quaternion.CreateFromAxisAngle(Vector3.Normalize(new Vector3((Fix64)random.NextDouble(), (Fix64)random.NextDouble(), (Fix64)random.NextDouble())), (Fix64)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((Fix64)random.NextDouble() * 6 + .5m, (Fix64)random.NextDouble() * 6 + .5m, (Fix64)random.NextDouble() * 6 + .5m),
                            Quaternion.CreateFromAxisAngle(Vector3.Normalize(new Vector3((Fix64)random.NextDouble(), (Fix64)random.NextDouble(), (Fix64)random.NextDouble())), (Fix64)random.NextDouble() * 100),
                            new Vector3(i * xSpacing - xCount * xSpacing * .5m, j * ySpacing + 50, k * zSpacing - zCount * zSpacing * .5m));
                        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 = 3;
            ySpacing = 5;
            zSpacing = 3;
            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 / 2,
                                              100 + k * (ySpacing),
                                              2 + zSpacing * j - (zCount - 1) * zSpacing / 2),
                                          1, 1, 1, 10));
                    }
                }
            }



            game.Camera.Position = new Vector3(0, 60, 90);
        }