[Bf-blender-cvs] [7432efd] hair_immediate_fixes: Better grid rasterization method for hair volumetric grids.

Lukas Tönne noreply at git.blender.org
Thu Nov 6 12:21:05 CET 2014


Commit: 7432efd9d72e8ffcd23feb0a0456edb140a4f890
Author: Lukas Tönne
Date:   Thu Nov 6 12:17:09 2014 +0100
Branches: hair_immediate_fixes
https://developer.blender.org/rB7432efd9d72e8ffcd23feb0a0456edb140a4f890

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.

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

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 91d0ac1..a1efdef 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -1059,6 +1059,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);
@@ -1070,8 +1071,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 c024344..b46f9ee 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -320,6 +320,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);
@@ -327,6 +328,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
 		}
 	}
 }
@@ -503,6 +505,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, solver_ij, solver_kl, solver_mn, s->target, kb, cb);
 		
+#if 0
 		{
 			float x_kl[3], x_mn[3], v[3], d[3];
 			
@@ -519,6 +522,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
 	}
 }
 
@@ -697,8 +701,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;
@@ -707,16 +843,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];
 		
-		if (vert->solver_index < 0) {
-			copy_v3_v3(x, vert->x);
-			copy_v3_v3(v, vert->v);
-		}
-		else {
-			BPH_mass_spring_get_position(data, vert->solver_index, x);
-			BPH_mass_spring_get_new_velocity(data, vert->solver_index, 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);
 }
 
@@ -733,6 +885,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 */
@@ -745,6 +898,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
@@ -789,16 +946,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_v

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list