1 /*
2  * Copyright 2011-2016 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "bvh/bvh_unaligned.h"
18 
19 #include "render/hair.h"
20 #include "render/object.h"
21 
22 #include "bvh/bvh_binning.h"
23 #include "bvh_params.h"
24 
25 #include "util/util_boundbox.h"
26 #include "util/util_transform.h"
27 
28 CCL_NAMESPACE_BEGIN
29 
BVHUnaligned(const vector<Object * > & objects)30 BVHUnaligned::BVHUnaligned(const vector<Object *> &objects) : objects_(objects)
31 {
32 }
33 
compute_aligned_space(const BVHObjectBinning & range,const BVHReference * references) const34 Transform BVHUnaligned::compute_aligned_space(const BVHObjectBinning &range,
35                                               const BVHReference *references) const
36 {
37   for (int i = range.start(); i < range.end(); ++i) {
38     const BVHReference &ref = references[i];
39     Transform aligned_space;
40     /* Use first primitive which defines correct direction to define
41      * the orientation space.
42      */
43     if (compute_aligned_space(ref, &aligned_space)) {
44       return aligned_space;
45     }
46   }
47   return transform_identity();
48 }
49 
compute_aligned_space(const BVHRange & range,const BVHReference * references) const50 Transform BVHUnaligned::compute_aligned_space(const BVHRange &range,
51                                               const BVHReference *references) const
52 {
53   for (int i = range.start(); i < range.end(); ++i) {
54     const BVHReference &ref = references[i];
55     Transform aligned_space;
56     /* Use first primitive which defines correct direction to define
57      * the orientation space.
58      */
59     if (compute_aligned_space(ref, &aligned_space)) {
60       return aligned_space;
61     }
62   }
63   return transform_identity();
64 }
65 
compute_aligned_space(const BVHReference & ref,Transform * aligned_space) const66 bool BVHUnaligned::compute_aligned_space(const BVHReference &ref, Transform *aligned_space) const
67 {
68   const Object *object = objects_[ref.prim_object()];
69   const int packed_type = ref.prim_type();
70   const int type = (packed_type & PRIMITIVE_ALL);
71   /* No motion blur curves here, we can't fit them to aligned boxes well. */
72   if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_CURVE_THICK)) {
73     const int curve_index = ref.prim_index();
74     const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
75     const Hair *hair = static_cast<const Hair *>(object->geometry);
76     const Hair::Curve &curve = hair->get_curve(curve_index);
77     const int key = curve.first_key + segment;
78     const float3 v1 = hair->curve_keys[key], v2 = hair->curve_keys[key + 1];
79     float length;
80     const float3 axis = normalize_len(v2 - v1, &length);
81     if (length > 1e-6f) {
82       *aligned_space = make_transform_frame(axis);
83       return true;
84     }
85   }
86   *aligned_space = transform_identity();
87   return false;
88 }
89 
compute_aligned_prim_boundbox(const BVHReference & prim,const Transform & aligned_space) const90 BoundBox BVHUnaligned::compute_aligned_prim_boundbox(const BVHReference &prim,
91                                                      const Transform &aligned_space) const
92 {
93   BoundBox bounds = BoundBox::empty;
94   const Object *object = objects_[prim.prim_object()];
95   const int packed_type = prim.prim_type();
96   const int type = (packed_type & PRIMITIVE_ALL);
97   /* No motion blur curves here, we can't fit them to aligned boxes well. */
98   if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_CURVE_THICK)) {
99     const int curve_index = prim.prim_index();
100     const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
101     const Hair *hair = static_cast<const Hair *>(object->geometry);
102     const Hair::Curve &curve = hair->get_curve(curve_index);
103     curve.bounds_grow(
104         segment, &hair->curve_keys[0], &hair->curve_radius[0], aligned_space, bounds);
105   }
106   else {
107     bounds = prim.bounds().transformed(&aligned_space);
108   }
109   return bounds;
110 }
111 
compute_aligned_boundbox(const BVHObjectBinning & range,const BVHReference * references,const Transform & aligned_space,BoundBox * cent_bounds) const112 BoundBox BVHUnaligned::compute_aligned_boundbox(const BVHObjectBinning &range,
113                                                 const BVHReference *references,
114                                                 const Transform &aligned_space,
115                                                 BoundBox *cent_bounds) const
116 {
117   BoundBox bounds = BoundBox::empty;
118   if (cent_bounds != NULL) {
119     *cent_bounds = BoundBox::empty;
120   }
121   for (int i = range.start(); i < range.end(); ++i) {
122     const BVHReference &ref = references[i];
123     BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space);
124     bounds.grow(ref_bounds);
125     if (cent_bounds != NULL) {
126       cent_bounds->grow(ref_bounds.center2());
127     }
128   }
129   return bounds;
130 }
131 
compute_aligned_boundbox(const BVHRange & range,const BVHReference * references,const Transform & aligned_space,BoundBox * cent_bounds) const132 BoundBox BVHUnaligned::compute_aligned_boundbox(const BVHRange &range,
133                                                 const BVHReference *references,
134                                                 const Transform &aligned_space,
135                                                 BoundBox *cent_bounds) const
136 {
137   BoundBox bounds = BoundBox::empty;
138   if (cent_bounds != NULL) {
139     *cent_bounds = BoundBox::empty;
140   }
141   for (int i = range.start(); i < range.end(); ++i) {
142     const BVHReference &ref = references[i];
143     BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space);
144     bounds.grow(ref_bounds);
145     if (cent_bounds != NULL) {
146       cent_bounds->grow(ref_bounds.center2());
147     }
148   }
149   return bounds;
150 }
151 
compute_node_transform(const BoundBox & bounds,const Transform & aligned_space)152 Transform BVHUnaligned::compute_node_transform(const BoundBox &bounds,
153                                                const Transform &aligned_space)
154 {
155   Transform space = aligned_space;
156   space.x.w -= bounds.min.x;
157   space.y.w -= bounds.min.y;
158   space.z.w -= bounds.min.z;
159   float3 dim = bounds.max - bounds.min;
160   return transform_scale(
161              1.0f / max(1e-18f, dim.x), 1.0f / max(1e-18f, dim.y), 1.0f / max(1e-18f, dim.z)) *
162          space;
163 }
164 
165 CCL_NAMESPACE_END
166