Cycles: refactor culling code into utility class.
This commit is contained in:
parent
e8641d4474
commit
aea4ed00d5
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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],
|
||||
|
|
Loading…
Reference in New Issue