| 1 | // Copyright 2009-2021 Intel Corporation | 
| 2 | // SPDX-License-Identifier: Apache-2.0 | 
| 3 |  | 
| 4 | #pragma once | 
| 5 |  | 
| 6 | #include "bvh_node_base.h" | 
| 7 |  | 
| 8 | namespace embree | 
| 9 | { | 
| 10 |   /*! Motion Blur AABBNode */ | 
| 11 |   template<typename NodeRef, int N> | 
| 12 |     struct AABBNodeMB_t : public BaseNode_t<NodeRef, N> | 
| 13 |   { | 
| 14 |     using BaseNode_t<NodeRef,N>::children; | 
| 15 |     typedef BVHNodeRecord<NodeRef>     NodeRecord; | 
| 16 |     typedef BVHNodeRecordMB<NodeRef>   NodeRecordMB; | 
| 17 |     typedef BVHNodeRecordMB4D<NodeRef> NodeRecordMB4D; | 
| 18 |      | 
| 19 |     struct Create | 
| 20 |     { | 
| 21 |       template<typename BuildRecord> | 
| 22 |       __forceinline NodeRef operator() (BuildRecord* children, const size_t num, const FastAllocator::CachedAllocator& alloc) const | 
| 23 |       { | 
| 24 |         AABBNodeMB_t* node = (AABBNodeMB_t*) alloc.malloc0(bytes: sizeof(AABBNodeMB_t),align: NodeRef::byteNodeAlignment); node->clear(); | 
| 25 |         return NodeRef::encodeNode(node); | 
| 26 |       } | 
| 27 |     }; | 
| 28 |      | 
| 29 |     struct Set | 
| 30 |     {  | 
| 31 |       template<typename BuildRecord> | 
| 32 |       __forceinline NodeRecordMB operator() (const BuildRecord& precord, const BuildRecord* crecords, NodeRef ref, NodeRecordMB* children, const size_t num) const | 
| 33 |       { | 
| 34 | #if defined(DEBUG) | 
| 35 |         // check that empty children are only at the end of the child list | 
| 36 |         bool emptyChild = false; | 
| 37 |         for (size_t i=0; i<num; i++) { | 
| 38 |           emptyChild |= (children[i].ref == NodeRef::emptyNode); | 
| 39 |           assert(emptyChild == (children[i].ref == NodeRef::emptyNode)); | 
| 40 |         } | 
| 41 | #endif | 
| 42 |         AABBNodeMB_t* node = ref.getAABBNodeMB(); | 
| 43 |          | 
| 44 |         LBBox3fa bounds = empty; | 
| 45 |         for (size_t i=0; i<num; i++) { | 
| 46 |           node->setRef(i,children[i].ref); | 
| 47 |           node->setBounds(i,children[i].lbounds); | 
| 48 |           bounds.extend(other: children[i].lbounds); | 
| 49 |         } | 
| 50 |         return NodeRecordMB(ref,bounds); | 
| 51 |       } | 
| 52 |     }; | 
| 53 |      | 
| 54 |     struct SetTimeRange | 
| 55 |     { | 
| 56 |       __forceinline SetTimeRange(BBox1f tbounds) : tbounds(tbounds) {} | 
| 57 |        | 
| 58 |       template<typename BuildRecord> | 
| 59 |       __forceinline NodeRecordMB operator() (const BuildRecord& precord, const BuildRecord* crecords, NodeRef ref, NodeRecordMB* children, const size_t num) const | 
| 60 |       { | 
| 61 |         AABBNodeMB_t* node = ref.getAABBNodeMB(); | 
| 62 |          | 
| 63 |         LBBox3fa bounds = empty; | 
| 64 |         for (size_t i=0; i<num; i++) { | 
| 65 |           node->setRef(i, children[i].ref); | 
| 66 |           node->setBounds(i, children[i].lbounds, tbounds); | 
| 67 |           bounds.extend(other: children[i].lbounds); | 
| 68 |         } | 
| 69 |         return NodeRecordMB(ref,bounds); | 
| 70 |       } | 
| 71 |        | 
| 72 |       BBox1f tbounds; | 
| 73 |     }; | 
| 74 |      | 
| 75 |     /*! Clears the node. */ | 
| 76 |     __forceinline void clear()  { | 
| 77 |       lower_x = lower_y = lower_z = vfloat<N>(pos_inf); | 
| 78 |       upper_x = upper_y = upper_z = vfloat<N>(neg_inf); | 
| 79 |       lower_dx = lower_dy = lower_dz = vfloat<N>(0.0f); | 
| 80 |       upper_dx = upper_dy = upper_dz = vfloat<N>(0.0f); | 
| 81 |       BaseNode_t<NodeRef,N>::clear(); | 
| 82 |     } | 
| 83 |      | 
| 84 |     /*! Sets ID of child. */ | 
| 85 |     __forceinline void setRef(size_t i, NodeRef ref) { | 
| 86 |       children[i] = ref; | 
| 87 |     } | 
| 88 |      | 
| 89 |     /*! Sets bounding box of child. */ | 
| 90 |     __forceinline void setBounds(size_t i, const BBox3fa& bounds0_i, const BBox3fa& bounds1_i) | 
| 91 |     { | 
| 92 |       /*! for empty bounds we have to avoid inf-inf=nan */ | 
| 93 |       BBox3fa bounds0(min(a: bounds0_i.lower,b: Vec3fa(+FLT_MAX)),max(a: bounds0_i.upper,b: Vec3fa(-FLT_MAX))); | 
| 94 |       BBox3fa bounds1(min(a: bounds1_i.lower,b: Vec3fa(+FLT_MAX)),max(a: bounds1_i.upper,b: Vec3fa(-FLT_MAX))); | 
| 95 |       bounds0 = bounds0.enlarge_by(a: 4.0f*float(ulp)); | 
| 96 |       bounds1 = bounds1.enlarge_by(a: 4.0f*float(ulp)); | 
| 97 |       Vec3fa dlower = bounds1.lower-bounds0.lower; | 
| 98 |       Vec3fa dupper = bounds1.upper-bounds0.upper; | 
| 99 |        | 
| 100 |       lower_x[i] = bounds0.lower.x; lower_y[i] = bounds0.lower.y; lower_z[i] = bounds0.lower.z; | 
| 101 |       upper_x[i] = bounds0.upper.x; upper_y[i] = bounds0.upper.y; upper_z[i] = bounds0.upper.z; | 
| 102 |        | 
| 103 |       lower_dx[i] = dlower.x; lower_dy[i] = dlower.y; lower_dz[i] = dlower.z; | 
| 104 |       upper_dx[i] = dupper.x; upper_dy[i] = dupper.y; upper_dz[i] = dupper.z; | 
| 105 |     } | 
| 106 |      | 
| 107 |     /*! Sets bounding box of child. */ | 
| 108 |     __forceinline void setBounds(size_t i, const LBBox3fa& bounds) { | 
| 109 |       setBounds(i, bounds.bounds0, bounds.bounds1); | 
| 110 |     } | 
| 111 |      | 
| 112 |     /*! Sets bounding box of child. */ | 
| 113 |     __forceinline void setBounds(size_t i, const LBBox3fa& bounds, const BBox1f& tbounds) { | 
| 114 |       setBounds(i, bounds.global(dt: tbounds)); | 
| 115 |     } | 
| 116 |      | 
| 117 |     /*! Sets bounding box and ID of child. */ | 
| 118 |     __forceinline void set(size_t i, NodeRef ref, const BBox3fa& bounds) { | 
| 119 |       lower_x[i] = bounds.lower.x; lower_y[i] = bounds.lower.y; lower_z[i] = bounds.lower.z; | 
| 120 |       upper_x[i] = bounds.upper.x; upper_y[i] = bounds.upper.y; upper_z[i] = bounds.upper.z; | 
| 121 |       children[i] = ref; | 
| 122 |     } | 
| 123 |      | 
| 124 |     /*! Sets bounding box and ID of child. */ | 
| 125 |     __forceinline void set(size_t i, const NodeRecordMB4D& child) | 
| 126 |     { | 
| 127 |       setRef(i, ref: child.ref); | 
| 128 |       setBounds(i, child.lbounds, child.dt); | 
| 129 |     } | 
| 130 |      | 
| 131 |     /*! Return bounding box for time 0 */ | 
| 132 |     __forceinline BBox3fa bounds0(size_t i) const { | 
| 133 |       return BBox3fa(Vec3fa(lower_x[i],lower_y[i],lower_z[i]), | 
| 134 |                      Vec3fa(upper_x[i],upper_y[i],upper_z[i])); | 
| 135 |     } | 
| 136 |      | 
| 137 |     /*! Return bounding box for time 1 */ | 
| 138 |     __forceinline BBox3fa bounds1(size_t i) const { | 
| 139 |       return BBox3fa(Vec3fa(lower_x[i]+lower_dx[i],lower_y[i]+lower_dy[i],lower_z[i]+lower_dz[i]), | 
| 140 |                      Vec3fa(upper_x[i]+upper_dx[i],upper_y[i]+upper_dy[i],upper_z[i]+upper_dz[i])); | 
| 141 |     } | 
| 142 |      | 
| 143 |     /*! Returns bounds of node. */ | 
| 144 |     __forceinline BBox3fa bounds() const { | 
| 145 |       return BBox3fa(Vec3fa(reduce_min(min(lower_x,lower_x+lower_dx)), | 
| 146 |                             reduce_min(min(lower_y,lower_y+lower_dy)), | 
| 147 |                             reduce_min(min(lower_z,lower_z+lower_dz))), | 
| 148 |                      Vec3fa(reduce_max(max(upper_x,upper_x+upper_dx)), | 
| 149 |                             reduce_max(max(upper_y,upper_y+upper_dy)), | 
| 150 |                             reduce_max(max(upper_z,upper_z+upper_dz)))); | 
| 151 |     } | 
| 152 |      | 
| 153 |     /*! Return bounding box of child i */ | 
| 154 |     __forceinline BBox3fa bounds(size_t i) const { | 
| 155 |       return merge(bounds0(i),bounds1(i)); | 
| 156 |     } | 
| 157 |      | 
| 158 |     /*! Return linear bounding box of child i */ | 
| 159 |     __forceinline LBBox3fa lbounds(size_t i) const { | 
| 160 |       return LBBox3fa(bounds0(i),bounds1(i)); | 
| 161 |     } | 
| 162 |      | 
| 163 |     /*! Return bounding box of child i at specified time */ | 
| 164 |     __forceinline BBox3fa bounds(size_t i, float time) const { | 
| 165 |       return lerp(bounds0(i),bounds1(i),time); | 
| 166 |     } | 
| 167 |      | 
| 168 |     /*! Returns the expected surface area when randomly sampling the time. */ | 
| 169 |     __forceinline float expectedHalfArea(size_t i) const { | 
| 170 |       return lbounds(i).expectedHalfArea(); | 
| 171 |     } | 
| 172 |      | 
| 173 |     /*! Returns the expected surface area when randomly sampling the time. */ | 
| 174 |     __forceinline float expectedHalfArea(size_t i, const BBox1f& t0t1) const { | 
| 175 |       return lbounds(i).expectedHalfArea(t0t1);  | 
| 176 |     } | 
| 177 |      | 
| 178 |     /*! swap two children of the node */ | 
| 179 |     __forceinline void swap(size_t i, size_t j) | 
| 180 |     { | 
| 181 |       assert(i<N && j<N); | 
| 182 |       std::swap(children[i],children[j]); | 
| 183 |        | 
| 184 |       std::swap(lower_x[i],lower_x[j]); | 
| 185 |       std::swap(upper_x[i],upper_x[j]); | 
| 186 |       std::swap(lower_y[i],lower_y[j]); | 
| 187 |       std::swap(upper_y[i],upper_y[j]); | 
| 188 |       std::swap(lower_z[i],lower_z[j]); | 
| 189 |       std::swap(upper_z[i],upper_z[j]); | 
| 190 |        | 
| 191 |       std::swap(lower_dx[i],lower_dx[j]); | 
| 192 |       std::swap(upper_dx[i],upper_dx[j]); | 
| 193 |       std::swap(lower_dy[i],lower_dy[j]); | 
| 194 |       std::swap(upper_dy[i],upper_dy[j]); | 
| 195 |       std::swap(lower_dz[i],lower_dz[j]); | 
| 196 |       std::swap(upper_dz[i],upper_dz[j]); | 
| 197 |     } | 
| 198 |  | 
| 199 |     /*! compacts a node (moves empty children to the end) */ | 
| 200 |     __forceinline static void compact(AABBNodeMB_t* a) | 
| 201 |     { | 
| 202 |       /* find right most filled node */ | 
| 203 |       ssize_t j=N; | 
| 204 |       for (j=j-1; j>=0; j--) | 
| 205 |         if (a->child(j) != NodeRef::emptyNode) | 
| 206 |           break; | 
| 207 |  | 
| 208 |       /* replace empty nodes with filled nodes */ | 
| 209 |       for (ssize_t i=0; i<j; i++) { | 
| 210 |         if (a->child(i) == NodeRef::emptyNode) { | 
| 211 |           a->swap(i,j); | 
| 212 |           for (j=j-1; j>i; j--) | 
| 213 |             if (a->child(j) != NodeRef::emptyNode) | 
| 214 |               break; | 
| 215 |         } | 
| 216 |       } | 
| 217 |     } | 
| 218 |      | 
| 219 |     /*! Returns reference to specified child */ | 
| 220 |     __forceinline       NodeRef& child(size_t i)       { assert(i<N); return children[i]; } | 
| 221 |     __forceinline const NodeRef& child(size_t i) const { assert(i<N); return children[i]; } | 
| 222 |      | 
| 223 |     /*! stream output operator */ | 
| 224 |     friend embree_ostream operator<<(embree_ostream cout, const AABBNodeMB_t& n)  | 
| 225 |     { | 
| 226 |       cout << "AABBNodeMB {"  << embree_endl; | 
| 227 |       for (size_t i=0; i<N; i++)  | 
| 228 |       { | 
| 229 |         const BBox3fa b0 = n.bounds0(i); | 
| 230 |         const BBox3fa b1 = n.bounds1(i); | 
| 231 |         cout << "  child"  << i << " { "  << embree_endl; | 
| 232 |         cout << "    bounds0 = "  << b0 << ", "  << embree_endl; | 
| 233 |         cout << "    bounds1 = "  << b1 << ", "  << embree_endl; | 
| 234 |         cout << "  }" ; | 
| 235 |       } | 
| 236 |       cout << "}" ; | 
| 237 |       return cout; | 
| 238 |     } | 
| 239 |      | 
| 240 |   public: | 
| 241 |     vfloat<N> lower_x;        //!< X dimension of lower bounds of all N children. | 
| 242 |     vfloat<N> upper_x;        //!< X dimension of upper bounds of all N children. | 
| 243 |     vfloat<N> lower_y;        //!< Y dimension of lower bounds of all N children. | 
| 244 |     vfloat<N> upper_y;        //!< Y dimension of upper bounds of all N children. | 
| 245 |     vfloat<N> lower_z;        //!< Z dimension of lower bounds of all N children. | 
| 246 |     vfloat<N> upper_z;        //!< Z dimension of upper bounds of all N children. | 
| 247 |      | 
| 248 |     vfloat<N> lower_dx;        //!< X dimension of lower bounds of all N children. | 
| 249 |     vfloat<N> upper_dx;        //!< X dimension of upper bounds of all N children. | 
| 250 |     vfloat<N> lower_dy;        //!< Y dimension of lower bounds of all N children. | 
| 251 |     vfloat<N> upper_dy;        //!< Y dimension of upper bounds of all N children. | 
| 252 |     vfloat<N> lower_dz;        //!< Z dimension of lower bounds of all N children. | 
| 253 |     vfloat<N> upper_dz;        //!< Z dimension of upper bounds of all N children. | 
| 254 |   }; | 
| 255 | } | 
| 256 |  |