Cycles: Add option to split triangle motion primitives by time steps
authorSergey Sharybin <sergey.vfx@gmail.com>
Tue, 17 Jan 2017 14:13:01 +0000 (15:13 +0100)
committerSergey Sharybin <sergey.vfx@gmail.com>
Fri, 20 Jan 2017 11:46:18 +0000 (12:46 +0100)
Similar to the previous commit, the statistics goes as:

BVH Steps     Render time (sec)       Memory usage (MB)
    0                46                    260
    1                27                    373
    2                18                    598
    3                15                    826

Scene used for the tests is the agent's body from one of the barber
shop scenes (no textures or anything, just a diffuse material).

Once again this is limited to regular (non-spatial split) BVH,
Support of spatial split to this feature will come later.

intern/cycles/blender/blender_sync.cpp
intern/cycles/bvh/bvh_build.cpp
intern/cycles/bvh/bvh_params.h
intern/cycles/render/mesh.cpp
intern/cycles/render/scene.h

index a9b7d7d3583099fff3f570ba0cce9612c9343d0f..f8f2303ec7681965de073ab317604aab7c782f5c 100644 (file)
@@ -498,7 +498,7 @@ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene,
 
        params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits");
        params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh");
-       params.num_bvh_motion_curve_steps = RNA_int_get(&cscene, "debug_bvh_time_steps");
+       params.num_bvh_time_steps = RNA_int_get(&cscene, "debug_bvh_time_steps");
 
        if(background && params.shadingsystem != SHADINGSYSTEM_OSL)
                params.persistent_data = r.use_persistent_data();
index 4d684e51c1bbf7983c88c909afc6b1c753748461..21b8b980405d4b626e1d9f5709380303c2297212 100644 (file)
@@ -120,31 +120,101 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh,
                if(mesh->has_motion_blur())
                        attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
 
-               size_t num_triangles = mesh->num_triangles();
+               const size_t num_triangles = mesh->num_triangles();
                for(uint j = 0; j < num_triangles; j++) {
                        Mesh::Triangle t = mesh->get_triangle(j);
-                       BoundBox bounds = BoundBox::empty;
-                       PrimitiveType type = PRIMITIVE_TRIANGLE;
-
-                       t.bounds_grow(&mesh->verts[0], bounds);
-
-                       /* motion triangles */
-                       if(attr_mP) {
+                       const float3 *verts = &mesh->verts[0];
+                       if(attr_mP == NULL) {
+                               BoundBox bounds = BoundBox::empty;
+                               t.bounds_grow(verts, bounds);
+                               if(bounds.valid()) {
+                                       references.push_back(BVHReference(bounds,
+                                                                         j,
+                                                                         i,
+                                                                         PRIMITIVE_TRIANGLE));
+                                       root.grow(bounds);
+                                       center.grow(bounds.center2());
+                               }
+                       }
+                       else if(params.num_motion_triangle_steps == 0 || params.use_spatial_split) {
+                               /* Motion triangles, simple case: single node for the whole
+                                * primitive. Lowest memory footprint and faster BVH build but
+                                * least optimal ray-tracing.
+                                */
+                               /* TODO(sergey): Support motion steps for spatially split BVH. */
                                const size_t num_verts = mesh->verts.size();
-                               const size_t num_steps = mesh->motion_steps - 1;
+                               const size_t num_steps = mesh->motion_steps;
                                const float3 *vert_steps = attr_mP->data_float3();
-
-                               for(size_t step = 0; step < num_steps; step++) {
+                               BoundBox bounds = BoundBox::empty;
+                               t.bounds_grow(verts, bounds);
+                               for(size_t step = 0; step < num_steps - 1; step++) {
                                        t.bounds_grow(vert_steps + step*num_verts, bounds);
                                }
-
-                               type = PRIMITIVE_MOTION_TRIANGLE;
+                               if(bounds.valid()) {
+                                       references.push_back(
+                                               BVHReference(bounds,
+                                                            j,
+                                                            i,
+                                                            PRIMITIVE_MOTION_TRIANGLE));
+                                       root.grow(bounds);
+                                       center.grow(bounds.center2());
+                               }
                        }
-
-                       if(bounds.valid()) {
-                               references.push_back(BVHReference(bounds, j, i, type));
-                               root.grow(bounds);
-                               center.grow(bounds.center2());
+                       else {
+                               /* Motion triangles, trace optimized case:  we split triangle
+                                * primitives into separate nodes for each of the time steps.
+                                * This way we minimize overlap of neighbor curve primitives.
+                                */
+                               const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1;
+                               const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
+                               const size_t num_verts = mesh->verts.size();
+                               const size_t num_steps = mesh->motion_steps;
+                               const float3 *vert_steps = attr_mP->data_float3();
+                               /* Calculate bounding box of the previous time step.
+                                * Will be reused later to avoid duplicated work on
+                                * calculating BVH time step boundbox.
+                                */
+                               float3 prev_verts[3];
+                               t.motion_verts(verts,
+                                              vert_steps,
+                                              num_verts,
+                                              num_steps,
+                                              0.0f,
+                                              prev_verts);
+                               BoundBox prev_bounds = BoundBox::empty;
+                               prev_bounds.grow(prev_verts[0]);
+                               prev_bounds.grow(prev_verts[1]);
+                               prev_bounds.grow(prev_verts[2]);
+                               /* Create all primitive time steps, */
+                               for(int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
+                                       const float curr_time = (float)(bvh_step) * num_bvh_steps_inv_1;
+                                       float3 curr_verts[3];
+                                       t.motion_verts(verts,
+                                                      vert_steps,
+                                                      num_verts,
+                                                      num_steps,
+                                                      curr_time,
+                                                      curr_verts);
+                                       BoundBox curr_bounds = BoundBox::empty;
+                                       curr_bounds.grow(curr_verts[0]);
+                                       curr_bounds.grow(curr_verts[1]);
+                                       curr_bounds.grow(curr_verts[2]);
+                                       BoundBox bounds = prev_bounds;
+                                       bounds.grow(curr_bounds);
+                                       if(bounds.valid()) {
+                                               references.push_back(
+                                                       BVHReference(bounds,
+                                                                    j,
+                                                                    i,
+                                                                    PRIMITIVE_MOTION_TRIANGLE));
+                                               root.grow(bounds);
+                                               center.grow(bounds.center2());
+                                       }
+                                       /* Current time boundbox becomes previous one for the
+                                        * next time step.
+                                        */
+                                       prev_bounds = curr_bounds;
+                               }
                        }
                }
        }
@@ -224,6 +294,7 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh,
                                                                   prev_keys);
                                        BoundBox prev_bounds = BoundBox::empty;
                                        curve.bounds_grow(prev_keys, prev_bounds);
+                                       /* Create all primitive time steps, */
                                        for(int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
                                                const float curr_time = (float)(bvh_step) * num_bvh_steps_inv_1;
                                                float4 curr_keys[4];
index 1521fe9b5e47fe3f257f21bb1c5ee328171a74ff..233c7adacba8b0e164e1c59269d5030e0fd3b6b4 100644 (file)
@@ -69,6 +69,9 @@ public:
         */
        int num_motion_curve_steps;
 
+       /* Same as above, but for triangle primitives. */
+       int num_motion_triangle_steps;
+
        /* fixed parameters */
        enum {
                MAX_DEPTH = 64,
index 1522a2dc18bc91a5f753756de6ca6890a251255d..c42b32919d4ef2499f7894d2266a329286bbaa03 100644 (file)
@@ -1053,7 +1053,8 @@ void Mesh::compute_bvh(DeviceScene *dscene,
                        bparams.use_qbvh = params->use_qbvh;
                        bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
                                                      params->use_bvh_unaligned_nodes;
-                       bparams.num_motion_curve_steps = params->num_bvh_motion_curve_steps;
+                       bparams.num_motion_triangle_steps = params->num_bvh_time_steps;
+                       bparams.num_motion_curve_steps = params->num_bvh_time_steps;
 
                        delete bvh;
                        bvh = BVH::create(bparams, objects);
@@ -1822,7 +1823,8 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
        bparams.use_spatial_split = scene->params.use_bvh_spatial_split;
        bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
                                      scene->params.use_bvh_unaligned_nodes;
-       bparams.num_motion_curve_steps = scene->params.num_bvh_motion_curve_steps;
+       bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps;
+       bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps;
 
        delete bvh;
        bvh = BVH::create(bparams, scene->objects);
index 948697dd1364ef1975f2dc0267bd10793d264dd1..8768682043f889fe7cca1da6a5e5df861c82bb47 100644 (file)
@@ -143,7 +143,7 @@ public:
        } bvh_type;
        bool use_bvh_spatial_split;
        bool use_bvh_unaligned_nodes;
-       int num_bvh_motion_curve_steps;
+       int num_bvh_time_steps;
        bool use_qbvh;
        bool persistent_data;
        int texture_limit;
@@ -154,7 +154,7 @@ public:
                bvh_type = BVH_DYNAMIC;
                use_bvh_spatial_split = false;
                use_bvh_unaligned_nodes = true;
-               num_bvh_motion_curve_steps = 0;
+               num_bvh_time_steps = 0;
                use_qbvh = false;
                persistent_data = false;
                texture_limit = 0;
@@ -165,7 +165,7 @@ public:
                && bvh_type == params.bvh_type
                && use_bvh_spatial_split == params.use_bvh_spatial_split
                && use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes
-               && num_bvh_motion_curve_steps == params.num_bvh_motion_curve_steps
+               && num_bvh_time_steps == params.num_bvh_time_steps
                && use_qbvh == params.use_qbvh
                && persistent_data == params.persistent_data
                && texture_limit == params.texture_limit); }