├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── README.md ├── README.tex.md ├── cmake └── FindLIBIGL.cmake ├── css └── github-markdown.css ├── data ├── bob.obj ├── cheburashka.obj ├── fandisk.obj ├── knight.obj ├── rubber-ducky.obj └── torus.obj ├── distances.cpp ├── images ├── Example_of_bounding_volume_hierarchy.png ├── Example_of_bounding_volume_hierarchy.svg ├── bounding-primitives.png ├── cheburashka-knight-intersections.gif ├── more-realistic-bvh-example.png ├── more-realistic-bvh-example.svg ├── point-cloud-aabb-tree.gif └── rubber-ducky-aabb-tree.png ├── include ├── AABBTree.h ├── BoundingBox.h ├── CloudPoint.h ├── MeshTriangle.h ├── Object.h ├── Ray.h ├── VectorXb.h ├── box_box_intersect.h ├── box_edges.h ├── definitions.h ├── find_all_intersecting_pairs_using_AABBTrees.h ├── insert_box_into_box.h ├── insert_triangle_into_box.h ├── k_nearest_neighbors_brute_force.h ├── k_nearest_neighbors_using_AABBTree.h ├── nearest_neighbor_brute_force.h ├── point_AABBTree_squared_distance.h ├── point_box_squared_distance.h ├── ray_intersect_box.h ├── ray_intersect_triangle.h ├── ray_intersect_triangle_mesh_brute_force.h ├── tictoc.h ├── triangle_triangle_intersection.h ├── visualize_aabbtree.h └── warnings.h ├── intersections.cpp ├── markdown └── header.md ├── rays.cpp ├── src ├── AABBTree.cpp ├── AABBTree_ray_intersect.cpp ├── box_box_intersect.cpp ├── find_all_intersecting_pairs_using_AABBTrees.cpp ├── insert_box_into_box.cpp ├── insert_triangle_into_box.cpp ├── nearest_neighbor_brute_force.cpp ├── point_AABBTree_squared_distance.cpp ├── point_box_squared_distance.cpp ├── ray_intersect_box.cpp ├── ray_intersect_triangle.cpp ├── ray_intersect_triangle_mesh_brute_force.cpp └── triangle_triangle_intersection.cpp └── tex ├── 1f08ccc9cd7309ba1e756c3d9345ad9f.svg ├── 55a049b8f161ae7cfeb0197d75aff967.svg ├── 7295bc071a3c9dc4d8627e19de64928f.svg ├── b7afe912ac7ed280f96e7cfb0f35a027.svg └── f9bb6ecace3a663c4adf0544035b4da4.svg /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | 31 | *.un~ 32 | *.swo 33 | *.swp 34 | build/* 35 | *.DS_Store 36 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libigl"] 2 | path = libigl 3 | url = https://github.com/libigl/libigl 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | project(boundaryvolumehierarchy) 3 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 4 | 5 | ### libIGL options: choose between header only and compiled static library 6 | option(LIBIGL_USE_STATIC_LIBRARY "Use libigl as static library" OFF) 7 | option(LIBIGL_WITH_OPENGL "Use OpenGL" ON) 8 | option(LIBIGL_WITH_OPENGL_GLFW "Use GLFW" ON) 9 | 10 | find_package(LIBIGL REQUIRED) 11 | 12 | # Add your project files 13 | include_directories("include/") 14 | if(USE_SOLUTION) 15 | file(GLOB SRCFILES solution/*.cpp) 16 | else() 17 | file(GLOB SRCFILES src/*.cpp) 18 | endif() 19 | 20 | add_library(core ${SRCFILES}) 21 | target_link_libraries(core igl::core igl::opengl igl::opengl_glfw ) 22 | 23 | add_executable(rays "rays.cpp") 24 | target_link_libraries(rays core igl::core igl::opengl igl::opengl_glfw ) 25 | 26 | add_executable(distances "distances.cpp") 27 | target_link_libraries(distances core igl::core igl::opengl igl::opengl_glfw ) 28 | 29 | add_executable(intersections "intersections.cpp") 30 | target_link_libraries(intersections core igl::core igl::opengl igl::opengl_glfw ) 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Computer Graphics – Bounding Volume Hierarchy 2 | 3 | > **To get started:** Clone this repository and all its [submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) dependencies using: 4 | > 5 | > git clone --recursive https://github.com/alecjacobson/computer-graphics-bounding-volume-hierarchy.git 6 | > 7 | > **Do not fork:** Clicking "Fork" will create a _public_ repository. If you'd like to use GitHub while you work on your assignment, then mirror this repo as a new _private_ repository: https://stackoverflow.com/questions/10065526/github-how-to-make-a-fork-of-public-repository-private 8 | 9 | > **Note for Linux users:** if you're using Ubuntu, make sure you've installed the following packages if 10 | > you haven't done so already: 11 | > 12 | > sudo apt-get install git 13 | > sudo apt-get install build-essential 14 | > sudo apt-get install cmake 15 | > sudo apt-get install libx11-dev 16 | > sudo apt-get install mesa-common-dev libgl1-mesa-dev libglu1-mesa-dev 17 | > sudo apt-get install libxinerama1 libxinerama-dev 18 | > sudo apt-get install libxcursor-dev 19 | > sudo apt-get install libxrandr-dev 20 | > sudo apt-get install libxi-dev 21 | > sudo apt-get install libxmu-dev 22 | > sudo apt-get install libblas-dev 23 | 24 | 25 | ## Background 26 | 27 | ### Read Section 12.3 of _Fundamentals of Computer Graphics (4th Edition)_. 28 | 29 | ![Visualize of all of the boxes of a hierarchical axis-aligned bounding-box tree 30 | around the triangles of a [rubber 31 | ducky](https://en.wikipedia.org/wiki/Rubber_duck) 32 | mesh.](images/rubber-ducky-aabb-tree.png) 33 | 34 | ### Object partitioning 35 | 36 | In this assignment, you will build an Axis-Aligned Bounding-Box 37 | [Tree](https://en.wikipedia.org/wiki/Tree_structure) (AABB Tree). This is one of the simplest 38 | instances of an _object partitioning_ scheme, where a group of input objects are 39 | arranged into a [bounding volume 40 | hierarchy](https://en.wikipedia.org/wiki/Bounding_volume_hierarchy). 41 | 42 | ![In the "scene" on the left, there are six objects. All objects fit into the 43 | axis-aligned bounding box **A** (the root of the tree), then we cluster nearby 44 | objects into subtrees rooted at **B** and **C**. We continue to apply this 45 | process recursively until leaves of the tree store a single object. Tree shown 46 | on right. ([image 47 | source](https://commons.wikimedia.org/wiki/File:Example_of_bounding_volume_hierarchy.svg))](images/Example_of_bounding_volume_hierarchy.png) 48 | 49 | In our assignment, we will build a binary tree. Conducting queries on the tree 50 | will be reminiscent of searching for values in a [binary search 51 | tree](https://en.wikipedia.org/wiki/Binary_search_tree). However, objects in our 52 | tree will not be _perfectly_ sorted. In general, the bounding boxes of 53 | "relatives" (even siblings) in our tree will overlap spatially. 54 | 55 | ![In most cases, bounding boxes will overlap. The tree topology remains the same 56 | in this case. ([original image 57 | source](https://commons.wikimedia.org/wiki/File:Example_of_bounding_volume_hierarchy.svg))](images/more-realistic-bvh-example.png) 58 | 59 | 60 | By allowing bounding boxes to overlap we avoid the need to geometric split our 61 | objects. 62 | 63 | > **Question:** If we use overlapping bounding boxes (i.e., no splitting) to 64 | > build an AABB Tree , how many leaves will there be? 65 | 66 | ![The AABB Tree around a point cloud starts with a single box. The next level 67 | has two boxes, roughly splitting the first box. This process continues 68 | recursively until there's only a single point in the 69 | box.](images/point-cloud-aabb-tree.gif) 70 | 71 | 72 | In contrast, space partitioning schemes (e.g., [kd 73 | trees](https://en.wikipedia.org/wiki/K-d_tree) or 74 | [octrees](https://en.wikipedia.org/wiki/Octree)) divide space _perfectly_ at 75 | each level of the tree, with no overlapping. This makes query code easy to 76 | write, but necessitates splitting of objects that inevitably straddle partition 77 | boundaries. 78 | 79 | > **Question:** Which is better for an unstructured set of points, _space partitioning_ or 80 | > _object partitioning_? 81 | > 82 | > **Hint:** No perfect answer, but consider: do you ever need to split a point? 83 | 84 | ### Bounding primitives 85 | 86 | In this assignment, we will use axis-aligned bounding boxes (AABBs) to enclose 87 | groups of objects (e.g., points, triangles, other bounding boxes). In general, 88 | AABBs will _not_ tightly enclose a set of objects. However, operations (e.g., 89 | growing the bounding box, testing ray-intersection or determining closest-point 90 | distances with an _axis-aligned_ bounding box) usually reduce to trivial 91 | per-component arithmetic. This means the code is simple to write/debug and also 92 | inexpensive to evaluate. 93 | 94 | ![Minimal axis-aligned bounding boxes provide a good trade-off between 95 | tightness, ease of construction and ease of query 96 | evaluation.](images/bounding-primitives.png) 97 | 98 | ### Ray-intersection queries 99 | 100 | See Section 12.3 of _Fundamentals of Computer Graphics (4th Edition)_. 101 | 102 | ### Distance queries 103 | 104 | The recursive algorithm in _Fundamentals of Computer Graphics (4th Edition)_ for 105 | ray-AABBTree-intersection is essentially performing a [depth first 106 | search](https://en.wikipedia.org/wiki/Depth-first_search). The search usually 107 | doesn't have to visit the entire tree because most boxes are not hit by the 108 | given ray. In this way, many search paths are quickly aborted. 109 | 110 | On the other hand, using this style of depth-first search for closest point 111 | queries can be a disaster. Every box has _some_ closest point to our query. A 112 | naive depth-first search could end up searching over every box before finding 113 | the one with the smallest query. 114 | 115 | Are we just talking about worst-case complexity for pathological arrangements 116 | (e.g., a bunch of overlapping triangles piled at the origin)? No. Even on a 117 | well-balanced, minimally overlapping AABB tree we could end up exploring most of 118 | the leaves before finally finding the leaf containing the true closest point at 119 | the very end. 120 | 121 | This implies that we can't just explore the left or right subtrees (or their 122 | progeny) in arbitrary order. A quick fix is to peek at the closet distance to 123 | the boxes containing the left and right trees respectively and prefer our depth 124 | first search in the closest direction. This helps, but we still end up 125 | _drilling_ down to leaves when there are potentially entire large subtrees that 126 | are closer. The problem is that depth first search is inherently 127 | [stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type))-based and we 128 | really want to use a [priority 129 | queue](https://en.wikipedia.org/wiki/Priority_queue) to explore the current best 130 | looking path in our tree wherever it might be. 131 | 132 | > **Question:** Hey! Where's the stack in depth first search? I implemented it 133 | > using recursion, there's no `#include ` in my code! 134 | > 135 | > **[Hint](https://en.wikipedia.org/wiki/Call_stack):** Where are the instructions and data of your program stored? 136 | 137 | [Breadth-first search](https://en.wikipedia.org/wiki/Breadth-first_search) is a 138 | much better structure for distance queries on a spatial acceleration 139 | data-structure. Pseudo-code for a closest distance algorithm might look like: 140 | 141 | ``` 142 | // initialize a queue prioritized by minimum distance 143 | d_r ← distance to root's box 144 | Q.insert(d_r, root) 145 | // initialize minimum distance seen so far 146 | d ← ∞ 147 | while Q not empty 148 | // d_s: distance from query to subtree's bounding box 149 | (d_s, subtree) ← Q.pop 150 | if d_s < d 151 | if subtree is a leaf 152 | d ← min[ d , distance from query to leaf object ] 153 | else 154 | d_l ← distance to left's box 155 | Q.insert(d_l ,subtree.left) 156 | d_r ← distance to right's box 157 | Q.insert(d_r ,subtree.right) 158 | ``` 159 | 160 | > **Question:** If I have just a single query to conduct on a set of 161 | > objects, is it worth it to use a BVH? 162 | > 163 | > **Hint:** What is the complexity of _building_ a BVH? What is the complexity 164 | > of a single brute force query? 165 | 166 | ### Intersection queries between two trees 167 | 168 | Suppose we want to find _all pairs_ of intersecting triangles between two 169 | meshes. One approach would be to put one mesh's triangles in an AABB tree, then 170 | loop over the other mesh's triangles using the tree to accelerate intersection 171 | tests. This works well if the mesh in the tree has many more triangles than the 172 | other mesh, but can we do better if both mesh have many triangles? How about 173 | putting both meshes in a AABB trees. If the root bounding boxes don't overlap we 174 | find out _instantaneously_ that there are no pairs of intersecting triangles. If 175 | they do overlap, we check their childrens' boxes against each other. Anytime two 176 | boxes don't overlap we save many expensive pairwise triangle checks. A rough 177 | sketch of this algorithm using a simple (i.e., non prioritized) queue is like 178 | this: 179 | 180 | ``` 181 | // initialize list of candidate leaf pairs 182 | leaf_pairs ← {} 183 | if root_A.box intersects root_B.box 184 | Q.insert( root_A, root_B ) 185 | while Q not empty 186 | {nodeA,nodeB} ← Q.pop 187 | if nodeA and nodeB are leaves 188 | leaf_pairs.insert( node_A, node_B ) 189 | else if node_A is a leaf 190 | if node_A.box intersects node_B.left.box 191 | Q.insert( node_A, node_B.left ) 192 | if node_A.box intersects node_B.right.box 193 | Q.insert( node_A, node_B.right ) 194 | else if node_B is a leaf 195 | if node_A.left.box intersects node_B.box 196 | Q.insert( node_A.left, node_B) 197 | if node_A.right.box intersects node_B.box 198 | Q.insert( node_A.right, node_B) 199 | else 200 | if node_A.left.box intersects node_B.left.box 201 | Q.insert( node_A.left, node_B.left ) 202 | if node_A.left.box intersects node_B.right.box 203 | Q.insert( node_A.left, node_B.right ) 204 | if node_A.right.box intersects node_B.right.box 205 | Q.insert( node_A.right, node_B.right ) 206 | if node_A.right.box intersects node_B.left.box 207 | Q.insert( node_A.right, node_B.left ) 208 | ``` 209 | 210 | Careful, this sketch only considers a perfectly filled tree where nodes (and 211 | their left/right children) are never null pointers. [Your trees may 212 | vary](https://en.wiktionary.org/wiki/your_mileage_may_vary). 213 | 214 | This _**broad phase**_ identifies a set of overlapping bounding boxes containing 215 | one triangle each. The broad phase is quick because it uses the bounding volume 216 | hierarchy for acceleration and intersection between bounding boxes is a simple 217 | and fast. The list of candidate pairs scales with the number of _actual 218 | intersections_ rather than the number of input triangles (as brute force 219 | double-for loops does). This list can then be processed using the (expensive) 220 | triangle-triangle intersection test in a **_narrow phase_**. 221 | 222 | ![Using an AABB Tree for each shape (light red and light blue triangle meshes), 223 | we identify a set of candidate intersecting bounding boxes (red and blue). 224 | ](images/cheburashka-knight-intersections.gif) 225 | 226 | > **Question:** Suppose we want to detect intersections for a simulation of two 227 | > deforming meshes (e.g., elastic solids bumping into each other). Can we reuse 228 | > our AABB Tree even if the meshes are deforming? What if they're just moving 229 | > rigidly (rotations and translations)? 230 | > 231 | > **Hint:** Is an axis-aligned box still axis-aligned if it's rotated 45°? 232 | 233 | ### Timing 234 | 235 | Never conduct performance evaluations in debug mode. To set up a "release" mode 236 | version of your project use: 237 | 238 | ``` 239 | mkdir build_release 240 | cd build_release 241 | cmake -DCMAKE_BUILD_TYPE=Release .. 242 | make 243 | ``` 244 | 245 | In this assignment, we're aiming to improve the asymptotic complexity for the 246 | [average case](https://en.wikipedia.org/wiki/Average-case_complexity). We will 247 | not formalize the [probability 248 | distribution](https://en.wikipedia.org/wiki/Probability_distribution) of inputs, 249 | but instead consider uniformly random [point 250 | clouds](https://en.wikipedia.org/wiki/Point_cloud) or real-world surface models. 251 | The AABB Tree algorithms should behave like compared to brute 252 | force algorithms. For large inputs the difference should be striking. 253 | 254 | ## Tasks 255 | 256 | ### Whitelist 257 | 258 | You're encouraged to use the following 259 | 260 | - `std::numeric_limits::infinity()` and 261 | `-std::numeric_limits::infinity()` in `#include ` are often 262 | useful for initializing values before calculating a running minimum or 263 | maximum respectively. 264 | - `std::priority_queue` 265 | - `std::list` useful as a simple (non-priority) queue 266 | - `std::pair` often useful to store key-value pairs (e.g., a priority and its 267 | corresponding object) 268 | 269 | #### Shared Pointers 270 | 271 | This assignment uses [smart 272 | pointers](https://en.wikipedia.org/wiki/Smart_pointer). In particular, 273 | [`std::shared_ptr`](https://en.cppreference.com/w/cpp/memory/shared_ptr). For 274 | the most part you can use these like regular "raw" 275 | [pointers](https://en.wikipedia.org/wiki/Pointer_(computer_programming)). But 276 | for initialization use: 277 | 278 | ``` 279 | // Instead of: 280 | // MyClass * A = new MyClass(); 281 | // Use 282 | std::shared_ptr A = std::make_shared(); 283 | ``` 284 | 285 | And omit deletion lines: 286 | 287 | ``` 288 | // No need for: 289 | // delete A; 290 | // Instead, it's destroyed when the last shared_ptr to A is destroyed 291 | ``` 292 | 293 | This assignment also uses 294 | [inheritance](https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)). 295 | For example, `AABBTree` and `MeshTriangle` and `CloudPoint` are all derived from 296 | a common _base case_ called `Object`. 297 | 298 | Using `std::dynamic_pointer_cast<>`, it is possible to _attempt_ to cast a 299 | `std::shared_ptr<>` to a base class instance into a `std::shared_ptr<>` of a 300 | subclass. This casting will only succeed if the underying instance actually is 301 | that subclass. Consider this self-contained example: 302 | 303 | ``` 304 | #include 305 | #include 306 | #include 307 | 308 | struct Object{/*Need a virtual function for polymorphism */virtual ~Object(){}}; 309 | struct AABBTree : public Object{}; 310 | struct CloudPoint : public Object{}; 311 | struct MeshTriangle : public Object{}; 312 | 313 | int main(int argc, char * argv[]) 314 | { 315 | // Make a bunch of different subclasses of Object 316 | std::shared_ptr A = std::make_shared(); 317 | std::shared_ptr B = std::make_shared(); 318 | std::shared_ptr C = std::make_shared(); 319 | // Put them in a list of Objects 320 | std::vector > list_of_objects = {A,B,C}; 321 | // Loop over each Object 322 | for(std::shared_ptr obj : list_of_objects) 323 | { 324 | // Attempt to cast to AABBTree 325 | std::shared_ptr aabb = std::dynamic_pointer_cast(obj); 326 | // Test whether cast succeed 327 | if(aabb) 328 | { 329 | // Hooray. We can do AABBTree-specific operations on `aabb` now. 330 | std::cout<<"This object is an AABBTree."< faces and record the closest hit. Use 369 | a brute force loop over all triangles, aim for complexity but focus on 370 | correctness. This will be your reference solution. 371 | 372 | ### `src/ray_intersect_box.cpp` 373 | Intersect a ray with a **_solid_** box (careful: if the ray or `min_t` lands 374 | _inside_ the box this could still hit something stored inside the box, so this 375 | counts as a hit). 376 | 377 | ### `src/insert_box_into_box.cpp` 378 | Grow a box `B` by inserting a box `A`. 379 | 380 | ### `src/insert_triangle_into_box.cpp` 381 | Grow a box `B` by inserting a triangle with corners `a`, `b`, and `c`. 382 | 383 | 384 | ### `AABBTree::AABBTree` in `src/AABBTree.cpp` 385 | 386 | Construct an axis-aligned bounding box tree given a list of objects. Use the 387 | midpoint along the longest axis of the box containing the given objects to 388 | determine the left-right split. 389 | 390 | ### `AABBTree::ray_intersect` in `src/AABBTree_ray_intersect.cpp` 391 | 392 | Determine whether and how a ray intersects the contents of an AABB tree. The 393 | method should perform in time for a tree containing 394 | (reasonably distributed) objects. 395 | 396 | If you run `./rays ../data/rubber-ducky.obj` you should see something like: 397 | 398 | ``` 399 | # Ray Triangle Mesh Intersection 400 | |V| 334 401 | |F| 668 402 | 403 | Firing 100 rays... 404 | 405 | | Method | Time in seconds | 406 | |:------------|----------------:| 407 | | brute force | 0.00158905983 | 408 | | build tree | 0.00064301491 | 409 | | use tree | 0.00004386902 | 410 | ``` 411 | 412 | If your method is incorrect, you will see some lines like this: 413 | 414 | ``` 415 | ... 416 | Error: #bf_hit(38) (1) != #tree_hit(38) (0) 417 | ... 418 | ``` 419 | 420 | This example line means that your brute force algorithm thinks ray 38 hits your 421 | object but your tree algorithm is not finding it. 422 | 423 | ### `src/nearest_neighbor_brute_force.cpp` 424 | 425 | Compute the nearest neighbor for a query in the set of points (rows of 426 | `points`). This should be a **_slow reference implementation_**. Aim for a 427 | computational complexity of but focus on correctness. 428 | 429 | ### `src/point_box_squared_distance.cpp` 430 | 431 | Compute the squared distance between a query point and a box 432 | 433 | ### `src/point_AABBTree_squared_distance.cpp` 434 | 435 | Compute the distrance from a query point to the objects stored in a AABBTree 436 | using a priority queue. _**Note:** this function is **not** meant to be called 437 | recursively._ 438 | 439 | Running `./distances 100000 10000` you should also see something like this: 440 | 441 | ``` 442 | # Point Cloud Distance Queries 443 | |points|: 100000 444 | |querires|: 10000 445 | 446 | | Method | Time in seconds | 447 | |:------------|----------------:| 448 | | brute force | 1.50723695755 | 449 | | build tree | 0.14633584023 | 450 | | use tree | 0.05846095085 | 451 | ``` 452 | 453 | ----------------------------- 454 | 455 | 456 | ### `src/triangle_triangle_intersection.cpp` 457 | 458 | Determine whether two triangles intersect. 459 | 460 | ### `src/box_box_intersect.cpp` 461 | 462 | Determine if two bounding boxes intersect 463 | 464 | ### `src/find_all_intersecting_pairs_using_AABBTrees.cpp` 465 | 466 | Find all intersecting pairs of _leaf boxes_ between one AABB tree and another 467 | 468 | Running `./intersections ../data/knight.obj ../data/cheburashka.obj` will also produce something like this: 469 | 470 | ``` 471 | # Triangle Mesh Intersection Detection 472 | |VA| 2002 473 | |FA| 4000 474 | 475 | |VB| 6669 476 | |FB| 13334 477 | 478 | | Method | Time in seconds | 479 | |:------------|----------------:| 480 | | brute force | 1.55577802658 | 481 | | build trees | 0.01804995537 | 482 | | use trees | 0.00816702843 | 483 | ``` 484 | 485 | If your method is incorrect, you will see some lines like this: 486 | 487 | ``` 488 | ... 489 | Error: Intersecting pairs found using tree but not brute force: 490 | 7,722 491 | ... 492 | ``` 493 | 494 | This indicates that your tree is finding _more_ intersecting triangles than your 495 | brute force method. In particular, the tree thinks the -th triangle of mesh A 496 | is intersecting the -th triangle of mesh B. 497 | -------------------------------------------------------------------------------- /README.tex.md: -------------------------------------------------------------------------------- 1 | # Computer Graphics – Bounding Volume Hierarchy 2 | 3 | > **To get started:** Clone this repository and all its [submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) dependencies using: 4 | > 5 | > git clone --recursive https://github.com/alecjacobson/computer-graphics-bounding-volume-hierarchy.git 6 | > 7 | > **Do not fork:** Clicking "Fork" will create a _public_ repository. If you'd like to use GitHub while you work on your assignment, then mirror this repo as a new _private_ repository: https://stackoverflow.com/questions/10065526/github-how-to-make-a-fork-of-public-repository-private 8 | 9 | > **Note for Linux users:** if you're using Ubuntu, make sure you've installed the following packages if 10 | > you haven't done so already: 11 | > 12 | > sudo apt-get install git 13 | > sudo apt-get install build-essential 14 | > sudo apt-get install cmake 15 | > sudo apt-get install libx11-dev 16 | > sudo apt-get install mesa-common-dev libgl1-mesa-dev libglu1-mesa-dev 17 | > sudo apt-get install libxinerama1 libxinerama-dev 18 | > sudo apt-get install libxcursor-dev 19 | > sudo apt-get install libxrandr-dev 20 | > sudo apt-get install libxi-dev 21 | > sudo apt-get install libxmu-dev 22 | > sudo apt-get install libblas-dev 23 | 24 | 25 | ## Background 26 | 27 | ### Read Section 12.3 of _Fundamentals of Computer Graphics (4th Edition)_. 28 | 29 | ![Visualize of all of the boxes of a hierarchical axis-aligned bounding-box tree 30 | around the triangles of a [rubber 31 | ducky](https://en.wikipedia.org/wiki/Rubber_duck) 32 | mesh.](images/rubber-ducky-aabb-tree.png) 33 | 34 | ### Object partitioning 35 | 36 | In this assignment, you will build an Axis-Aligned Bounding-Box 37 | [Tree](https://en.wikipedia.org/wiki/Tree_structure) (AABB Tree). This is one of the simplest 38 | instances of an _object partitioning_ scheme, where a group of input objects are 39 | arranged into a [bounding volume 40 | hierarchy](https://en.wikipedia.org/wiki/Bounding_volume_hierarchy). 41 | 42 | ![In the "scene" on the left, there are six objects. All objects fit into the 43 | axis-aligned bounding box **A** (the root of the tree), then we cluster nearby 44 | objects into subtrees rooted at **B** and **C**. We continue to apply this 45 | process recursively until leaves of the tree store a single object. Tree shown 46 | on right. ([image 47 | source](https://commons.wikimedia.org/wiki/File:Example_of_bounding_volume_hierarchy.svg))](images/Example_of_bounding_volume_hierarchy.png) 48 | 49 | In our assignment, we will build a binary tree. Conducting queries on the tree 50 | will be reminiscent of searching for values in a [binary search 51 | tree](https://en.wikipedia.org/wiki/Binary_search_tree). However, objects in our 52 | tree will not be _perfectly_ sorted. In general, the bounding boxes of 53 | "relatives" (even siblings) in our tree will overlap spatially. 54 | 55 | ![In most cases, bounding boxes will overlap. The tree topology remains the same 56 | in this case. ([original image 57 | source](https://commons.wikimedia.org/wiki/File:Example_of_bounding_volume_hierarchy.svg))](images/more-realistic-bvh-example.png) 58 | 59 | 60 | By allowing bounding boxes to overlap we avoid the need to geometric split our 61 | objects. 62 | 63 | > **Question:** If we use overlapping bounding boxes (i.e., no splitting) to 64 | > build an AABB Tree , how many leaves will there be? 65 | 66 | ![The AABB Tree around a point cloud starts with a single box. The next level 67 | has two boxes, roughly splitting the first box. This process continues 68 | recursively until there's only a single point in the 69 | box.](images/point-cloud-aabb-tree.gif) 70 | 71 | 72 | In contrast, space partitioning schemes (e.g., [kd 73 | trees](https://en.wikipedia.org/wiki/K-d_tree) or 74 | [octrees](https://en.wikipedia.org/wiki/Octree)) divide space _perfectly_ at 75 | each level of the tree, with no overlapping. This makes query code easy to 76 | write, but necessitates splitting of objects that inevitably straddle partition 77 | boundaries. 78 | 79 | > **Question:** Which is better for an unstructured set of points, _space partitioning_ or 80 | > _object partitioning_? 81 | > 82 | > **Hint:** No perfect answer, but consider: do you ever need to split a point? 83 | 84 | ### Bounding primitives 85 | 86 | In this assignment, we will use axis-aligned bounding boxes (AABBs) to enclose 87 | groups of objects (e.g., points, triangles, other bounding boxes). In general, 88 | AABBs will _not_ tightly enclose a set of objects. However, operations (e.g., 89 | growing the bounding box, testing ray-intersection or determining closest-point 90 | distances with an _axis-aligned_ bounding box) usually reduce to trivial 91 | per-component arithmetic. This means the code is simple to write/debug and also 92 | inexpensive to evaluate. 93 | 94 | ![Minimal axis-aligned bounding boxes provide a good trade-off between 95 | tightness, ease of construction and ease of query 96 | evaluation.](images/bounding-primitives.png) 97 | 98 | ### Ray-intersection queries 99 | 100 | See Section 12.3 of _Fundamentals of Computer Graphics (4th Edition)_. 101 | 102 | ### Distance queries 103 | 104 | The recursive algorithm in _Fundamentals of Computer Graphics (4th Edition)_ for 105 | ray-AABBTree-intersection is essentially performing a [depth first 106 | search](https://en.wikipedia.org/wiki/Depth-first_search). The search usually 107 | doesn't have to visit the entire tree because most boxes are not hit by the 108 | given ray. In this way, many search paths are quickly aborted. 109 | 110 | On the other hand, using this style of depth-first search for closest point 111 | queries can be a disaster. Every box has _some_ closest point to our query. A 112 | naive depth-first search could end up searching over every box before finding 113 | the one with the smallest query. 114 | 115 | Are we just talking about worst-case complexity for pathological arrangements 116 | (e.g., a bunch of overlapping triangles piled at the origin)? No. Even on a 117 | well-balanced, minimally overlapping AABB tree we could end up exploring most of 118 | the leaves before finally finding the leaf containing the true closest point at 119 | the very end. 120 | 121 | This implies that we can't just explore the left or right subtrees (or their 122 | progeny) in arbitrary order. A quick fix is to peek at the closet distance to 123 | the boxes containing the left and right trees respectively and prefer our depth 124 | first search in the closest direction. This helps, but we still end up 125 | _drilling_ down to leaves when there are potentially entire large subtrees that 126 | are closer. The problem is that depth first search is inherently 127 | [stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type))-based and we 128 | really want to use a [priority 129 | queue](https://en.wikipedia.org/wiki/Priority_queue) to explore the current best 130 | looking path in our tree wherever it might be. 131 | 132 | > **Question:** Hey! Where's the stack in depth first search? I implemented it 133 | > using recursion, there's no `#include ` in my code! 134 | > 135 | > **[Hint](https://en.wikipedia.org/wiki/Call_stack):** Where are the instructions and data of your program stored? 136 | 137 | [Breadth-first search](https://en.wikipedia.org/wiki/Breadth-first_search) is a 138 | much better structure for distance queries on a spatial acceleration 139 | data-structure. Pseudo-code for a closest distance algorithm might look like: 140 | 141 | ``` 142 | // initialize a queue prioritized by minimum distance 143 | d_r ← distance to root's box 144 | Q.insert(d_r, root) 145 | // initialize minimum distance seen so far 146 | d ← ∞ 147 | while Q not empty 148 | // d_s: distance from query to subtree's bounding box 149 | (d_s, subtree) ← Q.pop 150 | if d_s < d 151 | if subtree is a leaf 152 | d ← min[ d , distance from query to leaf object ] 153 | else 154 | d_l ← distance to left's box 155 | Q.insert(d_l ,subtree.left) 156 | d_r ← distance to right's box 157 | Q.insert(d_r ,subtree.right) 158 | ``` 159 | 160 | > **Question:** If I have just a single query to conduct on a set of $n$ 161 | > objects, is it worth it to use a BVH? 162 | > 163 | > **Hint:** What is the complexity of _building_ a BVH? What is the complexity 164 | > of a single brute force query? 165 | 166 | ### Intersection queries between two trees 167 | 168 | Suppose we want to find _all pairs_ of intersecting triangles between two 169 | meshes. One approach would be to put one mesh's triangles in an AABB tree, then 170 | loop over the other mesh's triangles using the tree to accelerate intersection 171 | tests. This works well if the mesh in the tree has many more triangles than the 172 | other mesh, but can we do better if both mesh have many triangles? How about 173 | putting both meshes in a AABB trees. If the root bounding boxes don't overlap we 174 | find out _instantaneously_ that there are no pairs of intersecting triangles. If 175 | they do overlap, we check their childrens' boxes against each other. Anytime two 176 | boxes don't overlap we save many expensive pairwise triangle checks. A rough 177 | sketch of this algorithm using a simple (i.e., non prioritized) queue is like 178 | this: 179 | 180 | ``` 181 | // initialize list of candidate leaf pairs 182 | leaf_pairs ← {} 183 | if root_A.box intersects root_B.box 184 | Q.insert( root_A, root_B ) 185 | while Q not empty 186 | {nodeA,nodeB} ← Q.pop 187 | if nodeA and nodeB are leaves 188 | leaf_pairs.insert( node_A, node_B ) 189 | else if node_A is a leaf 190 | if node_A.box intersects node_B.left.box 191 | Q.insert( node_A, node_B.left ) 192 | if node_A.box intersects node_B.right.box 193 | Q.insert( node_A, node_B.right ) 194 | else if node_B is a leaf 195 | if node_A.left.box intersects node_B.box 196 | Q.insert( node_A.left, node_B) 197 | if node_A.right.box intersects node_B.box 198 | Q.insert( node_A.right, node_B) 199 | else 200 | if node_A.left.box intersects node_B.left.box 201 | Q.insert( node_A.left, node_B.left ) 202 | if node_A.left.box intersects node_B.right.box 203 | Q.insert( node_A.left, node_B.right ) 204 | if node_A.right.box intersects node_B.right.box 205 | Q.insert( node_A.right, node_B.right ) 206 | if node_A.right.box intersects node_B.left.box 207 | Q.insert( node_A.right, node_B.left ) 208 | ``` 209 | 210 | Careful, this sketch only considers a perfectly filled tree where nodes (and 211 | their left/right children) are never null pointers. [Your trees may 212 | vary](https://en.wiktionary.org/wiki/your_mileage_may_vary). 213 | 214 | This _**broad phase**_ identifies a set of overlapping bounding boxes containing 215 | one triangle each. The broad phase is quick because it uses the bounding volume 216 | hierarchy for acceleration and intersection between bounding boxes is a simple 217 | and fast. The list of candidate pairs scales with the number of _actual 218 | intersections_ rather than the number of input triangles (as brute force 219 | double-for loops does). This list can then be processed using the (expensive) 220 | triangle-triangle intersection test in a **_narrow phase_**. 221 | 222 | ![Using an AABB Tree for each shape (light red and light blue triangle meshes), 223 | we identify a set of candidate intersecting bounding boxes (red and blue). 224 | ](images/cheburashka-knight-intersections.gif) 225 | 226 | > **Question:** Suppose we want to detect intersections for a simulation of two 227 | > deforming meshes (e.g., elastic solids bumping into each other). Can we reuse 228 | > our AABB Tree even if the meshes are deforming? What if they're just moving 229 | > rigidly (rotations and translations)? 230 | > 231 | > **Hint:** Is an axis-aligned box still axis-aligned if it's rotated 45°? 232 | 233 | ### Timing 234 | 235 | Never conduct performance evaluations in debug mode. To set up a "release" mode 236 | version of your project use: 237 | 238 | ``` 239 | mkdir build_release 240 | cd build_release 241 | cmake -DCMAKE_BUILD_TYPE=Release .. 242 | make 243 | ``` 244 | 245 | In this assignment, we're aiming to improve the asymptotic complexity for the 246 | [average case](https://en.wikipedia.org/wiki/Average-case_complexity). We will 247 | not formalize the [probability 248 | distribution](https://en.wikipedia.org/wiki/Probability_distribution) of inputs, 249 | but instead consider uniformly random [point 250 | clouds](https://en.wikipedia.org/wiki/Point_cloud) or real-world surface models. 251 | The AABB Tree algorithms should behave like $O(\log{n})$ compared to brute 252 | force $O(n)$ algorithms. For large inputs the difference should be striking. 253 | 254 | ## Tasks 255 | 256 | ### Whitelist 257 | 258 | You're encouraged to use the following 259 | 260 | - `std::numeric_limits::infinity()` and 261 | `-std::numeric_limits::infinity()` in `#include ` are often 262 | useful for initializing values before calculating a running minimum or 263 | maximum respectively. 264 | - `std::priority_queue` 265 | - `std::list` useful as a simple (non-priority) queue 266 | - `std::pair` often useful to store key-value pairs (e.g., a priority and its 267 | corresponding object) 268 | 269 | #### Shared Pointers 270 | 271 | This assignment uses [smart 272 | pointers](https://en.wikipedia.org/wiki/Smart_pointer). In particular, 273 | [`std::shared_ptr`](https://en.cppreference.com/w/cpp/memory/shared_ptr). For 274 | the most part you can use these like regular "raw" 275 | [pointers](https://en.wikipedia.org/wiki/Pointer_(computer_programming)). But 276 | for initialization use: 277 | 278 | ``` 279 | // Instead of: 280 | // MyClass * A = new MyClass(); 281 | // Use 282 | std::shared_ptr A = std::make_shared(); 283 | ``` 284 | 285 | And omit deletion lines: 286 | 287 | ``` 288 | // No need for: 289 | // delete A; 290 | // Instead, it's destroyed when the last shared_ptr to A is destroyed 291 | ``` 292 | 293 | This assignment also uses 294 | [inheritance](https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)). 295 | For example, `AABBTree` and `MeshTriangle` and `CloudPoint` are all derived from 296 | a common _base case_ called `Object`. 297 | 298 | Using `std::dynamic_pointer_cast<>`, it is possible to _attempt_ to cast a 299 | `std::shared_ptr<>` to a base class instance into a `std::shared_ptr<>` of a 300 | subclass. This casting will only succeed if the underying instance actually is 301 | that subclass. Consider this self-contained example: 302 | 303 | ``` 304 | #include 305 | #include 306 | #include 307 | 308 | struct Object{/*Need a virtual function for polymorphism */virtual ~Object(){}}; 309 | struct AABBTree : public Object{}; 310 | struct CloudPoint : public Object{}; 311 | struct MeshTriangle : public Object{}; 312 | 313 | int main(int argc, char * argv[]) 314 | { 315 | // Make a bunch of different subclasses of Object 316 | std::shared_ptr A = std::make_shared(); 317 | std::shared_ptr B = std::make_shared(); 318 | std::shared_ptr C = std::make_shared(); 319 | // Put them in a list of Objects 320 | std::vector > list_of_objects = {A,B,C}; 321 | // Loop over each Object 322 | for(std::shared_ptr obj : list_of_objects) 323 | { 324 | // Attempt to cast to AABBTree 325 | std::shared_ptr aabb = std::dynamic_pointer_cast(obj); 326 | // Test whether cast succeed 327 | if(aabb) 328 | { 329 | // Hooray. We can do AABBTree-specific operations on `aabb` now. 330 | std::cout<<"This object is an AABBTree."<*:first-child { 381 | margin-top: 0 !important; 382 | } 383 | 384 | .markdown-body>*:last-child { 385 | margin-bottom: 0 !important; 386 | } 387 | 388 | .markdown-body a:not([href]) { 389 | color: inherit; 390 | text-decoration: none; 391 | } 392 | 393 | .markdown-body .anchor { 394 | float: left; 395 | padding-right: 4px; 396 | margin-left: -20px; 397 | line-height: 1; 398 | } 399 | 400 | .markdown-body .anchor:focus { 401 | outline: none; 402 | } 403 | 404 | .markdown-body p, 405 | .markdown-body blockquote, 406 | .markdown-body ul, 407 | .markdown-body ol, 408 | .markdown-body dl, 409 | .markdown-body table, 410 | .markdown-body pre { 411 | margin-top: 0; 412 | margin-bottom: 16px; 413 | } 414 | 415 | .markdown-body hr { 416 | height: 0.25em; 417 | padding: 0; 418 | margin: 24px 0; 419 | background-color: #e1e4e8; 420 | border: 0; 421 | } 422 | 423 | .markdown-body blockquote { 424 | padding: 0 1em; 425 | color: #6a737d; 426 | border-left: 0.25em solid #dfe2e5; 427 | } 428 | 429 | .markdown-body blockquote>:first-child { 430 | margin-top: 0; 431 | } 432 | 433 | .markdown-body blockquote>:last-child { 434 | margin-bottom: 0; 435 | } 436 | 437 | .markdown-body kbd { 438 | display: inline-block; 439 | padding: 3px 5px; 440 | font-size: 11px; 441 | line-height: 10px; 442 | color: #444d56; 443 | vertical-align: middle; 444 | background-color: #fafbfc; 445 | border: solid 1px #c6cbd1; 446 | border-bottom-color: #959da5; 447 | border-radius: 3px; 448 | box-shadow: inset 0 -1px 0 #959da5; 449 | } 450 | 451 | .markdown-body h1, 452 | .markdown-body h2, 453 | .markdown-body h3, 454 | .markdown-body h4, 455 | .markdown-body h5, 456 | .markdown-body h6 { 457 | margin-top: 24px; 458 | margin-bottom: 16px; 459 | font-weight: 600; 460 | line-height: 1.25; 461 | } 462 | 463 | .markdown-body h1 .octicon-link, 464 | .markdown-body h2 .octicon-link, 465 | .markdown-body h3 .octicon-link, 466 | .markdown-body h4 .octicon-link, 467 | .markdown-body h5 .octicon-link, 468 | .markdown-body h6 .octicon-link { 469 | color: #1b1f23; 470 | vertical-align: middle; 471 | visibility: hidden; 472 | } 473 | 474 | .markdown-body h1:hover .anchor, 475 | .markdown-body h2:hover .anchor, 476 | .markdown-body h3:hover .anchor, 477 | .markdown-body h4:hover .anchor, 478 | .markdown-body h5:hover .anchor, 479 | .markdown-body h6:hover .anchor { 480 | text-decoration: none; 481 | } 482 | 483 | .markdown-body h1:hover .anchor .octicon-link, 484 | .markdown-body h2:hover .anchor .octicon-link, 485 | .markdown-body h3:hover .anchor .octicon-link, 486 | .markdown-body h4:hover .anchor .octicon-link, 487 | .markdown-body h5:hover .anchor .octicon-link, 488 | .markdown-body h6:hover .anchor .octicon-link { 489 | visibility: visible; 490 | } 491 | 492 | .markdown-body h1 { 493 | padding-bottom: 0.3em; 494 | font-size: 2em; 495 | border-bottom: 1px solid #eaecef; 496 | } 497 | 498 | .markdown-body h2 { 499 | padding-bottom: 0.3em; 500 | font-size: 1.5em; 501 | border-bottom: 1px solid #eaecef; 502 | } 503 | 504 | .markdown-body h3 { 505 | font-size: 1.25em; 506 | } 507 | 508 | .markdown-body h4 { 509 | font-size: 1em; 510 | } 511 | 512 | .markdown-body h5 { 513 | font-size: 0.875em; 514 | } 515 | 516 | .markdown-body h6 { 517 | font-size: 0.85em; 518 | color: #6a737d; 519 | } 520 | 521 | .markdown-body ul, 522 | .markdown-body ol { 523 | padding-left: 2em; 524 | } 525 | 526 | .markdown-body ul ul, 527 | .markdown-body ul ol, 528 | .markdown-body ol ol, 529 | .markdown-body ol ul { 530 | margin-top: 0; 531 | margin-bottom: 0; 532 | } 533 | 534 | .markdown-body li { 535 | word-wrap: break-all; 536 | } 537 | 538 | .markdown-body li>p { 539 | margin-top: 16px; 540 | } 541 | 542 | .markdown-body li+li { 543 | margin-top: 0.25em; 544 | } 545 | 546 | .markdown-body dl { 547 | padding: 0; 548 | } 549 | 550 | .markdown-body dl dt { 551 | padding: 0; 552 | margin-top: 16px; 553 | font-size: 1em; 554 | font-style: italic; 555 | font-weight: 600; 556 | } 557 | 558 | .markdown-body dl dd { 559 | padding: 0 16px; 560 | margin-bottom: 16px; 561 | } 562 | 563 | .markdown-body table { 564 | display: block; 565 | width: 100%; 566 | overflow: auto; 567 | } 568 | 569 | .markdown-body table th { 570 | font-weight: 600; 571 | } 572 | 573 | .markdown-body table th, 574 | .markdown-body table td { 575 | padding: 6px 13px; 576 | border: 1px solid #dfe2e5; 577 | } 578 | 579 | .markdown-body table tr { 580 | background-color: #fff; 581 | border-top: 1px solid #c6cbd1; 582 | } 583 | 584 | .markdown-body table tr:nth-child(2n) { 585 | background-color: #f6f8fa; 586 | } 587 | 588 | .markdown-body img { 589 | max-width: 100%; 590 | box-sizing: content-box; 591 | background-color: #fff; 592 | } 593 | 594 | .markdown-body img[align=right] { 595 | padding-left: 20px; 596 | } 597 | 598 | .markdown-body img[align=left] { 599 | padding-right: 20px; 600 | } 601 | 602 | .markdown-body code { 603 | padding: 0.2em 0.4em; 604 | margin: 0; 605 | font-size: 85%; 606 | background-color: rgba(27,31,35,0.05); 607 | border-radius: 3px; 608 | } 609 | 610 | .markdown-body pre { 611 | word-wrap: normal; 612 | } 613 | 614 | .markdown-body pre>code { 615 | padding: 0; 616 | margin: 0; 617 | font-size: 100%; 618 | word-break: normal; 619 | white-space: pre; 620 | background: transparent; 621 | border: 0; 622 | } 623 | 624 | .markdown-body .highlight { 625 | margin-bottom: 16px; 626 | } 627 | 628 | .markdown-body .highlight pre { 629 | margin-bottom: 0; 630 | word-break: normal; 631 | } 632 | 633 | .markdown-body .highlight pre, 634 | .markdown-body pre { 635 | padding: 16px; 636 | overflow: auto; 637 | font-size: 85%; 638 | line-height: 1.45; 639 | background-color: #f6f8fa; 640 | border-radius: 3px; 641 | } 642 | 643 | .markdown-body pre code { 644 | display: inline; 645 | max-width: auto; 646 | padding: 0; 647 | margin: 0; 648 | overflow: visible; 649 | line-height: inherit; 650 | word-wrap: normal; 651 | background-color: transparent; 652 | border: 0; 653 | } 654 | 655 | .markdown-body .full-commit .btn-outline:not(:disabled):hover { 656 | color: #005cc5; 657 | border-color: #005cc5; 658 | } 659 | 660 | .markdown-body kbd { 661 | display: inline-block; 662 | padding: 3px 5px; 663 | font: 11px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; 664 | line-height: 10px; 665 | color: #444d56; 666 | vertical-align: middle; 667 | background-color: #fafbfc; 668 | border: solid 1px #d1d5da; 669 | border-bottom-color: #c6cbd1; 670 | border-radius: 3px; 671 | box-shadow: inset 0 -1px 0 #c6cbd1; 672 | } 673 | 674 | .markdown-body :checked+.radio-label { 675 | position: relative; 676 | z-index: 1; 677 | border-color: #0366d6; 678 | } 679 | 680 | .markdown-body .task-list-item { 681 | list-style-type: none; 682 | } 683 | 684 | .markdown-body .task-list-item+.task-list-item { 685 | margin-top: 3px; 686 | } 687 | 688 | .markdown-body .task-list-item input { 689 | margin: 0 0.2em 0.25em -1.6em; 690 | vertical-align: middle; 691 | } 692 | 693 | .markdown-body hr { 694 | border-bottom-color: #eee; 695 | } 696 | -------------------------------------------------------------------------------- /data/torus.obj: -------------------------------------------------------------------------------- 1 | # This file uses centimeters as units for non-parametric coordinates. 2 | 3 | v -2.000000 0.000000 0.000000 4 | v -3.000000 0.000000 -1.000000 5 | v -4.000000 0.000000 -0.000001 6 | v -3.000000 0.000000 1.000000 7 | v -1.000000 -1.732050 0.000000 8 | v -1.500000 -2.598080 -1.000000 9 | v -2.000000 -3.464100 -0.000001 10 | v -1.500000 -2.598080 1.000000 11 | v 1.000000 -1.732050 0.000000 12 | v 1.500000 -2.598080 -1.000000 13 | v 2.000000 -3.464100 -0.000001 14 | v 1.500000 -2.598080 1.000000 15 | v 2.000000 0.000000 0.000000 16 | v 3.000000 0.000000 -1.000000 17 | v 4.000000 0.000000 -0.000001 18 | v 3.000000 0.000000 1.000000 19 | v 1.000000 1.732050 0.000000 20 | v 1.500000 2.598080 -1.000000 21 | v 2.000000 3.464100 -0.000001 22 | v 1.500000 2.598080 1.000000 23 | v -1.000000 1.732050 0.000000 24 | v -1.500000 2.598080 -1.000000 25 | v -2.000000 3.464100 -0.000001 26 | v -1.500000 2.598080 1.000000 27 | f 6 2 1 5 28 | f 7 3 2 6 29 | f 8 4 3 7 30 | f 5 1 4 8 31 | f 10 6 5 9 32 | f 11 7 6 10 33 | f 12 8 7 11 34 | f 9 5 8 12 35 | f 14 10 9 13 36 | f 15 11 10 14 37 | f 16 12 11 15 38 | f 13 9 12 16 39 | f 18 14 13 17 40 | f 19 15 14 18 41 | f 20 16 15 19 42 | f 17 13 16 20 43 | f 22 18 17 21 44 | f 23 19 18 22 45 | f 24 20 19 23 46 | f 21 17 20 24 47 | f 2 22 21 1 48 | f 3 23 22 2 49 | f 4 24 23 3 50 | f 1 21 24 4 51 | -------------------------------------------------------------------------------- /distances.cpp: -------------------------------------------------------------------------------- 1 | #include "nearest_neighbor_brute_force.h" 2 | #include "point_AABBTree_squared_distance.h" 3 | #include "CloudPoint.h" 4 | #include "Object.h" 5 | #include "AABBTree.h" 6 | #include "warnings.h" 7 | #include "VectorXb.h" 8 | #include "tictoc.h" 9 | #include "visualize_aabbtree.h" 10 | #include 11 | #include 12 | #include 13 | #include // std::stoi 14 | #include // std::setw 15 | #include // std::shared_ptr 16 | 17 | int main(int argc, char * argv[]) 18 | { 19 | ///////////////////////////////////////////////////////////////////////////// 20 | // POINT CLOUD DISTANCE QUERY 21 | ///////////////////////////////////////////////////////////////////////////// 22 | std::cout<<"# Point Cloud Distance Queries"<1?std::stoi(argv[1]):100000,3); 26 | Eigen::MatrixXd queries = 27 | Eigen::MatrixXd::Random(argc>2?std::stoi(argv[2]):10000,3); 28 | 29 | std::cout<<" |points|: "<< points.rows()< > point_indices; 47 | // Put a reference to each point in a boxable object 48 | point_indices.reserve(points.rows()); 49 | for(int i = 0;i(points,i)); 52 | } 53 | // Build tree 54 | std::shared_ptr root = std::make_shared(point_indices); 55 | std::cout<<" | build tree | " << FLOAT15 << toc() << " |"< closest_object; 65 | const double inf = std::numeric_limits::infinity(); 66 | point_AABBTree_squared_distance( 67 | query,root,0,inf,tree_sqrD(i),closest_object); 68 | if(closest_object) 69 | { 70 | tree_I(i) = std::static_pointer_cast(closest_object)->i; 71 | }else 72 | { 73 | tree_I(i) = -1; 74 | } 75 | } 76 | std::cout<<" | use tree | " << FLOAT15 << toc() << " |"< 2 | 3 | 4 | 18 | 20 | 27 | 34 | 35 | 57 | 64 | 65 | 67 | 68 | 70 | image/svg+xml 71 | 73 | 74 | 75 | 76 | 77 | 82 | 92 | 105 | 112 | 118 | 124 | 130 | 136 | 142 | 148 | 149 | 167 | 185 | 203 | 210 | 217 | 224 | 231 | 238 | A 250 | B 262 | C 274 | A 286 | B 298 | C 310 | 315 | 320 | 325 | 330 | 335 | 340 | 347 | 354 | 361 | 368 | 375 | 381 | 387 | 393 | 399 | 412 | 422 | 440 | 447 | 453 | 459 | 465 | 471 | 477 | 483 | 484 | 502 | 520 | 521 | 522 | -------------------------------------------------------------------------------- /images/bounding-primitives.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-bounding-volume-hierarchy/b5e801ea101fcba5a068cd564a905c11e6bc7635/images/bounding-primitives.png -------------------------------------------------------------------------------- /images/cheburashka-knight-intersections.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-bounding-volume-hierarchy/b5e801ea101fcba5a068cd564a905c11e6bc7635/images/cheburashka-knight-intersections.gif -------------------------------------------------------------------------------- /images/more-realistic-bvh-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-bounding-volume-hierarchy/b5e801ea101fcba5a068cd564a905c11e6bc7635/images/more-realistic-bvh-example.png -------------------------------------------------------------------------------- /images/more-realistic-bvh-example.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 49 | 50 | 52 | 53 | 54 | 55 | 56 | 57 | A 58 | B 59 | C 60 | A 61 | B 62 | C 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 83 | 84 | 86 | 87 | 89 | 90 | 91 | 93 | 95 | 97 | 99 | 101 | 103 | 104 | 105 | 109 | 110 | 112 | 113 | 117 | 118 | 120 | 121 | 123 | 124 | 125 | 127 | 129 | 131 | 133 | 135 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /images/point-cloud-aabb-tree.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-bounding-volume-hierarchy/b5e801ea101fcba5a068cd564a905c11e6bc7635/images/point-cloud-aabb-tree.gif -------------------------------------------------------------------------------- /images/rubber-ducky-aabb-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-bounding-volume-hierarchy/b5e801ea101fcba5a068cd564a905c11e6bc7635/images/rubber-ducky-aabb-tree.png -------------------------------------------------------------------------------- /include/AABBTree.h: -------------------------------------------------------------------------------- 1 | #ifndef AABBTREE_H 2 | #define AABBTREE_H 3 | 4 | #include "BoundingBox.h" 5 | #include "Object.h" 6 | #include 7 | #include 8 | #include 9 | 10 | // Implementation 11 | #include "ray_intersect_box.h" 12 | #include "point_box_squared_distance.h" 13 | 14 | struct AABBTree : public Object, public std::enable_shared_from_this 15 | { 16 | // Pointers to left and right subtree branches. These could be another 17 | // AABBTree (internal node) or a leaf (primitive Object like MeshTriangle, or 18 | // CloudPoint) 19 | std::shared_ptr left; 20 | std::shared_ptr right; 21 | // For debugging, keep track of the depth (root has depth == 0) 22 | int depth; 23 | // For debugging, keep track of the number leaf, descendants 24 | int num_leaves; 25 | // Construct a axis-aligned bounding box tree given a list of objects. Use the 26 | // midpoint along the longest axis of the box containing the given objects to 27 | // determine the left-right split. 28 | // 29 | // Inputs: 30 | // objects list of objects to store in this AABBTree 31 | // Optional inputs: 32 | // depth depth of this tree (usually set by constructor of parent as 33 | // their depth+1) 34 | // Side effects: num_leaves is set to objects.size() and left/right pointers 35 | // set to subtrees or leaf Objects accordingly. 36 | AABBTree( 37 | const std::vector > & objects, 38 | int depth=0); 39 | // Object implementations (see Object.h for API) 40 | bool ray_intersect( 41 | const Ray& ray, 42 | const double min_t, 43 | const double max_t, 44 | double & t, 45 | std::shared_ptr & descendant) const override; 46 | bool point_squared_distance( 47 | const Eigen::RowVector3d & query, 48 | const double min_sqrd, 49 | const double max_sqrd, 50 | double & sqrd, 51 | std::shared_ptr & descendant) const override 52 | { 53 | assert(false && "Do not use recursive DFS for AABBTree distance"); 54 | return false; 55 | } 56 | }; 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /include/BoundingBox.h: -------------------------------------------------------------------------------- 1 | #ifndef BOUNDING_BOX_H 2 | #define BOUNDING_BOX_H 3 | #include 4 | 5 | // Should change this name to AABB or AlignedBox 6 | struct BoundingBox 7 | { 8 | Eigen::RowVector3d min_corner; 9 | Eigen::RowVector3d max_corner; 10 | BoundingBox( 11 | Eigen::RowVector3d a_min_corner = 12 | Eigen::RowVector3d::Constant(1,3, std::numeric_limits::infinity()), 13 | Eigen::RowVector3d a_max_corner = 14 | Eigen::RowVector3d::Constant(1,3,-std::numeric_limits::infinity())) 15 | : 16 | min_corner(std::move(a_min_corner)), 17 | max_corner(std::move(a_max_corner)) 18 | { } 19 | Eigen::RowVector3d center() 20 | { 21 | return 0.5*(max_corner + min_corner); 22 | } 23 | }; 24 | #endif 25 | -------------------------------------------------------------------------------- /include/CloudPoint.h: -------------------------------------------------------------------------------- 1 | #ifndef CLOUD_POINT_H 2 | #define CLOUD_POINT_H 3 | #include "Object.h" 4 | #include 5 | #include 6 | 7 | struct CloudPoint final : public Object 8 | { 9 | int i; 10 | const Eigen::MatrixXd & points; 11 | CloudPoint(const Eigen::MatrixXd & a_points, int a_i) : 12 | points(a_points), 13 | i(std::move(a_i)) 14 | { 15 | box = BoundingBox(points.row(i),points.row(i)); 16 | } 17 | // Object implementations (see Object.h) 18 | inline bool ray_intersect( 19 | const Ray& ray, 20 | const double min_t, 21 | const double max_t, 22 | double & t, 23 | std::shared_ptr & descendant) const override; 24 | inline bool point_squared_distance( 25 | const Eigen::RowVector3d & query, 26 | const double min_sqrd, 27 | const double max_sqrd, 28 | double & sqrd, 29 | std::shared_ptr & descendant) const override; 30 | }; 31 | 32 | // Implementation 33 | 34 | inline bool CloudPoint::ray_intersect( 35 | const Ray& ray, 36 | const double min_t, 37 | const double max_t, 38 | double & t, 39 | std::shared_ptr & descendant) const 40 | { 41 | //Eigen::RowVector3d v = points.row(i)-ray.origin; 42 | //t = v.dot(ray.direction); 43 | //return t == v.norm()*ray.direction.norm(); 44 | // "100% chance" a hit will not happen 45 | return false; 46 | } 47 | 48 | inline bool CloudPoint::point_squared_distance( 49 | const Eigen::RowVector3d & query, 50 | const double min_sqrd, 51 | const double max_sqrd, 52 | double & sqrd, 53 | std::shared_ptr & descendant) const 54 | { 55 | const auto projection = points.row(i); 56 | // descendant doesn't make sense so it's not touched 57 | sqrd = (query-projection).squaredNorm(); 58 | return (sqrd >= min_sqrd && sqrd < max_sqrd); 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /include/MeshTriangle.h: -------------------------------------------------------------------------------- 1 | #ifndef MESH_TRIANGLE_H 2 | #define MESH_TRIANGLE_H 3 | 4 | #include "Object.h" 5 | #include 6 | #include 7 | 8 | struct MeshTriangle : public Object 9 | { 10 | public: 11 | // Pointer to mesh vertex position list 12 | const Eigen::MatrixXd & V; 13 | // Pointer to mesh indices list 14 | const Eigen::MatrixXi & F; 15 | // face index 16 | int f; 17 | // Record with vertex and face set this MeshTriangle references _and_ 18 | // compute bounding box for this triangle. 19 | // 20 | // Inputs: 21 | // V pointer to mesh vertex list 22 | // F pointer to mesh face list 23 | // f index of triangle in _F 24 | // Side effects: inserts this triangle into .box (see Object.h) 25 | inline MeshTriangle( 26 | const Eigen::MatrixXd & V, 27 | const Eigen::MatrixXi & F, 28 | const int f); 29 | // Object implementations (see Object.h) 30 | inline bool ray_intersect( 31 | const Ray& ray, 32 | const double min_t, 33 | const double max_t, 34 | double & t, 35 | std::shared_ptr & descendant) const override; 36 | bool point_squared_distance( 37 | const Eigen::RowVector3d & query, 38 | const double min_sqrd, 39 | const double max_sqrd, 40 | double & sqrd, 41 | std::shared_ptr & descendant) const override 42 | { 43 | /* Not implemented, nor used in this assignment */ 44 | assert(false); 45 | return false; 46 | } 47 | }; 48 | 49 | 50 | // Implementation 51 | 52 | #include "insert_triangle_into_box.h" 53 | #include "ray_intersect_triangle.h" 54 | 55 | inline MeshTriangle::MeshTriangle( 56 | const Eigen::MatrixXd & _V, 57 | const Eigen::MatrixXi & _F, 58 | const int _f): V(_V), F(_F), f(_f) 59 | { 60 | insert_triangle_into_box( 61 | V.row(F(f,0)), 62 | V.row(F(f,1)), 63 | V.row(F(f,2)), 64 | box); 65 | } 66 | 67 | // Simple wrapper around `ray_intersect_triangle` 68 | inline bool MeshTriangle::ray_intersect( 69 | const Ray& ray, 70 | const double min_t, 71 | const double max_t, 72 | double & t, 73 | std::shared_ptr & descendant) const 74 | { 75 | // descendant doesn't make sense so it's not touched 76 | return ray_intersect_triangle( 77 | ray, 78 | V.row(F(f,0)), 79 | V.row(F(f,1)), 80 | V.row(F(f,2)), 81 | min_t, 82 | max_t, 83 | t); 84 | } 85 | 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /include/Object.h: -------------------------------------------------------------------------------- 1 | #ifndef OBJECT_H 2 | #define OBJECT_H 3 | 4 | // Empty "boxable" and hierarchical object class 5 | // 6 | #include "BoundingBox.h" 7 | #include 8 | #include 9 | struct Ray; 10 | struct Object 11 | { 12 | BoundingBox box; 13 | // Intersect this object with a ray 14 | // 15 | // Inputs: 16 | // ray ray being shot 17 | // min_t minimum parametric distance along ray to consider 18 | // max_t maximum parametric distance along ray to consider 19 | // Object: 20 | // t parameteric distance of hit along ray 21 | // descendant if the hit was found at a descendant, pass along a pointer to 22 | // that descendant (only necessary for hierarchical Objects) 23 | // Returns true iff a valid hit was recorded 24 | virtual bool ray_intersect( 25 | const Ray& ray, 26 | const double min_t, 27 | const double max_t, 28 | double & t, 29 | std::shared_ptr & descendant) const = 0; 30 | // Compute squared distance from the given query point to this object. 31 | // 32 | // Inputs: 33 | // query 3D query point 34 | // min_sqrd minimum squared distance to consider 35 | // max_sqrd maximim squared distance to consider 36 | // Outputs: 37 | // sqrd squared distance 38 | // descendant if minimal distance was found at a descendant, pass along a 39 | // pointer to that descendant (only necessary for hierarchical Objects) 40 | // Returns true iff a valid squared distance was recorded 41 | virtual bool point_squared_distance( 42 | const Eigen::RowVector3d & query, 43 | const double min_sqrd, 44 | const double max_sqrd, 45 | double & sqrd, 46 | std::shared_ptr & descendant) const = 0; 47 | }; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /include/Ray.h: -------------------------------------------------------------------------------- 1 | #ifndef RAY_H 2 | #define RAY_H 3 | 4 | #include 5 | #include 6 | 7 | struct Ray 8 | { 9 | Ray(Eigen::Vector3d a_origin, Eigen::Vector3d a_direction) : 10 | origin(std::move(a_origin)), direction(std::move(a_direction)) 11 | { } 12 | Eigen::Vector3d origin; 13 | // Not necessarily unit-length direction vector. (It is often useful to have 14 | // non-unit length so that origin+t*direction lands on a special point when 15 | // t=1.) 16 | Eigen::Vector3d direction; 17 | }; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /include/VectorXb.h: -------------------------------------------------------------------------------- 1 | // List of bools 2 | #include 3 | namespace Eigen 4 | { 5 | typedef Eigen::Matrix VectorXb; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /include/box_box_intersect.h: -------------------------------------------------------------------------------- 1 | #ifndef BOX_BOX_INTERSECT_H 2 | #define BOX_BOX_INTERSECT_H 3 | #include "BoundingBox.h" 4 | // Determine if two bounding boxes intersect 5 | // 6 | // Inputs: 7 | // A first bounding box 8 | // B second bounding box 9 | // Returns true iff bounding boxes overlap 10 | bool box_box_intersect( 11 | const BoundingBox & A, 12 | const BoundingBox & B); 13 | #endif 14 | -------------------------------------------------------------------------------- /include/box_edges.h: -------------------------------------------------------------------------------- 1 | #ifndef BOX_EDGES_H 2 | #define BOX_EDGES_H 3 | 4 | #include "AABBTree.h" 5 | #include 6 | #include //std::shared_ptr 7 | #include //std::numeric_limits 8 | 9 | inline void box_edges( 10 | const std::shared_ptr & tree, 11 | const int min_depth, 12 | const int max_depth, 13 | Eigen::MatrixXd & EV, 14 | Eigen::MatrixXi & EE); 15 | inline void box_edges( 16 | const std::shared_ptr & tree, 17 | Eigen::MatrixXd & EV, 18 | Eigen::MatrixXi & EE) 19 | { return box_edges(tree,0,std::numeric_limits::max(),EV,EE); } 20 | inline void box_edges( 21 | const std::vector > & objects, 22 | Eigen::MatrixXd & EV, 23 | Eigen::MatrixXi & EE); 24 | 25 | // Implementation 26 | 27 | #include 28 | #include 29 | 30 | inline void box_edges( 31 | const std::shared_ptr & tree, 32 | const int min_depth, 33 | const int max_depth, 34 | Eigen::MatrixXd & EV, 35 | Eigen::MatrixXi & EE) 36 | { 37 | std::vector > objects; 38 | 39 | std::list > nodes; 40 | nodes.push_front(tree); 41 | while(!nodes.empty()) 42 | { 43 | std::shared_ptr node = nodes.front(); 44 | nodes.pop_front(); 45 | std::shared_ptr subtree = 46 | std::dynamic_pointer_cast(node); 47 | if(!subtree || (subtree->depth >= min_depth && subtree->depth <= max_depth)) 48 | { 49 | objects.emplace_back(node); 50 | } 51 | 52 | if(subtree) 53 | { 54 | if(subtree->left) nodes.push_back(subtree->left); 55 | if(subtree->right) nodes.push_back(subtree->right); 56 | } 57 | } 58 | return box_edges(objects,EV,EE); 59 | } 60 | 61 | inline void box_edges( 62 | const std::vector > & objects, 63 | Eigen::MatrixXd & EV, 64 | Eigen::MatrixXi & EE) 65 | { 66 | // This is a dumb way to visualize a lot of boxes. 67 | std::vector > vEV; 68 | std::vector > vEE; 69 | for(const auto & node : objects) 70 | { 71 | const int n = vEV.size(); 72 | vEE.push_back({n+0,n+1}); 73 | vEE.push_back({n+0,n+2}); 74 | vEE.push_back({n+0,n+6}); 75 | vEE.push_back({n+1,n+3}); 76 | vEE.push_back({n+1,n+7}); 77 | vEE.push_back({n+2,n+3}); 78 | vEE.push_back({n+2,n+4}); 79 | vEE.push_back({n+3,n+5}); 80 | vEE.push_back({n+4,n+5}); 81 | vEE.push_back({n+4,n+6}); 82 | vEE.push_back({n+5,n+7}); 83 | vEE.push_back({n+6,n+7}); 84 | const auto & min_corner = node->box.min_corner; 85 | const auto & max_corner = node->box.max_corner; 86 | vEV.push_back({min_corner(0),min_corner(1),min_corner(2)}); 87 | vEV.push_back({min_corner(0),max_corner(1),min_corner(2)}); 88 | vEV.push_back({max_corner(0),min_corner(1),min_corner(2)}); 89 | vEV.push_back({max_corner(0),max_corner(1),min_corner(2)}); 90 | vEV.push_back({max_corner(0),min_corner(1),max_corner(2)}); 91 | vEV.push_back({max_corner(0),max_corner(1),max_corner(2)}); 92 | vEV.push_back({min_corner(0),min_corner(1),max_corner(2)}); 93 | vEV.push_back({min_corner(0),max_corner(1),max_corner(2)}); 94 | } 95 | igl::list_to_matrix(vEV,EV); 96 | igl::list_to_matrix(vEE,EE); 97 | } 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /include/definitions.h: -------------------------------------------------------------------------------- 1 | // List of bools 2 | #include 3 | namespace Eigen 4 | { 5 | typedef Eigen::Matrix VectorXb; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /include/find_all_intersecting_pairs_using_AABBTrees.h: -------------------------------------------------------------------------------- 1 | #ifndef FIND_ALL_INTERSECTING_PAIRS_USING_AABBTREES_H 2 | #define FIND_ALL_INTERSECTING_PAIRS_USING_AABBTREES_H 3 | #include "AABBTree.h" 4 | #include // std::shared_ptr 5 | #include // std::pair 6 | #include 7 | 8 | // Find all intersecting pairs of _leaf boxes_ between one AABB tree and another 9 | // 10 | // Inputs: 11 | // rootA root of first AABB Tree 12 | // rootB root of second AABB Tree 13 | // Output: 14 | // leaf_pairs list of pairs {leaf_A,leaf_B} indicating that the box of leaf_A 15 | // intersects the box of leaf_B 16 | void find_all_intersecting_pairs_using_AABBTrees( 17 | const std::shared_ptr & rootA, 18 | const std::shared_ptr & rootB, 19 | std::vector,std::shared_ptr > > & 20 | leaf_pairs); 21 | #endif 22 | -------------------------------------------------------------------------------- /include/insert_box_into_box.h: -------------------------------------------------------------------------------- 1 | #ifndef INSERT_BOX_INTO_BOX_H 2 | #define INSERT_BOX_INTO_BOX_H 3 | #include "BoundingBox.h" 4 | #include 5 | // Grow a box `B` by inserting a box `A`. 6 | // 7 | // Inputs: 8 | // A bounding box to be inserted 9 | // B bounding box to be grown 10 | // Outputs: 11 | // B bounding box grown to include original contents and A 12 | void insert_box_into_box( 13 | const BoundingBox & A, 14 | BoundingBox & B); 15 | #endif 16 | -------------------------------------------------------------------------------- /include/insert_triangle_into_box.h: -------------------------------------------------------------------------------- 1 | #ifndef INSERT_TRIANGLE_INTO_BOX_H 2 | #define INSERT_TRIANGLE_INTO_BOX_H 3 | #include "BoundingBox.h" 4 | #include 5 | // Grow a box `B` by inserting a triangle with corners `a`,`b`, and `c`. 6 | // 7 | // Inputs: 8 | // a first corner position of the triangle 9 | // b second corner position of the triangle 10 | // c third corner position of the triangle 11 | // B bounding box to be grown 12 | // Outputs: 13 | // B bounding box grown to include original contents and A 14 | void insert_triangle_into_box( 15 | const Eigen::RowVector3d & a, 16 | const Eigen::RowVector3d & b, 17 | const Eigen::RowVector3d & c, 18 | BoundingBox & B); 19 | #endif 20 | -------------------------------------------------------------------------------- /include/k_nearest_neighbors_brute_force.h: -------------------------------------------------------------------------------- 1 | #ifndef K_NEAREST_NEIGHBORS_BRUTE_FORCE_H 2 | #define K_NEAREST_NEIGHBORS_BRUTE_FORCE_H 3 | 4 | #include 5 | 6 | // Compute the $k$-nearest neighbors for the query to the set of $n$ points 7 | // (rows of `points`). This should be a **_slow reference implementation_**. Aim 8 | // for a computational complexity of $O(nk)$ but focus on correctness. It's safe 9 | // to assume K <= #points. 10 | // 11 | // Inputs: 12 | // points #points by 3 list of points to search within 13 | // query 3D position fo the query 14 | // K number of neighbors to find 15 | // Outputs: 16 | // I K-list of indices into points, each row sorted from closest 17 | // to $k$-th closest 18 | // sqrD K-list of corresponding squared distances 19 | // 20 | void k_nearest_neighbors_brute_force( 21 | const Eigen::MatrixXd & points, 22 | const Eigen::RowVector3d & query, 23 | const int K, 24 | Eigen::RowVectorXi & I, 25 | Eigen::RowVectorXd & sqrD); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /include/k_nearest_neighbors_using_AABBTree.h: -------------------------------------------------------------------------------- 1 | #ifndef K_NEAREST_NEIGHBORS_USING_AABBTREE_H 2 | #define K_NEAREST_NEIGHBORS_USING_AABBTREE_H 3 | #include "AABBTree.h" 4 | #include 5 | #include 6 | 7 | void k_nearest_neighbors_using_AABBTree( 8 | const AABBTree & root, 9 | const Eigen::RowVector3d & query, 10 | const int K, 11 | Eigen::RowVectorXd & sqrD, 12 | Eigen::MatrixXd & projections, 13 | std::vector > & descendants); 14 | #endif 15 | -------------------------------------------------------------------------------- /include/nearest_neighbor_brute_force.h: -------------------------------------------------------------------------------- 1 | #ifndef NEAREST_NEIGHBOR_BRUTE_FORCE_H 2 | #define NEAREST_NEIGHBOR_BRUTE_FORCE_H 3 | 4 | #include 5 | 6 | // Compute the nearest neighbor for a query in the set of $n$ points 7 | // (rows of `points`). This should be a **_slow reference implementation_**. Aim 8 | // for a computational complexity of $O(n)$ but focus on correctness. 9 | // 10 | // Inputs: 11 | // points #points by 3 list of points to search within 12 | // query 3D position fo the query 13 | // Outputs: 14 | // I index into points of closest point 15 | // sqrD corresponding squared distance 16 | // 17 | void nearest_neighbor_brute_force( 18 | const Eigen::MatrixXd & points, 19 | const Eigen::RowVector3d & query, 20 | int & I, 21 | double & sqrD); 22 | 23 | #endif 24 | 25 | -------------------------------------------------------------------------------- /include/point_AABBTree_squared_distance.h: -------------------------------------------------------------------------------- 1 | #ifndef POINT_AABBTREE_SQUARED_DISTANCE_H 2 | #define POINT_AABBTREE_SQUARED_DISTANCE_H 3 | #include "AABBTree.h" 4 | #include "Object.h" 5 | #include // std::shared_ptr 6 | #include 7 | 8 | // Compute the distrance from a query point to the objects stored in a AABBTree 9 | // using a priority queue. **_note:** this function is _not_ meant to be called 10 | // recursively._ 11 | // 12 | // Inputs: 13 | // query 3D query point 14 | // root pointer to root of an AABB tree 15 | // min_sqrd minimum squared distance to consider (often 0) 16 | // max_sqrd maximum squared distance to consider (often infinity) 17 | // Outputs 18 | // sqrd squared distance 19 | // descendant if minimal distance was found at a descendant, pass along a 20 | // pointer to that descendant (only necessary for hierarchical Objects) 21 | bool point_AABBTree_squared_distance( 22 | const Eigen::RowVector3d & query, 23 | const std::shared_ptr & root, 24 | const double min_sqrd, 25 | const double max_sqrd, 26 | double & sqrd, 27 | std::shared_ptr & descendant); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /include/point_box_squared_distance.h: -------------------------------------------------------------------------------- 1 | #ifndef POINT_BOX_SQUARED_DISTANCE_H 2 | #define POINT_BOX_SQUARED_DISTANCE_H 3 | #include "BoundingBox.h" 4 | #include 5 | // Compute the squared distance between a query point and a box 6 | // 7 | // Inputs: 8 | // query 3D position of query point 9 | // box 3D axis-aligned bounding box 10 | // Returns squared distance to closest point on bounding box to query 11 | double point_box_squared_distance( 12 | const Eigen::RowVector3d & query, 13 | const BoundingBox & box); 14 | #endif 15 | -------------------------------------------------------------------------------- /include/ray_intersect_box.h: -------------------------------------------------------------------------------- 1 | #ifndef RAY_INTERSECT_BOX_H 2 | #define RAY_INTERSECT_BOX_H 3 | #include "BoundingBox.h" 4 | #include "Ray.h" 5 | #include 6 | 7 | // Intersect a ray with a **_solid_** box (careful: if the ray or `min_t` lands 8 | // _inside_ the box this could still hit something stored inside the box, so 9 | // this counts as a hit). 10 | // 11 | // Inputs: 12 | // ray ray to consider 13 | // box Axis-aligned solid box (presumably bounding some thing(s) 14 | // min_t minimum parameteric distance along ray to consider for hits 15 | // max_t maximum parameteric distance along ray to consider for hits 16 | // Returns true if ray intersects the box between min_t and max_t 17 | 18 | bool ray_intersect_box( 19 | const Ray & ray, 20 | const BoundingBox& box, 21 | const double min_t, 22 | const double max_t); 23 | #endif 24 | -------------------------------------------------------------------------------- /include/ray_intersect_triangle.h: -------------------------------------------------------------------------------- 1 | #ifndef RAY_INTERSECT_TRIANGLE_H 2 | #define RAY_INTERSECT_TRIANGLE_H 3 | #include "Ray.h" 4 | #include 5 | 6 | // Intersect a ray with a triangle 7 | // 8 | // Inputs: 9 | // ray ray to consider 10 | // A first triangle corner position 11 | // B second triangle corner position 12 | // C third triangle corner position 13 | // min_t minimum parameteric distance along ray to consider for hits 14 | // max_t maximum parameteric distance along ray to consider for hits 15 | // Outputs: 16 | // t parametric distance along ray to hit 17 | // Returns true if ray intersects the triangle between min_t and max_t 18 | bool ray_intersect_triangle( 19 | const Ray & ray, 20 | const Eigen::RowVector3d & A, 21 | const Eigen::RowVector3d & B, 22 | const Eigen::RowVector3d & C, 23 | const double min_t, 24 | const double max_t, 25 | double & t); 26 | #endif 27 | 28 | -------------------------------------------------------------------------------- /include/ray_intersect_triangle_mesh_brute_force.h: -------------------------------------------------------------------------------- 1 | #ifndef RAY_INTERSECT_TRIANGLE_MESH_BRUTE_FORCE_H 2 | #define RAY_INTERSECT_TRIANGLE_MESH_BRUTE_FORCE_H 3 | #include "Ray.h" 4 | #include 5 | // Shoot a ray at a triangle mesh with $n$ faces and record the closest hit. Use 6 | // a brute force loop over all triangles, aim for O(n) complexity but focus on 7 | // correctness. This will be your reference solution. 8 | // 9 | // Inputs: 10 | // ray ray being shot 11 | // V #V by 3 list of mesh vertex positions 12 | // F #F by 3 list of triangle indices into rows of V 13 | // min_t minimum parametric distance along ray to consider 14 | // max_t maximum parametric distance along ray to consider 15 | // Outputs: 16 | // hit_t parameteric distance of hit along ray 17 | // hit_f index into F of triangle that was hit 18 | // Returns true iff a valid hit was recorded 19 | bool ray_intersect_triangle_mesh_brute_force( 20 | const Ray & ray, 21 | const Eigen::MatrixXd & V, 22 | const Eigen::MatrixXi & F, 23 | const double min_t, 24 | const double max_t, 25 | double & hit_t, 26 | int & hit_f); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/tictoc.h: -------------------------------------------------------------------------------- 1 | #ifndef TIC_TOC_H 2 | #define TIC_TOC_H 3 | #include 4 | 5 | static double g_time; 6 | inline void tic() 7 | { 8 | g_time = igl::get_seconds(); 9 | } 10 | inline double toc() 11 | { 12 | return igl::get_seconds() - g_time; 13 | } 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /include/triangle_triangle_intersection.h: -------------------------------------------------------------------------------- 1 | #ifndef TRIANGLE_TRIANGLE_INTERSECTION_H 2 | #define TRIANGLE_TRIANGLE_INTERSECTION_H 3 | #include 4 | 5 | // Determine whether two triangles intersect. 6 | // 7 | // Inputs: 8 | // A0 3D position of first corner of first triangle 9 | // A1 3D position of second corner of first triangle 10 | // A2 3D position of third corner of first triangle 11 | // B0 3D position of first corner of second triangle 12 | // B1 3D position of second corner of second triangle 13 | // B2 3D position of third corner of second triangle 14 | // Returns true iff the two triangles intersect 15 | bool triangle_triangle_intersection( 16 | const Eigen::RowVector3d & A0, 17 | const Eigen::RowVector3d & A1, 18 | const Eigen::RowVector3d & A2, 19 | const Eigen::RowVector3d & B0, 20 | const Eigen::RowVector3d & B1, 21 | const Eigen::RowVector3d & B2); 22 | #endif 23 | -------------------------------------------------------------------------------- /include/visualize_aabbtree.h: -------------------------------------------------------------------------------- 1 | #ifndef VISUALIZE_AABBTREE_H 2 | #define VISUALIZE_AABBTREE_H 3 | 4 | #include "AABBTree.h" 5 | #include 6 | #include 7 | 8 | // Visualization of AABB tree around a mesh 9 | inline void visualize_aabbtree( 10 | const Eigen::MatrixXd & V, 11 | const Eigen::MatrixXi & F, 12 | const std::shared_ptr & tree); 13 | 14 | // Interactive vizualization of AABB tree around a point cloud 15 | inline void visualize_aabbtree( 16 | const Eigen::MatrixXd & P, 17 | const std::shared_ptr & tree); 18 | 19 | // Visualization of boxes and intersecting triangles between two meshes 20 | inline void visualize_aabbtree( 21 | const Eigen::MatrixXd & VA, 22 | const Eigen::MatrixXi & FA, 23 | const Eigen::MatrixXd & VB, 24 | const Eigen::MatrixXi & FB, 25 | const std::vector< std::pair,std::shared_ptr > > & leaf_pairs); 26 | 27 | // Implementation 28 | #include "box_edges.h" 29 | 30 | inline void visualize_aabbtree( 31 | const Eigen::MatrixXd & V, 32 | const Eigen::MatrixXi & F, 33 | const std::shared_ptr & tree) 34 | { 35 | igl::opengl::glfw::Viewer v; 36 | v.data().set_mesh(V,F); 37 | v.data().set_face_based(true); 38 | Eigen::MatrixXd EV; 39 | Eigen::MatrixXi EE; 40 | box_edges(tree,EV,EE); 41 | v.data().set_edges(EV,EE,Eigen::RowVector3d(1,1,1)); 42 | v.launch(); 43 | } 44 | 45 | inline void visualize_aabbtree( 46 | const Eigen::MatrixXd & P, 47 | const std::shared_ptr & tree) 48 | { 49 | igl::opengl::glfw::Viewer v; 50 | int depth = 0; 51 | const auto update = [&P,&v,&tree,&depth]() 52 | { 53 | v.data().clear(); 54 | v.data().point_size = 4; 55 | v.data().set_points(P,Eigen::RowVector3d(0,0,0)); 56 | Eigen::MatrixXd EV; 57 | Eigen::MatrixXi EE; 58 | box_edges(tree,depth,depth,EV,EE); 59 | v.data().set_edges(EV,EE,Eigen::RowVector3d(1,1,1)); 60 | }; 61 | v.callback_key_pressed = [&v,&tree,&update,&depth]( 62 | igl::opengl::glfw::Viewer & /*viewer*/, 63 | unsigned int key, 64 | int modifier)->bool 65 | { 66 | switch(key) 67 | { 68 | default: 69 | return false; 70 | case '.': 71 | depth++; 72 | break; 73 | case ',': 74 | depth = std::max(0,depth-1); 75 | break; 76 | } 77 | update(); 78 | return true; 79 | }; 80 | update(); 81 | std::cout<,std::shared_ptr > > & leaf_pairs) 94 | { 95 | //Eigen::MatrixXd V(VA.rows()+VB.rows(),3); 96 | //V< > BA,BB; 101 | BA.reserve(leaf_pairs.size()); 102 | BB.reserve(leaf_pairs.size()); 103 | //Eigen::MatrixXd CA(FA.rows(),3),CB(FB.rows(),3); 104 | const auto blue = Eigen::RowVector3d(0.2,0.3,0.8); 105 | const auto orange = Eigen::RowVector3d(1,0.7,0.2); 106 | for(const auto & pair : leaf_pairs) 107 | { 108 | BA.emplace_back(pair.first); 109 | BB.emplace_back(pair.second); 110 | //// Hmm, these are the _candidate_ triangles so it's a bit deceiving to 111 | //// visualize them. 112 | //std::shared_ptr triangleA = 113 | // std::static_pointer_cast(pair.first); 114 | //std::shared_ptr triangleB = 115 | // std::static_pointer_cast(pair.second); 116 | //const int fa = triangleA->f; 117 | //const int fb = triangleB->f; 118 | //CA.row(fa) = Eigen::RowVector3d(1,0,0); 119 | //CB.row(fb) = Eigen::RowVector3d(0,1,1); 120 | } 121 | 122 | Eigen::MatrixXd EVA,EVB; 123 | Eigen::MatrixXi EEA,EEB; 124 | box_edges(BA,EVA,EEA); 125 | box_edges(BB,EVB,EEB); 126 | v.data().set_mesh(VA,FA); 127 | v.data().set_face_based(true); 128 | v.data().set_colors(Eigen::RowVector3d(244,165,130)/255.); 129 | v.data().set_edges(EVA,EEA,Eigen::RowVector3d(202,0,32)/255.); 130 | v.append_mesh(); 131 | v.data().set_mesh(VB,FB); 132 | v.data().set_face_based(true); 133 | v.data().set_colors(Eigen::RowVector3d(146,197,222)/255.); 134 | v.data().set_edges(EVB,EEB,Eigen::RowVector3d(5,113,176)/255.); 135 | v.core().background_color.setConstant(0.8); 136 | v.launch(); 137 | } 138 | 139 | #endif 140 | -------------------------------------------------------------------------------- /include/warnings.h: -------------------------------------------------------------------------------- 1 | #ifndef WARNINGS_H 2 | #define WARNINGS_H 3 | 4 | // Three warning helper functions: 5 | // 6 | // WARN_IF_NOT_EQUAL 7 | // WARN_IF_NOT_APPROX 8 | // diff_and_warn 9 | // 10 | // One printer helper macro 11 | // 12 | // FLOAT15 13 | // 14 | 15 | #include 16 | #include // std::setw, std::setprecision, std::fixed 17 | // Macro for prettier printing of numbers 18 | #define FLOAT15 std::fixed << std::setw(15) << std::setprecision(11) 19 | // Macros to help debug Eigen matrices 20 | // if A(r) != B(r) print a warning 21 | #define WARN_IF_NOT_EQUAL(A,B,r) \ 22 | do { \ 23 | if(A(r) != B(r)) \ 24 | { \ 25 | std::cout<<"Error: "<< \ 26 | #A"("<epsilon print a warning 33 | #define WARN_IF_NOT_APPROX(A,B,r) \ 34 | do { \ 35 | if(std::abs(A(r)-B(r))>1e-10) \ 36 | { \ 37 | std::cout<<"Error: "<< \ 38 | #A"("< 46 | #include 47 | #include 48 | #include 49 | inline void diff_and_warn( 50 | std::vector > X_pairs, 51 | const std::string X_name, 52 | std::vector > Y_pairs, 53 | const std::string Y_name) 54 | { 55 | // http://www.cplusplus.com/reference/algorithm/set_symmetric_difference/ 56 | std::vector > diff(X_pairs.size()); 57 | std::sort (X_pairs.begin(),X_pairs.end()); 58 | std::sort (Y_pairs.begin(),Y_pairs.end()); 59 | std::vector >::iterator it = 60 | std::set_difference( 61 | X_pairs.begin(), X_pairs.end(), 62 | Y_pairs.begin(), Y_pairs.end(), 63 | diff.begin()); 64 | diff.resize(it-diff.begin()); 65 | if(diff.size() > 0) 66 | { 67 | std::cout<<"Error: Intersecting pairs found using "<first << "," << it->second << std::endl; 72 | } 73 | } 74 | } 75 | #endif 76 | -------------------------------------------------------------------------------- /intersections.cpp: -------------------------------------------------------------------------------- 1 | #include "MeshTriangle.h" 2 | #include "triangle_triangle_intersection.h" 3 | #include "find_all_intersecting_pairs_using_AABBTrees.h" 4 | #include "Object.h" 5 | #include "AABBTree.h" 6 | #include "warnings.h" 7 | #include "tictoc.h" 8 | #include "visualize_aabbtree.h" 9 | #include 10 | #include 11 | #include 12 | #include // std::setw 13 | #include // std::shared_ptr 14 | 15 | int main(int argc, char * argv[]) 16 | { 17 | ///////////////////////////////////////////////////////////////////////////// 18 | // TRIANGLE MESH INTERSECTION DETECTION 19 | ///////////////////////////////////////////////////////////////////////////// 20 | std::cout<<"# Triangle Mesh Intersection Detection"<1?argv[1]:"../data/knight.obj",VA,FA); 25 | std::cout<<" |VA| "<2?argv[2]:"../data/cheburashka.obj",VB,FB); 30 | std::cout<<" |VB| "< > bf_pairs; 35 | // Brute force 36 | for(int fa = 0;fa > tree_pairs; 59 | const auto triangle_tree = []( 60 | const Eigen::MatrixXd & V, 61 | const Eigen::MatrixXi & F)->std::shared_ptr 62 | { 63 | // Because we use shared_ptrs it's OK that this list is destroyed 64 | std::vector > triangles; 65 | triangles.reserve(F.rows()); 66 | // Create a box for each triangle 67 | for(int f = 0;f(V,F,f) ); 70 | } 71 | return std::make_shared(triangles); 72 | }; 73 | std::shared_ptr rootA = triangle_tree(VA,FA); 74 | std::shared_ptr rootB = triangle_tree(VB,FB); 75 | std::cout<<" | build trees | " << FLOAT15 << toc() << " |"<,std::shared_ptr > > 79 | leaf_pairs; 80 | // Broad phase 81 | find_all_intersecting_pairs_using_AABBTrees(rootA,rootB,leaf_pairs); 82 | for(const auto & pair : leaf_pairs) 83 | { 84 | std::shared_ptr triangleA = 85 | std::static_pointer_cast(pair.first); 86 | std::shared_ptr triangleB = 87 | std::static_pointer_cast(pair.second); 88 | const int fa = triangleA->f; 89 | const int fb = triangleB->f; 90 | // Narrow phase 91 | if(triangle_triangle_intersection( 92 | VA.row(FA(fa,0)), 93 | VA.row(FA(fa,1)), 94 | VA.row(FA(fa,2)), 95 | VB.row(FB(fb,0)), 96 | VB.row(FB(fb,1)), 97 | VB.row(FB(fb,2)))) 98 | { 99 | tree_pairs.emplace_back(fa,fb); 100 | } 101 | } 102 | std::cout<<" | use trees | " << FLOAT15 << toc() << " |"< 3 | 18 |
19 | 20 | 21 | 24 | 25 | 26 |
27 | $\newcommand{\A}{\mat{A}}$ 28 | $\newcommand{\B}{\mat{B}}$ 29 | $\newcommand{\C}{\mat{C}}$ 30 | $\newcommand{\D}{\mat{D}}$ 31 | $\newcommand{\E}{\mat{E}}$ 32 | $\newcommand{\F}{\mat{F}}$ 33 | $\newcommand{\G}{\mat{G}}$ 34 | $\newcommand{\H}{\mat{H}}$ 35 | $\newcommand{\I}{\mat{I}}$ 36 | $\newcommand{\J}{\mat{J}}$ 37 | $\newcommand{\K}{\mat{K}}$ 38 | $\newcommand{\L}{\mat{L}}$ 39 | $\newcommand{\M}{\mat{M}}$ 40 | $\newcommand{\N}{\mat{N}}$ 41 | $\newcommand{\One}{\mathbf{1}}$ 42 | $\newcommand{\P}{\mat{P}}$ 43 | $\newcommand{\Q}{\mat{Q}}$ 44 | $\newcommand{\Rot}{\mat{R}}$ 45 | $\newcommand{\R}{\mathbb{R}}$ 46 | $\newcommand{\S}{\mathcal{S}}$ 47 | $\newcommand{\T}{\mat{T}}$ 48 | $\newcommand{\U}{\mat{U}}$ 49 | $\newcommand{\V}{\mat{V}}$ 50 | $\newcommand{\W}{\mat{W}}$ 51 | $\newcommand{\X}{\mat{X}}$ 52 | $\newcommand{\Y}{\mat{Y}}$ 53 | $\newcommand{\argmax}{\mathop{\text{argmax}}}$ 54 | $\newcommand{\argmin}{\mathop{\text{argmin}}}$ 55 | $\newcommand{\a}{\vec{a}}$ 56 | $\newcommand{\b}{\vec{b}}$ 57 | $\newcommand{\c}{\vec{c}}$ 58 | $\newcommand{\d}{\vec{d}}$ 59 | $\newcommand{\e}{\vec{e}}$ 60 | $\newcommand{\f}{\vec{f}}$ 61 | $\newcommand{\g}{\vec{g}}$ 62 | $\newcommand{\mat}[1]{\mathbf{#1}}$ 63 | $\newcommand{\min}{\mathop{\text{min}}}$ 64 | $\newcommand{\m}{\vec{m}}$ 65 | $\newcommand{\n}{\vec{n}}$ 66 | $\newcommand{\p}{\vec{p}}$ 67 | $\newcommand{\q}{\vec{q}}$ 68 | $\newcommand{\r}{\vec{r}}$ 69 | $\newcommand{\transpose}{{\mathsf T}}$ 70 | $\newcommand{\tr}[1]{\mathop{\text{tr}}{\left(#1\right)}}$ 71 | $\newcommand{\s}{\vec{s}}$ 72 | $\newcommand{\t}{\vec{t}}$ 73 | $\newcommand{\u}{\vec{u}}$ 74 | $\newcommand{\vec}[1]{\mathbf{#1}}$ 75 | $\newcommand{\x}{\vec{x}}$ 76 | $\newcommand{\y}{\vec{y}}$ 77 | $\newcommand{\z}{\vec{z}}$ 78 | $\newcommand{\0}{\vec{0}}$ 79 | $\renewcommand{\v}{\vec{v}}$ 80 | 81 | $\renewcommand{\hat}[1]{\widehat{#1}}$ 82 |
83 | -------------------------------------------------------------------------------- /rays.cpp: -------------------------------------------------------------------------------- 1 | #include "ray_intersect_triangle_mesh_brute_force.h" 2 | #include "Ray.h" 3 | #include "MeshTriangle.h" 4 | #include "Object.h" 5 | #include "AABBTree.h" 6 | #include "warnings.h" 7 | #include "VectorXb.h" 8 | #include "tictoc.h" 9 | #include "visualize_aabbtree.h" 10 | #include 11 | #include 12 | #include // std::stoi 13 | #include 14 | #include // std::setw 15 | #include // std::shared_ptr 16 | 17 | int main(int argc, char * argv[]) 18 | { 19 | ///////////////////////////////////////////////////////////////////////////// 20 | // RAY TRIANGLE MESH INTERSECTION 21 | ///////////////////////////////////////////////////////////////////////////// 22 | std::cout<<"# Ray Triangle Mesh Intersection"<1?argv[1]:"../data/rubber-ducky.obj",V,F); 27 | std::cout<<" |V| "< rays; 31 | rays.reserve(argc>2?std::stoi(argv[2]):1000); 32 | // Default bounds on ray 33 | double min_t = 0; 34 | double max_t = std::numeric_limits::infinity(); 35 | for(int r = 0;r > triangles; 60 | triangles.reserve(F.rows()); 61 | // Create a box for each triangle 62 | for(int f = 0;f(V,F,f) ); 65 | } 66 | std::shared_ptr root = std::make_shared(triangles); 67 | std::cout<<" | build tree | " << FLOAT15 << toc() << " |"< hit_object; 79 | tree_hit(r) = 80 | root->ray_intersect(rays[r],min_t,max_t,tree_t(r),hit_object); 81 | if(tree_hit(r)) 82 | { 83 | const std::shared_ptr hit_triangle = 84 | std::static_pointer_cast(hit_object); 85 | tree_I(r) = hit_triangle->f; 86 | } 87 | } 88 | std::cout<<" | use tree | " << FLOAT15 << toc() << " |"< > & objects, 6 | int a_depth): 7 | depth(std::move(a_depth)), 8 | num_leaves(objects.size()) 9 | { 10 | //////////////////////////////////////////////////////////////////////////// 11 | // Add your code here 12 | //////////////////////////////////////////////////////////////////////////// 13 | } 14 | -------------------------------------------------------------------------------- /src/AABBTree_ray_intersect.cpp: -------------------------------------------------------------------------------- 1 | #include "AABBTree.h" 2 | 3 | // See AABBTree.h for API 4 | bool AABBTree::ray_intersect( 5 | const Ray& ray, 6 | const double min_t, 7 | const double max_t, 8 | double & t, 9 | std::shared_ptr & descendant) const 10 | { 11 | //////////////////////////////////////////////////////////////////////////// 12 | // Replace with your code here: 13 | t = 0; 14 | return false; 15 | //////////////////////////////////////////////////////////////////////////// 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/box_box_intersect.cpp: -------------------------------------------------------------------------------- 1 | #include "box_box_intersect.h" 2 | bool box_box_intersect( 3 | const BoundingBox & A, 4 | const BoundingBox & B) 5 | { 6 | //////////////////////////////////////////////////////////////////////////// 7 | // Replace with your code here: 8 | return false; 9 | //////////////////////////////////////////////////////////////////////////// 10 | } 11 | 12 | -------------------------------------------------------------------------------- /src/find_all_intersecting_pairs_using_AABBTrees.cpp: -------------------------------------------------------------------------------- 1 | #include "find_all_intersecting_pairs_using_AABBTrees.h" 2 | #include "box_box_intersect.h" 3 | // Hint: use a list as a queue 4 | #include 5 | 6 | void find_all_intersecting_pairs_using_AABBTrees( 7 | const std::shared_ptr & rootA, 8 | const std::shared_ptr & rootB, 9 | std::vector,std::shared_ptr > > & 10 | leaf_pairs) 11 | { 12 | //////////////////////////////////////////////////////////////////////////// 13 | // Add your code here 14 | //////////////////////////////////////////////////////////////////////////// 15 | } 16 | -------------------------------------------------------------------------------- /src/insert_box_into_box.cpp: -------------------------------------------------------------------------------- 1 | #include "insert_box_into_box.h" 2 | 3 | void insert_box_into_box( 4 | const BoundingBox & A, 5 | BoundingBox & B) 6 | { 7 | //////////////////////////////////////////////////////////////////////////// 8 | // Add your code here 9 | //////////////////////////////////////////////////////////////////////////// 10 | } 11 | 12 | -------------------------------------------------------------------------------- /src/insert_triangle_into_box.cpp: -------------------------------------------------------------------------------- 1 | #include "insert_triangle_into_box.h" 2 | 3 | void insert_triangle_into_box( 4 | const Eigen::RowVector3d & a, 5 | const Eigen::RowVector3d & b, 6 | const Eigen::RowVector3d & c, 7 | BoundingBox & B) 8 | { 9 | //////////////////////////////////////////////////////////////////////////// 10 | // Add your code here 11 | //////////////////////////////////////////////////////////////////////////// 12 | } 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/nearest_neighbor_brute_force.cpp: -------------------------------------------------------------------------------- 1 | #include "nearest_neighbor_brute_force.h" 2 | #include // std::numeric_limits::infinity(); 3 | 4 | void nearest_neighbor_brute_force( 5 | const Eigen::MatrixXd & points, 6 | const Eigen::RowVector3d & query, 7 | int & I, 8 | double & sqrD) 9 | { 10 | //////////////////////////////////////////////////////////////////////////// 11 | // Replace with your code here: 12 | I = -1; 13 | sqrD = 0; 14 | //////////////////////////////////////////////////////////////////////////// 15 | } 16 | -------------------------------------------------------------------------------- /src/point_AABBTree_squared_distance.cpp: -------------------------------------------------------------------------------- 1 | #include "point_AABBTree_squared_distance.h" 2 | #include // std::priority_queue 3 | 4 | bool point_AABBTree_squared_distance( 5 | const Eigen::RowVector3d & query, 6 | const std::shared_ptr & root, 7 | const double min_sqrd, 8 | const double max_sqrd, 9 | double & sqrd, 10 | std::shared_ptr & descendant) 11 | { 12 | //////////////////////////////////////////////////////////////////////////// 13 | // Replace with your code here 14 | sqrd = 0; 15 | return false; 16 | //////////////////////////////////////////////////////////////////////////// 17 | } 18 | -------------------------------------------------------------------------------- /src/point_box_squared_distance.cpp: -------------------------------------------------------------------------------- 1 | #include "point_box_squared_distance.h" 2 | 3 | double point_box_squared_distance( 4 | const Eigen::RowVector3d & query, 5 | const BoundingBox & box) 6 | { 7 | //////////////////////////////////////////////////////////////////////////// 8 | // Replace with your code here 9 | return 0; 10 | //////////////////////////////////////////////////////////////////////////// 11 | } 12 | -------------------------------------------------------------------------------- /src/ray_intersect_box.cpp: -------------------------------------------------------------------------------- 1 | #include "ray_intersect_box.h" 2 | #include 3 | 4 | bool ray_intersect_box( 5 | const Ray & ray, 6 | const BoundingBox& box, 7 | const double min_t, 8 | const double max_t) 9 | { 10 | //////////////////////////////////////////////////////////////////////////// 11 | // Replace with your code here: 12 | return false; 13 | //////////////////////////////////////////////////////////////////////////// 14 | } 15 | -------------------------------------------------------------------------------- /src/ray_intersect_triangle.cpp: -------------------------------------------------------------------------------- 1 | #include "ray_intersect_triangle.h" 2 | 3 | bool ray_intersect_triangle( 4 | const Ray & ray, 5 | const Eigen::RowVector3d & A, 6 | const Eigen::RowVector3d & B, 7 | const Eigen::RowVector3d & C, 8 | const double min_t, 9 | const double max_t, 10 | double & t) 11 | { 12 | //////////////////////////////////////////////////////////////////////////// 13 | // Replace with your code here: 14 | t = 0; 15 | return false; 16 | //////////////////////////////////////////////////////////////////////////// 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/ray_intersect_triangle_mesh_brute_force.cpp: -------------------------------------------------------------------------------- 1 | #include "ray_intersect_triangle_mesh_brute_force.h" 2 | #include "ray_intersect_triangle.h" 3 | 4 | bool ray_intersect_triangle_mesh_brute_force( 5 | const Ray & ray, 6 | const Eigen::MatrixXd & V, 7 | const Eigen::MatrixXi & F, 8 | const double min_t, 9 | const double max_t, 10 | double & hit_t, 11 | int & hit_f) 12 | { 13 | //////////////////////////////////////////////////////////////////////////// 14 | // Replace with your code here: 15 | hit_t = 0; 16 | hit_f = 0; 17 | return false; 18 | //////////////////////////////////////////////////////////////////////////// 19 | } 20 | -------------------------------------------------------------------------------- /src/triangle_triangle_intersection.cpp: -------------------------------------------------------------------------------- 1 | #include "triangle_triangle_intersection.h" 2 | 3 | bool triangle_triangle_intersection( 4 | const Eigen::RowVector3d & A0, 5 | const Eigen::RowVector3d & A1, 6 | const Eigen::RowVector3d & A2, 7 | const Eigen::RowVector3d & B0, 8 | const Eigen::RowVector3d & B1, 9 | const Eigen::RowVector3d & B2) 10 | { 11 | //////////////////////////////////////////////////////////////////////////// 12 | // Replace with your code here: 13 | return false; 14 | //////////////////////////////////////////////////////////////////////////// 15 | } 16 | -------------------------------------------------------------------------------- /tex/1f08ccc9cd7309ba1e756c3d9345ad9f.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /tex/55a049b8f161ae7cfeb0197d75aff967.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tex/7295bc071a3c9dc4d8627e19de64928f.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /tex/b7afe912ac7ed280f96e7cfb0f35a027.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tex/f9bb6ecace3a663c4adf0544035b4da4.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | --------------------------------------------------------------------------------