[Bf-blender-cvs] [1bfea8c] temp_merge_gooseberry_hair: Better grid rasterization method for hair volumetric grids.

Lukas Tönne noreply at git.blender.org
Mon Jan 19 20:50:34 CET 2015


Commit: 1bfea8c59d9d54754a18ee21a0fef371ea41745f
Author: Lukas Tönne
Date:   Thu Nov 6 12:17:09 2014 +0100
Branches: temp_merge_gooseberry_hair
https://developer.blender.org/rB1bfea8c59d9d54754a18ee21a0fef371ea41745f

Better grid rasterization method for hair volumetric grids.

This is based on the paper
"Detail Preserving Continuum Simulation of Straight Hair"
(McAdams, Selle, Ward, 2009)

The main difference is that hair line segments are used rather than only
rasterizing velocity at the vertices. This gives a much better coverage
of the hair volume grid, otherwise gaps can be produced at smaller grid
cell sizes and the distribution is uneven along the hair curve.

The algorithm for rasterizing is a variation of Bresenham's algorithm
extended onto 3D grids.

Conflicts:
	source/blender/physics/intern/BPH_mass_spring.cpp

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

M	source/blender/blenkernel/intern/collision.c
M	source/blender/physics/intern/BPH_mass_spring.cpp
M	source/blender/physics/intern/hair_volume.c
M	source/blender/physics/intern/implicit.h

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

diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index f4748f8..0690d0f 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -1061,6 +1061,7 @@ static bool cloth_points_collision_response_static(ClothModifierData *clmd, Coll
 				bounce = 0.0f;
 				mul_v3_v3fl(impulse, collpair->normal, repulse);
 			}
+#if 0
 			{
 				float d[3], md[3];
 				mul_v3_v3fl(d, collpair->normal, -collpair->distance);
@@ -1072,8 +1073,9 @@ static bool cloth_points_collision_response_static(ClothModifierData *clmd, Coll
 				BKE_sim_debug_data_add_line(clmd->debug_data, collmd->current_x[collpair->bp2].co, collmd->current_x[collpair->bp3].co, 0, 0, 1, "collision", hash_collpair(86, collpair));
 				BKE_sim_debug_data_add_line(clmd->debug_data, collmd->current_x[collpair->bp3].co, collmd->current_x[collpair->bp1].co, 0, 0, 1, "collision", hash_collpair(87, collpair));
 			}
+#endif
 			cloth1->verts[collpair->ap1].impulse_count++;
-			BKE_sim_debug_data_add_vector(clmd->debug_data, collpair->pa, impulse, 1.0, 1.0, 1.0, "collision", hash_collpair(873, collpair));
+//			BKE_sim_debug_data_add_vector(clmd->debug_data, collpair->pa, impulse, 1.0, 1.0, 1.0, "collision", hash_collpair(873, collpair));
 			
 			result = true;
 		}
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index 7a2d85f..16828d8 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -247,6 +247,7 @@ static void cloth_setup_constraints(ClothModifierData *clmd, ColliderContacts *c
 //			BKE_sim_debug_data_add_dot(clmd->debug_data, collpair->pb, 1, 0, 0, "collision", hash_collpair(937, collpair));
 //			BKE_sim_debug_data_add_line(clmd->debug_data, collpair->pa, collpair->pb, 0.7, 0.7, 0.7, "collision", hash_collpair(938, collpair));
 			
+#if 0
 			{ /* DEBUG */
 				float nor[3];
 				mul_v3_v3fl(nor, collpair->normal, -collpair->distance);
@@ -254,6 +255,7 @@ static void cloth_setup_constraints(ClothModifierData *clmd, ColliderContacts *c
 //				BKE_sim_debug_data_add_vector(clmd->debug_data, collpair->pb, impulse, 1, 1, 0, "collision", hash_collpair(940, collpair));
 //				BKE_sim_debug_data_add_vector(clmd->debug_data, collpair->pb, collpair->normal, 1, 1, 0, "collision", hash_collpair(941, collpair));
 			}
+#endif
 		}
 	}
 }
@@ -419,6 +421,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
 		/* XXX assuming same restlen for ij and jk segments here, this can be done correctly for hair later */
 		BPH_mass_spring_force_spring_bending_angular(data, s->ij, s->kl, s->mn, s->target, kb, cb);
 		
+#if 0
 		{
 			float x_kl[3], x_mn[3], v[3], d[3];
 			
@@ -435,6 +438,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
 //			BKE_sim_debug_data_add_vector(clmd->debug_data, x, d, 1, 0.4, 0.4, "target", hash_vertex(7983, s->kl));
 		}
 #endif
+#endif
 	}
 }
 
@@ -584,8 +588,140 @@ static void cloth_calc_volume_force(ClothModifierData *clmd)
 }
 #endif
 
+/* returns active vertexes' motion state, or original location the vertex is disabled */
+BLI_INLINE bool cloth_get_grid_location(Implicit_Data *data, const float cell_scale[3], const float cell_offset[3],
+                                        ClothVertex *vert, float x[3], float v[3])
+{
+	bool is_motion_state;
+	if (vert->solver_index < 0) {
+		copy_v3_v3(x, vert->x);
+		copy_v3_v3(v, vert->v);
+		is_motion_state = false;
+	}
+	else {
+		BPH_mass_spring_get_position(data, vert->solver_index, x);
+		BPH_mass_spring_get_new_velocity(data, vert->solver_index, v);
+		is_motion_state = true;
+	}
+	
+	mul_v3_v3(x, cell_scale);
+	add_v3_v3(x, cell_offset);
+	
+	return is_motion_state;
+}
+
+/* returns next spring forming a continous hair sequence */
+BLI_INLINE LinkNode *hair_spring_next(LinkNode *spring_link)
+{
+	ClothSpring *spring = (ClothSpring *)spring_link->link;
+	LinkNode *next = spring_link->next;
+	if (next) {
+		ClothSpring *next_spring = (ClothSpring *)next->link;
+		if (next_spring->type == CLOTH_SPRING_TYPE_STRUCTURAL && next_spring->kl == spring->ij)
+			return next;
+	}
+	return NULL;
+}
+
+/* XXX this is nasty: cloth meshes do not explicitly store
+ * the order of hair segments!
+ * We have to rely on the spring build function for now,
+ * which adds structural springs in reverse order:
+ *   (3,4), (2,3), (1,2)
+ * This is currently the only way to figure out hair geometry inside this code ...
+ */
+static LinkNode *cloth_continuum_add_hair_segments(HairVertexGrid *grid, const float cell_scale[3], const float cell_offset[3], Cloth *cloth, LinkNode *spring_link)
+{
+	Implicit_Data *data = cloth->implicit;
+	LinkNode *next_spring_link = NULL; /* return value */
+	ClothSpring *spring1, *spring2, *spring3;
+	ClothVertex *verts = cloth->verts;
+	ClothVertex *vert3, *vert4;
+	float x1[3], v1[3], x2[3], v2[3], x3[3], v3[3], x4[3], v4[3];
+	float dir1[3], dir2[3], dir3[3];
+	
+	spring1 = NULL;
+	spring2 = NULL;
+	spring3 = (ClothSpring *)spring_link->link;
+	
+	zero_v3(x1); zero_v3(v1);
+	zero_v3(dir1);
+	zero_v3(x2); zero_v3(v2);
+	zero_v3(dir2);
+	
+	vert3 = &verts[spring3->kl];
+	cloth_get_grid_location(data, cell_scale, cell_offset, vert3, x3, v3);
+	vert4 = &verts[spring3->ij];
+	cloth_get_grid_location(data, cell_scale, cell_offset, vert4, x4, v4);
+	sub_v3_v3v3(dir3, x4, x3);
+	normalize_v3(dir3);
+	
+	while (spring_link) {
+		/* move on */
+		spring1 = spring2;
+		spring2 = spring3;
+		
+		vert3 = vert4;
+		
+		copy_v3_v3(x1, x2); copy_v3_v3(v1, v2);
+		copy_v3_v3(x2, x3); copy_v3_v3(v2, v3);
+		copy_v3_v3(x3, x4); copy_v3_v3(v3, v4);
+		
+		copy_v3_v3(dir1, dir2);
+		copy_v3_v3(dir2, dir3);
+		
+		/* read next segment */
+		next_spring_link = spring_link->next;
+		spring_link = hair_spring_next(spring_link);
+		
+		if (spring_link) {
+			spring3 = (ClothSpring *)spring_link->link;
+			vert4 = &verts[spring3->ij];
+			cloth_get_grid_location(data, cell_scale, cell_offset, vert4, x4, v4);
+			sub_v3_v3v3(dir3, x4, x3);
+			normalize_v3(dir3);
+		}
+		else {
+			spring3 = NULL;
+			vert4 = NULL;
+			zero_v3(x4); zero_v3(v4);
+			zero_v3(dir3);
+		}
+		
+		BPH_hair_volume_add_segment(grid, x1, v1, x2, v2, x3, v3, x4, v4,
+		                            spring1 ? dir1 : NULL,
+		                            dir2,
+		                            spring3 ? dir3 : NULL);
+	}
+	
+	/* last segment */
+	spring1 = spring2;
+	spring2 = spring3;
+	spring3 = NULL;
+	
+	vert3 = vert4;
+	vert4 = NULL;
+	
+	copy_v3_v3(x1, x2); copy_v3_v3(v1, v2);
+	copy_v3_v3(x2, x3); copy_v3_v3(v2, v3);
+	copy_v3_v3(x3, x4); copy_v3_v3(v3, v4);
+	zero_v3(x4);        zero_v3(v4);
+	
+	copy_v3_v3(dir1, dir2);
+	copy_v3_v3(dir2, dir3);
+	zero_v3(dir3);
+	
+	BPH_hair_volume_add_segment(grid, x1, v1, x2, v2, x3, v3, x4, v4,
+	                            spring1 ? dir1 : NULL,
+	                            dir2,
+	                            NULL);
+	
+	return next_spring_link;
+}
+
 static void cloth_continuum_fill_grid(HairVertexGrid *grid, Cloth *cloth)
 {
+#if 0
 	Implicit_Data *data = cloth->implicit;
 	int numverts = cloth->numverts;
 	ClothVertex *vert;
@@ -594,10 +730,32 @@ static void cloth_continuum_fill_grid(HairVertexGrid *grid, Cloth *cloth)
 	for (i = 0, vert = cloth->verts; i < numverts; i++, vert++) {
 		float x[3], v[3];
 		
-		BPH_mass_spring_get_position(data, i, x);
-		BPH_mass_spring_get_new_velocity(data, i, v);
+		cloth_get_vertex_motion_state(data, vert, x, v);
 		BPH_hair_volume_add_vertex(grid, x, v);
 	}
+#else
+	LinkNode *link;
+	float cellsize[3], gmin[3], cell_scale[3], cell_offset[3];
+	
+	/* scale and offset for transforming vertex locations into grid space
+	 * (cell size is 0..1, gmin becomes origin)
+	 */
+	BPH_hair_volume_grid_geometry(grid, cellsize, NULL, gmin, NULL);
+	cell_scale[0] = cellsize[0] > 0.0f ? 1.0f / cellsize[0] : 0.0f;
+	cell_scale[1] = cellsize[1] > 0.0f ? 1.0f / cellsize[1] : 0.0f;
+	cell_scale[2] = cellsize[2] > 0.0f ? 1.0f / cellsize[2] : 0.0f;
+	mul_v3_v3v3(cell_offset, gmin, cell_scale);
+	negate_v3(cell_offset);
+	
+	link = cloth->springs;
+	while (link) {
+		ClothSpring *spring = (ClothSpring *)link->link;
+		if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL)
+			link = cloth_continuum_add_hair_segments(grid, cell_scale, cell_offset, cloth, link);
+		else
+			link = link->next;
+	}
+#endif
 	BPH_hair_volume_normalize_vertex_grid(grid);
 }
 
@@ -614,6 +772,7 @@ static void cloth_continuum_step(ClothModifierData *clmd)
 	float pressfac = parms->pressure;
 	float minpress = parms->pressure_threshold;
 	float gmin[3], gmax[3];
+	float cellsize[3];
 	int i;
 	
 	/* clear grid info */
@@ -626,6 +785,10 @@ static void cloth_continuum_step(ClothModifierData *clmd)
 	/* gather velocities & density */
 	if (smoothfac > 0.0f || pressfac > 0.0f) {
 		HairVertexGrid *vertex_grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_res, gmin, gmax);
+		BPH_hair_volume_set_debug_data(vertex_grid, clmd->debug_data);
+		
+		BPH_hair_volume_grid_geometry(vertex_grid, cellsize, NULL, NULL, NULL);
+		
 		cloth_continuum_fill_grid(vertex_grid, cloth);
 		
 #if 0
@@ -667,16 +830,20 @@ static void cloth_continuum_step(ClothModifierData *clmd)
 			a[(axis+1) % 3] = clmd->hair_grid_max[(axis+1) % 3] - clmd->hair_grid_min[(axis+1) % 3];
 			b[(axis+2) % 3] = clmd->hair_grid_max[(axis+2) % 3] - clmd->hair_grid_min[(axis+2) % 3];
 			
+			BKE_sim_debug_data_clear_category(clmd->debug_data, "grid velocity");
 			for (j = 0; j < size; ++j) {
 				for (i = 0; i < size; ++i) {
-					float x[3], v[3], nv[3];
+					float x[3], v[3], gvel[3], gdensity;
+					
 					madd_v3_v3v3fl(x, offset, a, (float)i / (float)(size-1));
 					madd_v3_v3fl(x, b, (float)j / (float)(size-1));
 					zero_v3(v);
 					
-					BPH_hair_volume_grid_velocity(vertex_grid, x, v, 0.0f, nv);
+					BPH_hair_volume_grid_interpolate(vertex_grid, x, &gdensity, gvel, NULL, NULL);
 					
-					BKE_sim_debug_data_add_vector(clmd->debug_data, x, nv, 0.4, 0, 1, "grid velocity", hash_int_2d(hash_int_2d(i, j), 3112));
+//					BKE_sim_debug_data_add_circle(clmd->debug_data, x, 

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list