Commit: 8a60de62f5d8db5449d2d60791d72593d9b7636e
Author: Lukas Tönne
Date:   Tue Dec 2 15:56:30 2014 +0100
Branches: hair_immediate_fixes
https://developer.blender.org/rB8a60de62f5d8db5449d2d60791d72593d9b7636e

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. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to