-
Notifications
You must be signed in to change notification settings - Fork 11
Performance Spatial Tree 2d Performance
github-actions[bot] edited this page Sep 14, 2026
·
11 revisions
- Fast range/bounds/nearest‑neighbor queries on 2D data without scanning everything.
- Quick picks: QuadTree2D for broad‑phase; KdTree2D (Balanced) for NN; KdTree2D (Unbalanced) for fast rebuilds; RTree2D for bounds‑based data.
This document contains performance benchmarks for the 2D spatial tree implementations in Unity Helpers.
- QuadTree2D - Easiest to use, good all-around performance
- KdTree2D - Balanced and unbalanced variants available
- RTree2D - Optimized for bounding box queries
- QuadTree2D and KdTree2D (balanced and unbalanced) guarantee the same results for the same input data and the same queries. They are both point-based trees and differ only in construction/query performance characteristics.
- RTree2D is bounds-based (stores rectangles/AABBs), not points. Its spatial knowledge and query semantics operate on rectangles, so its results will intentionally differ for sized objects and bounds intersection queries.
| Construction | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| 1,000,000 entries | 2 (0.362s) | 5 (0.195s) | 1 (0.745s) | 3 (0.313s) |
| Elements In Range | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| Full (~span/2) (r=499.5) | 100 | 98 | 92 | 16 |
| Half (~span/4) (r=249.8) | 406 | 409 | 405 | 78 |
| Quarter (~span/8) (r=124.9) | 1,600 | 1,594 | 1,644 | 344 |
| Tiny (~span/1000) (r=1) | 161,731 | 159,685 | 237,950 | 147,807 |
| Get Elements In Bounds | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| Full (size=999.0x999.0) | 315 | 362 | 328 | 20 |
| Half (size=499.5x499.5) | 1,746 | 1,723 | 1,772 | 108 |
| Quarter (size=249.8x249.8) | 6,787 | 6,916 | 6,997 | 546 |
| Unit (size=1) | 198,766 | 194,827 | 261,709 | 152,855 |
| Approximate Nearest Neighbors | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| 500 neighbors | 16,775 | 35,374 | 26,298 | 3,663 |
| 100 neighbors | 161,271 | 131,713 | 147,749 | 18,238 |
| 10 neighbors | 506,799 | 494,356 | 261,774 | 29,127 |
| 1 neighbor | 618,345 | 606,530 | 272,364 | 29,740 |
| Construction | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| 100,000 entries | 44 (0.023s) | 67 (0.015s) | 15 (0.064s) | 37 (0.026s) |
| Elements In Range | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| Full (~span/2) (r=199.5) | 1,020 | 1,004 | 1,021 | 215 |
| Half (~span/4) (r=99.75) | 2,281 | 2,306 | 2,341 | 538 |
| Quarter (~span/8) (r=49.88) | 7,804 | 8,704 | 9,376 | 2,105 |
| Tiny (~span/1000) (r=1) | 195,261 | 196,197 | 279,042 | 194,307 |
| Get Elements In Bounds | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| Full (size=399.0x249.0) | 4,482 | 4,379 | 4,487 | 341 |
| Half (size=199.5x124.5) | 11,228 | 12,982 | 14,742 | 1,412 |
| Quarter (size=99.75x62.25) | 31,186 | 37,446 | 43,419 | 5,631 |
| Unit (size=1) | 228,484 | 225,721 | 315,803 | 205,613 |
| Approximate Nearest Neighbors | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| 500 neighbors | 23,576 | 22,768 | 24,282 | 5,045 |
| 100 neighbors | 107,485 | 190,998 | 99,608 | 17,425 |
| 10 neighbors | 481,852 | 501,441 | 292,286 | 40,726 |
| 1 neighbor | 596,868 | 616,172 | 301,254 | 43,377 |
| Construction | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| 10,000 entries | 491 (0.002s) | 669 (0.001s) | 202 (0.005s) | 413 (0.002s) |
| Elements In Range | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| Full (~span/2) (r=49.50) | 10,059 | 10,063 | 10,024 | 2,149 |
| Half (~span/4) (r=24.75) | 38,194 | 37,816 | 39,638 | 8,431 |
| Quarter (~span/8) (r=12.38) | 70,930 | 83,939 | 99,255 | 33,540 |
| Tiny (~span/1000) (r=1) | 247,372 | 246,625 | 341,658 | 226,037 |
| Get Elements In Bounds | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| Full (size=99.00x99.00) | 44,817 | 44,113 | 44,394 | 3,536 |
| Half (size=49.50x49.50) | 164,390 | 168,864 | 172,050 | 13,410 |
| Quarter (size=24.75x24.75) | 98,908 | 135,348 | 171,080 | 50,695 |
| Unit (size=1) | 292,361 | 283,248 | 379,910 | 236,640 |
| Approximate Nearest Neighbors | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| 500 neighbors | 30,990 | 30,435 | 29,942 | 5,229 |
| 100 neighbors | 135,108 | 123,954 | 159,352 | 23,612 |
| 10 neighbors | 495,078 | 493,259 | 327,237 | 54,246 |
| 1 neighbor | 631,140 | 530,323 | 390,299 | 61,864 |
| Construction | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| 1,000 entries | 4,416 (0.000s) | 6,591 (0.000s) | 1,976 (0.001s) | 3,907 (0.000s) |
| Elements In Range | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| Full (~span/2) (r=24.50) | 95,715 | 97,169 | 97,918 | 21,417 |
| Half (~span/4) (r=12.25) | 94,861 | 123,468 | 119,436 | 40,197 |
| Quarter (~span/8) (r=6.13) | 147,619 | 169,956 | 181,777 | 84,623 |
| Tiny (~span/1000) (r=1) | 346,917 | 348,862 | 458,277 | 320,193 |
| Get Elements In Bounds | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| Full (size=49.00x19.00) | 432,109 | 441,180 | 465,708 | 35,018 |
| Half (size=24.50x9.5) | 209,301 | 357,349 | 363,098 | 105,115 |
| Quarter (size=12.25x4.75) | 334,684 | 364,976 | 466,838 | 228,618 |
| Unit (size=1) | 404,675 | 390,143 | 502,011 | 337,746 |
| Approximate Nearest Neighbors | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| 500 neighbors | 38,041 | 41,051 | 39,006 | 5,841 |
| 100 neighbors | 156,877 | 152,010 | 160,805 | 24,720 |
| 10 neighbors | 568,521 | 609,294 | 405,817 | 92,332 |
| 1 neighbor | 531,965 | 641,229 | 334,066 | 106,525 |
| Construction | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| 100 entries | 38,314 (0.000s) | 37,593 (0.000s) | 18,315 (0.000s) | 18,382 (0.000s) |
| Elements In Range | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| Full (~span/2) (r=4.5) | 707,466 | 707,344 | 698,430 | 190,481 |
| Half (~span/4) (r=2.25) | 579,526 | 574,963 | 734,467 | 379,167 |
| Quarter (~span/8) (r=1.13) | 580,850 | 585,912 | 742,405 | 427,445 |
| Tiny (~span/1000) (r=1) | 576,125 | 583,627 | 744,381 | 429,480 |
| Get Elements In Bounds | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| Full (size=9x9) | 1,564,474 | 1,567,597 | 1,584,871 | 282,253 |
| Half (size=4.5x4.5) | 641,201 | 644,062 | 792,659 | 419,895 |
| Quarter (size=2.25x2.25) | 650,761 | 653,857 | 788,861 | 438,508 |
| Unit (size=1) | 647,476 | 664,227 | 787,188 | 436,589 |
| Approximate Nearest Neighbors | KDTree2D (Balanced) | KDTree2D (Unbalanced) | QuadTree2D | RTree2D |
|---|---|---|---|---|
| 100 neighbors (max) | 191,767 | 191,405 | 180,671 | 154,573 |
| 10 neighbors | 640,162 | 540,897 | 472,754 | 265,960 |
| 1 neighbor | 658,223 | 565,971 | 517,711 | 350,069 |
All numbers represent operations per second (higher is better), except for construction times which show operations per second and absolute time.
QuadTree2D:
- Best for: General-purpose 2D spatial queries
- Strengths: Balanced performance across all operation types, simple to use
- Weaknesses: Slightly slower than KdTree for point queries
KdTree2D (Balanced):
- Best for: When you need consistent query performance
- Strengths: Fast nearest-neighbor queries, good for smaller datasets
- Weaknesses: Slower construction time
KdTree2D (Unbalanced):
- Best for: When you need fast construction and will rebuild frequently
- Strengths: Fastest construction, similar query performance to balanced
- Weaknesses: May degrade on pathological data distributions
RTree2D:
- Best for: Bounding box queries, especially with large query areas
- Strengths: Excellent for large bounding box queries, handles overlapping objects well
- Weaknesses: Slower for point queries and small ranges
- All spatial trees assume immutable positional data
- If positions change, you must reconstruct the tree
- Spatial queries are O(log n) vs O(n) for linear search
- Construction cost is amortized over many queries
📦 Unity Helpers | 📖 Documentation | 🐛 Issues | 📜 MIT License
- Inspector Button
- Inspector Conditional Display
- Inspector Grouping Attributes
- Inspector Inline Editor
- Inspector Overview
- Inspector Selection Attributes
- Inspector Settings
- Inspector Validation Attributes
- Utility Components
- Visual Components
- Data Structures
- Helper Utilities
- Math And Extensions
- Pooling Guide
- Random Generators
- Reflection Helpers
- Singletons
- Asset Change Detection
- Asset Validation
- Authored Asset Validation
- Editor Tools Guide
- Failed Tests Exporter
- Sprite Animation Motion
- Test Run Reporter
- Unity Method Analyzer
- Ai Model Backends
- Bundled Assembly Conflicts
- Mcp Ecosystem
- Mcp Local Setup
- Odin Migration Guide
- Unity Devcontainer Licensing