///<summary> /// Constructs a new space for things to live in. ///</summary> ///<param name="parallelLooper">Used by the space to perform multithreaded updates. Pass null if multithreading is not required.</param> public Space(IParallelLooper parallelLooper) { timeStepSettings = new TimeStepSettings(); this.parallelLooper = parallelLooper; SpaceObjectBuffer = new SpaceObjectBuffer(this); EntityStateWriteBuffer = new EntityStateWriteBuffer(); DeactivationManager = new DeactivationManager(TimeStepSettings, ParallelLooper); ForceUpdater = new ForceUpdater(TimeStepSettings, ParallelLooper); BoundingBoxUpdater = new BoundingBoxUpdater(TimeStepSettings, ParallelLooper); BroadPhase = new DynamicHierarchy(ParallelLooper); NarrowPhase = new NarrowPhase(TimeStepSettings, BroadPhase.Overlaps, ParallelLooper); Solver = new Solver(TimeStepSettings, DeactivationManager, ParallelLooper); NarrowPhase.Solver = Solver; PositionUpdater = new ContinuousPositionUpdater(TimeStepSettings, ParallelLooper); BufferedStates = new BufferedStatesManager(ParallelLooper); DeferredEventDispatcher = new DeferredEventDispatcher(); DuringForcesUpdateables = new DuringForcesUpdateableManager(timeStepSettings, ParallelLooper); BeforeNarrowPhaseUpdateables = new BeforeNarrowPhaseUpdateableManager(timeStepSettings, ParallelLooper); BeforeSolverUpdateables = new BeforeSolverUpdateableManager(timeStepSettings, ParallelLooper); BeforePositionUpdateUpdateables = new BeforePositionUpdateUpdateableManager(timeStepSettings, ParallelLooper); EndOfTimeStepUpdateables = new EndOfTimeStepUpdateableManager(timeStepSettings, ParallelLooper); EndOfFrameUpdateables = new EndOfFrameUpdateableManager(timeStepSettings, ParallelLooper); }
internal override void GetOverlaps(Node opposingNode, DynamicHierarchy owner) { bool intersects; //note: This is never executed when the opposing node is the current node. if (opposingNode.IsLeaf) { //We're both leaves! Our parents have already done the testing for us, so we know we're overlapping. owner.TryToAddOverlap(element, opposingNode.Element); } else { var opposingChildA = opposingNode.ChildA; var opposingChildB = opposingNode.ChildB; //If it's not a leaf, try to go deeper in the opposing hierarchy. BoundingBox.Intersects(ref opposingChildA.BoundingBox, out intersects); if (intersects) { GetOverlaps(opposingChildA, owner); } BoundingBox.Intersects(ref opposingChildB.BoundingBox, out intersects); if (intersects) { GetOverlaps(opposingChildB, owner); } } }
/// <summary> /// Constructs a new demo. /// </summary> /// <param name="game">Game owning this demo.</param> public BroadPhaseRemovalTestDemo(DemosGame game) : base(game) { Entity toAdd; //BoundingBox box = new BoundingBox(new Vector3(-5, 1, 1), new Vector3(5, 7, 7)); BoundingBox box = new BoundingBox(new Vector3(-500, -500, -500), new Vector3(500, 500, 500)); DynamicHierarchy dh = new DynamicHierarchy(); Random rand = new Random(0); RawList<Entity> entities = new RawList<Entity>(); for (int k = 0; k < 1000; k++) { Vector3 position = new Vector3((float)(rand.NextDouble() * (box.Max.X - box.Min.X) + box.Min.X), (float)(rand.NextDouble() * (box.Max.Y - box.Min.Y) + box.Min.Y), (float)(rand.NextDouble() * (box.Max.Z - box.Min.Z) + box.Min.Z)); toAdd = new Box(MathConverter.Convert(position), 1, 1, 1, 1); entities.Add(toAdd); } testResults = new double[2]; int runCount = 10; for (int k = 0; k < runCount; k++) { for (int i = 0; i < entities.Count; i++) { dh.Add(entities[i].CollisionInformation); } long start = Stopwatch.GetTimestamp(); for (int i = 0; i < entities.Count; i++) { //dh.RemoveFast(entities[i].CollisionInformation); } long end = Stopwatch.GetTimestamp(); testResults[0] += (end - start) / (double)Stopwatch.Frequency; for (int i = 0; i < entities.Count; i++) { dh.Add(entities[i].CollisionInformation); } start = Stopwatch.GetTimestamp(); for (int i = 0; i < entities.Count; i++) { //dh.RemoveBrute(entities[i].CollisionInformation); } end = Stopwatch.GetTimestamp(); testResults[1] += (end - start) / (double)Stopwatch.Frequency; } testResults[0] /= runCount; testResults[1] /= runCount; }
internal override void GetMultithreadedOverlaps(Node opposingNode, int splitDepth, int currentDepth, DynamicHierarchy owner, RawList <DynamicHierarchy.NodePair> multithreadingSourceOverlaps) { bool intersects; //note: This is never executed when the opposing node is the current node. if (opposingNode.IsLeaf) { //We're both leaves! Our parents have already done the testing for us, so we know we're overlapping. owner.TryToAddOverlap(element, opposingNode.Element); } else { var opposingChildA = opposingNode.ChildA; var opposingChildB = opposingNode.ChildB; if (splitDepth == currentDepth) { //Time to add the child overlaps to the multithreading set! BoundingBox.Intersects(ref opposingChildA.BoundingBox, out intersects); if (intersects) { multithreadingSourceOverlaps.Add(new DynamicHierarchy.NodePair() { a = this, b = opposingChildA }); } BoundingBox.Intersects(ref opposingChildB.BoundingBox, out intersects); if (intersects) { multithreadingSourceOverlaps.Add(new DynamicHierarchy.NodePair() { a = this, b = opposingChildB }); } return; } //If it's not a leaf, try to go deeper in the opposing hierarchy. BoundingBox.Intersects(ref opposingChildA.BoundingBox, out intersects); if (intersects) { GetOverlaps(opposingChildA, owner); } BoundingBox.Intersects(ref opposingChildB.BoundingBox, out intersects); if (intersects) { GetOverlaps(opposingChildB, owner); } } }
internal override void GetMultithreadedOverlaps(Node opposingNode, int splitDepth, int currentDepth, DynamicHierarchy owner, RawList <DynamicHierarchy.NodePair> multithreadingSourceOverlaps) { bool intersects; if (currentDepth == splitDepth) { //We've reached the depth where our child comparisons will be multithreaded. if (this == opposingNode) { //We are being compared against ourselves! //Obviously we're an internal node, so spawn three children: //A versus A: if (!childA.IsLeaf) //This is performed in the child method usually by convention, but this saves some time. { multithreadingSourceOverlaps.Add(new DynamicHierarchy.NodePair() { a = childA, b = childA }); } //B versus B: if (!childB.IsLeaf) //This is performed in the child method usually by convention, but this saves some time. { multithreadingSourceOverlaps.Add(new DynamicHierarchy.NodePair() { a = childB, b = childB }); } //A versus B (if they intersect): childA.BoundingBox.Intersects(ref childB.BoundingBox, out intersects); if (intersects) { multithreadingSourceOverlaps.Add(new DynamicHierarchy.NodePair() { a = childA, b = childB }); } } else { //Two different nodes. The other one may be a leaf. if (opposingNode.IsLeaf) { //If it's a leaf, go deeper in our hierarchy, but not the opposition. childA.BoundingBox.Intersects(ref opposingNode.BoundingBox, out intersects); if (intersects) { multithreadingSourceOverlaps.Add(new DynamicHierarchy.NodePair() { a = childA, b = opposingNode }); } childB.BoundingBox.Intersects(ref opposingNode.BoundingBox, out intersects); if (intersects) { multithreadingSourceOverlaps.Add(new DynamicHierarchy.NodePair() { a = childB, b = opposingNode }); } } else { var opposingChildA = opposingNode.ChildA; var opposingChildB = opposingNode.ChildB; //If it's not a leaf, try to go deeper in both hierarchies. childA.BoundingBox.Intersects(ref opposingChildA.BoundingBox, out intersects); if (intersects) { multithreadingSourceOverlaps.Add(new DynamicHierarchy.NodePair() { a = childA, b = opposingChildA }); } childA.BoundingBox.Intersects(ref opposingChildB.BoundingBox, out intersects); if (intersects) { multithreadingSourceOverlaps.Add(new DynamicHierarchy.NodePair() { a = childA, b = opposingChildB }); } childB.BoundingBox.Intersects(ref opposingChildA.BoundingBox, out intersects); if (intersects) { multithreadingSourceOverlaps.Add(new DynamicHierarchy.NodePair() { a = childB, b = opposingChildA }); } childB.BoundingBox.Intersects(ref opposingChildB.BoundingBox, out intersects); if (intersects) { multithreadingSourceOverlaps.Add(new DynamicHierarchy.NodePair() { a = childB, b = opposingChildB }); } } } return; } if (this == opposingNode) { //We are being compared against ourselves! //Obviously we're an internal node, so spawn three children: //A versus A: if (!childA.IsLeaf) //This is performed in the child method usually by convention, but this saves some time. { childA.GetMultithreadedOverlaps(childA, splitDepth, currentDepth + 1, owner, multithreadingSourceOverlaps); } //B versus B: if (!childB.IsLeaf) //This is performed in the child method usually by convention, but this saves some time. { childB.GetMultithreadedOverlaps(childB, splitDepth, currentDepth + 1, owner, multithreadingSourceOverlaps); } //A versus B (if they intersect): childA.BoundingBox.Intersects(ref childB.BoundingBox, out intersects); if (intersects) { childA.GetMultithreadedOverlaps(childB, splitDepth, currentDepth + 1, owner, multithreadingSourceOverlaps); } } else { //Two different nodes. The other one may be a leaf. if (opposingNode.IsLeaf) { //If it's a leaf, go deeper in our hierarchy, but not the opposition. childA.BoundingBox.Intersects(ref opposingNode.BoundingBox, out intersects); if (intersects) { childA.GetMultithreadedOverlaps(opposingNode, splitDepth, currentDepth + 1, owner, multithreadingSourceOverlaps); } childB.BoundingBox.Intersects(ref opposingNode.BoundingBox, out intersects); if (intersects) { childB.GetMultithreadedOverlaps(opposingNode, splitDepth, currentDepth + 1, owner, multithreadingSourceOverlaps); } } else { var opposingChildA = opposingNode.ChildA; var opposingChildB = opposingNode.ChildB; //If it's not a leaf, try to go deeper in both hierarchies. childA.BoundingBox.Intersects(ref opposingChildA.BoundingBox, out intersects); if (intersects) { childA.GetMultithreadedOverlaps(opposingChildA, splitDepth, currentDepth + 1, owner, multithreadingSourceOverlaps); } childA.BoundingBox.Intersects(ref opposingChildB.BoundingBox, out intersects); if (intersects) { childA.GetMultithreadedOverlaps(opposingChildB, splitDepth, currentDepth + 1, owner, multithreadingSourceOverlaps); } childB.BoundingBox.Intersects(ref opposingChildA.BoundingBox, out intersects); if (intersects) { childB.GetMultithreadedOverlaps(opposingChildA, splitDepth, currentDepth + 1, owner, multithreadingSourceOverlaps); } childB.BoundingBox.Intersects(ref opposingChildB.BoundingBox, out intersects); if (intersects) { childB.GetMultithreadedOverlaps(opposingChildB, splitDepth, currentDepth + 1, owner, multithreadingSourceOverlaps); } } } }
internal abstract void GetMultithreadedOverlaps(Node opposingNode, int splitDepth, int currentDepth, DynamicHierarchy owner, RawList <DynamicHierarchy.NodePair> multithreadingSourceOverlaps);
internal abstract void GetOverlaps(Node node, DynamicHierarchy owner);
internal override void GetOverlaps(Node opposingNode, DynamicHierarchy owner) { bool intersects; if (this == opposingNode) { //We are being compared against ourselves! //Obviously we're an internal node, so spawn three children: //A versus A: if (!childA.IsLeaf) //This is performed in the child method usually by convention, but this saves some time. { childA.GetOverlaps(childA, owner); } //B versus B: if (!childB.IsLeaf) //This is performed in the child method usually by convention, but this saves some time. { childB.GetOverlaps(childB, owner); } //A versus B (if they intersect): childA.BoundingBox.Intersects(ref childB.BoundingBox, out intersects); if (intersects) { childA.GetOverlaps(childB, owner); } } else { //Two different nodes. The other one may be a leaf. if (opposingNode.IsLeaf) { //If it's a leaf, go deeper in our hierarchy, but not the opposition. childA.BoundingBox.Intersects(ref opposingNode.BoundingBox, out intersects); if (intersects) { childA.GetOverlaps(opposingNode, owner); } childB.BoundingBox.Intersects(ref opposingNode.BoundingBox, out intersects); if (intersects) { childB.GetOverlaps(opposingNode, owner); } } else { var opposingChildA = opposingNode.ChildA; var opposingChildB = opposingNode.ChildB; //If it's not a leaf, try to go deeper in both hierarchies. childA.BoundingBox.Intersects(ref opposingChildA.BoundingBox, out intersects); if (intersects) { childA.GetOverlaps(opposingChildA, owner); } childA.BoundingBox.Intersects(ref opposingChildB.BoundingBox, out intersects); if (intersects) { childA.GetOverlaps(opposingChildB, owner); } childB.BoundingBox.Intersects(ref opposingChildA.BoundingBox, out intersects); if (intersects) { childB.GetOverlaps(opposingChildA, owner); } childB.BoundingBox.Intersects(ref opposingChildB.BoundingBox, out intersects); if (intersects) { childB.GetOverlaps(opposingChildB, owner); } } } }
internal DynamicHierarchyQueryAccelerator(DynamicHierarchy hierarchy) { this.hierarchy = hierarchy; }
double RunTest(int splitOffset, IParallelLooper parallelLooper) { Entity toAdd; //BoundingBox box = new BoundingBox(new Vector3(-5, 1, 1), new Vector3(5, 7, 7)); BoundingBox box = new BoundingBox(new Vector3(-500, -500, -500), new Vector3(500, 500, 500)); int splitDepth = splitOffset + (int)Math.Ceiling(Math.Log(parallelLooper.ThreadCount, 2)); DynamicHierarchy dh = new DynamicHierarchy(parallelLooper); Random rand = new Random(0); RawList<Entity> entities = new RawList<Entity>(); for (int k = 0; k < 10000; k++) { Vector3 position = new Vector3((float)(rand.NextDouble() * (box.Max.X - box.Min.X) + box.Min.X), (float)(rand.NextDouble() * (box.Max.Y - box.Min.Y) + box.Min.Y), (float)(rand.NextDouble() * (box.Max.Z - box.Min.Z) + box.Min.Z)); toAdd = new Box(position, 1, 1, 1, 1); toAdd.CollisionInformation.CollisionRules.Personal = CollisionRule.NoNarrowPhasePair; toAdd.CollisionInformation.UpdateBoundingBox(0); dh.Add(toAdd.CollisionInformation); entities.Add(toAdd); } Space.ForceUpdater.Gravity = new Vector3(); int numRuns = 3000; //Prime the system. dh.Update(); var testType = Test.Update; BroadPhaseOverlap[] overlapBasis = new BroadPhaseOverlap[dh.Overlaps.Count]; dh.Overlaps.CopyTo(overlapBasis, 0); double time = 0; double startTime, endTime; switch (testType) { #region Update Timing case Test.Update: for (int i = 0; i < numRuns; i++) { //DH4 startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; //dh.Update(); //lock (dh.Locker) //{ // dh.Overlaps.Clear(); // if (dh.ROOTEXISTS) // { // dh.MultithreadedRefitPhase(splitDepth); // dh.MultithreadedOverlapPhase(splitDepth); // } //} //dh.Update(); //lock (dh.Locker) //{ // dh.Overlaps.Clear(); // if (dh.ROOTEXISTS) // { // dh.SingleThreadedRefitPhase(); // dh.SingleThreadedOverlapPhase(); // } //} endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; time += endTime - startTime; //if (dh.Overlaps.Count != overlapBasis.Length) // Debug.WriteLine("Failed Update."); //for (int j = 0; j < overlapBasis.Length; j++) //{ // if (!dh.Overlaps.Contains(overlapBasis[j])) // Debug.WriteLine("Failed Update."); //} //MoveEntities(entities); } break; #endregion #region Refit Timing case Test.Refit: for (int i = 0; i < numRuns; i++) { dh.Overlaps.Clear(); //DH4 startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; //dh.MultithreadedRefitPhase(splitDepth); //dh.SingleThreadedRefitPhase(); endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; time += endTime - startTime; //dh.SingleThreadedOverlapPhase(); //if (dh.Overlaps.Count != overlapBasis.Length) // Debug.WriteLine("Failed Refit."); //for (int j = 0; j < overlapBasis.Length; j++) //{ // if (!dh.Overlaps.Contains(overlapBasis[j])) // Debug.WriteLine("Failed Refit."); //} //MoveEntities(entities); } break; #endregion #region Overlap Timing case Test.Overlap: for (int i = 0; i < numRuns; i++) { dh.Overlaps.Clear(); //dh.MultithreadedRefitPhase(splitDepth); //DH4 startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; //dh.MultithreadedOverlapPhase(splitDepth); //dh.SingleThreadedOverlapPhase(); endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; time += endTime - startTime; //if (dh.Overlaps.Count != overlapBasis.Length) // Debug.WriteLine("Failed Overlap."); //for (int j = 0; j < overlapBasis.Length; j++) //{ // if (!dh.Overlaps.Contains(overlapBasis[j])) // Debug.WriteLine("Failed Overlap."); //} //MoveEntities(entities); } break; #endregion #region Ray cast timing case Test.RayCast: float rayLength = 100; RawList<Ray> rays = new RawList<Ray>(); for (int i = 0; i < numRuns; i++) { rays.Add(new Ray() { Position = new Vector3((float)(rand.NextDouble() * (box.Max.X - box.Min.X) + box.Min.X), (float)(rand.NextDouble() * (box.Max.Y - box.Min.Y) + box.Min.Y), (float)(rand.NextDouble() * (box.Max.Z - box.Min.Z) + box.Min.Z)), Direction = Vector3.Normalize(new Vector3((float)(rand.NextDouble() - .5), (float)(rand.NextDouble() - .5), (float)(rand.NextDouble() - .5))) }); } RawList<BroadPhaseEntry> outputIntersections = new RawList<BroadPhaseEntry>(); //DH4 startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < numRuns; i++) { dh.QueryAccelerator.RayCast(rays.Elements[i], rayLength, outputIntersections); outputIntersections.Clear(); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; time = endTime - startTime; break; #endregion #region Bounding box query timing case Test.BoundingBoxQuery: float boundingBoxSize = 10; var boundingBoxes = new RawList<BoundingBox>(); Vector3 offset = new Vector3(boundingBoxSize / 2, boundingBoxSize / 2, boundingBoxSize / 2); for (int i = 0; i < numRuns; i++) { Vector3 center = new Vector3((float)(rand.NextDouble() * (box.Max.X - box.Min.X) + box.Min.X), (float)(rand.NextDouble() * (box.Max.Y - box.Min.Y) + box.Min.Y), (float)(rand.NextDouble() * (box.Max.Z - box.Min.Z) + box.Min.Z)); boundingBoxes.Add(new BoundingBox() { Min = center - offset, Max = center + offset }); } outputIntersections = new RawList<BroadPhaseEntry>(); //DH4 startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < numRuns; i++) { dh.QueryAccelerator.GetEntries(boundingBoxes.Elements[i], outputIntersections); outputIntersections.Clear(); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; time = endTime - startTime; break; #endregion } return time / numRuns; }
/// <summary> /// Constructs a new demo. /// </summary> /// <param name="game">Game owning this demo.</param> public BroadPhasesTestDemo(DemosGame game) : base(game) { Space.Solver.IterationLimit = 0; Entity toAdd; //BoundingBox box = new BoundingBox(new Vector3(-5, 1, 1), new Vector3(5, 7, 7)); BoundingBox box = new BoundingBox(new Vector3(-50, -50, -50), new Vector3(50, 50, 50)); //DynamicHierarchyOld dhOld = new DynamicHierarchyOld(Space.ThreadManager); DynamicHierarchy dh = new DynamicHierarchy(Space.ParallelLooper); SortAndSweep1D sas1d = new SortAndSweep1D(Space.ParallelLooper); Grid2DSortAndSweep grid2DSAS = new Grid2DSortAndSweep(Space.ParallelLooper); //DynamicHierarchy dh = new DynamicHierarchy(); //DynamicHierarchy4 dh4 = new DynamicHierarchy4(); //SortAndSweep1D sas1d = new SortAndSweep1D(); //Grid2DSortAndSweep grid2DSAS = new Grid2DSortAndSweep(); //DynamicHierarchy2 dh2 = new DynamicHierarchy2(); //DynamicHierarchy3 dh3 = new DynamicHierarchy3(); //SortAndSweep3D sap3d = new SortAndSweep3D(); RawList<Entity> entities = new RawList<Entity>(); for (int k = 0; k < 100; k++) { Vector3 position = new Vector3((float)(rand.NextDouble() * (box.Max.X - box.Min.X) + box.Min.X), (float)(rand.NextDouble() * (box.Max.Y - box.Min.Y) + box.Min.Y), (float)(rand.NextDouble() * (box.Max.Z - box.Min.Z) + box.Min.Z)); toAdd = new Box(position, 1, 1, 1, 1); toAdd.CollisionInformation.CollisionRules.Personal = CollisionRule.NoNarrowPhasePair; toAdd.CollisionInformation.UpdateBoundingBox(0); //Space.Add(toAdd); //dhOld.Add(toAdd.CollisionInformation); dh.Add(toAdd.CollisionInformation); sas1d.Add(toAdd.CollisionInformation); grid2DSAS.Add(toAdd.CollisionInformation); entities.Add(toAdd); } Space.ForceUpdater.Gravity = new Vector3(); int numRuns = 10000; //Prime the system. grid2DSAS.Update(); sas1d.Update(); //dhOld.Update(); dh.Update(); var testType = Test.Update; double startTime, endTime; switch (testType) { #region Update Timing case Test.Update: for (int i = 0; i < numRuns; i++) { ////DH //startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; //dhOld.Update(); //endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; //DHOldTime += endTime - startTime; //DH4 startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; dh.Update(); endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; DHtime += endTime - startTime; //SAP1D startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; sas1d.Update(); endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; SAS1Dtime += endTime - startTime; //Grid2D SOS startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; grid2DSAS.Update(); endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; grid2DSAStime += endTime - startTime; //if (sap1d.Overlaps.Count != dh.Overlaps.Count) // Debug.WriteLine("SAP1D Failure"); //if (grid2DSOS.Overlaps.Count != dh.Overlaps.Count) // Debug.WriteLine("grid2DSOS Failure"); //for (int j = 0; j < dh2.Overlaps.Count; j++) //{ // if (!grid2DSOS.Overlaps.Contains(dh2.Overlaps[j])) // Debug.WriteLine("Break."); //} //for (int j = 0; j < grid2DSOS.Overlaps.Count; j++) //{ // if (!dh2.Overlaps.Contains(grid2DSOS.Overlaps[j])) // break; //} //for (int j = 0; j < grid2DSOS.Overlaps.Count; j++) //{ // if (!dh4.Overlaps.Contains(grid2DSOS.Overlaps[j])) // break; //} //for (int j = 0; j < dh.Overlaps.Count; j++) //{ // if (!dh.Overlaps[j].EntryA.BoundingBox.Intersects(dh.Overlaps[j].EntryB.BoundingBox)) // Debug.WriteLine("Break."); //} //for (int j = 0; j < sap1d.Overlaps.Count; j++) //{ // if (!sap1d.Overlaps[j].EntryA.BoundingBox.Intersects(sap1d.Overlaps[j].EntryB.BoundingBox)) // Debug.WriteLine("Break."); //} //for (int j = 0; j < grid2DSOS.Overlaps.Count; j++) //{ // if (!grid2DSOS.Overlaps[j].EntryA.BoundingBox.Intersects(grid2DSOS.Overlaps[j].EntryB.BoundingBox)) // Debug.WriteLine("Break."); //} //MoveEntities(entities); } break; #endregion #region Ray cast timing case Test.RayCast: float rayLength = 100; RawList<Ray> rays = new RawList<Ray>(); for (int i = 0; i < numRuns; i++) { rays.Add(new Ray() { Position = new Vector3((float)(rand.NextDouble() * (box.Max.X - box.Min.X) + box.Min.X), (float)(rand.NextDouble() * (box.Max.Y - box.Min.Y) + box.Min.Y), (float)(rand.NextDouble() * (box.Max.Z - box.Min.Z) + box.Min.Z)), Direction = Vector3.Normalize(new Vector3((float)(rand.NextDouble() - .5), (float)(rand.NextDouble() - .5), (float)(rand.NextDouble() - .5))) }); } RawList<BroadPhaseEntry> outputIntersections = new RawList<BroadPhaseEntry>(); ////DH //startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; //for (int i = 0; i < numRuns; i++) //{ // dhOld.QueryAccelerator.RayCast(rays.Elements[i], rayLength, outputIntersections); // outputIntersections.Clear(); //} //endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; //DHOldTime = endTime - startTime; //DH4 startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < numRuns; i++) { dh.QueryAccelerator.RayCast(rays.Elements[i], rayLength, outputIntersections); outputIntersections.Clear(); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; DHtime = endTime - startTime; //Grid2DSAS startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < numRuns; i++) { grid2DSAS.QueryAccelerator.RayCast(rays.Elements[i], rayLength, outputIntersections); outputIntersections.Clear(); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; grid2DSAStime = endTime - startTime; break; #endregion #region Bounding box query timing case Test.BoundingBoxQuery: float boundingBoxSize = 10; var boundingBoxes = new RawList<BoundingBox>(); Vector3 offset = new Vector3(boundingBoxSize / 2, boundingBoxSize / 2, boundingBoxSize / 2); for (int i = 0; i < numRuns; i++) { Vector3 center = new Vector3((float)(rand.NextDouble() * (box.Max.X - box.Min.X) + box.Min.X), (float)(rand.NextDouble() * (box.Max.Y - box.Min.Y) + box.Min.Y), (float)(rand.NextDouble() * (box.Max.Z - box.Min.Z) + box.Min.Z)); boundingBoxes.Add(new BoundingBox() { Min = center - offset, Max = center + offset }); } outputIntersections = new RawList<BroadPhaseEntry>(); ////DH //startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; //for (int i = 0; i < numRuns; i++) //{ // dhOld.QueryAccelerator.GetEntries(boundingBoxes.Elements[i], outputIntersections); // outputIntersections.Clear(); //} //endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; //DHOldTime = endTime - startTime; //DH4 startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < numRuns; i++) { dh.QueryAccelerator.GetEntries(boundingBoxes.Elements[i], outputIntersections); outputIntersections.Clear(); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; DHtime = endTime - startTime; //Grid2DSAS startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < numRuns; i++) { grid2DSAS.QueryAccelerator.GetEntries(boundingBoxes.Elements[i], outputIntersections); outputIntersections.Clear(); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; grid2DSAStime = endTime - startTime; break; #endregion } DHOldTime /= numRuns; DH2time /= numRuns; DH3time /= numRuns; DHtime /= numRuns; SAS1Dtime /= numRuns; grid2DSAStime /= numRuns; }
internal DynamicHierarchyQueryAccelerator(DynamicHierarchy hierarchy) { this.hierarchy = hierarchy; }
///<summary> /// Constructs a new space for things to live in. ///</summary> public Space() { NarrowPhaseHelper.CollisionManagers = NarrowPhaseHelper.CollisionManagers; //Forces the NarrowPhaseHelper to run the static constructor. Better to do it now instead of mid-simulation. timeStepSettings = new TimeStepSettings(); #if !WINDOWS threadManager = new SpecializedThreadManager(); #else threadManager = new SpecializedThreadManager(); #endif SpaceObjectBuffer = new SpaceObjectBuffer(this); EntityStateWriteBuffer = new EntityStateWriteBuffer(); DeactivationManager = new DeactivationManager(TimeStepSettings, ThreadManager); ForceUpdater = new ForceUpdater(TimeStepSettings, ThreadManager); BoundingBoxUpdater = new BoundingBoxUpdater(TimeStepSettings, ThreadManager); BroadPhase = new DynamicHierarchy(ThreadManager); NarrowPhase = new NarrowPhase(TimeStepSettings, BroadPhase.Overlaps, ThreadManager); Solver = new Solver(TimeStepSettings, DeactivationManager, ThreadManager); NarrowPhase.Solver = Solver; PositionUpdater = new ContinuousPositionUpdater(TimeStepSettings, ThreadManager); BufferedStates = new BufferedStatesManager(ThreadManager); DeferredEventDispatcher = new DeferredEventDispatcher(); DuringForcesUpdateables = new DuringForcesUpdateableManager(timeStepSettings, ThreadManager); BeforeNarrowPhaseUpdateables = new BeforeNarrowPhaseUpdateableManager(timeStepSettings, ThreadManager); BeforeSolverUpdateables = new BeforeSolverUpdateableManager(timeStepSettings, ThreadManager); BeforePositionUpdateUpdateables = new BeforePositionUpdateUpdateableManager(timeStepSettings, ThreadManager); EndOfTimeStepUpdateables = new EndOfTimeStepUpdateableManager(timeStepSettings, ThreadManager); EndOfFrameUpdateables = new EndOfFrameUpdateableManager(timeStepSettings, ThreadManager); }
public static TestResults TestDH(TestCollidableBEPU[] leaves, BEPUutilities.BoundingBox[] queries, ref BoundingBox positionBounds, int queryCount, int selfTestCount, int refitCount, int frameCount, float dt, IParallelLooper looper) { GC.Collect(); { DynamicHierarchy tree = new DynamicHierarchy(looper); for (int i = 0; i < leaves.Length; ++i) { tree.Add(leaves[i]); } if (looper.ThreadCount > 1) tree.MultithreadedRefitPhase(tree.GetSplitDepth()); else tree.SingleThreadedRefitPhase(); tree.Overlaps.Count = 0; if (looper.ThreadCount > 1) tree.MultithreadedOverlapPhase(tree.GetSplitDepth()); else tree.SingleThreadedOverlapPhase(); for (int i = 0; i < leaves.Length; ++i) { tree.Remove(leaves[i]); } } GC.Collect(); { var startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; DynamicHierarchy tree = new DynamicHierarchy(looper); for (int i = 0; i < leaves.Length; ++i) { tree.Add(leaves[i]); } var endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"DH Build Time: {endTime - startTime}"); Console.WriteLine($"Cost metric: {tree.MeasureCostMetric()}"); //tree.SingleThreadedRefitPhase(); //startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; //for (int i = 0; i < refitCount; ++i) //{ // tree.SingleThreadedRefitPhase(); // //Console.WriteLine($"Cost metric: {tree.MeasureCostMetric()}"); //} //endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; //Console.WriteLine($"DH Refit Time: {endTime - startTime}"); //Console.WriteLine($"Cost metric: {tree.MeasureCostMetric()}"); //tree.SingleThreadedOverlapPhase(); //startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; //for (int i = 0; i < selfTestCount; ++i) //{ // tree.Overlaps.Clear(); // tree.SingleThreadedOverlapPhase(); //} //endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; //Console.WriteLine($"DH selftest Time: {endTime - startTime}, overlaps: {tree.Overlaps.Count}"); //**************** Dynamic Testing Random random = new Random(5); TestResults results = new TestResults("Old", frameCount); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int t = 0; t < frameCount; ++t) { //Update the positions of objects. for (int i = 0; i < leaves.Length; ++i) { var leaf = leaves[i]; //Bounce off the walls. if (leaf.Position.X < positionBounds.Min.X && leaf.Velocity.X < 0) leaf.Velocity.X = -leaf.Velocity.X; if (leaf.Position.Y < positionBounds.Min.Y && leaf.Velocity.Y < 0) leaf.Velocity.Y = -leaf.Velocity.Y; if (leaf.Position.Z < positionBounds.Min.Z && leaf.Velocity.Z < 0) leaf.Velocity.Z = -leaf.Velocity.Z; if (leaf.Position.X > positionBounds.Max.X && leaf.Velocity.X > 0) leaf.Velocity.X = -leaf.Velocity.X; if (leaf.Position.Y > positionBounds.Max.Y && leaf.Velocity.Y > 0) leaf.Velocity.Y = -leaf.Velocity.Y; if (leaf.Position.Z > positionBounds.Max.Z && leaf.Velocity.Z > 0) leaf.Velocity.Z = -leaf.Velocity.Z; leaf.Position += leaf.Velocity * dt; leaf.UpdateBoundingBox(); } var refineStartTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; if (looper.ThreadCount > 1) tree.MultithreadedRefitPhase(tree.GetSplitDepth()); else tree.SingleThreadedRefitPhase(); //tree.Refit(); //for (int i = 0; i < 1; ++i) //{ // subtreeReferences.Count = 0; // treeletInternalNodes.Count = 0; // tree.BinnedRefine(0, ref subtreeReferences, maximumSubtrees, ref treeletInternalNodes, ref spareNodes, ref resources, out nodesInvalidated); //} //tree.RemoveUnusedInternalNodes(ref spareNodes); var refineEndTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; tree.Overlaps.Count = 0; if (looper.ThreadCount > 1) tree.MultithreadedOverlapPhase(tree.GetSplitDepth()); else tree.SingleThreadedOverlapPhase(); var testEndTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; results.Refine[t] = 1000 * (refineEndTime - refineStartTime); results.SelfTest[t] = 1000 * (testEndTime - refineEndTime); results.Total[t] = 1000 * (testEndTime - refineStartTime); results.OverlapCounts[t] = tree.Overlaps.Count; results.TreeCosts[t] = tree.MeasureCostMetric(); if (t % 16 == 0) { Console.WriteLine($"_________________{t}_________________"); Console.WriteLine($"Refine time: {results.Refine[t]}"); Console.WriteLine($"Test time: {results.SelfTest[t]}"); Console.WriteLine($"TIME: {results.Total[t]}"); Console.WriteLine($"Cost metric: {results.TreeCosts[t]}"); Console.WriteLine($"Overlaps: {results.OverlapCounts[t]}"); GC.Collect(); } } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"Cost metric: {tree.MeasureCostMetric()}"); tree.Overlaps.Clear(); tree.SingleThreadedOverlapPhase(); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < selfTestCount; ++i) { tree.Overlaps.Clear(); tree.SingleThreadedOverlapPhase(); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"DH selftest Time2: {endTime - startTime}, overlaps: {tree.Overlaps.Count}"); return results; } }