[Bf-blender-cvs] [83b20c7] strand_editmode: Enforce hair constraints (constant segment length) after applying a tool.

Lukas Tönne noreply at git.blender.org
Mon Apr 20 14:23:30 CEST 2015


Commit: 83b20c7ddfe60ca779f53a0d337cc1b7854fb14c
Author: Lukas Tönne
Date:   Tue Dec 2 15:56:30 2014 +0100
Branches: strand_editmode
https://developer.blender.org/rB83b20c7ddfe60ca779f53a0d337cc1b7854fb14c

Enforce hair constraints (constant segment length) after applying a tool.

Currently uses the same approach as old particle edit mode (rescale
hair segments from the root on). A more sophisticated approach using
least-square error minimization of the displacement could yield better
results.

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

M	source/blender/blenkernel/BKE_edithair.h
M	source/blender/blenkernel/intern/edithair.c
M	source/blender/bmesh/intern/bmesh_strands.h
M	source/blender/bmesh/intern/bmesh_strands_conv.c
M	source/blender/bmesh/intern/bmesh_strands_conv.h
M	source/blender/editors/hair/hair_edit.c
M	source/blender/editors/hair/hair_stroke.c

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

diff --git a/source/blender/blenkernel/BKE_edithair.h b/source/blender/blenkernel/BKE_edithair.h
index ff3d91f..3c78021 100644
--- a/source/blender/blenkernel/BKE_edithair.h
+++ b/source/blender/blenkernel/BKE_edithair.h
@@ -39,6 +39,7 @@
 #include "BKE_customdata.h"
 #include "bmesh.h"
 
+struct BMesh;
 struct Object;
 
 typedef struct BMEditStrands {
@@ -59,10 +60,16 @@ typedef struct BMEditStrands {
 } BMEditStrands;
 
 struct BMEditStrands *BKE_editstrands_create(struct BMesh *bm);
-struct BMEditStrands *BKE_editstrands_copy(struct BMEditStrands *em);
+struct BMEditStrands *BKE_editstrands_copy(struct BMEditStrands *es);
 struct BMEditStrands *BKE_editstrands_from_object(struct Object *ob);
-void BKE_editstrands_update_linked_customdata(struct BMEditStrands *em);
-void BKE_editstrands_free(struct BMEditStrands *em);
+void BKE_editstrands_update_linked_customdata(struct BMEditStrands *es);
+void BKE_editstrands_free(struct BMEditStrands *es);
+
+/* === constraints === */
+
+void BKE_editstrands_calc_segment_lengths(struct BMesh *bm);
+
+void BKE_editstrands_solve_constraints(struct BMEditStrands *es);
 
 /* === particle conversion === */
 
diff --git a/source/blender/blenkernel/intern/edithair.c b/source/blender/blenkernel/intern/edithair.c
index d9ced64..6beb5f5 100644
--- a/source/blender/blenkernel/intern/edithair.c
+++ b/source/blender/blenkernel/intern/edithair.c
@@ -93,6 +93,56 @@ void BKE_editstrands_free(BMEditStrands *es)
 		BM_mesh_free(es->bm);
 }
 
+/* === constraints === */
+
+void BKE_editstrands_calc_segment_lengths(BMesh *bm)
+{
+	BMVert *root, *v, *vprev;
+	BMIter iter, iter_strand;
+	int k;
+	
+	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;
+		}
+	}
+}
+
+void BKE_editstrands_solve_constraints(BMEditStrands *es)
+{
+	/* XXX Simplistic implementation from particles:
+	 * adjust segment lengths starting from the root.
+	 * This should be replaced by a more advanced method using a least-squares
+	 * error metric with length and root location constraints
+	 */
+	
+	BMesh *bm = es->bm;
+	BMVert *root, *v, *vprev;
+	BMIter iter, iter_strand;
+	int k;
+	
+	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);
+			}
+			vprev = v;
+		}
+	}
+}
+
+
 /* === particle conversion === */
 
 BMesh *BKE_particles_to_bmesh(Object *ob, ParticleSystem *psys)
@@ -108,6 +158,8 @@ BMesh *BKE_particles_to_bmesh(Object *ob, ParticleSystem *psys)
 		DM_ensure_tessface(psmd->dm);
 		
 		BM_strands_bm_from_psys(bm, ob, psys, psmd->dm, true, psys->shapenr);
+		
+		BKE_editstrands_calc_segment_lengths(bm);
 	}
 
 	return bm;
diff --git a/source/blender/bmesh/intern/bmesh_strands.h b/source/blender/bmesh/intern/bmesh_strands.h
index 7df7eb6..96d5fa9 100644
--- a/source/blender/bmesh/intern/bmesh_strands.h
+++ b/source/blender/bmesh/intern/bmesh_strands.h
@@ -64,9 +64,15 @@ typedef enum 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))
 
+#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)++)
+
 #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))
 
+#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)++)
+
 typedef struct BMIter__vert_of_strand {
 	BMVert *v_next;
 	BMEdge *e_next;
diff --git a/source/blender/bmesh/intern/bmesh_strands_conv.c b/source/blender/bmesh/intern/bmesh_strands_conv.c
index 0c3a047..0dfb89c 100644
--- a/source/blender/bmesh/intern/bmesh_strands_conv.c
+++ b/source/blender/bmesh/intern/bmesh_strands_conv.c
@@ -45,9 +45,10 @@
 #include "bmesh.h"
 #include "intern/bmesh_private.h" /* for element checking */
 
-const char *CD_PSYS_MASS = "PSYS_MASS";
-const char *CD_PSYS_WEIGHT = "PSYS_WEIGHT";
-const char *CD_PSYS_ROOT_LOCATION = "PSYS_ROOT_LOCATION";
+const char *CD_HAIR_SEGMENT_LENGTH = "HAIR_SEGMENT_LENGTH";
+const char *CD_HAIR_MASS = "HAIR_MASS";
+const char *CD_HAIR_WEIGHT = "HAIR_WEIGHT";
+const char *CD_HAIR_ROOT_LOCATION = "HAIR_ROOT_LOCATION";
 
 static void BM_elem_msample_data_named_get(CustomData *cd, void *element, int type, const char *name, MSurfaceSample *val)
 {
@@ -106,14 +107,17 @@ void BM_strands_cd_flag_apply(BMesh *bm, const char UNUSED(cd_flag))
 	BLI_assert(bm->vdata.totlayer == 0 || bm->vdata.pool != NULL);
 	BLI_assert(bm->edata.totlayer == 0 || bm->edata.pool != NULL);
 	
-	if (CustomData_get_named_layer_index(&bm->vdata, CD_PROP_FLT, CD_PSYS_MASS) < 0) {
-		BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_FLT, CD_PSYS_MASS);
+	if (CustomData_get_named_layer_index(&bm->vdata, CD_PROP_FLT, CD_HAIR_MASS) < 0) {
+		BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_FLT, CD_HAIR_MASS);
 	}
-	if (CustomData_get_named_layer_index(&bm->vdata, CD_PROP_FLT, CD_PSYS_WEIGHT) < 0) {
-		BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_FLT, CD_PSYS_WEIGHT);
+	if (CustomData_get_named_layer_index(&bm->vdata, CD_PROP_FLT, CD_HAIR_WEIGHT) < 0) {
+		BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_FLT, CD_HAIR_WEIGHT);
 	}
-	if (CustomData_get_named_layer_index(&bm->vdata, CD_MSURFACE_SAMPLE, CD_PSYS_ROOT_LOCATION) < 0) {
-		BM_data_layer_add_named(bm, &bm->vdata, CD_MSURFACE_SAMPLE, CD_PSYS_ROOT_LOCATION);
+	if (CustomData_get_named_layer_index(&bm->vdata, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION) < 0) {
+		BM_data_layer_add_named(bm, &bm->vdata, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION);
+	}
+	if (CustomData_get_named_layer_index(&bm->vdata, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH) < 0) {
+		BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH);
 	}
 }
 
@@ -218,14 +222,14 @@ static void bm_make_particles(BMesh *bm, Object *ob, ParticleSystem *psys, struc
 //			CustomData_to_bmesh_block(&me->vdata, &bm->vdata, vindex, &v->head.data, true);
 			CustomData_bmesh_set_default(&bm->vdata, &v->head.data);
 			
-			BM_elem_float_data_named_set(&bm->vdata, v, CD_PROP_FLT, CD_PSYS_MASS, mass);
-			BM_elem_float_data_named_set(&bm->vdata, v, CD_PROP_FLT, CD_PSYS_WEIGHT, hkey->weight);
+			BM_elem_float_data_named_set(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_MASS, mass);
+			BM_elem_float_data_named_set(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_WEIGHT, hkey->weight);
 			
 			/* root */
 			if (k == 0) {
 				MSurfaceSample root_loc;
 				if (BKE_mesh_sample_from_particle(&root_loc, psys, emitter_dm, pa)) {
-					BM_elem_msample_data_named_set(&bm->vdata, v, CD_MSURFACE_SAMPLE, CD_PSYS_ROOT_LOCATION, &root_loc);
+					BM_elem_msample_data_named_set(&bm->vdata, v, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION, &root_loc);
 				}
 			}
 			
@@ -474,7 +478,7 @@ static void make_particle_hair(BMesh *bm, BMVert *root, Object *ob, ParticleSyst
 		/* root */
 		if (k == 0) {
 			MSurfaceSample root_loc;
-			BM_elem_msample_data_named_get(&bm->vdata, v, CD_MSURFACE_SAMPLE, CD_PSYS_ROOT_LOCATION, &root_loc);
+			BM_elem_msample_data_named_get(&bm->vdata, v, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION, &root_loc);
 			if (!BKE_mesh_sample_to_particle(&root_loc, psys, emitter_dm, emitter_bvhtree, pa)) {
 				pa->num = 0;
 				pa->num_dmcache = DMCACHE_NOTFOUND;
@@ -490,7 +494,7 @@ static void make_particle_hair(BMesh *bm, BMVert *root, Object *ob, ParticleSyst
 		mul_v3_m4v3(hkey->co, inv_hairmat, v->co);
 		
 		hkey->time = totkey > 0 ? (float)k / (float)(totkey - 1) : 0.0f;
-		hkey->weight = BM_elem_float_data_named_get(&bm->vdata, v, CD_PROP_FLT, CD_PSYS_WEIGHT);
+		hkey->weight = BM_elem_float_data_named_get(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_WEIGHT);
 		
 		++hkey;
 		++k;
diff --git a/source/blender/bmesh/intern/bmesh_strands_conv.h b/source/blender/bmesh/intern/bmesh_strands_conv.h
index 92a29ef..30bf139 100644
--- a/source/blender/bmesh/intern/bmesh_strands_conv.h
+++ b/source/blender/bmesh/intern/bmesh_strands_conv.h
@@ -39,9 +39,10 @@ struct ParticleSystem;
 struct DerivedMesh;
 struct BVHTreeFromMesh;
 
-extern const char *CD_PSYS_MASS;
-extern const char *CD_PSYS_WEIGHT;
-extern const char *CD_PSYS_ROOT_LOCATION;
+extern const char *CD_HAIR_SEGMENT_LENGTH;
+extern const char *CD_HAIR_MASS;
+extern const char *CD_HAIR_WEIGHT;
+extern const char *CD_HAIR_ROOT_LOCATION;
 
 void BM_strands_cd_validate(struct BMesh *bm);
 void BM_strands_cd_flag_ensure(struct BMesh *bm, struct ParticleSystem *psys, const char cd_flag);
diff --git a/source/blender/editors/hair/hair_edit.c b/source/blender/editors/hair/hair_edit.c
index e2b097c..90884f5 100644
--- a/source/blender/editors/hair/hair_edit.c
+++ b/source/blender/editors/hair/hair_edit.c
@@ -300,7 +300,12 @@ static bool hair_stroke_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
 	mul_mat3_m4_v3(imat, tool_data.delta);
 
 	for (step = 0; step < totsteps; ++step) {
-		updated |= hair_brush_step(&tool_data);
+		bool step_updated = hair_brush_step(&tool_data);
+		
+		if (step_updated)
+			BKE_editstrands_solve_constraints(edit);
+		
+		updated |= step_updated;
 	}
 	
 	copy_v2_v2(stroke->lastmouse, mouse);
diff --git a/source/blender/editors/hair/hair_stroke.c b/source/blender/editors/hair/hair_stroke.c
index 656adb2..6933c3b 100644
--- a/source/blender/editors/hair/hair_stroke.c
+++ b/source/blender/editors/hair/hair_stroke.c
@@ -49,6 +49,11 @@ typedef void (*VertexToolCb)(HairToolData *data, BMVert *v, float factor);
 
 BLI_INLINE float hair_tool_filter_vertex(HairToolData *da

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list