|
375 | 375 | <div class='together'>
|
376 | 376 | This gives the following result:
|
377 | 377 |
|
| 378 | + <div id="image-bouncing-spheres"> |
378 | 379 | 
|
| 381 | + </div> |
380 | 382 |
|
381 | 383 | </div>
|
382 | 384 |
|
|
926 | 928 | public:
|
927 | 929 | ...
|
928 | 930 | bvh_node(const std::vector<shared_ptr<hittable>>& src_objects, size_t start, size_t end) {
|
929 |
| - auto objects = src_objects; // Create a modifiable array of the source scene objects |
930 |
| - |
931 | 931 | int axis = random_int(0,2);
|
| 932 | + |
932 | 933 | auto comparator = (axis == 0) ? box_x_compare
|
933 | 934 | : (axis == 1) ? box_y_compare
|
934 | 935 | : box_z_compare;
|
935 | 936 |
|
| 937 | + auto objects = src_objects; // A modifiable array of the source scene objects |
| 938 | + |
936 | 939 | size_t object_span = end - start;
|
937 | 940 |
|
938 | 941 | if (object_span == 1) {
|
|
1038 | 1041 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
1039 | 1042 | [Listing [random-spheres-bvh]: <kbd>[main.cc]</kbd> Random spheres, using BVH]
|
1040 | 1043 |
|
| 1044 | +The rendered image should be identical to the non-BVH version shown in |
| 1045 | +[image 1](#image-bouncing-spheres). However, if you time the two versions, the BVH version should be |
| 1046 | +faster. I see a speedup of almost _six and a half times_ the prior version. |
| 1047 | + |
| 1048 | + |
| 1049 | +Another BVH Optimization |
| 1050 | +------------------------- |
| 1051 | +We can speed up the BVH optimization a bit more. Instead of choosing a random splitting axis, let's |
| 1052 | +split the longest axis of the enclosing bounding box to get the most subdivision. The change is |
| 1053 | +straight-forward, but we'll add a few things to the `aabb` class in the process. |
| 1054 | + |
| 1055 | +The first task is to construct an axis-aligned bounding box of the span of objects in the BVH |
| 1056 | +constructor. Basically, we'll construct the `bvh_node`s bounding box from this span by initializing |
| 1057 | +the bounding box to empty, and then augmenting it with each bounding box in the span of objects. |
| 1058 | + |
| 1059 | +We don't have a way yet to express an empty bounding box, so we'll imagine one for now and |
| 1060 | +implementing it shortly. |
| 1061 | + |
| 1062 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
| 1063 | + class bvh_node : public hittable { |
| 1064 | + public: |
| 1065 | + ... |
| 1066 | + bvh_node(const std::vector<shared_ptr<hittable>>& src_objects, size_t start, size_t end) { |
| 1067 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight |
| 1068 | + // Build the bounding box of the span of source objects. |
| 1069 | + bbox = aabb::empty; |
| 1070 | + for (int object_index=start; object_index < end; ++object_index) |
| 1071 | + bbox = aabb(bbox, src_objects[object_index]->bounding_box()); |
| 1072 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
| 1073 | + |
| 1074 | + ... |
| 1075 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 1076 | + [Listing [object-span-bbox]: <kbd>[bvh.h]</kbd> Building the bbox for the span of BVH objects] |
| 1077 | + |
| 1078 | +Now that we have the bounding box, set the splitting axis to the one with the longest side. Again, |
| 1079 | +we'll imagine a function that does that for us: `aabb::longest_axis()`. Finally, since we're |
| 1080 | +computing the bounding box of the object span up front, we can delete the original line that |
| 1081 | +computed it as the union of the left and right sides. |
| 1082 | + |
| 1083 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
| 1084 | + class bvh_node : public hittable { |
| 1085 | + public: |
| 1086 | + ... |
| 1087 | + bvh_node(const std::vector<shared_ptr<hittable>>& src_objects, size_t start, size_t end) { |
| 1088 | + // Build the bounding box of the span of source objects. |
| 1089 | + bbox = aabb::empty; |
| 1090 | + for (int object_index=start; object_index < end; ++object_index) |
| 1091 | + bbox = aabb(bbox, src_objects[object_index]->bounding_box()); |
| 1092 | + |
| 1093 | + |
| 1094 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight |
| 1095 | + int axis = bbox.longest_axis(); |
| 1096 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
| 1097 | + |
| 1098 | + auto comparator = (axis == 0) ? box_x_compare |
| 1099 | + : (axis == 1) ? box_y_compare |
| 1100 | + : box_z_compare; |
| 1101 | + |
| 1102 | + ... |
| 1103 | + |
| 1104 | + |
| 1105 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ delete |
| 1106 | + bbox = aabb(left->bounding_box(), right->bounding_box()); |
| 1107 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
| 1108 | + } |
| 1109 | + |
| 1110 | + ... |
| 1111 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 1112 | + [Listing [object-span-bbox]: <kbd>[bvh.h]</kbd> Building the bbox for the span of BVH objects] |
| 1113 | + |
| 1114 | +Now to implement the empty `aabb` code and the new `aabb::longest_axis()` function: |
| 1115 | + |
| 1116 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
| 1117 | + class aabb { |
| 1118 | + public: |
| 1119 | + ... |
| 1120 | + |
| 1121 | + |
| 1122 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight |
| 1123 | + int longest_axis() const { |
| 1124 | + // Returns the index of the longest axis of the bounding box. |
| 1125 | + |
| 1126 | + if (x.size() > y.size()) |
| 1127 | + return x.size() > z.size() ? 0 : 2; |
| 1128 | + else |
| 1129 | + return y.size() > z.size() ? 1 : 2; |
| 1130 | + } |
| 1131 | + |
| 1132 | + static const aabb empty, universe; |
| 1133 | + }; |
| 1134 | + |
| 1135 | + const aabb aabb::empty = aabb(interval::empty, interval::empty, interval::empty); |
| 1136 | + const aabb aabb::universe = aabb(interval::universe, interval::universe, interval::universe); |
| 1137 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
| 1138 | + |
| 1139 | + ... |
| 1140 | + |
| 1141 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 1142 | + [Listing [aabb-empty-and-axis]: <kbd>[aabb.h]</kbd> |
| 1143 | + New aabb constants and longest_axis() function] |
| 1144 | + |
| 1145 | +As before, you should see identical results to [image 1](#image-bouncing-spheres), but rendering a |
| 1146 | +little bit faster. On my system, this yields something like an additional 18% render speedup. Not |
| 1147 | +bad for a little extra work. |
| 1148 | + |
1041 | 1149 |
|
1042 | 1150 |
|
1043 | 1151 | Texture Mapping
|
|
0 commit comments