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