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