[Bf-blender-cvs] [4b9771a] hair_immediate_fixes: Switched to the modified CG method that supports constraints, and added back structural stretch springs.

Lukas Tönne noreply at git.blender.org
Mon Sep 8 19:02:53 CEST 2014


Commit: 4b9771a7cb88d059aee57865cede6d7a5f94e729
Author: Lukas Tönne
Date:   Mon Sep 8 19:03:39 2014 +0200
Branches: hair_immediate_fixes
https://developer.blender.org/rB4b9771a7cb88d059aee57865cede6d7a5f94e729

Switched to the modified CG method that supports constraints, and
added back structural stretch springs.

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

M	source/blender/blenkernel/intern/implicit_eigen.cpp

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

diff --git a/source/blender/blenkernel/intern/implicit_eigen.cpp b/source/blender/blenkernel/intern/implicit_eigen.cpp
index 5be6623..26bfa49 100644
--- a/source/blender/blenkernel/intern/implicit_eigen.cpp
+++ b/source/blender/blenkernel/intern/implicit_eigen.cpp
@@ -31,9 +31,17 @@
 
 #define IMPLICIT_SOLVER_EIGEN
 
+//#define USE_EIGEN_CORE
+#define USE_EIGEN_CONSTRAINED_CG
+
 #ifdef IMPLICIT_SOLVER_EIGEN
 
 #include <Eigen/Sparse>
+#include <Eigen/src/Core/util/DisableStupidWarnings.h>
+
+#ifdef USE_EIGEN_CONSTRAINED_CG
+#include <intern/ConstrainedConjugateGradient.h>
+#endif
 
 #include "MEM_guardedalloc.h"
 
@@ -54,7 +62,6 @@ extern "C" {
 #include "BKE_global.h"
 }
 
-
 /* ==== hash functions for debugging ==== */
 static unsigned int hash_int_2d(unsigned int kx, unsigned int ky)
 {
@@ -100,10 +107,16 @@ typedef Eigen::VectorXf lVector;
 typedef Eigen::Triplet<Scalar> Triplet;
 typedef std::vector<Triplet> TripletList;
 
+#ifdef USE_EIGEN_CORE
 typedef Eigen::ConjugateGradient<lMatrix, Eigen::Lower, Eigen::DiagonalPreconditioner<Scalar> > ConjugateGradient;
+#endif
+#ifdef USE_EIGEN_CONSTRAINED_CG
+typedef Eigen::ConstrainedConjugateGradient<lMatrix, Eigen::Lower, lMatrix,
+                                            Eigen::DiagonalPreconditioner<Scalar> >
+        ConstraintConjGrad;
+#endif
 using Eigen::ComputationInfo;
 
-
 static void print_lvector(const lVector &v)
 {
 	for (int i = 0; i < v.rows(); ++i) {
@@ -115,14 +128,16 @@ static void print_lmatrix(const lMatrix &m)
 {
 	for (int j = 0; j < m.rows(); ++j) {
 		for (int i = 0; i < m.cols(); ++i) {
-			printf("%-16f,", m.coeff(j, i));
+			printf("%-8.3f,", m.coeff(j, i));
 		}
 		printf("\n");
 	}
 }
 
+static float I[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
+static float ZERO[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
 
-BLI_INLINE void reserve_diagonal(lMatrix &m, int num)
+BLI_INLINE void lMatrix_reserve_elems(lMatrix &m, int num)
 {
 	m.reserve(Eigen::VectorXi::Constant(m.cols(), num));
 }
@@ -137,6 +152,59 @@ BLI_INLINE const float *lVector_v3(const lVector &v, int vertex)
 	return v.data() + 3 * vertex;
 }
 
+BLI_INLINE void lMatrix_copy_m3(lMatrix &r, float m[3][3], int i, int j)
+{
+	i *= 3;
+	j *= 3;
+	for (int l = 0; l < 3; ++l) {
+		for (int k = 0; k < 3; ++k) {
+			r.coeffRef(i + k, j + l) = m[k][l];
+		}
+	}
+}
+
+BLI_INLINE void lMatrix_add_m3(lMatrix &r, float m[3][3], int i, int j)
+{
+	lMatrix tmp(r.cols(), r.cols());
+	if (i == j) {
+		lMatrix_copy_m3(tmp, m, i, i);
+	}
+	else {
+		lMatrix_copy_m3(tmp, m, i, j);
+		lMatrix_copy_m3(tmp, m, j, i);
+	}
+	
+	r += tmp;
+}
+
+BLI_INLINE void lMatrix_sub_m3(lMatrix &r, float m[3][3], int i, int j)
+{
+	lMatrix tmp(r.cols(), r.cols());
+	if (i == j) {
+		lMatrix_copy_m3(tmp, m, i, i);
+	}
+	else {
+		lMatrix_copy_m3(tmp, m, i, j);
+		lMatrix_copy_m3(tmp, m, j, i);
+	}
+	
+	r -= tmp;
+}
+
+BLI_INLINE void lMatrix_madd_m3(lMatrix &r, float m[3][3], float s, int i, int j)
+{
+	lMatrix tmp(r.cols(), r.cols());
+	if (i == j) {
+		lMatrix_copy_m3(tmp, m, i, i);
+	}
+	else {
+		lMatrix_copy_m3(tmp, m, i, j);
+		lMatrix_copy_m3(tmp, m, j, i);
+	}
+	
+	r += s * tmp;
+}
+
 BLI_INLINE void triplets_m3(TripletList &t, float m[3][3], int i, int j)
 {
 	i *= 3;
@@ -148,6 +216,13 @@ BLI_INLINE void triplets_m3(TripletList &t, float m[3][3], int i, int j)
 	}
 }
 
+BLI_INLINE void outerproduct(float r[3][3], const float a[3], const float b[3])
+{
+	mul_v3_v3fl(r[0], a, b[0]);
+	mul_v3_v3fl(r[1], a, b[1]);
+	mul_v3_v3fl(r[2], a, b[2]);
+}
+
 struct Implicit_Data {
 	Implicit_Data(int numverts)
 	{
@@ -199,6 +274,7 @@ struct Implicit_Data {
 
 static bool simulate_implicit_euler(Implicit_Data *id, float dt)
 {
+#ifdef USE_EIGEN_CORE
 	ConjugateGradient cg;
 	cg.setMaxIterations(100);
 	cg.setTolerance(0.01f);
@@ -212,12 +288,62 @@ static bool simulate_implicit_euler(Implicit_Data *id, float dt)
 	id->Vnew = id->V + id->dV;
 	
 	return cg.info() != Eigen::Success;
+#endif
+
+#ifdef USE_EIGEN_CONSTRAINED_CG
+	ConstraintConjGrad cg;
+	cg.setMaxIterations(100);
+	cg.setTolerance(0.01f);
+	
+	id->A = id->M - dt * id->dFdV - dt*dt * id->dFdX;
+	cg.compute(id->A);
+	cg.filter() = id->S;
+	
+	id->B = dt * id->F + dt*dt * id->dFdX * id->V;
+	id->dV = cg.solveWithGuess(id->B, id->z);
+	
+	id->Vnew = id->V + id->dV;
+	
+	return cg.info() != Eigen::Success;
+#endif
+}
+
+BLI_INLINE void dfdx_spring(float to[3][3], const float dir[3], float length, float L, float k)
+{
+	// dir is unit length direction, rest is spring's restlength, k is spring constant.
+	//return  ( (I-outerprod(dir, dir))*Min(1.0f, rest/length) - I) * -k;
+	outerproduct(to, dir, dir);
+	sub_m3_m3m3(to, I, to);
+	
+	mul_m3_fl(to, (L/length)); 
+	sub_m3_m3m3(to, to, I);
+	mul_m3_fl(to, -k);
+}
+
+/* unused */
+#if 0
+BLI_INLINE void dfdx_damp(float to[3][3], const float dir[3], float length, const float vel[3], float rest, float damping)
+{
+	// inner spring damping   vel is the relative velocity  of the endpoints.  
+	// 	return (I-outerprod(dir, dir)) * (-damping * -(dot(dir, vel)/Max(length, rest)));
+	mul_fvectorT_fvector(to, dir, dir);
+	sub_fmatrix_fmatrix(to, I, to);
+	mul_fmatrix_S(to,  (-damping * -(dot_v3v3(dir, vel)/MAX2(length, rest))));
+}
+#endif
+
+DO_INLINE void dfdv_damp(float to[3][3], const float dir[3], float damping)
+{
+	// derivative of force wrt velocity
+	outerproduct(to, dir, dir);
+	mul_m3_fl(to, damping);
 }
 
 static void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, const lVector &X, const lVector &V, float time)
 {
 	Cloth *cloth = clmd->clothObject;
 	ClothVertex *verts = cloth->verts;
+	ClothVertex *v1 = &verts[s->ij], *v2 = &verts[s->kl];
 	float extent[3];
 	float length = 0, dot = 0;
 	float dir[3] = {0, 0, 0};
@@ -228,7 +354,6 @@ static void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, con
 	
 	float stretch_force[3] = {0, 0, 0};
 	float bending_force[3] = {0, 0, 0};
-	float damping_force[3] = {0, 0, 0};
 	float nulldfdx[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
 	
 	float scaling = 0.0;
@@ -239,14 +364,17 @@ static void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, con
 	zero_m3(s->dfdx);
 	zero_m3(s->dfdv);
 	
+	s->flags &= ~CLOTH_SPRING_FLAG_NEEDED;
+	/* ignore springs between pinned vertices */
+	if (v1->flags & CLOTH_VERT_FLAG_PINNED && v2->flags & CLOTH_VERT_FLAG_PINNED)
+		return;
+	
 	// calculate elonglation
 	sub_v3_v3v3(extent, lVector_v3(X, s->kl), lVector_v3(X, s->ij));
 	sub_v3_v3v3(vel, lVector_v3(V, s->kl), lVector_v3(V, s->ij));
 	dot = dot_v3v3(extent, extent);
 	length = sqrt(dot);
 	
-	s->flags &= ~CLOTH_SPRING_FLAG_NEEDED;
-	
 	if (length > ALMOST_ZERO) {
 		/*
 		if (length>L) {
@@ -264,18 +392,15 @@ static void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, con
 		zero_v3(dir);
 	}
 	
-#if 0
 	// calculate force of structural + shear springs
-	if ((s->type & CLOTH_SPRING_TYPE_STRUCTURAL) || (s->type & CLOTH_SPRING_TYPE_SHEAR) || (s->type & CLOTH_SPRING_TYPE_SEWING) ) {
+	if (ELEM(s->type, CLOTH_SPRING_TYPE_STRUCTURAL, CLOTH_SPRING_TYPE_SHEAR, CLOTH_SPRING_TYPE_SEWING)) {
 		if (length > L || no_compress) {
 			s->flags |= CLOTH_SPRING_FLAG_NEEDED;
 			
 			k = clmd->sim_parms->structural;
-
 			scaling = k + s->stiffness * fabsf(clmd->sim_parms->max_struct - k);
 
 			k = scaling / (clmd->sim_parms->avg_spring_len + FLT_EPSILON);
-
 			// TODO: verify, half verified (couldn't see error)
 			if (s->type & CLOTH_SPRING_TYPE_SEWING) {
 				// sewing springs usually have a large distance at first so clamp the force so we don't get tunnelling through colission objects
@@ -283,18 +408,17 @@ static void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, con
 				if (force > clmd->sim_parms->max_sewing) {
 					force = clmd->sim_parms->max_sewing;
 				}
-				mul_fvector_S(stretch_force, dir, force);
+				mul_v3_v3fl(stretch_force, dir, force);
 			}
 			else {
-				mul_fvector_S(stretch_force, dir, k * (length - L));
+				mul_v3_v3fl(stretch_force, dir, k * (length - L));
 			}
-
-			VECADD(s->f, s->f, stretch_force);
-
+			
+			add_v3_v3(s->f, stretch_force);
+			
 			// Ascher & Boxman, p.21: Damping only during elonglation
 			// something wrong with it...
-			mul_fvector_S(damping_force, dir, clmd->sim_parms->Cdis * dot_v3v3(vel, dir));
-			VECADD(s->f, s->f, damping_force);
+			madd_v3_v3fl(s->f, dir, clmd->sim_parms->Cdis * dot_v3v3(vel, dir));
 			
 			/* VERIFIED */
 			dfdx_spring(s->dfdx, dir, length, L, k);
@@ -304,17 +428,15 @@ static void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, con
 			
 		}
 	}
-	else
-#endif
-	if (s->type & CLOTH_SPRING_TYPE_GOAL) {
+	else if (s->type & CLOTH_SPRING_TYPE_GOAL) {
 		float target[3];
 		
 		s->flags |= CLOTH_SPRING_FLAG_NEEDED;
 		
 		// current_position = xold + t * (xnew - xold)
-		interp_v3_v3v3(target, verts[s->ij].xold, verts[s->ij].xconst, time);
+		interp_v3_v3v3(target, v1->xold, v1->xconst, time);
 		sub_v3_v3v3(extent, lVector_v3(X, s->ij), target);
-		BKE_sim_debug_data_add_line(clmd->debug_data, verts[s->ij].xconst, verts[s->ij].xold, 1,0,0, "springs", hash_vertex(7825, s->ij));
+		BKE_sim_debug_data_add_line(clmd->debug_data, v1->xconst, v1->xold, 1,0,0, "springs", hash_vertex(7825, s->ij));
 		
 		// SEE MSG BELOW (these are UNUSED)
 		// dot = dot_v3v3(extent, extent);
@@ -323,7 +445,7 @@ static void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, con
 		k = clmd->sim_parms->goalspring;
 		scaling = k + s->stiffness * fabsf(clmd->sim_parms->max_struct - k);
 			
-		k = verts[s->ij].goal * scaling / (clmd->sim_parms->avg_spring_len + FLT_EPSILON);
+		k = v1->goal * scaling / (clmd->sim_parms->avg_spring_len + FLT_EPSILON);
 		madd_v3_v3fl(s->f, extent, -k);
 		
 		/* XXX this has no effect: dir is always null at this point! - lukas_t
@@ -355,27 +477,23 @@ static void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, con
 
 static void cloth_apply_spring_force(ClothModifierData *clmd, ClothSpring *s, lVector &F, lMatrix &dFdX, lMatrix &dFdV)
 {
-	TripletList trips;
-//	lMatrix tmp(F.rows(), F.rows());
-	
-	if (s->flags & CLOTH_SPRING_FLAG_NEEDED) {
-//		if (!(s->type & CLOTH_SPRING_TYPE_BENDING)) {
-//			triplets_m3(trips, s

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list