[Bf-blender-cvs] [7a7778d] master: Simple initial implementation of angular bending springs.

Lukas Tönne noreply at git.blender.org
Tue Jan 20 09:51:09 CET 2015


Commit: 7a7778d003d1a31fb4eb3411e1b0512981cc4614
Author: Lukas Tönne
Date:   Fri Sep 19 11:15:16 2014 +0200
Branches: master
https://developer.blender.org/rB7a7778d003d1a31fb4eb3411e1b0512981cc4614

Simple initial implementation of angular bending springs.

These are much better suited for creating stiff hair. The previous
bending springs are based on "push" type spring along the hypothenuse
of 3 hair vertices. This sort of spring requires a very large force
in the direction of the spring for any angular effect, and is still
unstable in the equilibrium.

The new bending spring model is based on "target" vectors defined in a
local hair frame, which generates a force perpendicular to the hair
segment. For further details see
"Artistic Simulation of Curly Hair" (Pixar technical memo #12-03a)
or
"A Mass Spring Model for Hair Simulation" (Selle, Lentine, Fedkiw 2008)

Currently the implementation uses a single root frame that is not yet
propagated along the hair, so the resulting rest shape is not very
natural. Also damping and derivatives are still missing.

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

M	source/blender/blenkernel/BKE_cloth.h
M	source/blender/blenkernel/intern/cloth.c
M	source/blender/physics/intern/BPH_mass_spring.cpp
M	source/blender/physics/intern/implicit.h
M	source/blender/physics/intern/implicit_blender.c

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

diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index 571c0ec..838388f 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -124,6 +124,7 @@ ClothVertex;
 typedef struct ClothSpring {
 	int	ij;		/* Pij from the paper, one end of the spring.	*/
 	int	kl;		/* Pkl from the paper, one end of the spring.	*/
+	int mn;
 	float	restlen;	/* The original length of the spring.	*/
 	int	matrix_index; 	/* needed for implicit solver (fast lookup) */
 	int	type;		/* types defined in BKE_cloth.h ("springType") */
@@ -175,7 +176,8 @@ typedef enum {
 	CLOTH_SPRING_TYPE_SHEAR       = (1 << 2),
 	CLOTH_SPRING_TYPE_BENDING     = (1 << 3),
 	CLOTH_SPRING_TYPE_GOAL        = (1 << 4),
-	CLOTH_SPRING_TYPE_SEWING      = (1 << 5)
+	CLOTH_SPRING_TYPE_SEWING      = (1 << 5),
+	CLOTH_SPRING_TYPE_BENDING_ANG = (1 << 6),
 } CLOTH_SPRING_TYPES;
 
 /* SPRING FLAGS */
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 4132fc8..1b3b668 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -1287,39 +1287,71 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
 		}
 	}
 	else if (struct_springs > 2) {
-		/* bending springs for hair strands */
-		/* The current algorightm only goes through the edges in order of the mesh edges list	*/
-		/* and makes springs between the outer vert of edges sharing a vertice. This works just */
-		/* fine for hair, but not for user generated string meshes. This could/should be later	*/
-		/* extended to work with non-ordered edges so that it can be used for general "rope		*/
-		/* dynamics" without the need for the vertices or edges to be ordered through the length*/
-		/* of the strands. -jahka */
-		search = cloth->springs;
-		search2 = search->next;
-		while (search && search2) {
-			tspring = search->link;
-			tspring2 = search2->link;
-
-			if (tspring->ij == tspring2->kl) {
-				spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
+		if (G.debug_value != 1112) {
+			search = cloth->springs;
+			search2 = search->next;
+			while (search && search2) {
+				tspring = search->link;
+				tspring2 = search2->link;
 				
-				if (!spring) {
-					cloth_free_errorsprings(cloth, edgelist);
-					return 0;
+				if (tspring->ij == tspring2->kl) {
+					spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
+					
+					if (!spring) {
+						cloth_free_errorsprings(cloth, edgelist);
+						return 0;
+					}
+					
+					spring->ij = tspring->kl;
+					spring->kl = tspring->ij;
+					spring->mn = tspring2->ij;
+					spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest);
+					spring->type = CLOTH_SPRING_TYPE_BENDING_ANG;
+					spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
+					bend_springs++;
+					
+					BLI_linklist_prepend ( &cloth->springs, spring );
 				}
-
-				spring->ij = tspring2->ij;
-				spring->kl = tspring->kl;
-				spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest);
-				spring->type = CLOTH_SPRING_TYPE_BENDING;
-				spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
-				bend_springs++;
-
-				BLI_linklist_prepend ( &cloth->springs, spring );
+				
+				search = search->next;
+				search2 = search2->next;
+			}
+		}
+		else {
+			/* bending springs for hair strands */
+			/* The current algorightm only goes through the edges in order of the mesh edges list	*/
+			/* and makes springs between the outer vert of edges sharing a vertice. This works just */
+			/* fine for hair, but not for user generated string meshes. This could/should be later	*/
+			/* extended to work with non-ordered edges so that it can be used for general "rope		*/
+			/* dynamics" without the need for the vertices or edges to be ordered through the length*/
+			/* of the strands. -jahka */
+			search = cloth->springs;
+			search2 = search->next;
+			while (search && search2) {
+				tspring = search->link;
+				tspring2 = search2->link;
+				
+				if (tspring->ij == tspring2->kl) {
+					spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
+					
+					if (!spring) {
+						cloth_free_errorsprings(cloth, edgelist);
+						return 0;
+					}
+					
+					spring->ij = tspring2->ij;
+					spring->kl = tspring->kl;
+					spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest);
+					spring->type = CLOTH_SPRING_TYPE_BENDING;
+					spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
+					bend_springs++;
+					
+					BLI_linklist_prepend ( &cloth->springs, spring );
+				}
+				
+				search = search->next;
+				search2 = search2->next;
 			}
-			
-			search = search->next;
-			search2 = search2->next;
 		}
 	}
 	
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index db37199..56de54e 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -373,7 +373,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
 		BPH_mass_spring_force_spring_goal(data, s->ij, s->matrix_index, goal_x, goal_v, k, parms->goalfrict * 0.01f, s->f, s->dfdx, s->dfdv);
 #endif
 	}
-	else {  /* calculate force of bending springs */
+	else if (s->type & CLOTH_SPRING_TYPE_BENDING) {  /* calculate force of bending springs */
 #ifdef CLOTH_FORCE_SPRING_BEND
 		float kb, cb, scaling;
 		
@@ -385,6 +385,18 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
 		BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->matrix_index, s->restlen, kb, cb, s->f, s->dfdx, s->dfdv);
 #endif
 	}
+	else if (s->type & CLOTH_SPRING_TYPE_BENDING_ANG) {
+#ifdef CLOTH_FORCE_SPRING_BEND
+		float kb, cb, scaling;
+		
+		s->flags |= CLOTH_SPRING_FLAG_NEEDED;
+		
+		scaling = parms->bending + s->stiffness * fabsf(parms->max_bend - parms->bending);
+		cb = kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
+		
+		BPH_mass_spring_force_spring_bending_angular(data, s->ij, s->kl, s->matrix_index, s->restlen, kb, cb, s->f, s->dfdx, s->dfdv);
+#endif
+	}
 }
 
 static void hair_get_boundbox(ClothModifierData *clmd, float gmin[3], float gmax[3])
diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h
index 3743152..ea9a5b8 100644
--- a/source/blender/physics/intern/implicit.h
+++ b/source/blender/physics/intern/implicit.h
@@ -140,6 +140,10 @@ bool BPH_mass_spring_force_spring_linear(struct Implicit_Data *data, int i, int
 bool BPH_mass_spring_force_spring_bending(struct Implicit_Data *data, int i, int j, int spring_index, float restlen,
                                           float kb, float cb,
                                           float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]);
+/* Angular bending force based on local target vectors */
+bool BPH_mass_spring_force_spring_bending_angular(struct Implicit_Data *data, int i, int j, int spring_index, float restlen,
+                                                  float stiffness, float damping,
+                                                  float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]);
 /* Global goal spring */
 bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data, int i, int spring_index, const float goal_x[3], const float goal_v[3],
                                        float stiffness, float damping,
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
index bad883d..dd8cab6 100644
--- a/source/blender/physics/intern/implicit_blender.c
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -1181,12 +1181,12 @@ int BPH_mass_spring_init_spring(Implicit_Data *data, int index, int v1, int v2)
 {
 	int s = data->M[0].vcount + index; /* index from array start */
 	
+	/* tfm and S don't have spring entries (diagonal blocks only) */
 	init_fmatrix(data->bigI + s, v1, v2);
 	init_fmatrix(data->M + s, v1, v2);
 	init_fmatrix(data->dFdX + s, v1, v2);
 	init_fmatrix(data->dFdV + s, v1, v2);
 	init_fmatrix(data->A + s, v1, v2);
-//	init_fmatrix(data->S + s, v1, v2); // has no off-diagonal spring entries
 	init_fmatrix(data->P + s, v1, v2);
 	init_fmatrix(data->Pinv + s, v1, v2);
 	
@@ -1609,6 +1609,48 @@ bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, int
 	}
 }
 
+/* Angular spring that pulls the vertex toward the local target
+ * See "Artistic Simulation of Curly Hair" (Pixar technical memo #12-03a)
+ */
+bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, int j, int spring_index, float restlen,
+                                                  float stiffness, float damping,
+                                                  float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
+{
+	float target[3], dist[3], extent[3], length, dir[3], vel[3];
+	float f[3], dfdx[3][3], dfdv[3][3];
+	
+	target[0] = 0.0f;
+	target[1] = 0.0f;
+	target[2] = restlen;
+	
+	// calculate elonglation
+//	spring_length(data, i, j, extent, dir, &length, vel);
+	sub_v3_v3v3(extent, data->X[j], data->X[i]);
+	sub_v3_v3v3(vel, data->V[j], data->V[i]);
+	length = len_v3(extent);
+	
+	sub_v3_v3v3(dist, target, extent);
+	mul_v3_v3fl(f, dist, stiffness);
+//	mul_v3_v3fl(f, dir, fbstar(length, restlen, kb, cb));
+	
+	zero_m3(dfdx);
+	zero_m3(dfdv);
+	
+//	outerproduct(dfdx, dir, dir);
+//	mul_m3_fl(dfdx, fbstar_jacobi(length, restlen, kb, cb));
+	
+	/* XXX damping not supported */
+//	zero_m3(dfdv);
+	
+	apply_spring(data, i, j, spring_index, f, dfdx, dfdv);
+	
+	if (r_f) copy_v3_v3(r_f, f);
+	if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
+	if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
+	
+	return true;
+}
+
 bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, int i, int UNUSED(spring_index), const float goal_x[3], const float goal_v[3],
                                        flo

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list