protected override void OnUpdate()
        {
            // create kdtree
            PerfMarker1.Begin();

            var ballEntities = _ballQuery.ToEntityArray(Allocator.TempJob);
            var balls        = GetComponentDataFromEntity <BallData>(true);
            var kdRoot       = new KdRoot();

            Job.WithCode(() => {
                var ballBounds = new NativeArray <Aabb>(ballEntities.Length, Allocator.Temp);
                for (var i = 0; i < ballEntities.Length; i++)
                {
                    ballBounds[i] = balls[ballEntities[i]].GetAabb(ballEntities[i]);
                }
                kdRoot.Init(ballBounds, Allocator.TempJob);
            }).Run();

            ballEntities.Dispose();
            PerfMarker1.End();

            var overlappingEntities = GetBufferFromEntity <OverlappingDynamicBufferElement>();
            var marker = PerfMarker2;

            Entities
            .WithName("StaticBroadPhaseJob")
            .WithNativeDisableParallelForRestriction(overlappingEntities)
            .ForEach((Entity entity, in BallData ball) => {
                // don't play with frozen balls
                if (ball.IsFrozen)
                {
                    return;
                }

                marker.Begin();

                var colliderEntities = overlappingEntities[entity];
                colliderEntities.Clear();
                kdRoot.GetAabbOverlaps(in entity, in ball, ref colliderEntities);

                marker.End();
            }).Run();

            kdRoot.Dispose();
        }
Example #2
0
        protected override void OnUpdate()
        {
            // create kdtree
            PerfMarker1.Begin();

            var ballBounds = new NativeArray <Aabb>(_ballQuery.CalculateEntityCount(), Allocator.TempJob);

            Entities.ForEach((Entity ballEntity, int entityInQueryIndex, in BallData ballData) => {
                ballBounds[entityInQueryIndex] = ballData.GetAabb(ballEntity);
            }).Run();

            var kdRoot = new KdRoot();

            Job.WithCode(() => kdRoot.Init(ballBounds, Allocator.TempJob)).Run();

            PerfMarker1.End();

            var overlappingEntities = GetBufferFromEntity <OverlappingDynamicBufferElement>();
            var marker = PerfMarker2;

            Entities
            .WithName("DynamicBroadPhaseJob")
            .WithDisposeOnCompletion(kdRoot)
            .WithNativeDisableParallelForRestriction(overlappingEntities)
            .ForEach((Entity entity, in BallData ball) => {
                // don't play with frozen balls
                if (ball.IsFrozen)
                {
                    return;
                }

                marker.Begin();

                var colliderEntities = overlappingEntities[entity];
                colliderEntities.Clear();
                kdRoot.GetAabbOverlaps(in entity, in ball, ref colliderEntities);

                marker.End();
            }).Run();
        }
Example #3
0
        public void CreateNextLevel(int level, int levelEmpty, KdRoot hitOct)
        {
            var orgItems = Items & 0x3FFFFFFF;

            // !! magic
            if (orgItems <= 4 || level >= 128 / 2)
            {
                return;
            }

            var vDiag = new float3(
                Bounds.Right - Bounds.Left,
                Bounds.Bottom - Bounds.Top,
                Bounds.ZHigh - Bounds.ZLow
                );

            int axis;

            if (vDiag.x > vDiag.y && vDiag.x > vDiag.z)
            {
                if (vDiag.x < 0.0001)
                {
                    return;
                }
                axis = 0;
            }
            else if (vDiag.y > vDiag.z)
            {
                if (vDiag.y < 0.0001)
                {
                    return;
                }
                axis = 1;
            }
            else
            {
                if (vDiag.z < 0.0001)
                {
                    return;
                }
                axis = 2;
            }

            //!! weight this with ratio of elements going to middle vs left&right! (avoids volume split that goes directly through object)

            // create children
            if (!hitOct.HasNodesAvailable())
            {
                // ran out of nodes - abort
                return;
            }

            var childA = new KdNode(Bounds);
            var childB = new KdNode(Bounds);

            var vCenter = new float3(
                (Bounds.Left + Bounds.Right) * 0.5f,
                (Bounds.Top + Bounds.Bottom) * 0.5f,
                (Bounds.ZLow + Bounds.ZHigh) * 0.5f
                );

            switch (axis)
            {
            case 0:
                childA.Bounds.Right = vCenter.x;
                childB.Bounds.Left  = vCenter.x;
                break;

            case 1:
                childA.Bounds.Bottom = vCenter.y;
                childB.Bounds.Top    = vCenter.y;
                break;

            default:
                childA.Bounds.ZHigh = vCenter.z;
                childB.Bounds.ZLow  = vCenter.z;
                break;
            }

            childA.Reset();
            childB.Reset();

            // determine amount of items that cross splitplane, or are passed on to the children
            if (axis == 0)
            {
                for (var i = Start; i < Start + orgItems; ++i)
                {
                    var bounds = hitOct.GetItemAt(i);

                    if (bounds.Right < vCenter.x)
                    {
                        childA.Items++;
                    }
                    else if (bounds.Left > vCenter.x)
                    {
                        childB.Items++;
                    }
                }
            }
            else if (axis == 1)
            {
                for (var i = Start; i < Start + orgItems; ++i)
                {
                    var bounds = hitOct.GetItemAt(i);

                    if (bounds.Bottom < vCenter.y)
                    {
                        childA.Items++;
                    }
                    else if (bounds.Top > vCenter.y)
                    {
                        childB.Items++;
                    }
                }
            }
            else
            {
                // axis == 2
                for (var i = Start; i < Start + orgItems; ++i)
                {
                    var bounds = hitOct.GetItemAt(i);

                    if (bounds.ZHigh < vCenter.z)
                    {
                        childA.Items++;
                    }
                    else if (bounds.ZLow > vCenter.z)
                    {
                        childB.Items++;
                    }
                }
            }

            // check if at least two nodes feature objects, otherwise don"t bother subdividing further
            var countEmpty = 0;

            if (childA.Items == 0)
            {
                countEmpty = 1;
            }

            if (childB.Items == 0)
            {
                ++countEmpty;
            }

            if (orgItems - childA.Items - childB.Items == 0)
            {
                ++countEmpty;
            }

            if (countEmpty >= 2)
            {
                ++levelEmpty;
            }
            else
            {
                levelEmpty = 0;
            }

            if (levelEmpty > 8)
            {
                // If 8 levels were all just subdividing the same objects without luck, exit & Free the nodes again (but at least empty space was cut off)
                // no need to update NumNodes, since we didn't increment them yet.
                _childA = -1;
                _childB = -1;
                return;
            }

            childA.Start = Start + orgItems - childA.Items - childB.Items;
            childB.Start = childA.Start + childA.Items;

            var items = 0;

            childA.Items = 0;
            childB.Items = 0;

            switch (axis)
            {
            // sort items that cross splitplane in-place, the others are sorted into a temporary
            case 0: {
                for (var i = Start; i < Start + orgItems; ++i)
                {
                    var bounds = hitOct.GetItemAt(i);

                    if (bounds.Right < vCenter.x)
                    {
                        hitOct.Indices[childA.Start + childA.Items++] = hitOct.OrgIdx[i];
                    }
                    else if (bounds.Left > vCenter.x)
                    {
                        hitOct.Indices[childB.Start + childB.Items++] = hitOct.OrgIdx[i];
                    }
                    else
                    {
                        hitOct.OrgIdx[Start + items++] = hitOct.OrgIdx[i];
                    }
                }
                break;
            }

            case 1: {
                for (var i = Start; i < Start + orgItems; ++i)
                {
                    var bounds = hitOct.GetItemAt(i);

                    if (bounds.Bottom < vCenter.y)
                    {
                        hitOct.Indices[childA.Start + childA.Items++] = hitOct.OrgIdx[i];
                    }
                    else if (bounds.Top > vCenter.y)
                    {
                        hitOct.Indices[childB.Start + childB.Items++] = hitOct.OrgIdx[i];
                    }
                    else
                    {
                        hitOct.OrgIdx[Start + items++] = hitOct.OrgIdx[i];
                    }
                }
                break;
            }

            default: {                     // axis == 2
                for (var i = Start; i < Start + orgItems; ++i)
                {
                    var bounds = hitOct.GetItemAt(i);

                    if (bounds.ZHigh < vCenter.z)
                    {
                        hitOct.Indices[childA.Start + childA.Items++] = hitOct.OrgIdx[i];
                    }
                    else if (bounds.ZLow > vCenter.z)
                    {
                        hitOct.Indices[childB.Start + childB.Items++] = hitOct.OrgIdx[i];
                    }
                    else
                    {
                        hitOct.OrgIdx[Start + items++] = hitOct.OrgIdx[i];
                    }
                }
                break;
            }
            }

            // The following assertions hold after this step:
            //assert( this.Start + items == this.Children[0].This.Start );
            //assert( this.Children[0].This.Start + this.Children[0].This.Items == this.Children[1].This.Start );
            //assert( this.Children[1].This.Start + this.Children[1].This.Items == this.Start + org_items );
            //assert( this.Start + org_items <= this.HitOct->tmp.Size() );

            Items = items | (axis << 30);

            // copy temporary back //!! could omit this by doing everything inplace
            for (var i = 0; i < childA.Items; i++)
            {
                hitOct.OrgIdx[childA.Start + i] = hitOct.Indices[childA.Start + i];
            }
            for (var i = 0; i < childB.Items; i++)
            {
                hitOct.OrgIdx[childB.Start + i] = hitOct.Indices[childB.Start + i];
            }

            hitOct.AddNodes(childA, childB, out _childA, out _childB);

            childA.CreateNextLevel(level + 1, levelEmpty, hitOct);
            childB.CreateNextLevel(level + 1, levelEmpty, hitOct);
        }
Example #4
0
 public void GetAabbOverlaps(ref KdRoot hitOct, in Entity entity, in BallData ball, ref DynamicBuffer <OverlappingDynamicBufferElement> overlappingEntities)