Cycles: Implement unaligned nodes BVH builder
[blender.git] / intern / cycles / bvh / bvh_unaligned.cpp
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
18 #include "bvh_unaligned.h"
19
20 #include "mesh.h"
21 #include "object.h"
22
23 #include "bvh_binning.h"
24 #include "bvh_params.h"
25
26 #include "util_boundbox.h"
27 #include "util_debug.h"
28 #include "util_transform.h"
29
30 CCL_NAMESPACE_BEGIN
31
32
33 BVHUnaligned::BVHUnaligned(const vector<Object*>& objects)
34         : objects_(objects)
35 {
36 }
37
38 Transform BVHUnaligned::compute_aligned_space(
39         const BVHObjectBinning& range,
40         const BVHReference *references) const
41 {
42         for(int i = range.start(); i < range.end(); ++i) {
43                 const BVHReference& ref = references[i];
44                 Transform aligned_space;
45                 /* Use first primitive which defines correct direction to define
46                  * the orientation space.
47                  */
48                 if(compute_aligned_space(ref, &aligned_space)) {
49                         return aligned_space;
50                 }
51         }
52         return transform_identity();
53 }
54
55 Transform BVHUnaligned::compute_aligned_space(
56         const BVHRange& range,
57         const BVHReference *references) const
58 {
59         for(int i = range.start(); i < range.end(); ++i) {
60                 const BVHReference& ref = references[i];
61                 Transform aligned_space;
62                 /* Use first primitive which defines correct direction to define
63                  * the orientation space.
64                  */
65                 if(compute_aligned_space(ref, &aligned_space)) {
66                         return aligned_space;
67                 }
68         }
69         return transform_identity();
70 }
71
72 bool BVHUnaligned::compute_aligned_space(const BVHReference& ref,
73                                          Transform *aligned_space) const
74 {
75         const Object *object = objects_[ref.prim_object()];
76         const int packed_type = ref.prim_type();
77         const int type = (packed_type & PRIMITIVE_ALL);
78         if(type & PRIMITIVE_CURVE) {
79                 const int curve_index = ref.prim_index();
80                 const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
81                 const Mesh *mesh = object->mesh;
82                 const Mesh::Curve& curve = mesh->get_curve(curve_index);
83                 const int key = curve.first_key + segment;
84                 const float3 v1 = mesh->curve_keys[key],
85                              v2 = mesh->curve_keys[key + 1];
86                 float length;
87                 const float3 axis = normalize_len(v2 - v1, &length);
88                 if(length > 1e-6f) {
89                         *aligned_space = make_transform_frame(axis);
90                         return true;
91                 }
92         }
93         *aligned_space = transform_identity();
94         return false;
95 }
96
97 BoundBox BVHUnaligned::compute_aligned_prim_boundbox(
98         const BVHReference& prim,
99         const Transform& aligned_space) const
100 {
101         BoundBox bounds = BoundBox::empty;
102         const Object *object = objects_[prim.prim_object()];
103         const int packed_type = prim.prim_type();
104         const int type = (packed_type & PRIMITIVE_ALL);
105         if(type & PRIMITIVE_CURVE) {
106                 const int curve_index = prim.prim_index();
107                 const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
108                 const Mesh *mesh = object->mesh;
109                 const Mesh::Curve& curve = mesh->get_curve(curve_index);
110                 curve.bounds_grow(segment,
111                                   &mesh->curve_keys[0],
112                                   &mesh->curve_radius[0],
113                                   aligned_space,
114                                   bounds);
115         }
116         else {
117                 bounds = prim.bounds().transformed(&aligned_space);
118         }
119         return bounds;
120 }
121
122 BoundBox BVHUnaligned::compute_aligned_boundbox(
123         const BVHObjectBinning& range,
124         const BVHReference *references,
125         const Transform& aligned_space,
126         BoundBox *cent_bounds) const
127 {
128         BoundBox bounds = BoundBox::empty;
129         if(cent_bounds != NULL) {
130                 *cent_bounds = BoundBox::empty;
131         }
132         for(int i = range.start(); i < range.end(); ++i) {
133                 const BVHReference& ref = references[i];
134                 BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space);
135                 bounds.grow(ref_bounds);
136                 if(cent_bounds != NULL) {
137                         cent_bounds->grow(ref_bounds.center2());
138                 }
139         }
140         return bounds;
141 }
142
143 BoundBox BVHUnaligned::compute_aligned_boundbox(
144         const BVHRange& range,
145         const BVHReference *references,
146         const Transform& aligned_space,
147         BoundBox *cent_bounds) const
148 {
149         BoundBox bounds = BoundBox::empty;
150         if(cent_bounds != NULL) {
151                 *cent_bounds = BoundBox::empty;
152         }
153         for(int i = range.start(); i < range.end(); ++i) {
154                 const BVHReference& ref = references[i];
155                 BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space);
156                 bounds.grow(ref_bounds);
157                 if(cent_bounds != NULL) {
158                         cent_bounds->grow(ref_bounds.center2());
159                 }
160         }
161         return bounds;
162 }
163
164 Transform BVHUnaligned::compute_node_transform(
165         const BoundBox& bounds,
166         const Transform& aligned_space)
167 {
168         Transform space = aligned_space;
169         space.x.w -= bounds.min.x;
170         space.y.w -= bounds.min.y;
171         space.z.w -= bounds.min.z;
172         float3 dim = bounds.max - bounds.min;
173         return transform_scale(1.0f / max(1e-18f, dim.x),
174                                1.0f / max(1e-18f, dim.y),
175                                1.0f / max(1e-18f, dim.z)) * space;
176 }
177
178 CCL_NAMESPACE_END