diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2016-11-13 02:45:16 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2016-11-20 17:25:47 +0300 |
commit | aea4ed00d5a7fe661f12fbe1a16ad6574d9be8ea (patch) | |
tree | ad892c3792071b7fa5515cdc277a865c58c39516 /intern/cycles | |
parent | e8641d44740ed0e2c4a2a7bc4fb61aacec203c48 (diff) |
Cycles: refactor culling code into utility class.
Diffstat (limited to 'intern/cycles')
-rw-r--r-- | intern/cycles/blender/blender_object.cpp | 271 | ||||
-rw-r--r-- | intern/cycles/blender/blender_sync.h | 6 |
2 files changed, 150 insertions, 127 deletions
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 84701a22d0a..681a22e1f07 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -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); } } diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index aa6b0d66e80..6984cbda259 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -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], |