/// <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 rootNodeData, int i_instanceID, int i_entityVersion, Bounds instanceBounds, ref DynamicBuffer <NodeBufferElement> a_nodesBuffer, ref DynamicBuffer <NodeSparesBufferElement> a_nodeSparesBuffer, DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, ref DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, ref DynamicBuffer <InstanceBufferElement> a_instanceBuffer, ref DynamicBuffer <InstancesSpareIndexBufferElement> a_instancesSpareIndexBuffer)
        {
            NodeBufferElement nodeBufferElement = a_nodesBuffer [rootNodeData.i_rootNodeIndex];

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

            _NodeInstanceSubAdd(
                ref rootNodeData,
                rootNodeData.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);
        }
Esempio n. 2
0
        /// <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);
        }
Esempio n. 3
0
        /// <summary>
        /// Constructor for the bounds octree.
        /// For minimum size of 1 initial size could be for example 1, 2, 4, 8, 16 ect.
        /// For minimum size of 3 initial size could be for example 3, 9, 27, 81 etc.
        /// Also:
        /// Size 2 per node, with up to 16 instances per node (1x1x1 size each);
        /// Size 4 per node, with up to 64 instances per node (1x1x1 size each); Less memory usage, but more cpu demanding (for searching and removing elements).
        /// </summary>
        /// <param name="f_initialSize">Size of the sides of the initial node, in metres. The octree will never shrink smaller than this.</param>
        /// <param name="f3_initialPosition">Position of the centre of the initial node.</param>
        /// <param name="f_minNodeSize">Nodes will stop splitting if the new nodes would be smaller than this (metres).</param>
        /// <param name="f_looseness">Clamped between 1 and 2. Values > 1 let nodes overlap.</param>
        static public void _CreateNewOctree(EntityCommandBuffer ecb, Entity newOctreeEntity, float f_initialSize, float3 f3_initialPosition, float f_minNodeSize, float f_looseness)
        {
            Debug.Log("Create new octree #" + newOctreeEntity.Index);

            ecb.AddComponent(newOctreeEntity, new AddNewOctreeData()
            {
                f3_initialPosition = f3_initialPosition,
                f_initialSize      = f_initialSize
            });   // This tag is removed, after octree is created.



            if (f_minNodeSize > f_initialSize)
            {
                Debug.LogWarning("Minimum node size must be at least as big as the initial world size. Was: " + f_initialSize + " Adjusted to: " + f_minNodeSize);
                f_minNodeSize = f_initialSize;
            }

            // Minimum size to power 3
            // For example, size of 2, gives 8 instances per node
            int i_instancesAllowedInNodeCount = (int)math.round(f_minNodeSize * f_minNodeSize * f_minNodeSize);

            RootNodeData rootNodeData = new RootNodeData()
            {
                i_rootNodeIndex = 0,

                f_initialSize = f_initialSize,
                f_minSize     = f_minNodeSize,
                f_looseness   = math.clamp(f_looseness, 1.0f, 2.0f),

                i_totalInstancesCountInTree = 0,

                i_instancesSpareLastIndex = 0,
                i_nodeSpareLastIndex      = 0,

                i_instancesAllowedCount = i_instancesAllowedInNodeCount
            };


            // ***** Core Components ***** //


            ecb.AddComponent(newOctreeEntity, rootNodeData);     // Core of octree structure.

            // Add buffer arrays
            ecb.AddBuffer <NodeBufferElement> (newOctreeEntity);
            ecb.AddBuffer <NodeChildrenBufferElement> (newOctreeEntity);
            ecb.AddBuffer <NodeInstancesIndexBufferElement> (newOctreeEntity);
            ecb.AddBuffer <NodeSparesBufferElement> (newOctreeEntity);

            ecb.AddBuffer <InstanceBufferElement> (newOctreeEntity);
            ecb.AddBuffer <InstancesSpareIndexBufferElement> (newOctreeEntity);



            // ***** Instance Optional Components ***** //

            // ecb.AddBuffer <AddInstanceBufferElement> ( newOctreeEntity ) ; // Once system executed and instances were added, buffer will be deleted.
            // ecb.AddComponent ( newOctreeEntity, new RemoveInstanceBufferElement () ) ; // Once system executed and instances were removed, tag will be deleted.
        }
        /// <summary>
        /// Get total octree bounds (boundary box).
        /// </summary>
        /// <returns></returns>
        public Bounds _GetOctreeMaxBounds(RootNodeData rootNodeData, DynamicBuffer <NodeBufferElement> a_nodesBuffer)
        {
            NodeBufferElement nodeBuffer = a_nodesBuffer [rootNodeData.i_rootNodeIndex];

            // return _GetNodeBounds ( i_rootNodeIndex ) ;
            return(nodeBuffer.bounds);
        }
        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
            };


            EntityArray a_entities     = group.GetEntityArray();
            Entity      rootNodeEntity = a_entities [0];

            ComponentDataArray <RootNodeData> a_rootNodeData = group.GetComponentDataArray <RootNodeData> ( );
            RootNodeData rootNodeData = a_rootNodeData [0];

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



            Bounds maxBouds = _GetOctreeMaxBounds(rootNodeData, a_nodesBuffer);


            return(base.OnUpdate(inputDeps));
        }
Esempio n. 6
0
            public void Execute(int i_arrayIndex)
            {
                Entity octreeRootNodeEntity = a_octreeEntities [i_arrayIndex];

                DynamicBuffer <RemoveInstanceBufferElement> a_removeInstanceBufferElement = removeInstanceBufferElement [octreeRootNodeEntity];

                RootNodeData rootNodeData = 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_removeInstanceBufferElement.Length; i++)
                {
                    // RootNodeData rootNodeData = a_rootNodeData [octreeRootNodeEntity] ;

                    RemoveInstanceBufferElement removeInstanceBuffer = a_removeInstanceBufferElement [i];

                    bool removed = _NodeRemoveInstance(
                        ref rootNodeData,
                        rootNodeData.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)
                    {
                        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
                            );
                    }

                    a_rootNodeData [octreeRootNodeEntity] = rootNodeData;
                } // for
            }
Esempio n. 7
0
        /// <summary>
        /// Node Constructor.
        /// </summary>
        static public void _CreateNewNode(ref RootNodeData rootNodeData, 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 (rootNodeData.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);
                    rootNodeData.i_nodeSpareLastIndex++;
                    nodeSpareBuffer.i = i_initialSparesCount - i;
                    a_nodeSparesBuffer [rootNodeData.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 < rootNodeData.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_nodesIndex = -1;
                        nodeChildrenBuffer.bounds       = new Bounds();
                        a_nodeChildrenBuffer.Add(new NodeChildrenBufferElement());
                    }
                }
            }


            _SetValues(rootNodeData, i_nodeIndex, f_baseLength, f3_center, ref a_nodesBuffer, ref a_nodeChildrenBuffer);
        }
Esempio n. 8
0
            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];


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

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


                RootNodeData octreeRootNodeData = 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];

                // Ray entity pair, for collision checks

                Entity bounds2CheckEntity = rayEntityPair4CollisionData.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 (octreeRootNodeData.i_totalInstancesCountInTree > 0)
                    {
                        if (GetCollidingBoundsInstances_Common._GetNodeColliding(octreeRootNodeData, octreeRootNodeData.i_rootNodeIndex, checkBounds.bounds, ref a_collisionInstancesBuffer, ref isCollidingData, a_nodesBuffer, a_nodeChildrenBuffer, a_nodeInstancesIndexBuffer, a_instanceBuffer))
                        {
                            /*
                             * // Debug
                             * Debug.Log ( "Is colliding." ) ;
                             */
                        }
                    }
                }

                a_isCollidingData [octreeRootNodeEntity] = isCollidingData;  // Set back.
            }
Esempio n. 9
0
            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];

                isCollidingData.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 = octreeEntityPair4CollisionData.octree2CheckEntity;

                // Is target octree active
                if (a_isActiveTag.Exists(octreeRootNodeEntity))
                {
                    RootNodeData octreeRootNodeData = 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 (octreeRootNodeData.i_totalInstancesCountInTree > 0)
                    {
                        if (IsRayColliding_Common._IsNodeColliding(octreeRootNodeData, octreeRootNodeData.i_rootNodeIndex, rayData.ray, ref isCollidingData, a_nodesBuffer, a_nodeChildrenBuffer, a_nodeInstancesIndexBuffer, a_instanceBuffer, rayMaxDistanceData.f))
                        {
                            /*
                             * // Debug
                             * Debug.Log ( "Is colliding." ) ;
                             */
                        }
                    }
                }

                a_isCollidingData [octreeRayEntity] = isCollidingData;  // Set back.
            }
Esempio n. 10
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 rootNodeData, int i_nodeIndex, float f_baseLength, float3 f3_center, ref DynamicBuffer <NodeBufferElement> a_nodesBuffer, ref DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer)
        {
            NodeBufferElement nodeBuffer = new NodeBufferElement();

            nodeBuffer.f_baseLength = f_baseLength;
            nodeBuffer.f3_center    = f3_center;
            float f_adjustLength = rootNodeData.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) * rootNodeData.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
        }
Esempio n. 11
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 rootNodeData, 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.
            }
            rootNodeData.i_instancesSpareLastIndex++; // Put back to spare

            InstancesSpareIndexBufferElement instancesSpareIndexBuffer = new InstancesSpareIndexBufferElement();

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

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

            nodeInstancesIndexBuffer.i = -1;  // Reset instance index.
            a_nodeInstancesIndexBuffer [i_nodeIntstanceIndex] = nodeInstancesIndexBuffer;
        }
Esempio n. 12
0
        /// <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 rootNodeData, 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_nodesIndex;

                    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 <= rootNodeData.i_instancesAllowedCount);
        }
        /// <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 void _AssingInstance2Node(RootNodeData rootNodeData, int i_nodeIndex, int i_instanceID, int i_entityVersion, Bounds instanceBounds, ref DynamicBuffer <NodeBufferElement> a_nodesBuffer, ref DynamicBuffer <InstanceBufferElement> a_instanceBuffer, ref DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, DynamicBuffer <InstancesSpareIndexBufferElement> a_instancesSpareIndexBuffer)
        {
            int i_nodeInstanceIndexOffset = i_nodeIndex * rootNodeData.i_instancesAllowedCount;

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

            NodeInstancesIndexBufferElement nodeInstancesIndexBuffer;

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

                nodeInstancesIndexBuffer = a_nodeInstancesIndexBuffer [i_instanceIndexOffset];

                // Is spare.
                if (nodeInstancesIndexBuffer.i == -1)
                {
                    // Assign instance index.
                    nodeInstancesIndexBuffer.i = instancesSpareIndexBuffer.i;
                    a_nodeInstancesIndexBuffer [i_instanceIndexOffset] = nodeInstancesIndexBuffer;  // Set back.
                    break;
                }
            }

            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;
        }
Esempio n. 14
0
            public void Execute(int i_arrayIndex)
            {
                Entity octreeRootNodeEntity = a_newOctreeEntities [i_arrayIndex];


                AddNewOctreeData addNewOctreeData = a_addNewOctreeData [octreeRootNodeEntity];

                RootNodeData rootNodeData = a_rootNodeData [octreeRootNodeEntity];

                rootNodeData.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 rootNodeData, rootNodeData.i_rootNodeIndex, addNewOctreeData.f_initialSize, addNewOctreeData.f3_initialPosition, ref a_nodesBuffer, ref a_nodeSparesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer);

                rootNodeData.i_nodeSpareLastIndex--;

                rootNodeData.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 rootNodeData, ref a_instanceBuffer, ref a_instancesSpareIndexBuffer, i_requiredNumberOfSpareInstances);



                a_rootNodeData [octreeRootNodeEntity] = rootNodeData;  // Set back
            }
Esempio n. 15
0
        /// <summary>
        /// Add required new spare instances.
        /// </summary>
        static public void _AddInstanceSpares(ref RootNodeData rootNodeData, ref DynamicBuffer <InstanceBufferElement> a_instanceBuffer, ref DynamicBuffer <InstancesSpareIndexBufferElement> a_instancesSpareIndexBuffer, int i_requiredNumberOfInstances)
        {
            rootNodeData.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++)
            {
                rootNodeData.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 [rootNodeData.i_instancesSpareLastIndex] = instancesSpareIndexBuffer;
            }
        }
        /// <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(RootNodeData rootNodeData, int i_nodeIndex, Ray checkRay, ref IsCollidingData isCollidingData, DynamicBuffer <NodeBufferElement> a_nodesBuffer, DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, 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 * rootNodeData.i_instancesAllowedCount;

                // Check against any objects in this node
                for (int i = 0; i < rootNodeData.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_nodesIndex;

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

            return(false);
        }
            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];


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

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


                RootNodeData octreeRootNodeData = 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];


                RayEntityPair4CollisionData rayEntityPair4CollisionData = a_rayEntityPair4CollisionData [octreeRootNodeEntity];

                // Ray entity pair, for collision checks

                Entity ray2CheckEntity = rayEntityPair4CollisionData.ray2CheckEntity;

                // Is target octree active
                if (a_isActiveTag.Exists(ray2CheckEntity))
                {
                    RayData            rayData            = a_rayData [ray2CheckEntity];
                    RayMaxDistanceData rayMaxDistanceData = a_rayMaxDistanceData [ray2CheckEntity];


                    // To even allow instances collision checks, octree must have at least one instance.
                    if (octreeRootNodeData.i_totalInstancesCountInTree > 0)
                    {
                        if (GetCollidingRayInstances_Common._GetNodeColliding(octreeRootNodeData, octreeRootNodeData.i_rootNodeIndex, rayData.ray, ref a_collisionInstancesBuffer, ref isCollidingData, a_nodesBuffer, a_nodeChildrenBuffer, a_nodeInstancesIndexBuffer, a_instanceBuffer, rayMaxDistanceData.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 [octreeRootNodeEntity] = isCollidingData;  // Set back.
            }
Esempio n. 18
0
        /// <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(RootNodeData rootNodeData, int i_nodeIndex, Bounds checkBounds, ref IsCollidingData isCollidingData, DynamicBuffer <NodeBufferElement> a_nodesBuffer, DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, 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 * rootNodeData.i_instancesAllowedCount;

                // Check against any objects in this node
                for (int i = 0; i < rootNodeData.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_nodesIndex;

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

            return(false);
        }
Esempio n. 19
0
        /// <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 rootNodeData, 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 * rootNodeData.i_instancesAllowedCount;


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

            // Check objects in root
            for (int i = 0; i < rootNodeData.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;
                            }

                            break;
                        }
                        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_nodesIndex, 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(rootNodeData, 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_nodesIndex);
        }
Esempio n. 20
0
        /// <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 rootNodeData, 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 * rootNodeData.i_instancesAllowedCount;

            if (nodeBuffer.i_instancesCount > 0)
            {
                // Try remove instance from this node
                for (int i = 0; i < rootNodeData.i_instancesAllowedCount; 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 rootNodeData, i_existingInstanceIndex, i_nodeIndex, 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 ;
 *  }
 *
 *                          nodeBuffer.i_instancesCount -- ;
 *                          instanceBuffer.i_ID = -1 ; // Reset
 *                          a_instanceBuffer [i_existingInstanceIndex] = instanceBuffer ; // Set back
 *
 *
 *  Debug.LogWarning ( "Node: Remove #" + i_nodeIndex ) ;
 *  GameObject.Destroy ( GameObject.Find ( "Node " + i_nodeIndex.ToString () ) ) ;
 */
                            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_nodesIndex;

                    // Ignore negative index
                    if (i_childNodeIndex >= 0)
                    {
                        removed = _NodeRemoveInstance(
                            ref rootNodeData,
                            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 rootNodeData, i_nodeIndex, a_nodesBuffer, ref a_nodeChildrenBuffer))
                {
                    _MergeNodes(
                        ref rootNodeData,
                        i_nodeIndex,
                        ref a_nodesBuffer,
                        ref a_nodeSparesBuffer,
                        a_nodeChildrenBuffer,
                        a_nodeInstancesIndexBuffer,
                        ref a_instancesSpareIndexBuffer
                        );
                }
            }

            return(removed);
        }
        /// <summary>
        /// Grow the octree to fit in all objects.
        /// </summary>
        /// <param name="f3_direction">Direction to grow.</param>
        static private void _GrowOctree(ref RootNodeData rootNodeData, 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 = rootNodeData.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);

            // Create a new, bigger octree root node

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

                rootNodeData.i_nodeSpareLastIndex--;

                CommonMethods._CreateNewNode(
                    ref rootNodeData,
                    rootNodeData.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 [rootNodeData.i_rootNodeIndex];
                nodeBuffer.i_childrenCount = 8;
                a_nodesBuffer [rootNodeData.i_rootNodeIndex] = nodeBuffer;  // Set back.

                int i_newRootNodeChildrenIndexOffset = rootNodeData.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_nodesIndex = 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;

                        InstancesSpareIndexBufferElement instancesSpareIndexBuffer;
                        instancesSpareIndexBuffer = a_instancesSpareIndexBuffer [rootNodeData.i_nodeSpareLastIndex];
                        int i_newNodeIndex = instancesSpareIndexBuffer.i;                       // Expected output 0 at initialization
                        rootNodeData.i_nodeSpareLastIndex--;

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

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


                        nodeChildrenBuffer.i_nodesIndex = 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>
        /// 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 void _NodeInstanceSubAdd(ref RootNodeData rootNodeData, 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)
        {
            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 (i_instancesCount < rootNodeData.i_instancesAllowedCount || (nodeBuffer.f_baseLength / 2) < rootNodeData.f_minSize)
            {
                _AssingInstance2Node(rootNodeData, i_nodeIndex, i_instanceID, i_entityVersion, instanceBounds, ref a_nodesBuffer, ref a_instanceBuffer, ref a_nodeInstancesIndexBuffer, a_instancesSpareIndexBuffer);

                // a_nodesBuffer
                if (rootNodeData.i_instancesSpareLastIndex == 0 || i_requiredNumberOfInstances > a_instanceBuffer.Length)
                {
                    // Add some spares if needed.
                    CommonMethods._AddInstanceSpares(ref rootNodeData, ref a_instanceBuffer, ref a_instancesSpareIndexBuffer, i_requiredNumberOfInstances);
                }
                else
                {
                    rootNodeData.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?

                // Create the 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 rootNodeData, 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];

                            // 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))
                            {
                                _NodeInstanceSubAdd(
                                    ref rootNodeData,
                                    nodeChildrenBuffer.i_nodesIndex,
                                    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 rootNodeData, 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))
                {
                    _NodeInstanceSubAdd(
                        ref rootNodeData,
                        nodeChildrenBuffer.i_nodesIndex,
                        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
                {
                    _AssingInstance2Node(rootNodeData, i_nodeIndex, i_instanceID, i_entityVersion, instanceBounds, ref a_nodesBuffer, ref a_instanceBuffer, ref a_nodeInstancesIndexBuffer, a_instancesSpareIndexBuffer);

                    if (rootNodeData.i_instancesSpareLastIndex == 0 || i_requiredNumberOfInstances > a_instanceBuffer.Length)
                    {
                        // Add some spares if needed.
                        CommonMethods._AddInstanceSpares(ref rootNodeData, ref a_instanceBuffer, ref a_instancesSpareIndexBuffer, i_requiredNumberOfInstances);
                    }
                    else
                    {
                        rootNodeData.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 () ;
 */
                }
            }
        }
        /// <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(RootNodeData rootNodeData, int i_nodeIndex, Ray checkRay, ref DynamicBuffer <CollisionInstancesBufferElement> a_collisionInstancesBuffer, ref IsCollidingData isCollidingData, DynamicBuffer <NodeBufferElement> a_nodesBuffer, DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, 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)
            {
                return(isCollidingData.i_collisionsCount > 0 ? true : false);
            }

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

                CollisionInstancesBufferElement collisionInstancesBuffer = new CollisionInstancesBufferElement();

                // Check against any objects in this node
                for (int i = 0; i < rootNodeData.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_nodesIndex;

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

            return(isCollidingData.i_collisionsCount > 0 ? true : false);
        }
        /// <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(RootNodeData octreeRootNodeData, int i_nodeIndex, Bounds checkBounds, ref DynamicBuffer <CollisionInstancesBufferElement> a_collisionInstancesBuffer, ref IsCollidingData isCollidingData, DynamicBuffer <NodeBufferElement> a_nodesBuffer, DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer, DynamicBuffer <NodeInstancesIndexBufferElement> a_nodeInstancesIndexBuffer, 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(isCollidingData.i_collisionsCount > 0 ? true : false);
            }


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

                // Check against any objects in this node
                for (int i = 0; i < octreeRootNodeData.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 = 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_nodesIndex;

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

            return(isCollidingData.i_collisionsCount > 0 ? true : false);
        }
            public void Execute(int i_arrayIndex)
            {
                Entity octreeRootNodeEntity = a_octreeEntities [i_arrayIndex];

                DynamicBuffer <AddInstanceBufferElement> a_addInstanceBufferElement = addInstanceBufferElement [octreeRootNodeEntity];

                // RootNodeData rootNodeData                                                           = 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];


                /// <summary>
                /// Add an Instance.
                /// </summary>
                /// <param name="i_instanceID">External instance to add.</param>
                /// <param name="instanceBounds">External instance 3D bounding box around the instance.</param>
                //public void _OctreeAddInstance ( ref RootNodeData rootNodeData, int i_instanceID, 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 )
                //{

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

                    AddInstanceBufferElement addInstanceBuffer = a_addInstanceBufferElement [i];

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

                    while (
                        !_AddNodeInstance(ref rootNodeData,
                                          addInstanceBuffer.i_instanceID,
                                          addInstanceBuffer.i_version,
                                          addInstanceBuffer.instanceBounds,
                                          ref a_nodesBuffer,
                                          ref a_nodeSparesBuffer,
                                          a_nodeChildrenBuffer,
                                          ref a_nodeInstancesIndexBuffer,
                                          ref a_instanceBuffer,
                                          ref a_instancesSpareIndexBuffer
                                          )
                        )
                    {
                        NodeBufferElement nodeBufferElement = a_nodesBuffer [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;
                }
            }
Esempio n. 26
0
        /// <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 rootNodeData, 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 * rootNodeData.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_nodesIndex;

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

                    if (i_childNodeInstanceCount > 0)
                    {
                        int i_childModeInstancesIndexOffset = i_childNodeIndex * rootNodeData.i_instancesAllowedCount;

                        for (int i_unusedInstance = 0; i_unusedInstance < rootNodeData.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.
                                for (int j = rootNodeData.i_instancesAllowedCount - 1; j >= 0; j--)
                                {
                                    // Store old instance index
                                    nodeInstancesIndexBuffer = a_nodeInstancesIndexBuffer [i_childModeInstancesIndexOffset + j];
                                    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_childModeInstancesIndexOffset + j] = nodeInstancesIndexBuffer; // Set back

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

                                        i_childNodeInstanceCount--;
                                    }
                                } // 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_nodesIndex;

                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_nodesIndex             = -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 < rootNodeData.i_instancesAllowedCount; j++)
                        {
                            nodeInstancesIndexBuffer = a_nodeInstancesIndexBuffer [i_childNodeIndex];  // Set back
                            int i_instanceIndex = nodeInstancesIndexBuffer.i;

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

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

                    // Reset child
                    nodeChildrenBuffer.i_nodesIndex = -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
        }
Esempio n. 27
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 rootNodeData, 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 * rootNodeData.i_instancesAllowedCount;

            // Reuse spare store
            InstancesSpareIndexBufferElement instancesSpareIndexBuffer = a_instancesSpareIndexBuffer [rootNodeData.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 < rootNodeData.i_instancesAllowedCount; i++)
            {
                int i_instanceIndexOffset = i_nodeInstanceIndexOffset + i;

                nodeInstancesIndexBuffer = a_nodeInstancesIndexBuffer [i_instanceIndexOffset];

                // Is spare.
                if (nodeInstancesIndexBuffer.i == -1)
                {
                    // Assign instance index.
                    nodeInstancesIndexBuffer.i = instancesSpareIndexBuffer.i;
                    a_nodeInstancesIndexBuffer [i_instanceIndexOffset] = nodeInstancesIndexBuffer;  // Set back.

                    isInstanceAdded = true;

                    break;
                }
            } // for

            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];

                    // Check if instance bounds fit in child
                    if (CommonMethods._Encapsulates(nodeChildrenBuffer.bounds, instanceBounds))
                    {
                        //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 rootNodeData,
                            nodeChildrenBuffer.i_nodesIndex,
                            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
                        }
                    }
                }

// Debug.LogError ( "Found no child node, to fit instance. Try grow octree." ) ;

                NodeBufferElement nodeBufferElement = a_nodesBuffer [rootNodeData.i_rootNodeIndex];

                // Try add node at the root

// Debug.LogError ( "Grow again." ) ;
                _GrowOctree(ref rootNodeData,
                            (float3)instanceBounds.center - nodeBufferElement.f3_center,
                            ref a_nodesBuffer,
                            ref a_nodeSparesBuffer,
                            ref a_nodeChildrenBuffer,
                            ref a_nodeInstancesIndexBuffer,
                            ref a_instanceBuffer,
                            ref a_instancesSpareIndexBuffer
                            );

                _AddNodeInstance(ref rootNodeData,
                                 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);
        }
        /// <summary>
        /// Splits the octree into eight children.
        /// </summary>
        /// <param name="i_nodeIndex">Internal octree node index.</param>
        static private void _Split(ref RootNodeData rootNodeData, 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 [rootNodeData.i_nodeSpareLastIndex];
                nodeChildrenBuffer = a_nodeChildrenBuffer [i_childrenIndexOffset + i];
                nodeChildrenBuffer.i_nodesIndex = nodeSparesBuffer.i;
                a_nodeChildrenBuffer [i_childrenIndexOffset + i] = nodeChildrenBuffer;         // Set back
                rootNodeData.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 rootNodeData, nodeChildrenBuffer.i_nodesIndex, 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 rootNodeData, nodeChildrenBuffer.i_nodesIndex, 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 rootNodeData, nodeChildrenBuffer.i_nodesIndex, 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 rootNodeData, nodeChildrenBuffer.i_nodesIndex, 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 rootNodeData, nodeChildrenBuffer.i_nodesIndex, 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 rootNodeData, nodeChildrenBuffer.i_nodesIndex, 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 rootNodeData, nodeChildrenBuffer.i_nodesIndex, 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 rootNodeData, nodeChildrenBuffer.i_nodesIndex, f_newBaseLength, f3_childCenterQuater, ref a_nodesBuffer, ref a_nodeSparesBuffer, ref a_nodeChildrenBuffer, ref a_nodeInstancesIndexBuffer);
        }