Fix T49818: Crash when rendering with motion blur
[blender.git] / intern / cycles / bvh / bvh_split.h
index cc61899c9b5361d6597dfb2b81249eaffb6fd673..dbdb51f1a5ba9c3808754bd2d45eb3d551f759d4 100644 (file)
@@ -24,6 +24,7 @@
 CCL_NAMESPACE_BEGIN
 
 class BVHBuild;
+struct Transform;
 
 /* Object Split */
 
@@ -40,15 +41,31 @@ public:
        BVHObjectSplit(BVHBuild *builder,
                       BVHSpatialStorage *storage,
                       const BVHRange& range,
-                      float nodeSAH);
+                      vector<BVHReference> *references,
+                      float nodeSAH,
+                      const BVHUnaligned *unaligned_heuristic = NULL,
+                      const Transform *aligned_space = NULL);
 
-       void split(BVHBuild *builder,
-                  BVHRange& left,
+       void split(BVHRange& left,
                   BVHRange& right,
                   const BVHRange& range);
 
 protected:
        BVHSpatialStorage *storage_;
+       vector<BVHReference> *references_;
+       const BVHUnaligned *unaligned_heuristic_;
+       const Transform *aligned_space_;
+
+       __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const
+       {
+               if(aligned_space_ == NULL) {
+                       return prim.bounds();
+               }
+               else {
+                       return unaligned_heuristic_->compute_aligned_prim_boundbox(
+                               prim, *aligned_space_);
+               }
+       }
 };
 
 /* Spatial Split */
@@ -60,14 +77,25 @@ public:
        int dim;
        float pos;
 
-       BVHSpatialSplit() : sah(FLT_MAX), dim(0), pos(0.0f) {}
-       BVHSpatialSplit(BVHBuild *builder,
+       BVHSpatialSplit() : sah(FLT_MAX),
+                           dim(0),
+                           pos(0.0f),
+                           storage_(NULL),
+                           references_(NULL) {}
+       BVHSpatialSplit(const BVHBuild& builder,
                        BVHSpatialStorage *storage,
                        const BVHRange& range,
-                       float nodeSAH);
+                       vector<BVHReference> *references,
+                       float nodeSAH,
+                       const BVHUnaligned *unaligned_heuristic = NULL,
+                       const Transform *aligned_space = NULL);
 
-       void split(BVHBuild *builder, BVHRange& left, BVHRange& right, const BVHRange& range);
-       void split_reference(BVHBuild *builder,
+       void split(BVHBuild *builder,
+                  BVHRange& left,
+                  BVHRange& right,
+                  const BVHRange& range);
+
+       void split_reference(const BVHBuild& builder,
                             BVHReference& left,
                             BVHReference& right,
                             const BVHReference& ref,
@@ -76,6 +104,9 @@ public:
 
 protected:
        BVHSpatialStorage *storage_;
+       vector<BVHReference> *references_;
+       const BVHUnaligned *unaligned_heuristic_;
+       const Transform *aligned_space_;
 
        /* Lower-level functions which calculates boundaries of left and right nodes
         * needed for spatial split.
@@ -121,6 +152,27 @@ protected:
                                    float pos,
                                    BoundBox& left_bounds,
                                    BoundBox& right_bounds);
+
+       __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const
+       {
+               if(aligned_space_ == NULL) {
+                       return prim.bounds();
+               }
+               else {
+                       return unaligned_heuristic_->compute_aligned_prim_boundbox(
+                               prim, *aligned_space_);
+               }
+       }
+
+       __forceinline float3 get_unaligned_point(const float3& point) const
+       {
+               if(aligned_space_ == NULL) {
+                       return point;
+               }
+               else {
+                       return transform_point(aligned_space_, point);
+               }
+       }
 };
 
 /* Mixed Object-Spatial Split */
@@ -137,42 +189,74 @@ public:
 
        bool no_split;
 
+       BoundBox bounds;
+
+       BVHMixedSplit() {}
+
        __forceinline BVHMixedSplit(BVHBuild *builder,
                                    BVHSpatialStorage *storage,
                                    const BVHRange& range,
-                                   int level)
+                                   vector<BVHReference> *references,
+                                   int level,
+                                   const BVHUnaligned *unaligned_heuristic = NULL,
+                                   const Transform *aligned_space = NULL)
        {
+               if(aligned_space == NULL) {
+                       bounds = range.bounds();
+               }
+               else {
+                       bounds = unaligned_heuristic->compute_aligned_boundbox(
+                               range,
+                               &references->at(0),
+                               *aligned_space);
+               }
                /* find split candidates. */
-               float area = range.bounds().safe_area();
+               float area = bounds.safe_area();
 
                leafSAH = area * builder->params.primitive_cost(range.size());
                nodeSAH = area * builder->params.node_cost(2);
 
-               object = BVHObjectSplit(builder, storage, range, nodeSAH);
+               object = BVHObjectSplit(builder,
+                                       storage,
+                                       range,
+                                       references,
+                                       nodeSAH,
+                                       unaligned_heuristic,
+                                       aligned_space);
 
                if(builder->params.use_spatial_split && level < BVHParams::MAX_SPATIAL_DEPTH) {
                        BoundBox overlap = object.left_bounds;
                        overlap.intersect(object.right_bounds);
 
-                       if(overlap.safe_area() >= builder->spatial_min_overlap)
-                               spatial = BVHSpatialSplit(builder, storage, range, nodeSAH);
+                       if(overlap.safe_area() >= builder->spatial_min_overlap) {
+                               spatial = BVHSpatialSplit(*builder,
+                                                         storage,
+                                                         range,
+                                                         references,
+                                                         nodeSAH,
+                                                         unaligned_heuristic,
+                                                         aligned_space);
+                       }
                }
 
                /* leaf SAH is the lowest => create leaf. */
                minSAH = min(min(leafSAH, object.sah), spatial.sah);
-               no_split = (minSAH == leafSAH && builder->range_within_max_leaf_size(range));
+               no_split = (minSAH == leafSAH &&
+                           builder->range_within_max_leaf_size(range, *references));
        }
 
-       __forceinline void split(BVHBuild *builder, BVHRange& left, BVHRange& right, const BVHRange& range)
+       __forceinline void split(BVHBuild *builder,
+                                BVHRange& left,
+                                BVHRange& right,
+                                const BVHRange& range)
        {
                if(builder->params.use_spatial_split && minSAH == spatial.sah)
                        spatial.split(builder, left, right, range);
                if(!left.size() || !right.size())
-                       object.split(builder, left, right, range);
+                       object.split(left, right, range);
        }
 };
 
 CCL_NAMESPACE_END
 
 #endif /* __BVH_SPLIT_H__ */
-