ClangFormat: apply to source, most of intern
[blender.git] / intern / cycles / blender / blender_object_cull.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 #include <cstdlib>
18
19 #include "render/camera.h"
20
21 #include "blender/blender_object_cull.h"
22
23 CCL_NAMESPACE_BEGIN
24
25 BlenderObjectCulling::BlenderObjectCulling(Scene *scene, BL::Scene &b_scene)
26     : use_scene_camera_cull_(false),
27       use_camera_cull_(false),
28       camera_cull_margin_(0.0f),
29       use_scene_distance_cull_(false),
30       use_distance_cull_(false),
31       distance_cull_margin_(0.0f)
32 {
33   if (b_scene.render().use_simplify()) {
34     PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
35
36     use_scene_camera_cull_ = scene->camera->type != CAMERA_PANORAMA &&
37                              !b_scene.render().use_multiview() &&
38                              get_boolean(cscene, "use_camera_cull");
39     use_scene_distance_cull_ = scene->camera->type != CAMERA_PANORAMA &&
40                                !b_scene.render().use_multiview() &&
41                                get_boolean(cscene, "use_distance_cull");
42
43     camera_cull_margin_ = get_float(cscene, "camera_cull_margin");
44     distance_cull_margin_ = get_float(cscene, "distance_cull_margin");
45
46     if (distance_cull_margin_ == 0.0f) {
47       use_scene_distance_cull_ = false;
48     }
49   }
50 }
51
52 void BlenderObjectCulling::init_object(Scene *scene, BL::Object &b_ob)
53 {
54   if (!use_scene_camera_cull_ && !use_scene_distance_cull_) {
55     return;
56   }
57
58   PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
59
60   use_camera_cull_ = use_scene_camera_cull_ && get_boolean(cobject, "use_camera_cull");
61   use_distance_cull_ = use_scene_distance_cull_ && get_boolean(cobject, "use_distance_cull");
62
63   if (use_camera_cull_ || use_distance_cull_) {
64     /* Need to have proper projection matrix. */
65     scene->camera->update(scene);
66   }
67 }
68
69 bool BlenderObjectCulling::test(Scene *scene, BL::Object &b_ob, Transform &tfm)
70 {
71   if (!use_camera_cull_ && !use_distance_cull_) {
72     return false;
73   }
74
75   /* Compute world space bounding box corners. */
76   float3 bb[8];
77   BL::Array<float, 24> boundbox = b_ob.bound_box();
78   for (int i = 0; i < 8; ++i) {
79     float3 p = make_float3(boundbox[3 * i + 0], boundbox[3 * i + 1], boundbox[3 * i + 2]);
80     bb[i] = transform_point(&tfm, p);
81   }
82
83   bool camera_culled = use_camera_cull_ && test_camera(scene, bb);
84   bool distance_culled = use_distance_cull_ && test_distance(scene, bb);
85
86   return ((camera_culled && distance_culled) || (camera_culled && !use_distance_cull_) ||
87           (distance_culled && !use_camera_cull_));
88 }
89
90 /* TODO(sergey): Not really optimal, consider approaches based on k-DOP in order
91  * to reduce number of objects which are wrongly considered visible.
92  */
93 bool BlenderObjectCulling::test_camera(Scene *scene, float3 bb[8])
94 {
95   Camera *cam = scene->camera;
96   const ProjectionTransform &worldtondc = cam->worldtondc;
97   float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
98          bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
99   bool all_behind = true;
100   for (int i = 0; i < 8; ++i) {
101     float3 p = bb[i];
102     float4 b = make_float4(p.x, p.y, p.z, 1.0f);
103     float4 c = make_float4(
104         dot(worldtondc.x, b), dot(worldtondc.y, b), dot(worldtondc.z, b), dot(worldtondc.w, b));
105     p = float4_to_float3(c / c.w);
106     if (c.z < 0.0f) {
107       p.x = 1.0f - p.x;
108       p.y = 1.0f - p.y;
109     }
110     if (c.z >= -camera_cull_margin_) {
111       all_behind = false;
112     }
113     bb_min = min(bb_min, p);
114     bb_max = max(bb_max, p);
115   }
116   if (all_behind) {
117     return true;
118   }
119   return (bb_min.x >= 1.0f + camera_cull_margin_ || bb_min.y >= 1.0f + camera_cull_margin_ ||
120           bb_max.x <= -camera_cull_margin_ || bb_max.y <= -camera_cull_margin_);
121 }
122
123 bool BlenderObjectCulling::test_distance(Scene *scene, float3 bb[8])
124 {
125   float3 camera_position = transform_get_column(&scene->camera->matrix, 3);
126   float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
127          bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
128
129   /* Find min & max points for x & y & z on bounding box */
130   for (int i = 0; i < 8; ++i) {
131     float3 p = bb[i];
132     bb_min = min(bb_min, p);
133     bb_max = max(bb_max, p);
134   }
135
136   float3 closest_point = max(min(bb_max, camera_position), bb_min);
137   return (len_squared(camera_position - closest_point) >
138           distance_cull_margin_ * distance_cull_margin_);
139 }
140
141 CCL_NAMESPACE_END