Ejemplo n.º 1
0
        } // Job

        /// <summary>
        /// Add an object.
        /// </summary>
        /// <param name="i_rootNodeIndex">Internal octree node index.</param>
        /// <param name="i_instanceID">External instance index ID to remove. Is assumed, only one unique instance ID exists in the tree.</param>
        /// <param name="i_entityVersion">Optional, used when Id is used as entity index.</param>
        /// <param name="instanceBounds">External 3D bounding box around the instance.</param>
        /// <returns>True if the object fits entirely within this node.</returns>
        static private bool _AddNodeInstance(ref RootNodeData rootNode, int i_instanceID, int i_entityVersion, Bounds instanceBounds, ref DynamicBuffer <NodeBufferElement> a_nodesBuffer, ref DynamicBuffer <NodeSparesBufferElement> a_nodeSparesBuffer, ref DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, ref DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, ref DynamicBuffer <InstanceBufferElement> a_instanceBuffer, ref DynamicBuffer <InstancesSpareIndexBufferElement> a_instancesSpareIndexBuffer, out bool isInstanceAdded)
        {
            isInstanceAdded = false;

            NodeBufferElement nodeBufferElement = a_nodesBuffer [rootNode.i_rootNodeIndex];

            if (!CommonMethods._Encapsulates(nodeBufferElement.bounds, instanceBounds))
            {
                return(false);                                                     // Early exit
            }
            int i_requiredNumberOfInstances = a_nodeInstancesIndexBuffer.Length;   // l_nodeBounds.Count ;

            isInstanceAdded = _NodeInstanceSubAdd(
                ref rootNode,
                rootNode.i_rootNodeIndex,
                i_instanceID,
                i_entityVersion,
                instanceBounds,
                ref a_nodesBuffer,
                ref a_nodeSparesBuffer,
                ref a_nodeChildrenBuffer,
                ref a_nodeInstancesIndexBuffer,
                ref a_instanceBuffer,
                ref a_instancesSpareIndexBuffer,
                i_requiredNumberOfInstances
                );

            return(true);
        }
        protected override JobHandle OnUpdate(JobHandle inputDeps)
        {
            // Debug.LogWarning ( "Col" ) ;
            Bounds checkBounds = new Bounds()
            {
                center = new float3(10, 2, 10),
                size   = new float3(1, 1, 1) * 5  // Total size of boundry
            };

            int i_firstEntity = 0;

            NativeArray <Entity> na_entities = group.ToEntityArray(Allocator.TempJob);
            Entity rootNodeEntity            = na_entities [i_firstEntity];

            na_entities.Dispose();

            ComponentDataFromEntity <RootNodeData> a_rootNodeData = GetComponentDataFromEntity <RootNodeData> (true);
            // ComponentDataArray <RootNodeData> a_rootNodeData       = group.GetComponentDataArray <RootNodeData> ( ) ;
            RootNodeData rootNode = a_rootNodeData [rootNodeEntity];

            BufferFromEntity <NodeBufferElement> nodeBufferElement = GetBufferFromEntity <NodeBufferElement> (true);
            DynamicBuffer <NodeBufferElement>    a_nodesBuffer     = nodeBufferElement [rootNodeEntity];


            Bounds maxBouds = _GetOctreeMaxBounds(ref rootNode, ref a_nodesBuffer);


            return(inputDeps);
        }
        /// <summary>
        /// Get total octree bounds (boundary box).
        /// </summary>
        /// <returns></returns>
        public Bounds _GetOctreeMaxBounds([ReadOnly] ref RootNodeData rootNode, [ReadOnly] ref DynamicBuffer <NodeBufferElement> a_nodesBuffer)
        {
            NodeBufferElement nodeBuffer = a_nodesBuffer [rootNode.i_rootNodeIndex];

            // return _GetNodeBounds ( i_rootNodeIndex ) ;
            return(nodeBuffer.bounds);
        }
            public void Execute(Entity octreeRootNodeEntity, int jobIndex, DynamicBuffer <RemoveInstanceBufferElement> a_removeInstanceBuffer)
            // public void Execute ( int i_arrayIndex )
            {
                // Entity octreeRootNodeEntity = a_octreeEntities [i_arrayIndex] ;

                // DynamicBuffer <RemoveInstanceBufferElement> a_removeInstanceBufferElement           = removeInstanceBufferElement [octreeRootNodeEntity] ;

                RootNodeData rootNode = a_rootNodeData [octreeRootNodeEntity];

                DynamicBuffer <NodeSparesBufferElement>         a_nodeSparesBuffer         = nodeSparesBufferElement [octreeRootNodeEntity];
                DynamicBuffer <NodeBufferElement>               a_nodesBuffer              = nodeBufferElement [octreeRootNodeEntity];
                DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer = nodeInstancesIndexBufferElement [octreeRootNodeEntity];
                DynamicBuffer <NodeChildrenBufferElement>       a_nodeChildrenBuffer       = nodeChildrenBufferElement [octreeRootNodeEntity];

                DynamicBuffer <InstanceBufferElement>            a_instanceBuffer            = instanceBufferElement [octreeRootNodeEntity];
                DynamicBuffer <InstancesSpareIndexBufferElement> a_instancesSpareIndexBuffer = instancesSpareIndexBufferElement [octreeRootNodeEntity];



                // Iterate through number of instances to add, from the buffer
                for (int i = 0; i < a_removeInstanceBuffer.Length; i++)
                {
                    // RootNodeData rootNodeData = a_rootNodeData [octreeRootNodeEntity] ;

                    RemoveInstanceBufferElement removeInstanceBuffer = a_removeInstanceBuffer [i];

                    bool removed = _NodeRemoveInstance(
                        ref rootNode,
                        rootNode.i_rootNodeIndex,
                        removeInstanceBuffer.i_instanceID,
                        ref a_nodesBuffer,
                        ref a_nodeSparesBuffer,
                        a_nodeChildrenBuffer,
                        a_nodeInstancesIndexBuffer,
                        ref a_instanceBuffer,
                        ref a_instancesSpareIndexBuffer
                        );

                    // See if we can shrink the octree down now that we've removed the item
                    if (removed)
                    {
                        rootNode.i_totalInstancesCountInTree--;

                        // Shrink if possible.
                        rootNode.i_rootNodeIndex = _ShrinkIfPossible(
                            rootNode,
                            rootNode.i_rootNodeIndex,
                            rootNode.f_initialSize,
                            a_nodesBuffer,
                            ref a_nodeChildrenBuffer,
                            a_nodeInstancesIndexBuffer,
                            a_instanceBuffer
                            );
                    }

                    a_rootNodeData [octreeRootNodeEntity] = rootNode;
                } // for

                a_removeInstanceBuffer.ResizeUninitialized(0);     // Clear buffer, after removing is complete.
            }
Ejemplo n.º 5
0
        //public const int numOfSpareInstances2Add = 100 ;

        /// <summary>
        /// Node Constructor.
        /// </summary>
        static public void _CreateNewNode(ref RootNodeData rootNode, int i_nodeIndex, float f_baseLength, float3 f3_center, ref DynamicBuffer <NodeBufferElement> a_nodesBuffer, ref DynamicBuffer <NodeSparesBufferElement> a_nodeSparesBuffer, ref DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, ref DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer)
        {
            // Expand storage if needed
            if (rootNode.i_nodeSpareLastIndex <= 9)
            {
                int i_baseAddNodeCount = 100;

                int i_initialSparesCount = a_nodeSparesBuffer.Length + i_baseAddNodeCount - 1;

                NodeSparesBufferElement nodeSpareBuffer = new NodeSparesBufferElement();

                NodeBufferElement nodeBuffer = new NodeBufferElement();


                // Populate with default data.
                for (int i = 0; i < i_baseAddNodeCount; i++)
                {
                    // Add spares in reversed order, from higher index, to lower index.
                    nodeSpareBuffer.i = -1;
                    a_nodeSparesBuffer.Add(nodeSpareBuffer);
                    rootNode.i_nodeSpareLastIndex++;
                    nodeSpareBuffer.i = i_initialSparesCount - i;
                    a_nodeSparesBuffer [rootNode.i_nodeSpareLastIndex] = nodeSpareBuffer;

                    nodeBuffer.f_baseLength = -1;
                    nodeBuffer.f_adjLength  = -1;
                    nodeBuffer.f3_center    = float3.zero;
                    nodeBuffer.bounds       = new Bounds();
                    a_nodesBuffer.Add(nodeBuffer);
                    nodeBuffer.i_childrenCount  = 0;
                    nodeBuffer.i_instancesCount = 0;


                    for (int j = 0; j < rootNode.i_instancesAllowedCount; j++)
                    {
                        a_nodeInstancesIndexBuffer.Add(new NodeInstancesIndexBufferElement()
                        {
                            i = -1
                        });
                    }


                    NodeChildrenBufferElement nodeChildrenBuffer = new NodeChildrenBufferElement();

                    // Generate 8 new empty children.
                    for (int j = 0; j < 8; j++)
                    {
                        nodeChildrenBuffer.i_group8NodesIndex = -1;
                        nodeChildrenBuffer.bounds             = new Bounds();
                        a_nodeChildrenBuffer.Add(new NodeChildrenBufferElement());
                    }
                }
            }


            _SetValues(rootNode, i_nodeIndex, f_baseLength, f3_center, ref a_nodesBuffer, ref a_nodeChildrenBuffer);
        }
            public void Execute(Entity octreeRootNodeEntity, int jobIndex, DynamicBuffer <CollisionInstancesBufferElement> a_collisionInstancesBuffer, ref IsCollidingData isColliding, [ReadOnly] ref BoundsEntityPair4CollisionData boundsEntityPair4Collision)
            // public void Execute ( int i_arrayIndex )
            {
                // Entity octreeRootNodeEntity = a_collisionChecksEntities [i_arrayIndex] ;


                // Its value should be 0, if no collision is detected.
                // And >= 1, if instance collision is detected, or there is more than one collision,
                // indicating number of collisions.
                // IsCollidingData isCollidingData                                            = a_isCollidingData [octreeRootNodeEntity] ;
                // Stores reference to detected colliding instance.
                // DynamicBuffer <CollisionInstancesBufferElement> a_collisionInstancesBuffer = collisionInstancesBufferElement [octreeRootNodeEntity] ;


                isColliding.i_nearestInstanceCollisionIndex = 0;
                isColliding.f_nearestDistance = float.PositiveInfinity;

                isColliding.i_collisionsCount = 0;                                           // Reset colliding instances counter.


                RootNodeData rootNode = a_octreeRootNodeData [octreeRootNodeEntity];

                DynamicBuffer <NodeBufferElement> a_nodesBuffer = nodeBufferElement [octreeRootNodeEntity];
                DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer = nodeInstancesIndexBufferElement [octreeRootNodeEntity];
                DynamicBuffer <NodeChildrenBufferElement>       a_nodeChildrenBuffer       = nodeChildrenBufferElement [octreeRootNodeEntity];
                DynamicBuffer <InstanceBufferElement>           a_instanceBuffer           = instanceBufferElement [octreeRootNodeEntity];


                // BoundsEntityPair4CollisionData rayEntityPair4CollisionData                 = a_boundsEntityPair4CollisionData [octreeRootNodeEntity] ;
                // BoundsEntityPair4CollisionData rayEntityPair4CollisionData                 = a_boundsEntityPair4CollisionData [octreeRootNodeEntity] ;

                // Ray entity pair, for collision checks

                Entity bounds2CheckEntity = boundsEntityPair4Collision.bounds2CheckEntity;


                // Is target octree active
                if (a_isActiveTag.Exists(bounds2CheckEntity))
                {
                    BoundsData checkBounds = a_boundsData [bounds2CheckEntity];


                    // To even allow instances collision checks, octree must have at least one instance.
                    if (rootNode.i_totalInstancesCountInTree > 0)
                    {
                        if (GetCollidingBoundsInstances_Common._GetNodeColliding(ref rootNode, rootNode.i_rootNodeIndex, checkBounds.bounds, ref a_collisionInstancesBuffer, ref isColliding, ref a_nodesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer, ref a_instanceBuffer))
                        {
                            /*
                             * // Debug
                             * Debug.Log ( "Is colliding." ) ;
                             */
                        }
                    }
                }

                // a_isCollidingData [octreeRootNodeEntity] = isCollidingData ; // Set back.
            }
Ejemplo n.º 7
0
            public void Execute(ref IsCollidingData isColliding, [ReadOnly] ref OctreeEntityPair4CollisionData octreeEntityPair4Collision, [ReadOnly] ref RayData rayData, [ReadOnly] ref RayMaxDistanceData rayMaxDistance)
            // public void Execute ( int i_arrayIndex )
            {
                // Entity octreeRayEntity = a_collisionChecksEntities [i_arrayIndex] ;


                // Its value should be 0, if no collision is detected.
                // And >= 1, if instance collision is detected, or there is more than one collision,
                // indicating number of collisions.
                // IsCollidingData isCollidingData                                                     = a_isCollidingData [octreeRayEntity] ;

                isColliding.i_collisionsCount = 0;  // Reset colliding instances counter.
                // isCollidingData.i_nearestInstanceCollisionIndex  = 0 ; // Unused
                // isCollidingData.f_nearestDistance                = float.PositiveInfinity ; // Unused



                // OctreeEntityPair4CollisionData octreeEntityPair4CollisionData                       = a_octreeEntityPair4CollisionData [octreeRayEntity] ;
                // RayData rayData                                                                     = a_rayData [octreeRayEntity] ;
                // RayMaxDistanceData rayMaxDistanceData   = a_rayMaxDistanceData [octreeRayEntity] ;


                // Octree entity pair, for collision checks

                Entity octreeRootNodeEntity = octreeEntityPair4Collision.octree2CheckEntity;

                // Is target octree active
                if (a_isActiveTag.Exists(octreeRootNodeEntity))
                {
                    RootNodeData rootNode = a_octreeRootNodeData [octreeRootNodeEntity];

                    DynamicBuffer <NodeBufferElement> a_nodesBuffer = nodeBufferElement [octreeRootNodeEntity];
                    DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer = nodeInstancesIndexBufferElement [octreeRootNodeEntity];
                    DynamicBuffer <NodeChildrenBufferElement>       a_nodeChildrenBuffer       = nodeChildrenBufferElement [octreeRootNodeEntity];
                    DynamicBuffer <InstanceBufferElement>           a_instanceBuffer           = instanceBufferElement [octreeRootNodeEntity];



                    // To even allow instances collision checks, octree must have at least one instance.
                    if (rootNode.i_totalInstancesCountInTree > 0)
                    {
                        if (IsRayColliding_Common._IsNodeColliding(ref rootNode, rootNode.i_rootNodeIndex, rayData.ray, ref isColliding, ref a_nodesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer, ref a_instanceBuffer, rayMaxDistance.f))
                        {
                            /*
                             * // Debug
                             * Debug.Log ( "Is colliding." ) ;
                             */
                        }
                    }
                }

                // a_isCollidingData [octreeRayEntity] = isCollidingData ; // Set back.
            }
Ejemplo n.º 8
0
        /// <summary>
        /// Set values for this node.
        /// </summary>
        /// <param name="f_baseLength">Length of this node, not taking looseness into account.</param>
        /// <param name="f_minSize">Minimum size of nodes in this octree.</param>
        /// <param name="f_looseness">Multiplier for baseLengthVal to get the actual size.</param>
        /// <param name="f3_center">Centre position of this node.</param>
        static public void _SetValues(RootNodeData rootNode, int i_nodeIndex, float f_baseLength, float3 f3_center, ref DynamicBuffer <NodeBufferElement> a_nodesBuffer, ref DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer)
        {
            NodeBufferElement nodeBuffer = a_nodesBuffer [i_nodeIndex];

            nodeBuffer.f_baseLength = f_baseLength;
            nodeBuffer.f3_center    = f3_center;
            float f_loosness     = rootNode.f_looseness - 1;
            float f_adjustLength = f_baseLength + f_loosness;

            // float f_adjustLength               = rootNode.f_looseness * f_baseLength ;
            nodeBuffer.f_adjLength = f_adjustLength;
            float3 size = new float3(f_adjustLength, f_adjustLength, f_adjustLength);

            // Create the bounding box.
            nodeBuffer.bounds           = new Bounds(f3_center, size);
            a_nodesBuffer [i_nodeIndex] = nodeBuffer;

            float f_quarter           = f_baseLength / 4f;
            float f_childActualLength = (f_baseLength / 2) + f_loosness;
            // float f_childActualLength          = ( f_baseLength / 2 ) * rootNode.f_looseness ;
            float3 f3_childActualSize    = new float3(f_childActualLength, f_childActualLength, f_childActualLength);
            int    i_childrenIndexOffset = i_nodeIndex * 8;



            NodeChildrenBufferElement nodeChildrenBuffer;

            // Set 8 children for this node
            nodeChildrenBuffer        = a_nodeChildrenBuffer [i_childrenIndexOffset];     // Get
            nodeChildrenBuffer.bounds = new Bounds(f3_center + new float3(-f_quarter, f_quarter, -f_quarter), f3_childActualSize);
            a_nodeChildrenBuffer [i_childrenIndexOffset] = nodeChildrenBuffer;            // Set back
            nodeChildrenBuffer        = a_nodeChildrenBuffer [i_childrenIndexOffset + 1]; // Get
            nodeChildrenBuffer.bounds = new Bounds(f3_center + new float3(f_quarter, f_quarter, -f_quarter), f3_childActualSize);
            a_nodeChildrenBuffer [i_childrenIndexOffset + 1] = nodeChildrenBuffer;        // Set back
            nodeChildrenBuffer        = a_nodeChildrenBuffer [i_childrenIndexOffset + 2]; // Get
            nodeChildrenBuffer.bounds = new Bounds(f3_center + new float3(-f_quarter, f_quarter, f_quarter), f3_childActualSize);
            a_nodeChildrenBuffer [i_childrenIndexOffset + 2] = nodeChildrenBuffer;        // Set back
            nodeChildrenBuffer        = a_nodeChildrenBuffer [i_childrenIndexOffset + 3]; // Get
            nodeChildrenBuffer.bounds = new Bounds(f3_center + new float3(f_quarter, f_quarter, f_quarter), f3_childActualSize);
            a_nodeChildrenBuffer [i_childrenIndexOffset + 3] = nodeChildrenBuffer;        // Set back
            nodeChildrenBuffer        = a_nodeChildrenBuffer [i_childrenIndexOffset + 4]; // Get
            nodeChildrenBuffer.bounds = new Bounds(f3_center + new float3(-f_quarter, -f_quarter, -f_quarter), f3_childActualSize);
            a_nodeChildrenBuffer [i_childrenIndexOffset + 4] = nodeChildrenBuffer;        // Set back
            nodeChildrenBuffer        = a_nodeChildrenBuffer [i_childrenIndexOffset + 5]; // Get
            nodeChildrenBuffer.bounds = new Bounds(f3_center + new float3(f_quarter, -f_quarter, -f_quarter), f3_childActualSize);
            a_nodeChildrenBuffer [i_childrenIndexOffset + 5] = nodeChildrenBuffer;        // Set back
            nodeChildrenBuffer        = a_nodeChildrenBuffer [i_childrenIndexOffset + 6]; // Get
            nodeChildrenBuffer.bounds = new Bounds(f3_center + new float3(-f_quarter, -f_quarter, f_quarter), f3_childActualSize);
            a_nodeChildrenBuffer [i_childrenIndexOffset + 6] = nodeChildrenBuffer;        // Set back
            nodeChildrenBuffer        = a_nodeChildrenBuffer [i_childrenIndexOffset + 7]; // Get
            nodeChildrenBuffer.bounds = new Bounds(f3_center + new float3(f_quarter, -f_quarter, f_quarter), f3_childActualSize);
            a_nodeChildrenBuffer [i_childrenIndexOffset + 7] = nodeChildrenBuffer;        // Set back
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Allows future reuse of spare instance, by putting it into the end of spares store.
        /// </summary>
        /// <param name="i_instanceIndex">Instance index, to pu back into spares of instances.</param>
        /// <param name="i_nodeIntstanceIndex">Node instance index holder, to be reset.</param>
        static public void _PutBackSpareInstance(ref RootNodeData rootNode, int i_instanceIndex, int i_nodeIntstanceIndex, ref DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, ref DynamicBuffer <InstancesSpareIndexBufferElement> a_instancesSpareIndexBuffer)
        {
            if (i_instanceIndex < 0)
            {
                return;                           // This instance index has not been used.
            }
            rootNode.i_instancesSpareLastIndex++; // Put back to spare

            // Is assumed, that size of spares store, is appropriate.
            InstancesSpareIndexBufferElement instancesSpareIndexBuffer = new InstancesSpareIndexBufferElement();

            instancesSpareIndexBuffer.i = i_instanceIndex;
            a_instancesSpareIndexBuffer [rootNode.i_instancesSpareLastIndex] = instancesSpareIndexBuffer;

            NodeInstancesIndexBufferElement nodeInstancesIndexBuffer = new NodeInstancesIndexBufferElement();

            nodeInstancesIndexBuffer.i = -1;  // Reset instance index.
            a_nodeInstancesIndexBuffer [i_nodeIntstanceIndex] = nodeInstancesIndexBuffer;
        }
        /// <summary>
        /// Checks if there are few enough objects in this node and its children that the children should all be merged into this.
        /// </summary>
        /// <param name="i_nodeIndex">Internal octree node index.</param>
        /// <returns>True there are less or the same abount of objects in this and its children than numObjectsAllowed.</returns>
        static private bool _ShouldMerge(ref RootNodeData rootNode, int i_nodeIndex, DynamicBuffer <NodeBufferElement> a_nodesBuffer, ref DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer)
        {
            NodeBufferElement nodeBuffer = a_nodesBuffer [i_nodeIndex];

            int i_totalInstancesCount     = nodeBuffer.i_instancesCount;
            int i_nodeChildrenIndexOffset = i_nodeIndex * 8;

            int i_childrenCount = nodeBuffer.i_childrenCount;

            // Has children?
            if (i_childrenCount > 0)
            {
                for (int i = 0; i < 8; i++)
                {
                    NodeChildrenBufferElement nodeChildrenBuffer = a_nodeChildrenBuffer [i_nodeChildrenIndexOffset + i];
                    int i_childNodeIndex = nodeChildrenBuffer.i_group8NodesIndex;

                    if (i_childNodeIndex >= 0)
                    {
                        nodeBuffer = a_nodesBuffer [i_childNodeIndex];
                        int i_nodefChildChildrenCount = nodeBuffer.i_childrenCount;

                        if (i_nodefChildChildrenCount > 0)
                        {
                            // If any of the *children* have children, there are definitely too many to merge,
                            // or the child would have been merged already
                            return(false);
                        }

                        i_totalInstancesCount += nodeBuffer.i_instancesCount;

                        i_childrenCount--;

                        if (i_childrenCount == 0)
                        {
                            break;
                        }
                    }
                }
            }

            return(i_totalInstancesCount <= rootNode.i_instancesAllowedCount);
        }
Ejemplo n.º 11
0
            public void Execute(Entity octreeRootNodeEntity, int jobIndex, [ReadOnly] ref AddNewOctreeData addNewOctree)
            // public void Execute ( int i_arrayIndex )
            {
                // Entity octreeRootNodeEntity = a_newOctreeEntities [i_arrayIndex] ;


                // AddNewOctreeData addNewOctreeData                                                   = a_addNewOctreeData [octreeRootNodeEntity] ;

                RootNodeData rootNode = a_rootNodeData [octreeRootNodeEntity];

                rootNode.i_nodeSpareLastIndex--;


                DynamicBuffer <NodeSparesBufferElement>         a_nodeSparesBuffer         = nodeSparesBufferElement [octreeRootNodeEntity];
                DynamicBuffer <NodeBufferElement>               a_nodesBuffer              = nodeBufferElement [octreeRootNodeEntity];
                DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer = nodeInstancesIndexBufferElement [octreeRootNodeEntity];
                DynamicBuffer <NodeChildrenBufferElement>       a_nodeChildrenBuffer       = nodeChildrenBufferElement [octreeRootNodeEntity];

                CommonMethods._CreateNewNode(ref rootNode, rootNode.i_rootNodeIndex, addNewOctree.f_initialSize, addNewOctree.f3_initialPosition, ref a_nodesBuffer, ref a_nodeSparesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer);

                rootNode.i_nodeSpareLastIndex--;

                rootNode.i_instancesSpareLastIndex = 0;


                DynamicBuffer <InstanceBufferElement>            a_instanceBuffer            = instanceBufferElement [octreeRootNodeEntity];
                DynamicBuffer <InstancesSpareIndexBufferElement> a_instancesSpareIndexBuffer = instancesSpareIndexBufferElement [octreeRootNodeEntity];

                // Add some spares if needed.
                //int i_requiredNumberOfInstances = CommonMethods.numOfSpareInstances2Add ;
                //int i_requiredNumberOfInstances = Octree.Examples.ExampleSelector.i_generateInstanceInOctreeCount ;
                int i_requiredNumberOfSpareInstances = 100;

                CommonMethods._AddInstanceSpares(ref rootNode, ref a_instanceBuffer, ref a_instancesSpareIndexBuffer, i_requiredNumberOfSpareInstances);



                a_rootNodeData [octreeRootNodeEntity] = rootNode;  // Set back
            }
Ejemplo n.º 12
0
        /// <summary>
        /// Add required new spare instances.
        /// </summary>
        static public void _AddInstanceSpares(ref RootNodeData rootNode, ref DynamicBuffer <InstanceBufferElement> a_instanceBuffer, ref DynamicBuffer <InstancesSpareIndexBufferElement> a_instancesSpareIndexBuffer, int i_requiredNumberOfInstances)
        {
            rootNode.i_instancesSpareLastIndex--;

            int i_initialSparesCount      = a_instanceBuffer.Length;
            int i_spareInstances2AddCount = i_requiredNumberOfInstances - i_initialSparesCount;

            InstancesSpareIndexBufferElement instancesSpareIndexBuffer = new InstancesSpareIndexBufferElement();

            instancesSpareIndexBuffer.i = -1;

            InstanceBufferElement instanceBuffer = new InstanceBufferElement();

            instanceBuffer.bounds          = new Bounds();
            instanceBuffer.i_ID            = -1;
            instanceBuffer.i_entityVersion = -1;                                    // Optional, used when Id is used as entity index


            // Add new spares, from the end of storage.
            for (int i = 0; i < i_spareInstances2AddCount; i++)
            {
                // Need to expand spare store.
                a_instancesSpareIndexBuffer.Add(instancesSpareIndexBuffer);
                a_instanceBuffer.Add(instanceBuffer);
            }

            // Populate indexes references, with new spares.
            for (int i = 0; i < i_spareInstances2AddCount; i++)
            {
                rootNode.i_instancesSpareLastIndex++;

                // Add new spares.
                // Add spares in reversed order, from higher index, to lower index.
                instancesSpareIndexBuffer.i = i_initialSparesCount + i_spareInstances2AddCount - i - 1;
                a_instancesSpareIndexBuffer [rootNode.i_instancesSpareLastIndex] = instancesSpareIndexBuffer;
            }
        }
        /// <summary>
        /// Check if the specified bounds intersect with anything in the tree. See also: GetColliding.
        /// </summary>
        /// <param name="i_nodeIndex">Internal octree node index.</param>
        /// <param name="checkBounds">Bounds to check.</param>
        /// <returns>True if there was a collision.</returns>
        static public bool _IsNodeColliding([ReadOnly] ref RootNodeData rootNode, int i_nodeIndex, Bounds checkBounds, ref IsCollidingData isCollidingData, [ReadOnly] ref DynamicBuffer <NodeBufferElement> a_nodesBuffer, [ReadOnly] ref DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, [ReadOnly] ref DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, [ReadOnly] ref DynamicBuffer <InstanceBufferElement> a_instanceBuffer)
        {
            NodeBufferElement nodeBuffer = a_nodesBuffer [i_nodeIndex];

            // Are the input bounds at least partially in this node?
            if (!nodeBuffer.bounds.Intersects(checkBounds))
            {
                return(false);
            }


            if (nodeBuffer.i_instancesCount >= 0)
            {
                int i_nodeInstancesIndexOffset = i_nodeIndex * rootNode.i_instancesAllowedCount;

                // Check against any objects in this node
                for (int i = 0; i < rootNode.i_instancesAllowedCount; i++)
                {
                    NodeInstancesIndexBufferElement nodeInstancesIndexBuffer = a_nodeInstancesIndexBuffer [i_nodeInstancesIndexOffset + i];

                    // Get index of instance
                    int i_instanceIndex = nodeInstancesIndexBuffer.i;

                    // Check if instance exists, and if has intersecting bounds.
                    if (i_instanceIndex >= 0)
                    {
                        InstanceBufferElement instanceBuffer = a_instanceBuffer [i_instanceIndex];

                        // Check if instance exists, and if has intersecting bounds.
                        if (instanceBuffer.bounds.Intersects(checkBounds))
                        {
                            isCollidingData.i_collisionsCount = 1;
                            return(true);
                        }
                    }
                }
            }

            // Check children for collisions
            // Check if having children
            if (nodeBuffer.i_childrenCount > 0)
            {
                int i_nodeChildrenIndexOffset = i_nodeIndex * 8;

                // We checked that is having children.
                for (int i = 0; i < 8; i++)
                {
                    NodeChildrenBufferElement nodeChildrenBuffer = a_nodeChildrenBuffer [i_nodeChildrenIndexOffset + i];
                    int i_nodeChildIndex = nodeChildrenBuffer.i_group8NodesIndex;

                    // Check if node exists
                    if (i_nodeChildIndex >= 0)
                    {
                        if (_IsNodeColliding(ref rootNode, i_nodeChildIndex, checkBounds, ref isCollidingData, ref a_nodesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer, ref a_instanceBuffer))
                        {
                            isCollidingData.i_collisionsCount = 1;
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
        } // Job


        /*
         * /// <summary>
         *  /// Remove an instance. Makes the assumption that the instance only exists once in the tree.
         *  /// </summary>
         *  /// <param name="i_instanceID">External instance to remove.</param>
         *  /// <returns>True if the object was removed successfully.</returns>
         *  public bool _OctreeRemoveInstance ( ref RootNodeData rootNodeData, int i_instanceID, DynamicBuffer <NodeBufferElement> a_nodesBuffer, ref DynamicBuffer <NodeSparesBufferElement> a_nodeSparesBuffer, ref DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, ref DynamicBuffer <InstanceBufferElement> a_instanceBuffer, ref DynamicBuffer <InstancesSpareIndexBufferElement> a_instancesSpareIndexBuffer )
         * {
         *
         *  bool removed = _NodeRemoveInstance (
         *      ref rootNodeData,
         *      rootNodeData.i_rootNodeIndex,
         *      i_instanceID,
         *      ref a_nodesBuffer,
         *      ref a_nodeSparesBuffer,
         *      a_nodeChildrenBuffer,
         *      a_nodeInstancesIndexBuffer,
         *      ref a_instanceBuffer,
         *      ref a_instancesSpareIndexBuffer
         *  );
         *
         *          // See if we can shrink the octree down now that we've removed the item
         *          if ( removed )
         *  {
         *                  rootNodeData.i_totalInstancesCountInTree -- ;
         *
         *      // Shrink if possible.
         *      rootNodeData.i_rootNodeIndex = _ShrinkIfPossible (
         *          rootNodeData,
         *          rootNodeData.i_rootNodeIndex,
         *          rootNodeData.f_initialSize,
         *          a_nodesBuffer,
         *          ref a_nodeChildrenBuffer,
         *          a_nodeInstancesIndexBuffer,
         *          a_instanceBuffer
         *      ) ;
         *          }
         *
         *          return removed ;
         *  }
         */


        /// <summary>
        /// Remove an instace. Makes the assumption that the instance only exists once in the tree.
        /// </summary>
        /// <param name="i_nodeIndex">Internal octree node index.</param>
        /// <param name="i_instanceID">External instance index ID to remove. Is assumed, only one unique instance ID exists in the tree.</param>
        /// <returns>True if the object was removed successfully.</returns>
        static private bool _NodeRemoveInstance(ref RootNodeData rootNode, int i_nodeIndex, int i_instanceID, ref DynamicBuffer <NodeBufferElement> a_nodesBuffer, ref DynamicBuffer <NodeSparesBufferElement> a_nodeSparesBuffer, DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, ref DynamicBuffer <InstanceBufferElement> a_instanceBuffer, ref DynamicBuffer <InstancesSpareIndexBufferElement> a_instancesSpareIndexBuffer)
        {
            bool removed = false;

            NodeBufferElement nodeBuffer = a_nodesBuffer [i_nodeIndex];

            int i_nodeInstancesIndexOffset = i_nodeIndex * rootNode.i_instancesAllowedCount;

            if (nodeBuffer.i_instancesCount > 0)
            {
                // Try remove instance from this node
                for (int i = 0; i < rootNode.i_instancesAllowedCount; i++)
                {
                    int i_nodeInstanceIndex = i_nodeInstancesIndexOffset + i;

                    NodeInstancesIndexBufferElement nodeInstancesIndexBuffer = a_nodeInstancesIndexBuffer [i_nodeInstancesIndexOffset + i];
                    int i_existingInstanceIndex = nodeInstancesIndexBuffer.i;

                    // If instance exists
                    if (i_existingInstanceIndex >= 0)
                    {
                        InstanceBufferElement instanceBuffer = a_instanceBuffer [i_existingInstanceIndex];
                        if (instanceBuffer.i_ID == i_instanceID)
                        {
                            removed = true;

                            // Remove from here
                            CommonMethods._PutBackSpareInstance(ref rootNode, i_existingInstanceIndex, i_nodeInstanceIndex, ref a_nodeInstancesIndexBuffer, ref a_instancesSpareIndexBuffer);

/*
 *                          // Debugging
 *  GameObject go = GameObject.Find ( "Instance " + i_instanceID.ToString () ) ;
 *
 *  if ( go != null )
 *  {
 *      Debug.Log ( "Instance: Hide game object #" + i_instanceID.ToString () ) ;
 *      go.SetActive ( false ) ;
 *      // go.transform.localScale = instanceBounds.size ;
 *  }
 *
 *     Debug.LogWarning ( "Node: Remove #" + i_nodeIndex ) ;
 *  GameObject.Destroy ( GameObject.Find ( "Node " + i_nodeIndex.ToString () ) ) ;
 */
                            nodeBuffer.i_instancesCount--;
                            instanceBuffer.i_ID = -1;                                    // Reset
                            a_instanceBuffer [i_existingInstanceIndex] = instanceBuffer; // Set back



                            break;
                        }
                    }
                }                                         // for

                a_nodesBuffer [i_nodeIndex] = nodeBuffer; // Set back
            }


            int i_nodeChildrenCount       = nodeBuffer.i_childrenCount;
            int i_nodeChildrenIndexOffset = i_nodeIndex * 8;

            // Try remove instance from this node children, if node don't have this instance
            if (!removed && i_nodeChildrenCount > 0)
            {
                for (int i = 0; i < 8; i++)
                {
                    // Get children index of this node

                    NodeChildrenBufferElement nodeChildrenBuffer = a_nodeChildrenBuffer [i_nodeChildrenIndexOffset + i];
                    int i_childNodeIndex = nodeChildrenBuffer.i_group8NodesIndex;

                    // Ignore negative index
                    if (i_childNodeIndex >= 0)
                    {
                        removed = _NodeRemoveInstance(
                            ref rootNode,
                            i_childNodeIndex,
                            i_instanceID,
                            ref a_nodesBuffer,
                            ref a_nodeSparesBuffer,
                            a_nodeChildrenBuffer,
                            a_nodeInstancesIndexBuffer,
                            ref a_instanceBuffer,
                            ref a_instancesSpareIndexBuffer
                            );

                        if (removed)
                        {
                            break;
                        }
                    }
                }
            }

            if (removed && i_nodeChildrenCount > 0)
            {
                // Check if we should merge nodes now that we've removed an item
                if (_ShouldMerge(ref rootNode, i_nodeIndex, a_nodesBuffer, ref a_nodeChildrenBuffer))
                {
                    _MergeNodes(
                        ref rootNode,
                        i_nodeIndex,
                        ref a_nodesBuffer,
                        ref a_nodeSparesBuffer,
                        a_nodeChildrenBuffer,
                        a_nodeInstancesIndexBuffer,
                        ref a_instancesSpareIndexBuffer
                        );
                }
            }

            return(removed);
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Grow the octree to fit in all objects.
        /// </summary>
        /// <param name="f3_direction">Direction to grow.</param>
        static private void _GrowOctree(ref RootNodeData rootNode, float3 f3_direction, ref DynamicBuffer <NodeBufferElement> a_nodesBuffer, ref DynamicBuffer <NodeSparesBufferElement> a_nodeSparesBuffer, ref DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, ref DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, ref DynamicBuffer <InstanceBufferElement> a_instanceBuffer, ref DynamicBuffer <InstancesSpareIndexBufferElement> a_instancesSpareIndexBuffer)
        {
            int xDirection = f3_direction.x >= 0 ? 1 : -1;
            int yDirection = f3_direction.y >= 0 ? 1 : -1;
            int zDirection = f3_direction.z >= 0 ? 1 : -1;



            int i_oldRootNodeIndex = rootNode.i_rootNodeIndex;
            NodeBufferElement nodeBufferElement = a_nodesBuffer [i_oldRootNodeIndex];
            float             f_baseLength      = nodeBufferElement.f_baseLength;
            float             f_half            = f_baseLength / 2;
            float             f_newBaseLength   = f_baseLength * 2;

            float3 f3_newCenter = nodeBufferElement.f3_center + new float3(xDirection * f_half, yDirection * f_half, zDirection * f_half);

// Debug.LogWarning ( "Grow: " + f3_newCenter + "; new base length: " + f_newBaseLength + "; halve: " + f_half + "; pos: " + f3_newCenter ) ;
            // Create a new, bigger octree root node

            if (!CommonMethods._HasAnyInstances(i_oldRootNodeIndex, a_nodesBuffer, a_nodeChildrenBuffer))
            {
                CommonMethods._CreateNewNode(
                    ref rootNode,
                    rootNode.i_rootNodeIndex,
                    f_newBaseLength,
                    f3_newCenter,
                    ref a_nodesBuffer,
                    ref a_nodeSparesBuffer,
                    ref a_nodeChildrenBuffer,
                    ref a_nodeInstancesIndexBuffer
                    );
            }
            else
            {
                NodeSparesBufferElement nodeSparesBuffer = a_nodeSparesBuffer [rootNode.i_nodeSpareLastIndex];
                rootNode.i_rootNodeIndex = nodeSparesBuffer.i;

                rootNode.i_nodeSpareLastIndex--;

                CommonMethods._CreateNewNode(
                    ref rootNode,
                    rootNode.i_rootNodeIndex,
                    f_newBaseLength,
                    f3_newCenter,
                    ref a_nodesBuffer,
                    ref a_nodeSparesBuffer,
                    ref a_nodeChildrenBuffer,
                    ref a_nodeInstancesIndexBuffer
                    );


                // Create 7 new octree children to go with the old root as children of the new root
                int i_rootPos = _GetRootPosIndex(xDirection, yDirection, zDirection);


                NodeBufferElement nodeBuffer = a_nodesBuffer [rootNode.i_rootNodeIndex];
                nodeBuffer.i_childrenCount = 8;
                a_nodesBuffer [rootNode.i_rootNodeIndex] = nodeBuffer;  // Set back.

                int i_newRootNodeChildrenIndexOffset = rootNode.i_rootNodeIndex * 8;

                for (int i = 0; i < 8; i++)
                {
                    int i_childIndexOffset = i_newRootNodeChildrenIndexOffset + i;

                    NodeChildrenBufferElement nodeChildrenBuffer = a_nodeChildrenBuffer [i_childIndexOffset];

                    if (i == i_rootPos)
                    {
                        // Assign old root node as a child.
                        nodeChildrenBuffer.i_group8NodesIndex = i_oldRootNodeIndex;
                        InstanceBufferElement instanceBuffer = a_instanceBuffer [i_oldRootNodeIndex];
                        nodeChildrenBuffer.bounds = instanceBuffer.bounds;
                    }
                    else
                    {
                        // Assign rest 7 children
                        xDirection = i % 2 == 0 ? -1 : 1;
                        yDirection = i > 3 ? -1 : 1;
                        zDirection = (i < 2 || (i > 3 && i < 6)) ? -1 : 1;

                        nodeSparesBuffer = a_nodeSparesBuffer [rootNode.i_nodeSpareLastIndex];
                        int i_newNodeIndex = nodeSparesBuffer.i;                       // Expected output 0 at initialization
                        rootNode.i_nodeSpareLastIndex--;

                        float3 f3_childVector = f3_newCenter + new float3(xDirection * f_half, yDirection * f_half, zDirection * f_half);

                        CommonMethods._CreateNewNode(
                            ref rootNode,
                            i_newNodeIndex,
                            f_newBaseLength,
                            f3_childVector,
                            ref a_nodesBuffer,
                            ref a_nodeSparesBuffer,
                            ref a_nodeChildrenBuffer,
                            ref a_nodeInstancesIndexBuffer
                            );


                        nodeChildrenBuffer.i_group8NodesIndex = i_newNodeIndex;

                        Bounds bounds = new Bounds( )
                        {
                            center = f3_childVector,
                            size   = Vector3.one * f_newBaseLength
                        };

                        nodeChildrenBuffer.bounds = bounds;
                    }

                    a_nodeChildrenBuffer [i_childIndexOffset] = nodeChildrenBuffer; // Set back.
                }                                                                   // for
            }
        }
        /// <summary>
        /// Returns an array of objects that intersect with the specified ray, if any. Otherwise returns an empty array. See also: IsColliding.
        /// </summary>
        /// <param name="i_nodeIndex">Internal octree node index.</param>
        /// <param name="checkRay">Ray to check. Passing by ref as it improves performance with structs.</param>
        /// <param name="l_resultInstanceIDs">List result.</param>
        /// <param name="i_nearestIndex">Nerest collision index from the lits.</param>
        /// <param name="f_nearestDistance">Nerest collision distance.</param>
        /// <param name="maxDistance">Distance to check.</param>
        /// <returns>Instances index, that intersect with the specified ray.</returns>
        static public bool _GetNodeColliding([ReadOnly] ref RootNodeData rootNode, int i_nodeIndex, Ray checkRay, ref DynamicBuffer <CollisionInstancesBufferElement> a_collisionInstancesBuffer, ref IsCollidingData isCollidingData, [ReadOnly] ref DynamicBuffer <NodeBufferElement> a_nodesBuffer, [ReadOnly] ref DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, [ReadOnly] ref DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, [ReadOnly] ref DynamicBuffer <InstanceBufferElement> a_instanceBuffer, float f_maxDistance = float.PositiveInfinity)
        {
            float f_distance;

            NodeBufferElement nodeBuffer = a_nodesBuffer [i_nodeIndex];

            if (!nodeBuffer.bounds.IntersectRay(checkRay, out f_distance) || f_distance > f_maxDistance)
            {
                // Debug.Log ( "None intersect: " + rootNode.i_rootNodeIndex + "; " + i_nodeIndex + "; " + isCollidingData.i_collisionsCount + "; ch count: " + nodeBuffer.i_childrenCount + "; i count: " + nodeBuffer.i_instancesCount ) ;

                return(isCollidingData.i_collisionsCount > 0 ? true : false);
            }

            // Debug.Log ( "Intersect: " + rootNode.i_rootNodeIndex + "; " + i_nodeIndex + "; " + isCollidingData.i_collisionsCount + "; ch count: " + nodeBuffer.i_childrenCount + "; i count: " + nodeBuffer.i_instancesCount ) ;

            if (nodeBuffer.i_instancesCount > 0)
            {
                int i_nodeInstancesIndexOffset = i_nodeIndex * rootNode.i_instancesAllowedCount;

                CollisionInstancesBufferElement collisionInstancesBuffer = new CollisionInstancesBufferElement();

                // Check against any objects in this node
                for (int i = 0; i < rootNode.i_instancesAllowedCount; i++)
                {
                    NodeInstancesIndexBufferElement nodeInstancesIndexBuffer = a_nodeInstancesIndexBuffer [i_nodeInstancesIndexOffset + i];

                    // Get index of instance
                    int i_instanceIndex = nodeInstancesIndexBuffer.i;

                    // Check if instance exists, and if has intersecting bounds.
                    if (i_instanceIndex >= 0)
                    {
                        InstanceBufferElement instanceBuffer = a_instanceBuffer [i_instanceIndex];


                        if (instanceBuffer.bounds.IntersectRay(checkRay, out f_distance) && f_distance <= f_maxDistance)
                        {
                            if (f_distance < isCollidingData.f_nearestDistance)
                            {
                                isCollidingData.f_nearestDistance = f_distance;
                                isCollidingData.i_nearestInstanceCollisionIndex = isCollidingData.i_collisionsCount;
                            }


                            // Is expected, that the required length is no greater than current length + 1
                            // And is not negative.
                            int i_collisionsCount = isCollidingData.i_collisionsCount;
                            collisionInstancesBuffer.i_ID      = instanceBuffer.i_ID;
                            collisionInstancesBuffer.i_version = instanceBuffer.i_entityVersion;  // Optional, used when Id is used as entity index

                            // Assign colliding instance ID to buffer.
                            if (a_collisionInstancesBuffer.Length <= i_collisionsCount)
                            {
                                // Expand buffer if needed
                                a_collisionInstancesBuffer.Add(collisionInstancesBuffer);
                            }
                            else
                            {
                                a_collisionInstancesBuffer [i_collisionsCount] = collisionInstancesBuffer;
                            }

                            isCollidingData.i_collisionsCount++;
                        }
                    }
                }
            }

            // Check children for collisions
            // Check if having children
            if (nodeBuffer.i_childrenCount > 0)
            {
                int i_nodeChildrenIndexOffset = i_nodeIndex * 8;

                // We checked that is having children.
                for (int i = 0; i < 8; i++)
                {
                    NodeChildrenBufferElement nodeChildrenBuffer = a_nodeChildrenBuffer [i_nodeChildrenIndexOffset + i];
                    int i_nodeChildIndex = nodeChildrenBuffer.i_group8NodesIndex;

                    // Check if node exists
                    if (i_nodeChildIndex >= 0)
                    {
                        _GetNodeColliding(ref rootNode, i_nodeChildIndex, checkRay, ref a_collisionInstancesBuffer, ref isCollidingData, ref a_nodesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer, ref a_instanceBuffer, f_maxDistance);
                    }
                }
            }

            return(isCollidingData.i_collisionsCount > 0 ? true : false);
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Check if the specified ray intersects with anything in the tree. See also: GetColliding.
        /// </summary>
        /// <param name="i_nodeIndex">Internal octree node index.</param>
        /// <param name="checkRay">Ray to check.</param>
        /// <param name="f_maxDistance">Distance to check.</param>
        /// <returns>True if there was a collision.</returns>
        static public bool _IsNodeColliding([ReadOnly] ref RootNodeData rootNode, int i_nodeIndex, Ray checkRay, ref IsCollidingData isCollidingData, [ReadOnly] ref DynamicBuffer <NodeBufferElement> a_nodesBuffer, [ReadOnly] ref DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, [ReadOnly] ref DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, [ReadOnly] ref DynamicBuffer <InstanceBufferElement> a_instanceBuffer, float f_maxDistance = float.PositiveInfinity)
        {
            // Is the input ray at least partially in this node?

            float f_distance;

            NodeBufferElement nodeBuffer = a_nodesBuffer [i_nodeIndex];

            if (!nodeBuffer.bounds.IntersectRay(checkRay, out f_distance) || f_distance > f_maxDistance)
            {
                return(false);
            }

            if (nodeBuffer.i_instancesCount >= 0)
            {
                int i_nodeInstancesIndexOffset = i_nodeIndex * rootNode.i_instancesAllowedCount;

                // Check against any objects in this node
                for (int i = 0; i < rootNode.i_instancesAllowedCount; i++)
                {
                    NodeInstancesIndexBufferElement nodeInstancesIndexBuffer = a_nodeInstancesIndexBuffer [i_nodeInstancesIndexOffset + i];

                    // Get index of instance
                    int i_instanceIndex = nodeInstancesIndexBuffer.i;

                    // Check if instance exists, and if has intersecting bounds.
                    if (i_instanceIndex >= 0)
                    {
                        InstanceBufferElement instanceBuffer = a_instanceBuffer [i_instanceIndex];

                        if (instanceBuffer.bounds.IntersectRay(checkRay, out f_distance) && f_distance <= f_maxDistance)
                        {
                            isCollidingData.i_collisionsCount = 1;  // Is colliding
                            return(true);
                        }
                    }
                }
            }

            // Check children for collisions
            // Check if having children
            if (nodeBuffer.i_childrenCount > 0)
            {
                int i_nodeChildrenIndexOffset = i_nodeIndex * 8;

                // We checked that is having children.
                for (int i = 0; i < 8; i++)
                {
                    NodeChildrenBufferElement nodeChildrenBuffer = a_nodeChildrenBuffer [i_nodeChildrenIndexOffset + i];
                    int i_nodeChildIndex = nodeChildrenBuffer.i_group8NodesIndex;

                    // Check if node exists
                    if (i_nodeChildIndex >= 0)
                    {
                        if (_IsNodeColliding(ref rootNode, i_nodeChildIndex, checkRay, ref isCollidingData, ref a_nodesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer, ref a_instanceBuffer, f_maxDistance))
                        {
                            isCollidingData.i_collisionsCount = 1;  // Is colliding
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Returns an collection of instances, that intersect with the specified bounds, if any. Otherwise returns an empty array. See also: IsColliding.
        /// </summary>
        /// <param name="i_nodeIndex">Internal octree node index.</param>
        /// <param name="checkBounds">Bounds to check. Passing by ref as it improves performance with structs.</param>
        /// <param name="l_resultInstanceIDs">List result.</param>
        static public bool _GetNodeColliding([ReadOnly] ref RootNodeData octreeRootNode, int i_nodeIndex, Bounds checkBounds, ref DynamicBuffer <CollisionInstancesBufferElement> a_collisionInstancesBuffer, ref IsCollidingData isColliding, [ReadOnly] ref DynamicBuffer <NodeBufferElement> a_nodesBuffer, [ReadOnly] ref DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, [ReadOnly] ref DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, [ReadOnly] ref DynamicBuffer <InstanceBufferElement> a_instanceBuffer)
        {
            // float f_distance ;
            CollisionInstancesBufferElement collisionInstancesBuffer = new CollisionInstancesBufferElement();

            NodeBufferElement nodeBuffer = a_nodesBuffer [i_nodeIndex];

            // Are the input bounds at least partially in this node?
            if (!nodeBuffer.bounds.Intersects(checkBounds))
            {
                return(isColliding.i_collisionsCount > 0 ? true : false);
            }


            if (nodeBuffer.i_instancesCount >= 0)
            {
                int i_nodeInstancesIndexOffset = i_nodeIndex * octreeRootNode.i_instancesAllowedCount;

                // Check against any objects in this node
                for (int i = 0; i < octreeRootNode.i_instancesAllowedCount; i++)
                {
                    NodeInstancesIndexBufferElement nodeInstancesIndexBuffer = a_nodeInstancesIndexBuffer [i_nodeInstancesIndexOffset + i];

                    // Get index of instance
                    int i_instanceIndex = nodeInstancesIndexBuffer.i;

                    // Check if instance exists, and if has intersecting bounds.
                    if (i_instanceIndex >= 0)
                    {
                        InstanceBufferElement instanceBuffer = a_instanceBuffer [i_instanceIndex];

                        // Check if instance exists, and if has intersecting bounds.
                        if (instanceBuffer.bounds.Intersects(checkBounds))
                        {
                            // l_resultInstanceIDs.Add ( instanceBuffer.i_ID ) ;

                            //if ( f_distance < isCollidingData.f_nearestDistance )
                            //{
                            //    isCollidingData.f_nearestDistance = f_distance ;
                            //    isCollidingData.i_nearestInstanceCollisionIndex = isCollidingData.i_collisionsCount ;
                            //}



                            // Is expected, that the required length is no greater than current length + 1
                            // And is not negative.
                            int i_collisionsCount = isColliding.i_collisionsCount;
                            collisionInstancesBuffer.i_ID      = instanceBuffer.i_ID;
                            collisionInstancesBuffer.i_version = instanceBuffer.i_entityVersion;  // Optional, used when Id is used as entity index

                            // Assign colliding instance ID to buffer.
                            if (a_collisionInstancesBuffer.Length <= i_collisionsCount)
                            {
                                // Expand buffer if needed
                                a_collisionInstancesBuffer.Add(collisionInstancesBuffer);
                            }
                            else
                            {
                                a_collisionInstancesBuffer [i_collisionsCount] = collisionInstancesBuffer;
                            }

                            isColliding.i_collisionsCount++;
                        }
                    }
                }
            }

            // Check children for collisions
            // Check if having children
            if (nodeBuffer.i_childrenCount > 0)
            {
                int i_nodeChildrenIndexOffset = i_nodeIndex * 8;

                // We checked that is having children.
                for (int i = 0; i < 8; i++)
                {
                    NodeChildrenBufferElement nodeChildrenBuffer = a_nodeChildrenBuffer [i_nodeChildrenIndexOffset + i];
                    int i_nodeChildIndex = nodeChildrenBuffer.i_group8NodesIndex;

                    // Check if node exists
                    if (i_nodeChildIndex >= 0)
                    {
                        _GetNodeColliding(ref octreeRootNode, i_nodeChildIndex, checkBounds, ref a_collisionInstancesBuffer, ref isColliding, ref a_nodesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer, ref a_instanceBuffer);
                    }
                }
            }

            return(isColliding.i_collisionsCount > 0 ? true : false);
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Assign instance to node.
        /// </summary>
        /// <param name="i_nodeIndex">Internal octree node index.</param>
        /// <param name="i_instanceID">External instance index, ot unique entity index.</param>
        /// <param name="i_entityVersion">Optional, used when Id is used as entity index.</param>
        /// // Optional, used when Id is used as entity index
        /// <param name="instanceBounds">Boundary of external instance index.</param>
        static private bool _AssingInstance2Node(ref RootNodeData rootNode, int i_nodeIndex, int i_instanceID, int i_entityVersion, Bounds instanceBounds, ref DynamicBuffer <NodeBufferElement> a_nodesBuffer, ref DynamicBuffer <NodeSparesBufferElement> a_nodeSparesBuffer, ref DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, ref DynamicBuffer <InstanceBufferElement> a_instanceBuffer, ref DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, ref DynamicBuffer <InstancesSpareIndexBufferElement> a_instancesSpareIndexBuffer)
        {
            int i_nodeInstanceIndexOffset = i_nodeIndex * rootNode.i_instancesAllowedCount;

//             Debug.Log ( "Assign instance 2 Node; node offset " + i_nodeInstanceIndexOffset + " Instance ID: " + i_instanceID ) ;

            // Reuse spare store
            InstancesSpareIndexBufferElement instancesSpareIndexBuffer = a_instancesSpareIndexBuffer [rootNode.i_instancesSpareLastIndex];

            NodeInstancesIndexBufferElement nodeInstancesIndexBuffer;

            bool isInstanceAdded = false;

            // Find next spare instance allocation for this node.
            // Find next spare instance allocation for this node.
            for (int i = 0; i < rootNode.i_instancesAllowedCount; i++)
            {
                int i_instanceIndexOffset = i_nodeInstanceIndexOffset + i;

                nodeInstancesIndexBuffer = a_nodeInstancesIndexBuffer [i_instanceIndexOffset];

                NodeChildrenBufferElement nodeChildrenBuffer = a_nodeChildrenBuffer [i_nodeIndex]; // Only test. Remove.
// Debug.Log ( "#" + i + " offset: " + i_instanceIndexOffset + " node index -1? " + nodeInstancesIndexBuffer.i + " <= " + instancesSpareIndexBuffer.i + "; bounds: " + nodeChildrenBuffer.bounds ) ;
                // Is spare.
                if (nodeInstancesIndexBuffer.i == -1)
                {
                    // Assign instance index.
                    nodeInstancesIndexBuffer.i = instancesSpareIndexBuffer.i;
                    a_nodeInstancesIndexBuffer [i_instanceIndexOffset] = nodeInstancesIndexBuffer;  // Set back.

                    isInstanceAdded = true;

                    break;
                }
            } // for

// Debug.Log ( "Node index: " + i_nodeIndex + " Is instance ID " + i_instanceID + " added: " + isInstanceAdded ) ;

            if (!isInstanceAdded)
            {
                // Node has 8 children and an more instances, than capacity.
                // Try to move instance to child, with instance space.
                // if ( i_instancesCount < rootNodeData.i_instancesAllowedCount && i_childrenCount > 0 )

                // Iterate though node's children
                for (int i_childIndex = 0; i_childIndex < 8; i_childIndex++)
                {
                    int i_childIndexOffset = i_nodeIndex * 8 + i_childIndex;

                    NodeChildrenBufferElement nodeChildrenBuffer = a_nodeChildrenBuffer [i_childIndexOffset];

// Debug.Log ( "Is instance child " + i_childIndex + " / " + 8 + "; " + i_instanceID + "; child buffer: " + nodeChildrenBuffer.bounds ) ;

                    // Check if instance bounds fit in child
                    if (CommonMethods._Encapsulates(nodeChildrenBuffer.bounds, instanceBounds))
                    {
// Debug.Log ( "Encapsulates B instance ID: " + i_instanceID + "; bound: " + instanceBounds + " in node " + nodeChildrenBuffer.bounds ) ;

                        //NodeBufferElement childNode = a_nodesBuffer [nodeChildrenBuffer.i_nodesIndex] ;

                        // Debug.LogWarning ( "ChNode: " + childNode.i_instancesCount + "; " + childNode.bounds ) ;


                        int i_requiredNumberOfInstances = a_nodeInstancesIndexBuffer.Length;   // l_nodeBounds.Count ;

                        isInstanceAdded = _NodeInstanceSubAdd(
                            ref rootNode,
                            nodeChildrenBuffer.i_group8NodesIndex,
                            i_instanceID,
                            i_entityVersion,
                            instanceBounds,
                            ref a_nodesBuffer,
                            ref a_nodeSparesBuffer,
                            ref a_nodeChildrenBuffer,
                            ref a_nodeInstancesIndexBuffer,
                            ref a_instanceBuffer,
                            ref a_instancesSpareIndexBuffer,
                            i_requiredNumberOfInstances
                            );

                        if (isInstanceAdded)
                        {
                            return(true);                    // Added instance
                        }
                    }
                }


                /*
                 * NodeBufferElement rootNodeBufferElement = a_nodesBuffer [rootNode.i_rootNodeIndex] ;
                 *
                 * /Debug.LogError ( "Found no child node, to fit instance. Try grow octree; Instance ID " + i_instanceID + " bounds: " + instanceBounds + "; root node bounds: " + rootNodeBufferElement.bounds ) ;
                 *
                 * // Check if still fits in the root node.
                 * if ( CommonMethods._Encapsulates ( rootNodeBufferElement.bounds, instanceBounds ) )
                 * {
                 * Debug.Log ( "Still Fits in root." ) ;
                 * }
                 * else
                 * {
                 *
                 * // Try add node at the root
                 *
                 * Debug.LogError ( "Grow again." ) ;
                 *
                 *  _GrowOctree ( ref rootNode,
                 *      (float3) instanceBounds.center - rootNodeBufferElement.f3_center,
                 *      ref a_nodesBuffer,
                 *      ref a_nodeSparesBuffer,
                 *      ref a_nodeChildrenBuffer,
                 *      ref a_nodeInstancesIndexBuffer,
                 *      ref a_instanceBuffer,
                 *      ref a_instancesSpareIndexBuffer
                 *  ) ;
                 *
                 *
                 * }
                 */

// TODO: Requires double check.

                /*
                 * _AddNodeInstance ( ref rootNode,
                 *  i_instanceID,
                 *  i_entityVersion,
                 *  instanceBounds,
                 *  ref a_nodesBuffer,
                 *  ref a_nodeSparesBuffer,
                 *  ref a_nodeChildrenBuffer,
                 *  ref a_nodeInstancesIndexBuffer,
                 *  ref a_instanceBuffer,
                 *  ref a_instancesSpareIndexBuffer,
                 *  out isInstanceAdded
                 * ) ;
                 */

// Debug.LogWarning ( "Is instant added? " + (isInstanceAdded? "y" : "n") ) ;
                return(isInstanceAdded);
            } // if


            NodeBufferElement nodeBuffer = a_nodesBuffer [i_nodeIndex];

            nodeBuffer.i_instancesCount++;
            a_nodesBuffer [i_nodeIndex] = nodeBuffer;  // Set back.

            InstanceBufferElement instanceBuffer = new InstanceBufferElement()
            {
                i_ID            = i_instanceID,
                i_entityVersion = i_entityVersion, // Optional, used when Id is used as entity index.
                bounds          = instanceBounds
            };

            a_instanceBuffer [instancesSpareIndexBuffer.i] = instanceBuffer;

            return(true);
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Splits the octree into eight children.
        /// </summary>
        /// <param name="i_nodeIndex">Internal octree node index.</param>
        static private void _Split(ref RootNodeData rootNode, int i_nodeIndex, ref DynamicBuffer <NodeBufferElement> a_nodesBuffer, ref DynamicBuffer <NodeSparesBufferElement> a_nodeSparesBuffer, ref DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, ref DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer)
        {
            NodeBufferElement nodeBuffer = a_nodesBuffer [i_nodeIndex];

            float  f_nodeBaseLength = nodeBuffer.f_baseLength;
            float  f_quarter        = f_nodeBaseLength / 4f;
            float  f_newBaseLength  = f_nodeBaseLength / 2;
            float3 f3_center        = nodeBuffer.f3_center;

            nodeBuffer.i_childrenCount  = 8;
            a_nodesBuffer [i_nodeIndex] = nodeBuffer;

            int i_childrenIndexOffset = i_nodeIndex * 8;

            // Create for this node, 8 new children nodes


            NodeChildrenBufferElement nodeChildrenBuffer;

            // Allocate spare nodes, to children nodes.
            // Is assumed, there is enough spare nodes
            for (int i = 0; i < 8; i++)
            {
                NodeSparesBufferElement nodeSparesBuffer = a_nodeSparesBuffer [rootNode.i_nodeSpareLastIndex];
                nodeChildrenBuffer = a_nodeChildrenBuffer [i_childrenIndexOffset + i];
                nodeChildrenBuffer.i_group8NodesIndex            = nodeSparesBuffer.i;
                a_nodeChildrenBuffer [i_childrenIndexOffset + i] = nodeChildrenBuffer;         // Set back
                rootNode.i_nodeSpareLastIndex--;
            }

            float3 f3_childCenterQuater;


            nodeChildrenBuffer   = a_nodeChildrenBuffer [i_childrenIndexOffset];
            f3_childCenterQuater = f3_center + new float3(-f_quarter, f_quarter, -f_quarter);
            CommonMethods._CreateNewNode(ref rootNode, nodeChildrenBuffer.i_group8NodesIndex, f_newBaseLength, f3_childCenterQuater, ref a_nodesBuffer, ref a_nodeSparesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer);

            nodeChildrenBuffer   = a_nodeChildrenBuffer [i_childrenIndexOffset + 1];
            f3_childCenterQuater = f3_center + new float3(f_quarter, f_quarter, -f_quarter);
            CommonMethods._CreateNewNode(ref rootNode, nodeChildrenBuffer.i_group8NodesIndex, f_newBaseLength, f3_childCenterQuater, ref a_nodesBuffer, ref a_nodeSparesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer);

            nodeChildrenBuffer   = a_nodeChildrenBuffer [i_childrenIndexOffset + 2];
            f3_childCenterQuater = f3_center + new float3(-f_quarter, f_quarter, f_quarter);
            CommonMethods._CreateNewNode(ref rootNode, nodeChildrenBuffer.i_group8NodesIndex, f_newBaseLength, f3_childCenterQuater, ref a_nodesBuffer, ref a_nodeSparesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer);

            nodeChildrenBuffer   = a_nodeChildrenBuffer [i_childrenIndexOffset + 3];
            f3_childCenterQuater = f3_center + new float3(f_quarter, f_quarter, f_quarter);
            CommonMethods._CreateNewNode(ref rootNode, nodeChildrenBuffer.i_group8NodesIndex, f_newBaseLength, f3_childCenterQuater, ref a_nodesBuffer, ref a_nodeSparesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer);

            nodeChildrenBuffer   = a_nodeChildrenBuffer [i_childrenIndexOffset + 4];
            f3_childCenterQuater = f3_center + new float3(-f_quarter, -f_quarter, -f_quarter);
            CommonMethods._CreateNewNode(ref rootNode, nodeChildrenBuffer.i_group8NodesIndex, f_newBaseLength, f3_childCenterQuater, ref a_nodesBuffer, ref a_nodeSparesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer);

            nodeChildrenBuffer   = a_nodeChildrenBuffer [i_childrenIndexOffset + 5];
            f3_childCenterQuater = f3_center + new float3(f_quarter, -f_quarter, -f_quarter);
            CommonMethods._CreateNewNode(ref rootNode, nodeChildrenBuffer.i_group8NodesIndex, f_newBaseLength, f3_childCenterQuater, ref a_nodesBuffer, ref a_nodeSparesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer);

            nodeChildrenBuffer   = a_nodeChildrenBuffer [i_childrenIndexOffset + 6];
            f3_childCenterQuater = f3_center + new float3(-f_quarter, -f_quarter, f_quarter);
            CommonMethods._CreateNewNode(ref rootNode, nodeChildrenBuffer.i_group8NodesIndex, f_newBaseLength, f3_childCenterQuater, ref a_nodesBuffer, ref a_nodeSparesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer);

            nodeChildrenBuffer   = a_nodeChildrenBuffer [i_childrenIndexOffset + 7];
            f3_childCenterQuater = f3_center + new float3(f_quarter, -f_quarter, f_quarter);
            CommonMethods._CreateNewNode(ref rootNode, nodeChildrenBuffer.i_group8NodesIndex, f_newBaseLength, f3_childCenterQuater, ref a_nodesBuffer, ref a_nodeSparesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer);
        }
Ejemplo n.º 21
0
        /// <summary>
        /// Private counterpart to the public Add method.
        /// </summary>
        /// <param name="i_nodeIndex">Internal octree node index.</param>
        /// <param name="i_instanceID">External instance index, ot unique entity index.</param>
        /// <param name="i_entityVersion">Optional, used when Id is used as entity index.</param>
        /// <param name="instanceBounds">External 3D bounding box around the instance to add.</param>
        static private bool _NodeInstanceSubAdd(ref RootNodeData rootNode, int i_nodeIndex, int i_instanceID, int i_entityVersion, Bounds instanceBounds, ref DynamicBuffer <NodeBufferElement> a_nodesBuffer, ref DynamicBuffer <NodeSparesBufferElement> a_nodeSparesBuffer, ref DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, ref DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, ref DynamicBuffer <InstanceBufferElement> a_instanceBuffer, ref DynamicBuffer <InstancesSpareIndexBufferElement> a_instancesSpareIndexBuffer, int i_requiredNumberOfInstances)
        {
// Debug.Log ( "SubAdd node index: " + i_nodeIndex + "; instance ID: " + i_instanceID + "; inst bounds: " + instanceBounds ) ;
            bool isInstanceAdded = false;

            NodeBufferElement nodeBuffer = a_nodesBuffer [i_nodeIndex];

            // We know it fits at this level if we've got this far
            // Just add if few objects are here, or children would be below min size
            int i_instancesCount = nodeBuffer.i_instancesCount;

            if (nodeBuffer.i_childrenCount == 0 && i_instancesCount < rootNode.i_instancesAllowedCount || (nodeBuffer.f_baseLength / 2) < rootNode.f_minSize)
            {
// Debug.Log ( "Instance allowed?" ) ;

                isInstanceAdded = _AssingInstance2Node(ref rootNode, i_nodeIndex, i_instanceID, i_entityVersion, instanceBounds, ref a_nodesBuffer, ref a_nodeSparesBuffer, ref a_nodeChildrenBuffer, ref a_instanceBuffer, ref a_nodeInstancesIndexBuffer, ref a_instancesSpareIndexBuffer);

// Debug.Log ( "Is Instance Addded A: " + isInstanceAdded ) ;
                // a_nodesBuffer
                if (rootNode.i_instancesSpareLastIndex == 0 || i_requiredNumberOfInstances > a_instanceBuffer.Length)
                {
                    // Add some spares if needed.
                    CommonMethods._AddInstanceSpares(ref rootNode, ref a_instanceBuffer, ref a_instancesSpareIndexBuffer, i_requiredNumberOfInstances);
                }
                else
                {
                    rootNode.i_instancesSpareLastIndex--;
                }


                /*
                 * // Debugging
                 * GameObject go = GameObject.Find ( "Instance " + i_instanceID.ToString () ) ;
                 *
                 * if ( go != null )
                 * {
                 * Debug.Log ( "Instance: New game object #" + i_instanceID.ToString () ) ;
                 * go.SetActive ( true ) ;
                 * go.transform.localScale = instanceBounds.size ;
                 * }
                 * else
                 * {
                 * Debug.Log ( "Instance: New game object #" + i_instanceID.ToString () ) ;
                 *
                 * GameObject newGameObject = GameObject.Instantiate ( GameObject.Find ( "TempInstance" ), instanceBounds.center, Quaternion.identity ) ;
                 * newGameObject.transform.localScale = instanceBounds.size ;
                 *
                 * newGameObject.name = "Instance " + i_instanceID.ToString () ;
                 * }
                 */
            }
            else
            {
                // Fits at this level, but we can go deeper. Would it fit there?

// Debug.Log ( "Instance fits at other level?" ) ;
                // Create 8 children.
                int i_bestFitChildLocalIndex;
                int i_bestChildIndex;

                nodeBuffer = a_nodesBuffer [i_nodeIndex];
                int i_childrenCount       = nodeBuffer.i_childrenCount;
                int i_childrenIndexOffset = i_nodeIndex * 8;

                NodeChildrenBufferElement nodeChildrenBuffer;

                if (i_childrenCount == 0)
                {
                    // Split Octree node, into 8 new smaller nodes as children nodex.
                    _Split(ref rootNode, i_nodeIndex, ref a_nodesBuffer, ref a_nodeSparesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer);

                    NodeInstancesIndexBufferElement nodeInstancesIndexBuffer = a_nodeInstancesIndexBuffer [i_nodeIndex];

                    int i_nodeInstanceIndexOffset = nodeInstancesIndexBuffer.i;

                    // Now that we have the new children, see if this node's existing objects would fit there
                    for (int i = i_instancesCount - 1; i >= 0; i--)
                    {
                        int i_instanceIndexOffset = i_nodeInstanceIndexOffset + i;

                        if (i_instanceIndexOffset >= 0)
                        {
                            InstanceBufferElement existingInstanceBuffer = a_instanceBuffer [i_instanceIndexOffset];

                            if (existingInstanceBuffer.i_ID >= 0)
                            {
                                // Find which child the object is closest to based on, where the
                                // object's center is located in relation to the octree's center.
                                i_bestFitChildLocalIndex = CommonMethods._BestFitChild(i_nodeIndex, existingInstanceBuffer.bounds, a_nodesBuffer);

                                i_bestChildIndex   = i_childrenIndexOffset + i_bestFitChildLocalIndex;
                                nodeChildrenBuffer = a_nodeChildrenBuffer [i_bestChildIndex];


                                // Does it fit?
                                if (CommonMethods._Encapsulates(nodeChildrenBuffer.bounds, existingInstanceBuffer.bounds))
                                {
// Debug.Log ( "Encapsulates split instance " + i_instanceID + "; " + instanceBounds + " in child node " + nodeChildrenBuffer.bounds ) ;
// Debug.Log ( "Best Chuld index " + i_bestChildIndex + " node child index: " + nodeChildrenBuffer.i_group8NodesIndex + "; for instance ID: " + existingInstanceBuffer.i_ID ) ;
                                    isInstanceAdded = _NodeInstanceSubAdd(
                                        ref rootNode,
                                        nodeChildrenBuffer.i_group8NodesIndex,
                                        existingInstanceBuffer.i_ID,
                                        existingInstanceBuffer.i_entityVersion,
                                        existingInstanceBuffer.bounds,
                                        ref a_nodesBuffer,
                                        ref a_nodeSparesBuffer,
                                        ref a_nodeChildrenBuffer,
                                        ref a_nodeInstancesIndexBuffer,
                                        ref a_instanceBuffer,
                                        ref a_instancesSpareIndexBuffer,
                                        i_requiredNumberOfInstances
                                        ); // Go a level deeper


                                    // Remove from here
                                    CommonMethods._PutBackSpareInstance(ref rootNode, i_instanceIndexOffset, i_nodeIndex, ref a_nodeInstancesIndexBuffer, ref a_instancesSpareIndexBuffer);

                                    nodeBuffer = a_nodesBuffer [i_nodeIndex];
                                    nodeBuffer.i_instancesCount--;
                                    a_nodesBuffer [i_nodeIndex] = nodeBuffer;
                                }
                            }
                        }
                    }
                }


                // Now handle the new object we're adding now.
                i_bestFitChildLocalIndex = CommonMethods._BestFitChild(i_nodeIndex, instanceBounds, a_nodesBuffer);
                i_bestChildIndex         = i_childrenIndexOffset + i_bestFitChildLocalIndex;

                nodeChildrenBuffer = a_nodeChildrenBuffer [i_bestChildIndex];

                if (CommonMethods._Encapsulates(nodeChildrenBuffer.bounds, instanceBounds))
                {
// Debug.Log ( "Encapsulates A instance " + i_instanceID + "; " + instanceBounds + " in node " + nodeChildrenBuffer.bounds + "; " + nodeChildrenBuffer.bounds.extents.ToString ("F7") ) ;
                    isInstanceAdded = _NodeInstanceSubAdd
                                      (
                        ref rootNode,
                        nodeChildrenBuffer.i_group8NodesIndex,
                        i_instanceID,
                        i_entityVersion,
                        instanceBounds,
                        ref a_nodesBuffer,
                        ref a_nodeSparesBuffer,
                        ref a_nodeChildrenBuffer,
                        ref a_nodeInstancesIndexBuffer,
                        ref a_instanceBuffer,
                        ref a_instancesSpareIndexBuffer,
                        i_requiredNumberOfInstances
                                      );
                }
                else
                {
// Debug.Log ( "Does not encapsulates instance " + instanceBounds + " in node " + nodeChildrenBuffer.bounds ) ;
                    isInstanceAdded = _AssingInstance2Node(ref rootNode, i_nodeIndex, i_instanceID, i_entityVersion, instanceBounds, ref a_nodesBuffer, ref a_nodeSparesBuffer, ref a_nodeChildrenBuffer, ref a_instanceBuffer, ref a_nodeInstancesIndexBuffer, ref a_instancesSpareIndexBuffer);

// Debug.Log ( "Is Instance Addded B: " + isInstanceAdded ) ;
                    if (rootNode.i_instancesSpareLastIndex == 0 || i_requiredNumberOfInstances > a_instanceBuffer.Length)
                    {
                        // Add some spares if needed.
                        CommonMethods._AddInstanceSpares(ref rootNode, ref a_instanceBuffer, ref a_instancesSpareIndexBuffer, i_requiredNumberOfInstances);
                    }
                    else
                    {
                        rootNode.i_instancesSpareLastIndex--;
                    }

/*
 * // Debugging
 * Debug.Log ( "Instance: New game object #" + i_instanceID.ToString () ) ;
 *
 * GameObject newGameObject = GameObject.Instantiate ( GameObject.Find ( "TempInstance" ), instanceBounds.center, Quaternion.identity ) ;
 * newGameObject.transform.localScale = instanceBounds.size ;
 * newGameObject.name = i_instanceID.ToString () ;
 */
                }
            }

            return(isInstanceAdded);
        }
            public void Execute(DynamicBuffer <CollisionInstancesBufferElement> a_collisionInstancesBuffer, ref IsCollidingData isColliding, [ReadOnly] ref OctreeEntityPair4CollisionData octreeEntityPair4Collision, [ReadOnly] ref RayData rayData, [ReadOnly] ref RayMaxDistanceData rayMaxDistance)
            // public void Execute ( int i_arrayIndex )
            {
                // Entity octreeRayEntity = a_collisionChecksEntities [i_arrayIndex] ;


                // Its value should be 0, if no collision is detected.
                // And >= 1, if instance collision is detected, or there is more than one collision,
                // indicating number of collisions.
                // IsCollidingData isCollidingData                                                     = a_isCollidingData [octreeRayEntity] ;
                // Stores reference to detected colliding instance.
                // DynamicBuffer <CollisionInstancesBufferElement> a_collisionInstancesBuffer          = collisionInstancesBufferElement [octreeRayEntity] ;


                isColliding.i_nearestInstanceCollisionIndex = 0;
                isColliding.f_nearestDistance = float.PositiveInfinity;

                isColliding.i_collisionsCount = 0;                // Reset colliding instances counter.


                // OctreeEntityPair4CollisionData octreeEntityPair4CollisionData    = a_octreeEntityPair4CollisionData [octreeRayEntity] ;
                // RayData rayData                                                     = a_rayData [octreeRayEntity] ;
                // RayMaxDistanceData rayMaxDistanceData                               = a_rayMaxDistanceData [octreeRayEntity] ;


                // Octree entity pair, for collision checks

                Entity octreeRootNodeEntity = octreeEntityPair4Collision.octree2CheckEntity;

                // Is target octree active
                if (a_isActiveTag.Exists(octreeRootNodeEntity))
                {
                    RootNodeData octreeRootNode = a_octreeRootNodeData [octreeRootNodeEntity];

                    DynamicBuffer <NodeBufferElement> a_nodesBuffer = nodeBufferElement [octreeRootNodeEntity];
                    DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer = nodeInstancesIndexBufferElement [octreeRootNodeEntity];
                    DynamicBuffer <NodeChildrenBufferElement>       a_nodeChildrenBuffer       = nodeChildrenBufferElement [octreeRootNodeEntity];
                    DynamicBuffer <InstanceBufferElement>           a_instanceBuffer           = instanceBufferElement [octreeRootNodeEntity];



                    // To even allow instances collision checks, octree must have at least one instance.
                    if (octreeRootNode.i_totalInstancesCountInTree > 0)
                    {
                        if (GetCollidingRayInstances_Common._GetNodeColliding(ref octreeRootNode, octreeRootNode.i_rootNodeIndex, rayData.ray, ref a_collisionInstancesBuffer, ref isColliding, ref a_nodesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer, ref a_instanceBuffer, rayMaxDistance.f))
                        {
                            /*
                             * // Debug
                             * string s_collidingIDs = "" ;
                             * int i_collisionsCount = isCollidingData.i_collisionsCount ;
                             *
                             * for ( int i = 0; i < i_collisionsCount; i ++ )
                             * {
                             *  CollisionInstancesBufferElement collisionInstancesBuffer = a_collisionInstancesBuffer [i] ;
                             *  s_collidingIDs += collisionInstancesBuffer.i_ID + ", " ;
                             * }
                             *
                             * Debug.Log ( "Is colliding with #" + i_collisionsCount + " instances of IDs: " + s_collidingIDs + "; Nearest collided instance is at " + isCollidingData.f_nearestDistance + "m, with index #" + isCollidingData.i_nearestInstanceCollisionIndex ) ;
                             */
                        }
                    }
                }

                // a_isCollidingData [octreeRayEntity] = isCollidingData ; // Set back.
            }
        /// <summary>
        /// Merge all children into this node - the opposite of Split.
        /// Note: We only have to check one level down since a merge will never happen if the children already have children,
        /// since THAT won't happen unless there are already too many objects to merge.
        /// </summary>
        /// <param name="i_nodeIndex">Internal octree node index.</param>
        static private void _MergeNodes(ref RootNodeData rootNode, int i_nodeIndex, ref DynamicBuffer <NodeBufferElement> a_nodesBuffer, ref DynamicBuffer <NodeSparesBufferElement> a_nodeSparesBuffer, DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, ref DynamicBuffer <InstancesSpareIndexBufferElement> a_instancesSpareIndexBuffer)
        {
            NodeBufferElement               nodeBuffer;
            NodeChildrenBufferElement       nodeChildrenBuffer;
            NodeInstancesIndexBufferElement nodeInstancesIndexBuffer;

            int i_nodeChildrenIndexOffset        = i_nodeIndex * 8;
            int i_nodeUnusedInstancesIndexOffset = i_nodeIndex * rootNode.i_instancesAllowedCount;

            // Note: We know children != null or we wouldn't be merging
            for (int i = 0; i < 8; i++)
            {
                nodeChildrenBuffer = a_nodeChildrenBuffer [i_nodeChildrenIndexOffset + i];
                int i_childNodeIndex = nodeChildrenBuffer.i_group8NodesIndex;

                if (i_childNodeIndex >= 0)
                {
                    nodeBuffer = a_nodesBuffer [i_childNodeIndex];
                    int i_childNodeInstanceCount = nodeBuffer.i_instancesCount;

                    if (i_childNodeInstanceCount > 0)
                    {
                        int i_childModeInstancesIndexOffset = i_childNodeIndex * rootNode.i_instancesAllowedCount;
                        int i_instancesAllowedCount         = rootNode.i_instancesAllowedCount - 1;

                        for (int i_unusedInstance = 0; i_unusedInstance < rootNode.i_instancesAllowedCount; i_unusedInstance++)
                        {
                            int i_unusedInstanceIndexOffset = i_nodeUnusedInstancesIndexOffset + i_unusedInstance;


                            nodeInstancesIndexBuffer = a_nodeInstancesIndexBuffer [i_unusedInstanceIndexOffset];

                            if (nodeInstancesIndexBuffer.i == -1)
                            {
                                // Iterate through number of children instances.
                                while (i_instancesAllowedCount >= 0)
                                //for (int j = rootNodeData.i_instancesAllowedCount - 1; j >= 0; j--)
                                {
                                    int i_nodeIstancesIndexOffset = i_childModeInstancesIndexOffset + i_instancesAllowedCount;

                                    // Store old instance index
                                    nodeInstancesIndexBuffer = a_nodeInstancesIndexBuffer [i_nodeIstancesIndexOffset];
                                    int i_childInstanceIndex = nodeInstancesIndexBuffer.i;


                                    // If node instance exists (none negative), assign to node
                                    if (i_childInstanceIndex >= 0)
                                    {
                                        // Reassign instance index, to next available spare index.
                                        nodeInstancesIndexBuffer.i = i_childInstanceIndex;
                                        a_nodeInstancesIndexBuffer [i_unusedInstanceIndexOffset] = nodeInstancesIndexBuffer;          // Set back

                                        nodeBuffer = a_nodesBuffer [i_nodeIndex];
                                        nodeBuffer.i_instancesCount++;
                                        a_nodesBuffer [i_nodeIndex] = nodeBuffer;                                       // Set back


                                        nodeInstancesIndexBuffer.i = -1;                                                   // Reset
                                        a_nodeInstancesIndexBuffer [i_nodeIstancesIndexOffset] = nodeInstancesIndexBuffer; // Set back

                                        nodeBuffer = a_nodesBuffer [i_childNodeIndex];
                                        nodeBuffer.i_instancesCount--;
                                        a_nodesBuffer [i_childNodeIndex] = nodeBuffer;                                  // Set back

                                        i_childNodeInstanceCount--;

                                        i_instancesAllowedCount--;

                                        break;
                                    }
                                    else
                                    {
                                        i_instancesAllowedCount--;
                                    }
                                } // for
                            }
                        }         // for
                    }
                }
            } // for


            // Reset children
            // Remove the child nodes (and the objects in them - they've been added elsewhere now)
            for (int i = 0; i < 8; i++)
            {
                int i_childNodeIndexOffset = i_nodeChildrenIndexOffset + i;
                nodeChildrenBuffer = a_nodeChildrenBuffer [i_childNodeIndexOffset];
                int i_childNodeIndex = nodeChildrenBuffer.i_group8NodesIndex;

                if (i_childNodeIndex >= 0)
                {
                    // Get child node ;
                    nodeBuffer = a_nodesBuffer [i_childNodeIndex];

                    // Iterate though node children.
                    if (nodeBuffer.i_childrenCount > 0)
                    {
                        // Reset node children node index reference.
                        for (int j = 0; j < 8; j++)
                        {
                            // Reset child
                            nodeChildrenBuffer.i_group8NodesIndex       = -1;                 // Bounds are ignored
                            a_nodeChildrenBuffer [i_childNodeIndex + j] = nodeChildrenBuffer; // Set back
                        }

                        nodeBuffer.i_instancesCount      = 0;          // Reset
                        a_nodesBuffer [i_childNodeIndex] = nodeBuffer; // Set back

                        // Put back node instances to spare instance.
                        for (int j = 0; j < rootNode.i_instancesAllowedCount; j++)
                        {
                            nodeInstancesIndexBuffer = a_nodeInstancesIndexBuffer [i_childNodeIndex];  // Set back
                            int i_instanceIndex = nodeInstancesIndexBuffer.i;

                            // Remove from here
                            CommonMethods._PutBackSpareInstance(ref rootNode, i_instanceIndex + j, i_nodeIndex, ref a_nodeInstancesIndexBuffer, ref a_instancesSpareIndexBuffer);
                        }
                    }

                    // Pu back child nodes to spares
                    rootNode.i_nodeSpareLastIndex++;
                    a_nodeSparesBuffer [rootNode.i_nodeSpareLastIndex] = new NodeSparesBufferElement()
                    {
                        i = i_childNodeIndex
                    };

                    // Reset child
                    nodeChildrenBuffer.i_group8NodesIndex         = -1;                  // Bounds are ignored
                    a_nodeChildrenBuffer [i_childNodeIndexOffset] = nodeChildrenBuffer;  // Set back
                }
            }


            nodeBuffer = a_nodesBuffer [i_nodeIndex];
            nodeBuffer.i_childrenCount  = 0;
            a_nodesBuffer [i_nodeIndex] = nodeBuffer;   // Set back
        }
Ejemplo n.º 24
0
            public void Execute(Entity octreeRootNodeEntity, int jobIndex, DynamicBuffer <AddInstanceBufferElement> a_addInstanceBuffer)
            {
                DynamicBuffer <NodeSparesBufferElement>         a_nodeSparesBuffer         = nodeSparesBufferElement [octreeRootNodeEntity];
                DynamicBuffer <NodeBufferElement>               a_nodesBuffer              = nodeBufferElement [octreeRootNodeEntity];
                DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer = nodeInstancesIndexBufferElement [octreeRootNodeEntity];
                DynamicBuffer <NodeChildrenBufferElement>       a_nodeChildrenBuffer       = nodeChildrenBufferElement [octreeRootNodeEntity];

                DynamicBuffer <InstanceBufferElement>            a_instanceBuffer            = instanceBufferElement [octreeRootNodeEntity];
                DynamicBuffer <InstancesSpareIndexBufferElement> a_instancesSpareIndexBuffer = instancesSpareIndexBufferElement [octreeRootNodeEntity];


                // Iterate through number of instances to add, from the buffer
                for (int i = 0; i < a_addInstanceBuffer.Length; i++)
                {
                    RootNodeData rootNodeData = a_rootNodeData [octreeRootNodeEntity];

                    AddInstanceBufferElement addInstanceBuffer = a_addInstanceBuffer [i];

// Debug.LogWarning ( "Add instance 2 Node " + i + " / " + a_addInstanceBuffer.Length + "; Instance ID: " + addInstanceBuffer.i_instanceID ) ;

                    // Add object or expand the octree until it can be added
                    int  i_count         = 0; // Safety check against infinite/excessive growth
                    bool isInstanceAdded = false;

                    while (
                        !_AddNodeInstance(ref rootNodeData,
                                          addInstanceBuffer.i_instanceID,
                                          addInstanceBuffer.i_version,
                                          addInstanceBuffer.instanceBounds,
                                          ref a_nodesBuffer,
                                          ref a_nodeSparesBuffer,
                                          ref a_nodeChildrenBuffer,
                                          ref a_nodeInstancesIndexBuffer,
                                          ref a_instanceBuffer,
                                          ref a_instancesSpareIndexBuffer,
                                          out isInstanceAdded
                                          )
                        )
                    {
                        NodeBufferElement nodeBufferElement = a_nodesBuffer [rootNodeData.i_rootNodeIndex];
// Debug.LogWarning ( "Execute -> Grow " + rootNodeData.i_rootNodeIndex ) ;
                        _GrowOctree(ref rootNodeData,
                                    (float3)addInstanceBuffer.instanceBounds.center - nodeBufferElement.f3_center,
                                    ref a_nodesBuffer,
                                    ref a_nodeSparesBuffer,
                                    ref a_nodeChildrenBuffer,
                                    ref a_nodeInstancesIndexBuffer,
                                    ref a_instanceBuffer,
                                    ref a_instancesSpareIndexBuffer
                                    );

                        if (++i_count > 20)
                        {
                            // Debug.LogError("Aborted Add operation as it seemed to be going on forever (" + (i_count - 1) + ") attempts at growing the octree.");
                            return;
                        }
                    }

                    rootNodeData.i_totalInstancesCountInTree++;

                    a_rootNodeData [octreeRootNodeEntity] = rootNodeData;
                } // for

                a_addInstanceBuffer.ResizeUninitialized(0);     // Clear buffer after instances are added.
            }
        /// <summary>
        /// Shrink the octree if possible, else leave it the same.
        /// We can shrink the octree if:
        /// - This node is >= double minLength in length
        /// - All objects in the root node are within one octant
        /// - This node doesn't have children, or does but 7/8 children are empty
        /// We can also shrink it if there are no objects left at all!
        /// </summary>
        /// <param name="i_nodeIndex">Internal octree node index.</param>
        /// <param name="minLength">Minimum dimensions of a node in this octree.</param>
        /// <returns>The new root index, or the existing one if we didn't shrink.</returns>
        static private int _ShrinkIfPossible(RootNodeData rootNode, int i_nodeIndex, float minLength, DynamicBuffer <NodeBufferElement> a_nodesBuffer, ref DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, DynamicBuffer <InstanceBufferElement> a_instanceBuffer)
        {
            NodeBufferElement nodeBuffer = a_nodesBuffer [i_nodeIndex];


            NodeChildrenBufferElement nodeChildrenBuffer;


            if (nodeBuffer.f_baseLength < (2 * minLength))
            {
                return(i_nodeIndex);
            }

            if (nodeBuffer.i_instancesCount == 0 && nodeBuffer.i_childrenCount == 0)
            {
                return(i_nodeIndex);
            }

            int i_nodeChildrenIndexOffset  = i_nodeIndex * 8;
            int i_nodeInstancesIndexOffset = i_nodeIndex * rootNode.i_instancesAllowedCount;


            // -1 to 7, where -1 is no result found
            int i_bestFit = -1;

            // Check objects in root
            for (int i = 0; i < rootNode.i_instancesAllowedCount; i++)
            {
                if (nodeBuffer.i_instancesCount == 0)
                {
                    break;
                }

                NodeInstancesIndexBufferElement nodeInstancesIndexBuffer = a_nodeInstancesIndexBuffer [i_nodeInstancesIndexOffset + i];


                if (nodeInstancesIndexBuffer.i >= 0)
                {
                    InstanceBufferElement instanceBuffer = a_instanceBuffer [nodeInstancesIndexBuffer.i];

                    int newBestFit = CommonMethods._BestFitChild(i_nodeIndex, instanceBuffer.bounds, a_nodesBuffer);

                    if (i == 0 || newBestFit == i_bestFit)
                    {
                        nodeChildrenBuffer = a_nodeChildrenBuffer [i_nodeChildrenIndexOffset + newBestFit];

                        // In same octant as the other(s). Does it fit completely inside that octant?
                        if (CommonMethods._Encapsulates(nodeChildrenBuffer.bounds, instanceBuffer.bounds))
                        {
                            if (i_bestFit < 0)
                            {
                                i_bestFit = newBestFit;
                            }
                        }
                        else
                        {
                            // Nope, so we can't reduce. Otherwise we continue
                            return(i_nodeIndex);
                        }
                    }
                    else
                    {
                        return(i_nodeIndex);                 // Can't reduce - objects fit in different octants
                    }
                }
            }         // for


            // Check instances in children if there are any
            if (nodeBuffer.i_childrenCount > 0)
            {
                bool childHadContent = false;

                for (int i = 0; i < 8; i++)
                {
                    nodeChildrenBuffer = a_nodeChildrenBuffer [i_nodeChildrenIndexOffset + i];

                    // Has child any instances
                    if (CommonMethods._HasAnyInstances(nodeChildrenBuffer.i_group8NodesIndex, a_nodesBuffer, a_nodeChildrenBuffer))
                    {
                        if (childHadContent)
                        {
                            return(i_nodeIndex);                         // Can't shrink - another child had content already
                        }
                        if (i_bestFit >= 0 && i_bestFit != i)
                        {
                            return(i_nodeIndex);                         // Can't reduce - objects in root are in a different octant to objects in child
                        }

                        childHadContent = true;
                        i_bestFit       = i;
                    }
                }
            }
            // Can reduce
            else if (nodeBuffer.i_childrenCount == 0)
            {
                nodeChildrenBuffer = a_nodeChildrenBuffer [i_nodeChildrenIndexOffset + i_bestFit];
                Bounds childBounds = nodeChildrenBuffer.bounds;

                // We don't have any children, so just shrink this node to the new size
                // We already know that everything will still fit in it
                CommonMethods._SetValues(rootNode, i_nodeIndex, nodeBuffer.f_baseLength / 2, childBounds.center, ref a_nodesBuffer, ref a_nodeChildrenBuffer);

                return(i_nodeIndex);
            }

            // No objects in entire octree
            if (i_bestFit == -1)
            {
                return(i_nodeIndex);
            }


            // We have children. Use the appropriate child as the new root node
            nodeChildrenBuffer = a_nodeChildrenBuffer [i_nodeChildrenIndexOffset + i_bestFit];
            return(nodeChildrenBuffer.i_group8NodesIndex);
        }