예제 #1
0
        public void GetEntries(BoundingSphere boundingShape, IList <BroadPhaseEntry> overlaps)
        {
            //Create a bounding box based on the bounding sphere.
            //Compute the min and max of the bounding box.
            //Loop through the cells and select bounding boxes which overlap the x axis.
#if !WINDOWS
            Vector3f offset = new Vector3f();
#else
            Vector3f offset;
#endif
            offset.X = boundingShape.Radius;
            offset.Y = offset.X;
            offset.Z = offset.Y;
            BoundingBox box;
            Vector3f.Add(ref boundingShape.Center, ref offset, out box.Max);
            Vector3f.Subtract(ref boundingShape.Center, ref offset, out box.Min);

            Int2 min, max;
            Grid2DSortAndSweep.ComputeCell(ref box.Min, out min);
            Grid2DSortAndSweep.ComputeCell(ref box.Max, out max);
            for (int i = min.Y; i <= max.Y; i++)
            {
                for (int j = min.Z; j <= max.Z; j++)
                {
                    //Grab the cell that we are currently in.
                    Int2 cellIndex;
                    cellIndex.Y = i;
                    cellIndex.Z = j;
                    GridCell2D cell;
                    if (owner.cellSet.TryGetCell(ref cellIndex, out cell))
                    {
                        //To fully accelerate this, the entries list would need to contain both min and max interval markers.
                        //Since it only contains the sorted min intervals, we can't just start at a point in the middle of the list.
                        //Consider some giant bounding box that spans the entire list.
                        for (int k = 0; k < cell.entries.Count &&
                             cell.entries.Elements[k].item.boundingBox.Min.X <= box.Max.X; k++)   //TODO: Try additional x axis pruning? A bit of optimization potential due to overlap with AABB test.
                        {
                            bool intersects;
                            var  item = cell.entries.Elements[k].item;
                            item.boundingBox.Intersects(ref boundingShape, out intersects);
                            if (intersects && !overlaps.Contains(item))
                            {
                                overlaps.Add(item);
                            }
                        }
                    }
                }
            }
        }
예제 #2
0
 public Grid2DSortAndSweepQueryAccelerator(Grid2DSortAndSweep owner)
 {
     this.owner = owner;
 }
예제 #3
0
        public bool RayCast(Ray ray, float maximumLength, IList <BroadPhaseEntry> outputIntersections)
        {
            if (maximumLength == float.MaxValue)
            {
                throw new NotSupportedException("The Grid2DSortAndSweep broad phase cannot accelerate infinite ray casts.  Consider specifying a maximum length or using a broad phase which supports infinite ray casts.");
            }

            //Use 2d line rasterization.
            //Compute the exit location in the cell.
            //Test against each bounding box up until the exit value is reached.
            float    length = 0;
            Int2     cellIndex;
            Vector3f currentPosition = ray.Position;

            Grid2DSortAndSweep.ComputeCell(ref currentPosition, out cellIndex);
            while (true)
            {
                float cellWidth = 1 / Grid2DSortAndSweep.cellSizeInverse;
                float nextT;  //Distance along ray to next boundary.
                float nextTy; //Distance along ray to next boundary along y axis.
                float nextTz; //Distance along ray to next boundary along z axis.
                //Find the next cell.
                if (ray.Direction.Y > 0)
                {
                    nextTy = ((cellIndex.Y + 1) * cellWidth - currentPosition.Y) / ray.Direction.Y;
                }
                else if (ray.Direction.Y < 0)
                {
                    nextTy = ((cellIndex.Y) * cellWidth - currentPosition.Y) / ray.Direction.Y;
                }
                else
                {
                    nextTy = 10e10f;
                }
                if (ray.Direction.Z > 0)
                {
                    nextTz = ((cellIndex.Z + 1) * cellWidth - currentPosition.Z) / ray.Direction.Z;
                }
                else if (ray.Direction.Z < 0)
                {
                    nextTz = ((cellIndex.Z) * cellWidth - currentPosition.Z) / ray.Direction.Z;
                }
                else
                {
                    nextTz = 10e10f;
                }

                bool yIsMinimum = nextTy < nextTz;
                nextT = yIsMinimum ? nextTy : nextTz;



                //Grab the cell that we are currently in.
                GridCell2D cell;
                if (owner.cellSet.TryGetCell(ref cellIndex, out cell))
                {
                    float endingX;
                    if (ray.Direction.X < 0)
                    {
                        endingX = currentPosition.X;
                    }
                    else
                    {
                        endingX = currentPosition.X + ray.Direction.X * nextT;
                    }

                    //To fully accelerate this, the entries list would need to contain both min and max interval markers.
                    //Since it only contains the sorted min intervals, we can't just start at a point in the middle of the list.
                    //Consider some giant bounding box that spans the entire list.
                    for (int i = 0; i < cell.entries.Count &&
                         cell.entries.Elements[i].item.boundingBox.Min.X <= endingX; i++)   //TODO: Try additional x axis pruning?
                    {
                        var   item = cell.entries.Elements[i].item;
                        float t;
                        if (ray.Intersects(ref item.boundingBox, out t) && t < maximumLength && !outputIntersections.Contains(item))
                        {
                            outputIntersections.Add(item);
                        }
                    }
                }

                //Move the position forward.
                length += nextT;
                if (length > maximumLength) //Note that this catches the case in which the ray is pointing right down the middle of a row (resulting in a nextT of 10e10f).
                {
                    break;
                }
                Vector3f offset;
                Vector3f.Multiply(ref ray.Direction, nextT, out offset);
                Vector3f.Add(ref offset, ref currentPosition, out currentPosition);
                if (yIsMinimum)
                {
                    if (ray.Direction.Y < 0)
                    {
                        cellIndex.Y -= 1;
                    }
                    else
                    {
                        cellIndex.Y += 1;
                    }
                }
                else
                if (ray.Direction.Z < 0)
                {
                    cellIndex.Z -= 1;
                }
                else
                {
                    cellIndex.Z += 1;
                }
            }
            return(outputIntersections.Count > 0);
        }
예제 #4
0
 internal void Initialize(BroadPhaseEntry entry)
 {
     this.item = entry;
     Grid2DSortAndSweep.ComputeCell(ref entry.boundingBox.Min, out previousMin);
     Grid2DSortAndSweep.ComputeCell(ref entry.boundingBox.Max, out previousMax);
 }
예제 #5
0
        internal void UpdateOverlaps(Grid2DSortAndSweep owner)
        {
            //Sort along x axis using insertion sort; the list will be nearly sorted, so very few swaps are necessary.
            for (int i = 1; i < entries.Count; i++)
            {
                var entry = entries.Elements[i];
                for (int j = i - 1; j >= 0; j--)
                {
                    if (entry.item.boundingBox.Min.X < entries.Elements[j].item.boundingBox.Min.X)
                    {
                        entries.Elements[j + 1] = entries.Elements[j];
                        entries.Elements[j]     = entry;
                    }
                    else
                    {
                        break;
                    }
                }
            }
            //Sweep the list looking for overlaps.
            for (int i = 0; i < entries.Count; i++)
            {
                Grid2DEntry a = entries.Elements[i];
                Grid2DEntry b;
                //TODO: Microoptimize
                for (int j = i + 1; j < entries.Count && a.item.boundingBox.Max.X >= (b = entries.Elements[j]).item.boundingBox.Min.X; j++)
                {
                    if (!(a.item.boundingBox.Min.Y > b.item.boundingBox.Max.Y || a.item.boundingBox.Max.Y < b.item.boundingBox.Min.Y ||
                          a.item.boundingBox.Min.Z > b.item.boundingBox.Max.Z || a.item.boundingBox.Max.Z < b.item.boundingBox.Min.Z))
                    {
                        //Now we know this pair is overlapping, but we do not know if this overlap is already added.
                        //Rather than use a hashset or other heavy structure to check, rely on the rules of the grid.

                        //It's possible to avoid adding pairs entirely unless we are the designated 'responsible' cell.
                        //All other cells will defer to the cell 'responsible' for a pair.
                        //A simple rule for determining the cell which is responsible is to choose the cell which is the
                        //smallest index in the shared cells.  So first, compute that cell's index.

                        Int2 minimumSharedIndex = a.previousMin;

                        if (minimumSharedIndex.Y < b.previousMin.Y)
                        {
                            minimumSharedIndex.Y = b.previousMin.Y;
                        }
                        if (minimumSharedIndex.Y > b.previousMax.Y)
                        {
                            minimumSharedIndex.Y = b.previousMax.Y;
                        }

                        if (minimumSharedIndex.Z < b.previousMin.Z)
                        {
                            minimumSharedIndex.Z = b.previousMin.Z;
                        }
                        if (minimumSharedIndex.Z > b.previousMax.Z)
                        {
                            minimumSharedIndex.Z = b.previousMax.Z;
                        }

                        //Is our cell the minimum cell?
                        if (minimumSharedIndex.Y == cellIndex.Y && minimumSharedIndex.Z == cellIndex.Z)
                        {
                            owner.TryToAddOverlap(a.item, b.item);
                        }
                    }
                }
            }
        }