예제 #1
0
        /// <summary>
        /// Checks if this node or anything below it has something in it.
        /// </summary>
        /// <param name="i_nodeIndex">Internal octree node index.</param>
        /// <returns>True if this node or any of its children, grandchildren etc have something in them</returns>
        static public bool _HasAnyInstances(int i_nodeIndex, DynamicBuffer <NodeBufferElement> a_nodesBuffer, DynamicBuffer <NodeChildrenBufferElement> a_nodeChildrenBuffer)
        {
            if (i_nodeIndex == -1)
            {
                return(false);
            }


            NodeBufferElement nodeBuffer = a_nodesBuffer [i_nodeIndex];

            if (nodeBuffer.i_instancesCount > 0)
            {
                return(true);
            }

            // Has children?
            if (nodeBuffer.i_childrenCount > 0)
            {
                int i_nodeChildrenIndexOffset = i_nodeIndex * 8;

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

                    // Has child any instances
                    if (_HasAnyInstances(nodeChildBuffer.i_nodesIndex, a_nodesBuffer, a_nodeChildrenBuffer))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
예제 #2
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);
        }
예제 #3
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>
        /// 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);
        }
예제 #5
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
            }
        }
예제 #7
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);
        }
        /// <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);
        }
        /// <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);
        }
예제 #10
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);
        }