Cycles: refactor culling code into utility class.
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Sat, 12 Nov 2016 23:45:16 +0000 (00:45 +0100)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Sun, 20 Nov 2016 14:25:47 +0000 (15:25 +0100)
intern/cycles/blender/blender_object.cpp
intern/cycles/blender/blender_sync.h

index 84701a22d0a4b61b2382199cbfdd066b414cf72d..681a22e1f07d1693ff6e15e586b410663a10acfb 100644 (file)
@@ -88,6 +88,143 @@ static uint object_ray_visibility(BL::Object& b_ob)
        return flag;
 }
 
+/* Culling */
+
+class BlenderObjectCulling
+{
+public:
+       BlenderObjectCulling(Scene *scene, BL::Scene& b_scene)
+       : use_scene_camera_cull(false),
+         use_camera_cull(false),
+         camera_cull_margin(0.0f),
+         use_scene_distance_cull(false),
+         use_distance_cull(false),
+         distance_cull_margin(0.0f)
+       {
+               if(b_scene.render().use_simplify()) {
+                       PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+
+                       use_scene_camera_cull = scene->camera->type != CAMERA_PANORAMA &&
+                                                                       !b_scene.render().use_multiview() &&
+                                                                       get_boolean(cscene, "use_camera_cull");
+                       use_scene_distance_cull = scene->camera->type != CAMERA_PANORAMA &&
+                                                                         !b_scene.render().use_multiview() &&
+                                                                         get_boolean(cscene, "use_distance_cull");
+
+                       camera_cull_margin = get_float(cscene, "camera_cull_margin");
+                       distance_cull_margin = get_float(cscene, "distance_cull_margin");
+
+                       if (distance_cull_margin == 0.0f) {
+                               use_scene_distance_cull = false;
+                       }
+               }
+       }
+
+       void init_object(Scene *scene, BL::Object& b_ob)
+       {
+               if(!use_scene_camera_cull && !use_scene_distance_cull) {
+                       return;
+               }
+
+               PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
+
+               use_camera_cull = use_scene_camera_cull && get_boolean(cobject, "use_camera_cull");
+               use_distance_cull = use_scene_distance_cull && get_boolean(cobject, "use_distance_cull");
+
+               if(use_camera_cull || use_distance_cull) {
+                       /* Need to have proper projection matrix. */
+                       scene->camera->update();
+               }
+       }
+
+       bool test(Scene *scene, BL::Object& b_ob, Transform& tfm)
+       {
+               if(!use_camera_cull && !use_distance_cull) {
+                       return false;
+               }
+
+               /* Compute world space bounding box corners. */
+               float3 bb[8];
+               BL::Array<float, 24> boundbox = b_ob.bound_box();
+               for(int i = 0; i < 8; ++i) {
+                       float3 p = make_float3(boundbox[3 * i + 0],
+                                                                  boundbox[3 * i + 1],
+                                                                  boundbox[3 * i + 2]);
+                       bb[i] = transform_point(&tfm, p);
+               }
+
+               bool camera_culled = use_camera_cull && test_camera(scene, bb);
+               bool distance_culled = use_distance_cull && test_distance(scene, bb);
+
+               return ((camera_culled && distance_culled) ||
+                       (camera_culled && !use_distance_cull) ||
+                       (distance_culled && !use_camera_cull));
+       }
+
+private:
+       /* TODO(sergey): Not really optimal, consider approaches based on k-DOP in order
+        * to reduce number of objects which are wrongly considered visible.
+        */
+       bool test_camera(Scene *scene, float3 bb[8])
+       {
+               Camera *cam = scene->camera;
+               Transform& worldtondc = cam->worldtondc;
+               float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
+                          bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+               bool all_behind = true;
+               for(int i = 0; i < 8; ++i) {
+                       float3 p = bb[i];
+                       float4 b = make_float4(p.x, p.y, p.z, 1.0f);
+                       float4 c = make_float4(dot(worldtondc.x, b),
+                                              dot(worldtondc.y, b),
+                                              dot(worldtondc.z, b),
+                                              dot(worldtondc.w, b));
+                       p = float4_to_float3(c / c.w);
+                       if(c.z < 0.0f) {
+                               p.x = 1.0f - p.x;
+                               p.y = 1.0f - p.y;
+                       }
+                       if(c.z >= -camera_cull_margin) {
+                               all_behind = false;
+                       }
+                       bb_min = min(bb_min, p);
+                       bb_max = max(bb_max, p);
+               }
+               if(all_behind) {
+                       return true;
+               }
+               return (bb_min.x >= 1.0f + camera_cull_margin ||
+                       bb_min.y >= 1.0f + camera_cull_margin ||
+                       bb_max.x <= -camera_cull_margin ||
+                       bb_max.y <= -camera_cull_margin);
+       }
+
+       bool test_distance(Scene *scene, float3 bb[8])
+       {
+               float3 camera_position = transform_get_column(&scene->camera->matrix, 3);
+               float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
+                          bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+
+               /* Find min & max points for x & y & z on bounding box */
+               for(int i = 0; i < 8; ++i) {
+                       float3 p = bb[i];
+                       bb_min = min(bb_min, p);
+                       bb_max = max(bb_max, p);
+               }
+
+               float3 closest_point = max(min(bb_max,camera_position),bb_min);
+               return (len_squared(camera_position - closest_point) >
+                       distance_cull_margin * distance_cull_margin);
+       }
+
+       bool use_scene_camera_cull;
+       bool use_camera_cull;
+       float camera_cull_margin;
+       bool use_scene_distance_cull;
+       bool use_distance_cull;
+       float distance_cull_margin;
+};
+
 /* Light */
 
 void BlenderSync::sync_light(BL::Object& b_parent,
@@ -235,80 +372,6 @@ void BlenderSync::sync_background_light(bool use_portal)
 
 /* Object */
 
-/* TODO(sergey): Not really optimal, consider approaches based on k-DOP in order
- * to reduce number of objects which are wrongly considered visible.
- */
-static bool object_boundbox_clip(Scene *scene,
-                                 BL::Object& b_ob,
-                                 Transform& tfm,
-                                 float margin)
-{
-       Camera *cam = scene->camera;
-       Transform& worldtondc = cam->worldtondc;
-       BL::Array<float, 24> boundbox = b_ob.bound_box();
-       float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
-              bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
-       bool all_behind = true;
-       for(int i = 0; i < 8; ++i) {
-               float3 p = make_float3(boundbox[3 * i + 0],
-                                      boundbox[3 * i + 1],
-                                      boundbox[3 * i + 2]);
-               p = transform_point(&tfm, p);
-
-               float4 b = make_float4(p.x, p.y, p.z, 1.0f);
-               float4 c = make_float4(dot(worldtondc.x, b),
-                                      dot(worldtondc.y, b),
-                                      dot(worldtondc.z, b),
-                                      dot(worldtondc.w, b));
-               p = float4_to_float3(c / c.w);
-               if(c.z < 0.0f) {
-                       p.x = 1.0f - p.x;
-                       p.y = 1.0f - p.y;
-               }
-               if(c.z >= -margin) {
-                       all_behind = false;
-               }
-               bb_min = min(bb_min, p);
-               bb_max = max(bb_max, p);
-       }
-       if(!all_behind) {
-               if(bb_min.x >= 1.0f + margin ||
-                  bb_min.y >= 1.0f + margin ||
-                  bb_max.x <= -margin ||
-                  bb_max.y <= -margin)
-               {
-                       return true;
-               }
-               return false;
-       }
-       return true;
-}
-
-static bool object_distance_clip(Scene *scene,
-                                 BL::Object& b_ob,
-                                 Transform& tfm,
-                                 float margin)
-{
-       BL::Array<float, 24> boundbox = b_ob.bound_box();
-       float3 camera_position = transform_get_column(&scene->camera->matrix, 3);
-
-       float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
-              bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
-
-       /* Find min & max points for x & y & z on bounding box */
-       for(int i = 0; i < 8; ++i) {
-               float3 p = make_float3(boundbox[3 * i + 0],
-                                      boundbox[3 * i + 1],
-                                      boundbox[3 * i + 2]);
-               p = transform_point(&tfm, p);
-               bb_min = min(bb_min, p);
-               bb_max = max(bb_max, p);
-       }
-
-       float3 closest_point = max(min(bb_max,camera_position),bb_min);
-       return (len_squared(camera_position - closest_point) > margin * margin);
-}
-
 Object *BlenderSync::sync_object(BL::Object& b_parent,
                                  int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
                                  BL::DupliObject& b_dupli_ob,
@@ -316,10 +379,7 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
                                  uint layer_flag,
                                  float motion_time,
                                  bool hide_tris,
-                                 bool use_camera_cull,
-                                 bool use_distance_cull,
-                                 float camera_cull_margin,
-                                 float distance_cull_margin,
+                                 BlenderObjectCulling& culling,
                                  bool *use_portal)
 {
        BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
@@ -335,17 +395,12 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
        }
 
        /* only interested in object that we can create meshes from */
-       if(!object_is_mesh(b_ob))
+       if(!object_is_mesh(b_ob)) {
                return NULL;
+       }
 
        /* Perform object culling. */
-       bool camera_culled = use_camera_cull && object_boundbox_clip(scene, b_ob, tfm, camera_cull_margin);
-       bool distance_culled = use_distance_cull && object_distance_clip(scene, b_ob, tfm, distance_cull_margin);
-
-       if ((camera_culled && distance_culled) ||
-           (camera_culled && !use_distance_cull) ||
-           (distance_culled && !use_camera_cull))
-       {
+       if(culling.test(scene, b_ob, tfm)) {
                return NULL;
        }
 
@@ -581,28 +636,8 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time)
                mesh_motion_synced.clear();
        }
 
-       bool allow_camera_cull = false;
-       bool allow_distance_cull = false;
-       float camera_cull_margin = 0.0f;
-       float distance_cull_margin = 0.0f;
-       if(b_scene.render().use_simplify()) {
-               PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
-               allow_camera_cull = scene->camera->type != CAMERA_PANORAMA &&
-                                   !b_scene.render().use_multiview() &&
-                                   get_boolean(cscene, "use_camera_cull");
-               allow_distance_cull = scene->camera->type != CAMERA_PANORAMA &&
-                                   !b_scene.render().use_multiview() &&
-                                   get_boolean(cscene, "use_distance_cull");
-               if(allow_camera_cull) {
-                       camera_cull_margin = get_float(cscene, "camera_cull_margin");
-               }
-               if(allow_distance_cull) {
-                       distance_cull_margin = get_float(cscene, "distance_cull_margin");
-                       if (distance_cull_margin == 0.0f) {
-                               allow_distance_cull = false;
-                       }
-               }
-       }
+       /* initialize culling */
+       BlenderObjectCulling culling(scene, b_scene);
 
        /* object loop */
        BL::Scene::object_bases_iterator b_base;
@@ -634,13 +669,9 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time)
                        if(!hide) {
                                progress.set_sync_status("Synchronizing object", b_ob.name());
 
-                               PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
-                               bool use_camera_cull = allow_camera_cull && get_boolean(cobject, "use_camera_cull");
-                               bool use_distance_cull = allow_distance_cull && get_boolean(cobject, "use_distance_cull");
-                               if(use_camera_cull || use_distance_cull) {
-                                       /* Need to have proper projection matrix. */
-                                       scene->camera->update();
-                               }
+                               /* load per-object culling data */
+                               culling.init_object(scene, b_ob);
+
                                if(b_ob.is_duplicator() && !object_render_hide_duplis(b_ob)) {
                                        /* dupli objects */
                                        b_ob.dupli_list_create(b_scene, dupli_settings);
@@ -667,10 +698,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time)
                                                                                     ob_layer,
                                                                                     motion_time,
                                                                                     hide_tris,
-                                                                                    use_camera_cull,
-                                                                                    use_distance_cull,
-                                                                                    camera_cull_margin,
-                                                                                    distance_cull_margin,
+                                                                                    culling,
                                                                                     &use_portal);
 
                                                        /* sync possible particle data, note particle_id
@@ -699,10 +727,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time)
                                                    ob_layer,
                                                    motion_time,
                                                    hide_tris,
-                                                   use_camera_cull,
-                                                   use_distance_cull,
-                                                   camera_cull_margin,
-                                                   distance_cull_margin,
+                                                   culling,
                                                    &use_portal);
                                }
                        }
index aa6b0d66e80e80bce5191b6f346ef6ae8a3bfda2..6984cbda2596787ace976f5e0a2e5394deabe366 100644 (file)
@@ -35,6 +35,7 @@
 CCL_NAMESPACE_BEGIN
 
 class Background;
+class BlenderObjectCulling;
 class Camera;
 class Film;
 class Light;
@@ -122,10 +123,7 @@ private:
                            uint layer_flag,
                            float motion_time,
                            bool hide_tris,
-                           bool use_camera_cull,
-                           bool use_distance_cull,
-                           float camera_cull_margin,
-                           float distance_cull_margin,
+                           BlenderObjectCulling& culling,
                            bool *use_portal);
        void sync_light(BL::Object& b_parent,
                        int persistent_id[OBJECT_PERSISTENT_ID_SIZE],