[Bf-blender-cvs] [7f0a000] hair_immediate_fixes: IK solver for hair strands that provides a better solution for keeping consistent segment lengths when transforming vertices.

Lukas Tönne noreply at git.blender.org
Sat Dec 27 11:32:58 CET 2014


Commit: 7f0a000fbca228182283a6f8741166f827e866b0
Author: Lukas Tönne
Date:   Fri Dec 12 13:48:36 2014 +0100
Branches: hair_immediate_fixes
https://developer.blender.org/rB7f0a000fbca228182283a6f8741166f827e866b0

IK solver for hair strands that provides a better solution for keeping
consistent segment lengths when transforming vertices.

Warning: The implementation is not correct yet, but all the steps should
be there.

The main idea is to treat strands as a sequence of joints that are
displaced out of their original locations by a transform or other tool.
The solver then tries to find a global per-strand solution that keeps
the segment lengths unmodified, with a minimum change in angles from
the original starting shape. Such a solution is much more usable and
efficient than the current O(n^2) attempt of "spreading the error"
across the strand.

The inverse kinematics method is very flexible. It can also include
stretching, which would be very welcome for features like the length
tool. Different parts of the strand could be weighted separately using
scaling factors for the angle/stretch parameters.

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

M	source/blender/blenkernel/BKE_editstrands.h
M	source/blender/blenkernel/intern/editstrands.c
M	source/blender/bmesh/bmesh_class.h
M	source/blender/bmesh/intern/bmesh_strands.h
M	source/blender/editors/hair/hair_edit.c
M	source/blender/editors/transform/transform_conversions.c
A	source/blender/physics/BPH_strands.h
M	source/blender/physics/CMakeLists.txt
M	source/blender/physics/intern/eigen_utils.h
M	source/blender/physics/intern/implicit.h
M	source/blender/physics/intern/implicit_blender.c
M	source/blender/physics/intern/implicit_eigen.cpp
A	source/blender/physics/intern/strands.cpp

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

diff --git a/source/blender/blenkernel/BKE_editstrands.h b/source/blender/blenkernel/BKE_editstrands.h
index 2768e86..d8b822d 100644
--- a/source/blender/blenkernel/BKE_editstrands.h
+++ b/source/blender/blenkernel/BKE_editstrands.h
@@ -76,7 +76,15 @@ void BKE_editstrands_free(struct BMEditStrands *es);
 
 /* === constraints === */
 
-void BKE_editstrands_solve_constraints(struct BMEditStrands *es);
+/* Stores vertex locations for temporary reference:
+ * Vertex locations get modified by tools, but then need to be corrected
+ * by calculating a smooth solution based on the difference to original pre-tool locations.
+ */
+typedef float (*BMEditStrandsLocations)[3];
+BMEditStrandsLocations BKE_editstrands_get_locations(struct BMEditStrands *edit);
+void BKE_editstrands_free_locations(BMEditStrandsLocations locs);
+
+void BKE_editstrands_solve_constraints(struct Object *ob, struct BMEditStrands *es, BMEditStrandsLocations orig);
 void BKE_editstrands_ensure(struct BMEditStrands *es);
 
 /* === particle conversion === */
diff --git a/source/blender/blenkernel/intern/editstrands.c b/source/blender/blenkernel/intern/editstrands.c
index 94aa9b9..777c8bd 100644
--- a/source/blender/blenkernel/intern/editstrands.c
+++ b/source/blender/blenkernel/intern/editstrands.c
@@ -48,6 +48,8 @@
 #include "BKE_mesh_sample.h"
 #include "BKE_particle.h"
 
+#include "BPH_strands.h"
+
 #include "intern/bmesh_strands_conv.h"
 
 BMEditStrands *BKE_editstrands_create(BMesh *bm, DerivedMesh *root_dm)
@@ -105,106 +107,35 @@ void BKE_editstrands_free(BMEditStrands *es)
 
 /* === constraints === */
 
-static void editstrands_calc_segment_lengths(BMesh *bm)
+BMEditStrandsLocations BKE_editstrands_get_locations(BMEditStrands *edit)
 {
-	BMVert *root, *v, *vprev;
-	BMIter iter, iter_strand;
-	int k;
+	BMesh *bm = edit->bm;
+	BMEditStrandsLocations locs = MEM_mallocN(3*sizeof(float) * bm->totvert, "editstrands locations");
 	
-	BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) {
-		BM_ITER_STRANDS_ELEM_INDEX(v, &iter_strand, root, BM_VERTS_OF_STRAND, k) {
-			if (k > 0) {
-				float length = len_v3v3(v->co, vprev->co);
-				BM_elem_float_data_named_set(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH, length);
-			}
-			vprev = v;
-		}
+	BMVert *v;
+	BMIter iter;
+	int i;
+	
+	BM_ITER_MESH_INDEX(v, &iter, bm, BM_VERTS_OF_MESH, i) {
+		copy_v3_v3(locs[i], v->co);
 	}
+	
+	return locs;
 }
 
-static void editstrands_apply_root_locations(BMesh *bm, DerivedMesh *root_dm)
+void BKE_editstrands_free_locations(BMEditStrandsLocations locs)
 {
-	BMVert *root;
-	BMIter iter;
-	
-	if (!root_dm)
-		return;
-	
-	BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) {
-		MSurfaceSample root_sample;
-		float loc[3], nor[3], tang[3];
-		
-		BM_elem_meshsample_data_named_get(&bm->vdata, root, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION, &root_sample);
-		if (BKE_mesh_sample_eval(root_dm, &root_sample, loc, nor, tang)) {
-			copy_v3_v3(root->co, loc);
-		}
-	}
+	MEM_freeN(locs);
 }
 
-/* try to find a nice solution to keep distances between neighboring keys */
-/* XXX Stub implementation ported from particles:
- * Successively relax each segment starting from the root,
- * repeat this for every vertex (O(n^2) !!)
- * This should be replaced by a more advanced method using a least-squares
- * error metric with length and root location constraints (IK solver)
- */
-static void editstrands_solve_targets(BMEditStrands *edit)
+void BKE_editstrands_solve_constraints(Object *ob, BMEditStrands *es, BMEditStrandsLocations orig)
 {
-	BMesh *bm = edit->bm;
-	BMVert *root;
-	BMIter iter;
-	
-	if (!edit)
-		return;
-//	if (!(pset->flag & PE_KEEP_LENGTHS)) // XXX TODO
-//		return;
+	BKE_editstrands_ensure(es);
 	
-	BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) {
-		const int numvert = BM_strands_keys_count(root);
-		float relax_factor = numvert > 0 ? 1.0f / numvert : 0.0f;
-		
-		BMVert *vj;
-		BMIter iterj;
-		int j;
-		
-		BM_ITER_STRANDS_ELEM_INDEX(vj, &iterj, root, BM_VERTS_OF_STRAND, j) {
-			BMVert *vk, *vk_prev;
-			float lenk, lenk_prev;
-			BMIter iterk;
-			int k;
-			bool skip_first;
-			
-			if (j == 0)
-				continue;
-			
-			if (true /* XXX particles use PE_LOCK_FIRST option */)
-				skip_first = true;
-			else
-				skip_first = false;
-			
-			BM_ITER_STRANDS_ELEM_INDEX(vk, &iterk, root, BM_VERTS_OF_STRAND, k) {
-				float dir[3], tlen, relax;
-				
-				lenk = BM_elem_float_data_named_get(&bm->vdata, vk, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH);
-				
-				if (k > 0) {
-					sub_v3_v3v3(dir, vk->co, vk_prev->co);
-					tlen = normalize_v3(dir);
-					relax = relax_factor * (tlen - lenk_prev);
-					
-					if (!(k == 1 && skip_first))
-						madd_v3_v3fl(vk_prev->co, dir, relax);
-					madd_v3_v3fl(vk->co, dir, -relax);
-				}
-				
-				vk_prev = vk;
-				lenk_prev = lenk;
-			}
-		}
-	}
+	BPH_strands_solve_constraints(ob, es, orig);
 }
 
-static void editstrands_adjust_segment_lengths(BMesh *bm)
+static void editstrands_calc_segment_lengths(BMesh *bm)
 {
 	BMVert *root, *v, *vprev;
 	BMIter iter, iter_strand;
@@ -213,31 +144,14 @@ static void editstrands_adjust_segment_lengths(BMesh *bm)
 	BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) {
 		BM_ITER_STRANDS_ELEM_INDEX(v, &iter_strand, root, BM_VERTS_OF_STRAND, k) {
 			if (k > 0) {
-				float base_length = BM_elem_float_data_named_get(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH);
-				float dist[3];
-				float length;
-				
-				sub_v3_v3v3(dist, v->co, vprev->co);
-				length = len_v3(dist);
-				if (length > 0.0f)
-					madd_v3_v3v3fl(v->co, vprev->co, dist, base_length / length);
+				float length = len_v3v3(v->co, vprev->co);
+				BM_elem_float_data_named_set(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH, length);
 			}
 			vprev = v;
 		}
 	}
 }
 
-void BKE_editstrands_solve_constraints(BMEditStrands *es)
-{
-	BKE_editstrands_ensure(es);
-	
-	editstrands_apply_root_locations(es->bm, es->root_dm);
-	
-	editstrands_solve_targets(es);
-	
-	editstrands_adjust_segment_lengths(es->bm);
-}
-
 void BKE_editstrands_ensure(BMEditStrands *es)
 {
 	BM_strands_cd_flag_ensure(es->bm, 0);
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index 120ff49..75de216 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -259,8 +259,16 @@ enum {
 #define BM_CHECK_TYPE_ELEM(ele) \
 	CHECK_TYPE_ANY(ele, void *, BMFace *, BMEdge *, BMVert *, BMLoop *, BMElem *, BMElemF *, BMHeader *)
 
+#ifndef __cplusplus
 #define BM_CHECK_TYPE_ELEM_ASSIGN(ele) \
 	(BM_CHECK_TYPE_ELEM(ele), CHECK_TYPE_NONCONST(ele)), ele
+#else
+/* for C++: cast the lhs to a void*,
+ * because C++ does not allow implicit void* casting of the rhs
+ */
+#define BM_CHECK_TYPE_ELEM_ASSIGN(ele) \
+	(BM_CHECK_TYPE_ELEM(ele), CHECK_TYPE_NONCONST(ele)), *(void**)(&(ele))
+#endif
 
 /* BMHeader->hflag (char) */
 enum {
diff --git a/source/blender/bmesh/intern/bmesh_strands.h b/source/blender/bmesh/intern/bmesh_strands.h
index a0b0cfb..f326331 100644
--- a/source/blender/bmesh/intern/bmesh_strands.h
+++ b/source/blender/bmesh/intern/bmesh_strands.h
@@ -87,16 +87,24 @@ typedef enum BMStrandsIterType {
 } BMStrandsIterType;
 
 #define BM_ITER_STRANDS(ele, iter, bm, itype) \
-	for (ele = BM_strand_iter_new(iter, bm, itype, NULL); ele; ele = BM_iter_step(iter))
+	for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_strand_iter_new(iter, bm, itype, NULL); \
+	     ele; \
+	     BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter))
 
 #define BM_ITER_STRANDS_INDEX(ele, iter, bm, itype, indexvar) \
-	for (ele = BM_strand_iter_new(iter, bm, itype, NULL), indexvar = 0; ele; ele = BM_iter_step(iter), (indexvar)++)
+	for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_strand_iter_new(iter, bm, itype, NULL), indexvar = 0; \
+	     ele; \
+	     BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter), (indexvar)++)
 
 #define BM_ITER_STRANDS_ELEM(ele, iter, data, itype) \
-	for (ele = BM_strand_iter_new(iter, NULL, itype, data); ele; ele = BM_iter_step(iter))
+	for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_strand_iter_new(iter, NULL, itype, data); \
+	     ele; \
+	     BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter))
 
 #define BM_ITER_STRANDS_ELEM_INDEX(ele, iter, data, itype, indexvar) \
-	for (ele = BM_strand_iter_new(iter, NULL, itype, data), indexvar = 0; ele; ele = BM_iter_step(iter), (indexvar)++)
+	for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_strand_iter_new(iter, NULL, itype, data), indexvar = 0; \
+	     ele; \
+	     BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter), (indexvar)++)
 
 typedef struct BMIter__vert_of_strand {
 	BMVert *v_next;
diff --git a/source/blender/editors/hair/hair_edit.c b/source/blender/editors/hair/hair_edit.c
index 71ff41f..4be4570 100644
--- a/source/blender/editors/hair/hair_edit.c
+++ b/source/blender/editors/hair/hair_edit.c
@@ -357,7 +357,7 @@ static bool hair_stroke_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
 		bool step_updated = hair_brush_step(&tool_data);
 		
 		if (step_updated)
-			BKE_editstrands_solve_constraints(edit);
+			BKE_editstrands_solve_constraints(ob, edit, NULL);
 		
 		updated |= step_updated;
 	}
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 7add2e1..9b1fa21 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -2049,7 +2049,10 @@ static void createTransStrandVerts(TransInfo *t)
 		}
 #endif
 	}
-
+	
+	t->customData = BKE_editstrands_get_locations(edit);
+	t->flag |= T_FREE_CUSTOMDATA;
+	
 	BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
 		if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
 			if (propmode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
@@ -2125,8 +2128,9 @@ void flushTransStrands(TransInfo *t)
 	Scene *scene = t->scene;
 	Object *ob = OBACT;
 	BMEditStrands *edit = BKE_editstrands_from_object(ob);
+	BMEditStrandsLocations origlocs = t->customData;
 	
-	BKE_editstrands_solve_constraints(edit);
+	BKE_editstrands_solve_constraints(ob, edit, origlocs);
 }
 
 /* ********************* mesh ****************** */
diff --git a/source/blender/physics/BPH_strands.h b/source/blender/physics/BPH_strands.h

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list