Example #1
0
void Octree::CollectNodes(Vector<Pair<OctreeNode*, float> >& result, const Octant* octant, const Ray& ray, unsigned short nodeFlags,
    float maxDistance, unsigned layerMask) const
{
    float octantDist = ray.HitDistance(octant->cullingBox);
    if (octantDist >= maxDistance)
        return;

    const Vector<OctreeNode*>& octantNodes = octant->nodes;
    for (auto it = octantNodes.Begin(); it != octantNodes.End(); ++it)
    {
        OctreeNode* node = *it;
        if ((node->Flags() & nodeFlags) == nodeFlags && (node->LayerMask() & layerMask))
        {
            float distance = ray.HitDistance(node->WorldBoundingBox());
            if (distance < maxDistance)
                result.Push(MakePair(node, distance));
        }
    }

    for (size_t i = 0; i < NUM_OCTANTS; ++i)
    {
        if (octant->children[i])
            CollectNodes(result, octant->children[i], ray, nodeFlags, maxDistance, layerMask);
    }
}
Example #2
0
void Octree::Update()
{
    PROFILE(UpdateOctree);

    for (auto it = updateQueue.Begin(); it != updateQueue.End(); ++it)
    {
        OctreeNode* node = *it;
        // If node was removed before update could happen, a null pointer will be in its place
        if (node)
        {
            node->SetFlag(NF_OCTREE_UPDATE_QUEUED, false);

            // Do nothing if still fits the current octant
            const BoundingBox& box = node->WorldBoundingBox();
            Vector3 boxSize = box.Size();
            Octant* oldOctant = node->octant;
            if (oldOctant && oldOctant->cullingBox.IsInside(box) == INSIDE && oldOctant->FitBoundingBox(box, boxSize))
                continue;

            // Begin reinsert process. Start from root and check what level child needs to be used
            Octant* newOctant = &root;
            Vector3 boxCenter = box.Center();

            for (;;)
            {
                bool insertHere;
                // If node does not fit fully inside root octant, must remain in it
                if (newOctant == &root)
                    insertHere = newOctant->cullingBox.IsInside(box) != INSIDE || newOctant->FitBoundingBox(box, boxSize);
                else
                    insertHere = newOctant->FitBoundingBox(box, boxSize);

                if (insertHere)
                {
                    if (newOctant != oldOctant)
                    {
                        // Add first, then remove, because node count going to zero deletes the octree branch in question
                        AddNode(node, newOctant);
                        if (oldOctant)
                            RemoveNode(node, oldOctant);
                    }
                    break;
                }
                else
                    newOctant = CreateChildOctant(newOctant, newOctant->ChildIndex(boxCenter));
            }
        }
    }

    updateQueue.Clear();
}