[Bf-blender-cvs] [9bf3b4679e] blender-v2.78b-release: Cycles: Add option to split curve motion primitives by time steps

Sergey Sharybin noreply at git.blender.org
Thu Jan 26 13:46:52 CET 2017


Commit: 9bf3b4679e238e966a2e8fc6782c1ab97dd9c864
Author: Sergey Sharybin
Date:   Tue Jan 17 14:37:32 2017 +0100
Branches: blender-v2.78b-release
https://developer.blender.org/rB9bf3b4679e238e966a2e8fc6782c1ab97dd9c864

Cycles: Add option to split curve motion primitives by time steps

The idea is to create several smaller BVH nodes for each of the motion
curve primitives. This acts as a forced spatial split for the single
primitive.

This gives up render time speedup of motion blurred hair in the cost
of extra memory usage. The numbers goes as:

BVH Steps     Render time (sec)       Memory usage (MB)
    0               258                    191
    1               123                    278
    2                69                    453
    3                43                    627

Scene used for the tests is the agent's hair from one of the barber
shop scenes.

Currently it's only limited to scenes without spatial split enabled,
since the spatial split builder requires some changes to work properly
with motion steps coordinates.

===================================================================

M	intern/cycles/blender/addon/properties.py
M	intern/cycles/blender/addon/ui.py
M	intern/cycles/blender/blender_sync.cpp
M	intern/cycles/bvh/bvh_build.cpp
M	intern/cycles/bvh/bvh_params.h
M	intern/cycles/render/scene.h

===================================================================

diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 3616b13e75..802b9b76c5 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -528,6 +528,12 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
                 description="Use special type BVH optimized for hair (uses more ram but renders faster)",
                 default=True,
                 )
+        cls.debug_bvh_time_steps = IntProperty(
+                name="BVH Time Steps",
+                description="Split BVH primitives by this number of time steps to speed up render time in cost of memory",
+                default=0,
+                min=0, max=16,
+                )
         cls.tile_order = EnumProperty(
                 name="Tile Order",
                 description="Tile order for rendering",
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 53bd208c0e..d26ab73fac 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -432,6 +432,10 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
         col.prop(cscene, "debug_use_spatial_splits")
         col.prop(cscene, "debug_use_hair_bvh")
 
+        row = col.row()
+        row.active = not cscene.debug_use_spatial_splits
+        row.prop(cscene, "debug_bvh_time_steps")
+
 
 class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel):
     bl_label = "Layer"
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index 38b2ce19e8..a9b7d7d358 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -498,6 +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");
 
 	if(background && params.shadingsystem != SHADINGSYSTEM_OSL)
 		params.persistent_data = r.use_persistent_data();
diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp
index a045481e50..4d684e51c1 100644
--- a/intern/cycles/bvh/bvh_build.cpp
+++ b/intern/cycles/bvh/bvh_build.cpp
@@ -158,32 +158,101 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh,
 		size_t num_curves = mesh->num_curves();
 		for(uint j = 0; j < num_curves; j++) {
 			const Mesh::Curve curve = mesh->get_curve(j);
-			PrimitiveType type = PRIMITIVE_CURVE;
 			const float *curve_radius = &mesh->curve_radius[0];
-
 			for(int k = 0; k < curve.num_keys - 1; k++) {
-				BoundBox bounds = BoundBox::empty;
-				curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds);
-
-				/* motion curve */
-				if(curve_attr_mP) {
+				if(curve_attr_mP == NULL) {
+					/* Really simple logic for static hair. */
+					BoundBox bounds = BoundBox::empty;
+					curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds);
+					if(bounds.valid()) {
+						int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_CURVE, k);
+						references.push_back(BVHReference(bounds, j, i, packed_type));
+						root.grow(bounds);
+						center.grow(bounds.center2());
+					}
+				}
+				else if(params.num_motion_curve_steps == 0 || params.use_spatial_split) {
+					/* Simple case of motion curves: single node for the while
+					 * shutter time. Lowest memory usage but less optimal
+					 * rendering.
+					 */
+					/* TODO(sergey): Support motion steps for spatially split BVH. */
+					BoundBox bounds = BoundBox::empty;
+					curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds);
 					const size_t num_keys = mesh->curve_keys.size();
-					const size_t num_steps = mesh->motion_steps - 1;
+					const size_t num_steps = mesh->motion_steps;
 					const float3 *key_steps = curve_attr_mP->data_float3();
-
-					for(size_t step = 0; step < num_steps; step++) {
-						curve.bounds_grow(k, key_steps + step*num_keys, curve_radius, bounds);
+					for(size_t step = 0; step < num_steps - 1; step++) {
+						curve.bounds_grow(k,
+						                  key_steps + step*num_keys,
+						                  curve_radius,
+						                  bounds);
+					}
+					if(bounds.valid()) {
+						int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_MOTION_CURVE, k);
+						references.push_back(BVHReference(bounds,
+						                                  j,
+						                                  i,
+						                                  packed_type));
+						root.grow(bounds);
+						center.grow(bounds.center2());
 					}
-
-					type = PRIMITIVE_MOTION_CURVE;
 				}
-
-				if(bounds.valid()) {
-					int packed_type = PRIMITIVE_PACK_SEGMENT(type, k);
-
-					references.push_back(BVHReference(bounds, j, i, packed_type));
-					root.grow(bounds);
-					center.grow(bounds.center2());
+				else {
+					/* Motion curves, trace optimized case:  we split curve keys
+					 * 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_steps = mesh->motion_steps;
+					const float3 *curve_keys = &mesh->curve_keys[0];
+					const float3 *key_steps = curve_attr_mP->data_float3();
+					const size_t num_keys = mesh->curve_keys.size();
+					/* Calculate bounding box of the previous time step.
+					 * Will be reused later to avoid duplicated work on
+					 * calculating BVH time step boundbox.
+					 */
+					float4 prev_keys[4];
+					curve.cardinal_motion_keys(curve_keys,
+					                           curve_radius,
+					                           key_steps,
+					                           num_keys,
+					                           num_steps,
+					                           0.0f,
+					                           k - 1, k, k + 1, k + 2,
+					                           prev_keys);
+					BoundBox prev_bounds = BoundBox::empty;
+					curve.bounds_grow(prev_keys, prev_bounds);
+					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];
+						curve.cardinal_motion_keys(curve_keys,
+						                           curve_radius,
+						                           key_steps,
+						                           num_keys,
+						                           num_steps,
+						                           curr_time,
+						                           k - 1, k, k + 1, k + 2,
+						                           curr_keys);
+						BoundBox curr_bounds = BoundBox::empty;
+						curve.bounds_grow(curr_keys, curr_bounds);
+						BoundBox bounds = prev_bounds;
+						bounds.grow(curr_bounds);
+						if(bounds.valid()) {
+							int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_MOTION_CURVE, k);
+							references.push_back(BVHReference(bounds,
+							                                  j,
+							                                  i,
+							                                  packed_type));
+							root.grow(bounds);
+							center.grow(bounds.center2());
+						}
+						/* Current time boundbox becomes previous one for the
+						 * next time step.
+						 */
+						prev_bounds = curr_bounds;
+					}
 				}
 			}
 		}
diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h
index 6d42647573..1521fe9b5e 100644
--- a/intern/cycles/bvh/bvh_params.h
+++ b/intern/cycles/bvh/bvh_params.h
@@ -61,6 +61,14 @@ public:
 	 */
 	bool use_unaligned_nodes;
 
+	/* Split time range to this number of steps and create leaf node for each
+	 * of this time steps.
+	 *
+	 * Speeds up rendering of motion curve primitives in the cost of higher
+	 * memory usage.
+	 */
+	int num_motion_curve_steps;
+
 	/* fixed parameters */
 	enum {
 		MAX_DEPTH = 64,
@@ -91,6 +99,8 @@ public:
 		use_unaligned_nodes = false;
 
 		primitive_mask = PRIMITIVE_ALL;
+
+		num_motion_curve_steps = 0;
 	}
 
 	/* SAH costs */
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index df9363cc76..948697dd13 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -143,6 +143,7 @@ public:
 	} bvh_type;
 	bool use_bvh_spatial_split;
 	bool use_bvh_unaligned_nodes;
+	int num_bvh_motion_curve_steps;
 	bool use_qbvh;
 	bool persistent_data;
 	int texture_limit;
@@ -153,6 +154,7 @@ public:
 		bvh_type = BVH_DYNAMIC;
 		use_bvh_spatial_split = false;
 		use_bvh_unaligned_nodes = true;
+		num_bvh_motion_curve_steps = 0;
 		use_qbvh = false;
 		persistent_data = false;
 		texture_limit = 0;
@@ -163,6 +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
 		&& use_qbvh == params.use_qbvh
 		&& persistent_data == params.persistent_data
 		&& texture_limit == params.texture_limit); }




More information about the Bf-blender-cvs mailing list