Fix T49818: Crash when rendering with motion blur
[blender.git] / intern / cycles / bvh / bvh_split.h
index 1f4befbe8e2674f106b1a5812a34a7172af3b5f9..dbdb51f1a5ba9c3808754bd2d45eb3d551f759d4 100644 (file)
@@ -24,6 +24,7 @@
 CCL_NAMESPACE_BEGIN
 
 class BVHBuild;
+struct Transform;
 
 /* Object Split */
 
@@ -37,9 +38,34 @@ public:
        BoundBox right_bounds;
 
        BVHObjectSplit() {}
-       BVHObjectSplit(BVHBuild *builder, const BVHRange& range, float nodeSAH);
+       BVHObjectSplit(BVHBuild *builder,
+                      BVHSpatialStorage *storage,
+                      const BVHRange& range,
+                      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(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 */
@@ -51,11 +77,102 @@ public:
        int dim;
        float pos;
 
-       BVHSpatialSplit() : sah(FLT_MAX), dim(0), pos(0.0f) {}
-       BVHSpatialSplit(BVHBuild *builder, const BVHRange& range, float nodeSAH);
+       BVHSpatialSplit() : sah(FLT_MAX),
+                           dim(0),
+                           pos(0.0f),
+                           storage_(NULL),
+                           references_(NULL) {}
+       BVHSpatialSplit(const BVHBuild& builder,
+                       BVHSpatialStorage *storage,
+                       const BVHRange& range,
+                       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(BVHBuild *builder, BVHRange& left, BVHRange& right, const BVHRange& range);
-       void split_reference(BVHBuild *builder, BVHReference& left, BVHReference& right, const BVHReference& ref, int dim, float pos);
+       void split_reference(const BVHBuild& builder,
+                            BVHReference& left,
+                            BVHReference& right,
+                            const BVHReference& ref,
+                            int dim,
+                            float pos);
+
+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.
+        *
+        * Operates directly with primitive specified by it's index, reused by higher
+        * level splitting functions.
+        */
+       void split_triangle_primitive(const Mesh *mesh,
+                                     const Transform *tfm,
+                                     int prim_index,
+                                     int dim,
+                                     float pos,
+                                     BoundBox& left_bounds,
+                                     BoundBox& right_bounds);
+       void split_curve_primitive(const Mesh *mesh,
+                                  const Transform *tfm,
+                                  int prim_index,
+                                  int segment_index,
+                                  int dim,
+                                  float pos,
+                                  BoundBox& left_bounds,
+                                  BoundBox& right_bounds);
+
+       /* Lower-level functions which calculates boundaries of left and right nodes
+        * needed for spatial split.
+        *
+        * Operates with BVHReference, internally uses lower level API functions.
+        */
+       void split_triangle_reference(const BVHReference& ref,
+                                     const Mesh *mesh,
+                                     int dim,
+                                     float pos,
+                                     BoundBox& left_bounds,
+                                     BoundBox& right_bounds);
+       void split_curve_reference(const BVHReference& ref,
+                                  const Mesh *mesh,
+                                  int dim,
+                                  float pos,
+                                  BoundBox& left_bounds,
+                                  BoundBox& right_bounds);
+       void split_object_reference(const Object *object,
+                                   int dim,
+                                   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 */
@@ -72,39 +189,74 @@ public:
 
        bool no_split;
 
-       __forceinline BVHMixedSplit(BVHBuild *builder, const BVHRange& range, int level)
+       BoundBox bounds;
+
+       BVHMixedSplit() {}
+
+       __forceinline BVHMixedSplit(BVHBuild *builder,
+                                   BVHSpatialStorage *storage,
+                                   const BVHRange& range,
+                                   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.triangle_cost(range.size());
+               leafSAH = area * builder->params.primitive_cost(range.size());
                nodeSAH = area * builder->params.node_cost(2);
 
-               object = BVHObjectSplit(builder, 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, 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 && range.size() <= builder->params.max_leaf_size);
+               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__ */
-