Octree
Octree implementation. An octree is a data structure that allows for quick spatial data queries of static objects. For example, trees can be stored in an octree, and nearby trees could be found near the player.
Octrees exists as a grid of nodes, which are subdivided in half in each axis, which results in 8 different regions. This recursively happens to a set depth.
This allows for O(n) data storage and log(n) retrieval of nearby objects. With a large quantity of items in the octree, this can make data retrieval significantly faster.
See also: https://en.wikipedia.org/wiki/Octree
local octree = Octree.new()
octree:CreateNode(Vector3.zero, "A")
octree:CreateNode(Vector3.zero, "B")
octree:CreateNode(Vector3.zero, workspace)
octree:CreateNode(Vector3.new(0, 0, 1000), "C")
print(octree:RadiusSearch(Vector3.zero, 100)) --> { "A", "B", workspace }
tip
Octrees are best for static objects in the world, and not objects moving around, since then data can be statically cached.
Sometimes using Roblox's spatial hash using the region API is faster than using an octree. However, for data that is centralized, or static, an octree can be a very efficient spatial query mechanism.
That said, it is totally fine to track the objects that DO move around using octree, as long as you apply proper optimizations. The main performance cost of doing this comes down to tracking and updating the position of the objects, which is fine if: 1) You have a way to detect the movement without having to loop through all the moving objects to update the position 2) You can tolerate some inaccuracy with positions and smear this update 3) You have less than 1000 objects to track, in this case looping through everything shouldn't be too costly.
Functions
new
Constructs a new Octree.
GetAllNodes
Returns all octree nodes stored in the octree!
local octree = Octree.new()
octree:CreateNode(Vector3.zero, "Hi")
octree:CreateNode(Vector3.zero, "Bob")
print(octree:GetAllNodes()) --> { "Hi", "Bob" }
Order is not guaranteed.
warning
If you have 100,000 nodes in your octree, this is going to be very slow.
CreateNode
Creates a new OctreeNode at the given position which can be retrieved
tip
Be sure to call :Destroy() on a node if the data becomes stale. Note that this is not necessary if the whole octree is removed from memory.
local octree = Octree.new()
octree:CreateNode(Vector3.zero, "A")
octree:CreateNode(Vector3.zero, "B")
RadiusSearch
Octree:
RadiusSearch
(
radius:
number
) →
(
{
T
}
,
--
Objects found
{
number
}
--
Distances squared
)
Searches at the position and radius for any objects that may be within this radius.
local octree = Octree.new()
octree:CreateNode(Vector3.zero, "A")
octree:CreateNode(Vector3.zero, "B")
octree:CreateNode(Vector3.new(0, 0, 1000), "C")
print(octree:RadiusSearch(Vector3.zero, 100)) --> { "A", "B" }
KNearestNeighborsSearch
Octree:
KNearestNeighborsSearch
(
) →
(
{
any
}
,
--
Objects found
{
number
}
--
Distances squared
)
Searches at the position and radius for any objects that may be within this radius. Returns the knearest entries.
The closest entities will be first in the list.