{"id":13676411,"url":"https://github.com/bartofzo/NativeTrees","last_synced_at":"2025-04-29T07:32:06.828Z","repository":{"id":64991562,"uuid":"564881757","full_name":"bartofzo/NativeTrees","owner":"bartofzo","description":"Burst compatible Octree and Quadtree for Unity","archived":false,"fork":false,"pushed_at":"2024-04-02T13:20:37.000Z","size":10565,"stargazers_count":333,"open_issues_count":1,"forks_count":24,"subscribers_count":9,"default_branch":"main","last_synced_at":"2024-11-25T08:45:04.932Z","etag":null,"topics":["dots","ecs","partitioning","spatial","unity"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bartofzo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"ko_fi":"bartofzo"}},"created_at":"2022-11-11T18:15:14.000Z","updated_at":"2024-11-25T08:31:15.000Z","dependencies_parsed_at":"2024-11-11T18:34:11.069Z","dependency_job_id":"98e3aa39-f976-4f96-905b-11e3fded04e8","html_url":"https://github.com/bartofzo/NativeTrees","commit_stats":{"total_commits":18,"total_committers":2,"mean_commits":9.0,"dds":0.05555555555555558,"last_synced_commit":"7025372e13aabb2adde09bc06c2b2bdea67b71f5"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bartofzo%2FNativeTrees","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bartofzo%2FNativeTrees/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bartofzo%2FNativeTrees/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bartofzo%2FNativeTrees/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bartofzo","download_url":"https://codeload.github.com/bartofzo/NativeTrees/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251455888,"owners_count":21592256,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dots","ecs","partitioning","spatial","unity"],"created_at":"2024-08-02T13:00:26.182Z","updated_at":"2025-04-29T07:32:06.413Z","avatar_url":"https://github.com/bartofzo.png","language":"C#","readme":"![NativeTrees](./Packages/NativeTrees/NativeTrees.png \"NativeTrees\")\n\nGeneric sparse octree and quadtree\nthat store objects together with their axis aligned bounding boxes (AABB's)\n\nWritten in C# for Unity's burst compiler and the ECS/DOTS framework.\nTested with Unity 2021.3.11f1\n\n### Supported queries:\n- Raycast\n- Range (AABB overlap)\n- K-Nearest neighbours\n\n### Other features:\n- Implemented as a sparse tree, so only stores nodes that are occupied. Memory usage is therefore relatively low.\n  The octree has a max depth of 10 and the quad tree a max depth of 15.\n- Supports insertion of AABB's\n- Fast insertion path for points\n- Optimized with SIMD instructions so greatly benefits from burst compilation\n\n### Limitations:\n- Objects must be structs (Burst limitation)\n- No remove or update. Tried several approaches but they either left an unbalanced tree or doing a\n  full clear and re-insert was faster.\n- No foreach support, we leverage the stack and \"struct\" delegates, which suits the recursive\n  nature of the tree better.\n\n- Insertion can only be done on a single thread. Queries ofcourse can be across multiple threads.\n\n### Future todo's:\n- Frustrum query\n- 'Fat' raycast (virtually expand AABB's of nodes and objects when testing for ray intersections)\n\n## Installation\n\nUsing the Unity package manager, choose Add Package from git URL and enter:\n\n    https://github.com/bartofzo/NativeTrees.git?path=/Packages/NativeTrees\n\n## Performance\n\nThe trees are heaviliy optimized to make use of SIMD instructions.\nTherefore performance is best when used in burst compiled code.\n\nQueries are *very* fast.\nThe raycast never visits more nodes than absolutely neccessary.\nThe overlap (and insertion) use a technique where to test in which child nodes AABB's should go, only\ntwo comparisons are made followed up by some bitwise operations. (See the source for an explanation).\n\nNearest neighbour is the slowest of the bunch (but still fast) as it has some overhead in keeping track of a priority queue.\n\nActual performance can vary wildly depending on the structure of your tree and it's\nsettings. For the sake of cool stats, here are some numbers on insertion times and raycasts for random points and AABB's,\nSingle thread burst compiled, maxDepth of 8. These numbers should not be taken too seriously because it's random data\nand the tree will be divided almost equally everywhere, which in most realistic scenarios is not the case.\n\nRun on a MBP 16\" i9 2.3 GHz from 2019.\n\n|Obj Count| QT Points Insert | QT AABB Insert| OT Points Insert | OT AABB Insert| OT 1000 Inf Raycasts| OT 1000 Max Dist Raycasts\n|---------|-----------|---------|-----------|---------|---------------------|----------------------\n|1000     |0.07ms     |0.08ms   |0.07ms     |0.10ms   |0.25ms (4M Rays/sec) |0.13ms (7M Rays/sec)\n|5000     |0.34ms     |0.57ms   |0.25ms     |0.50ms   |0.38ms               |0.19ms\n|10K      |0.69ms     |1.23ms   |0.82ms     |1.55ms   |0.45ms               |0.23ms\n|25K      |2.18ms     |4.15ms   |1.91ms     |3.89ms   |0.51ms               |0.32ms\n|50K      |3.86ms     |10.87ms  |4.04ms     |9.61ms   |0.49ms               |0.32ms\n|100K     |9.64ms     |26.12ms  |11.46ms    |18.81ms  |0.51ms               |0.28ms\n|250K     |24.13ms    |76.85ms  |22.47ms    |50.95ms  |0.64ms               |0.39ms\n|500K     |51.00ms    |131.58ms |60.08ms    |164.17ms |0.84ms               |0.45ms\n|1M       |129.03ms   |260.55ms |152.50ms   |301.99ms |1.04ms               |0.55ms\n\n## Usage\n\nThere are two samples included that show how to use the octree and quadtree.\nThe extension classes provide readymade solutions for AABB only checking. For more complicated\nshapes you must provide your own ray/overlap/distance calculations.\n\nNOTE: If you've imported the package via the Unity Package Manager, you need to copy the\nsample scenes to your Assets folder to open them.\n[See this thread](https://forum.unity.com/threads/it-is-not-allowed-to-open-a-scene-in-a-read-only-package-why.1148036/)\n\n### Insertion\nThe objects can be of any unmanaged type, when inserting, an AABB must be provided:\n```cs\n// Insert a bunch of triangles\nfor (int i = 0; i \u003c tris.Length; i++)\n{\n  var triangle = tris[i];\n  octree.Insert(triangle, triangle.GetAABB());\n}\n```\nOften times however, it's more efficient to insert Id's that map to something outside of\nthe tree (like DOTS entities).\n\nIf you know your objects are points, you can insert them faster by using:\n```cs\n// Insert entities that are 'points'\nfor (int i = 0; i \u003c entities.Length; i++)\n{\n  octree.InsertPoint(entities[i], positions[i]);\n}\n```\nNote that objects inserted as points only support range and nearest neighbour queries.\n\n### Queries\n\nAll of the supported queries use the same pattern which is\nto (ab)use structs as a sort of delegate. This separates collision/intersection\ncode from the type of objects, allowing you to insert even primitive types or types from another assembly.\nThis turned out to be the most efficent and easiest to implement while keeping things fully compatibly with Unity's Burst compiler.\n\n### Raycast\n\nA raycast query for example, requires you to implement IOctreeRayIntersecter which\nacts as a delegate to determine if a ray intersects with an object that's in the tree.\n```cs\npublic static bool RaycastAABB\u003cT\u003e(this NativeOctree\u003cT\u003e octree, Ray ray, out OctreeRaycastHit\u003cT\u003e hit) where T : unmanaged\n{ \n  return octree.Raycast\u003cRayAABBIntersecter\u003cT\u003e\u003e(ray, out hit);\n}\n\nstruct RayAABBIntersecter\u003cT\u003e : IOctreeRayIntersecter\u003cT\u003e\n{\n  public bool IntersectRay(in PrecomputedRay ray, T obj, AABB objBounds, out float distance)\n  {\n    return objBounds.IntersectsRay(ray, out distance);\n  }\n}\n```\n\nThe example above just tests the ray against the object's bounds. (See NativeOctreeExtensions) But you could go a step further\nand test it against a triangle, a collider and so forth. Note that the tree itself\ndoes not automatically test for Ray-AABB intersections on the objects, so it's usually a good decision to early exit\nif the ray doesn't exit with the object's bounds since those checks are cheap.\n\n### Nearest Neighbour\nNativeTrees support nearest neighbour queries. You should implement IOctreeNearestVisitor and IOctreeDistanceProvider.\n```cs\nstruct AABBDistanceSquaredProvider\u003cT\u003e : IOctreeDistanceProvider\u003cT\u003e \n{\n  // Just return the distance squared to our bounds\n  public float DistanceSquared(float3 point, T obj, AABB bounds) =\u003e bounds.DistanceSquared(point);\n}\n\nstruct OctreeNearestAABBVisitor\u003cT\u003e : IOctreeNearestVisitor\u003cT\u003e\n{\n  public T nearest;\n  public bool found;\n        \n  public bool OnVist(T obj)\n  {\n    this.found = true;\n    this.nearest = obj;\n            \n    return false; // immediately stop iterating at first hit\n    // if we want the 2nd or 3rd neighbour, we could iterate on and keep track of the count!\n  }\n}\n```\nThe extensions classes show an example of these implementation. But only for AABB's.\nIf you need more detail on your distance, you can implement your type specific behaviour using these interfaces.\n\nTo get the nearest neighbour:\n```cs\nvar visitor = new OctreeNearestAABBVisitor\u003cEntity\u003e();\noctree.Nearest(point, maxDistance, ref visitor, default(AABBDistanceSquaredProvider\u003cEntity\u003e));\nEntity nearestEntity = visitor.nearest;\n```\n### Range\n\nHere's an example that adds unique objects that overlap with a range to a hashset:\n```cs\npublic static void RangeAABBUnique\u003cT\u003e(this NativeOctree\u003cT\u003e octree, AABB range, NativeParallelHashSet\u003cT\u003e results)\n  where T : unmanaged, IEquatable\u003cT\u003e\n{\n  var vistor = new RangeAABBUniqueVisitor\u003cT\u003e()\n  {\n    results = results\n  };\n     \n  octree.Range(range, ref vistor);\n}\n\nstruct RangeAABBUniqueVisitor\u003cT\u003e : IOctreeRangeVisitor\u003cT\u003e where T : unmanaged, IEquatable\u003cT\u003e\n{\n  public NativeParallelHashSet\u003cT\u003e results;\n        \n  public bool OnVisit(T obj, AABB objBounds, AABB queryRange)\n  {\n    // check if our object's AABB overlaps with the query AABB\n    if (objBounds.Overlaps(queryRange))\n    results.Add(obj);\n\n    return true; // always keep iterating, we want to catch all objects\n  }\n}\n```\nIt's important to note that the query itself iterates all of the objects that are in nodes that overlap with\nthe input range. An extra check should be performed to test if the object overlaps.\nAlso, if the objects aren't points, it's possible for them to be visited multiple times as they reside in more than one node.\nA hashset can be used to only visit each object once.\n\n### Support\nFeel free to raise an issue or contact me for any questions.\nThe code is free to use in your project(s).\nIf this was helpful to you, consider buying me a coffee ;)\n\n\u003ca href='https://ko-fi.com/bartofzo' target='_blank'\u003e\u003cimg height='35' style='border:0px;height:46px;' src='https://az743702.vo.msecnd.net/cdn/kofi3.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' /\u003e\n\n\nThank you!\n\n### Sources\n\nFast raycast traversal algorithm:\nhttps://daeken.svbtle.com/a-stupidly-simple-fast-quadtree-traversal-for-ray-intersection\n\nRay box 'slab' intersection method:\nhttps://tavianator.com/2011/ray_box.html\n\nNearest neighbour search:\nhttps://stackoverflow.com/a/41306992\n\nAnyPath, my pathfinding library on the Unity Asset store:\nhttps://assetstore.unity.com/packages/tools/ai/anypath-213200\n","funding_links":["https://ko-fi.com/bartofzo","https://ko-fi.com/bartofzo'"],"categories":["Open Source Repositories"],"sub_categories":["DOTS"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbartofzo%2FNativeTrees","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbartofzo%2FNativeTrees","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbartofzo%2FNativeTrees/lists"}