[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