diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2014-12-05 16:42:22 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2015-04-20 13:23:15 +0300 |
commit | 56a09434c533e5ca72d2f8ff6e144bfcdd88886c (patch) | |
tree | 9ca26e1fc412da4c3cd21fba2334af8a89103105 | |
parent | 8672304e30a207767888b75ebe9015ad7f3210a3 (diff) |
Basic Add tool for creating new strands in hair edit mode.
-rw-r--r-- | source/blender/blenkernel/BKE_edithair.h | 10 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_mesh_sample.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/edithair.c | 21 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh_sample.c | 49 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_strands.c | 28 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_strands.h | 3 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_strands_conv.c | 5 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_strands_conv.h | 2 | ||||
-rw-r--r-- | source/blender/editors/hair/hair_edit.c | 8 | ||||
-rw-r--r-- | source/blender/editors/hair/hair_intern.h | 1 | ||||
-rw-r--r-- | source/blender/editors/hair/hair_stroke.c | 115 |
11 files changed, 207 insertions, 37 deletions
diff --git a/source/blender/blenkernel/BKE_edithair.h b/source/blender/blenkernel/BKE_edithair.h index 070f8df2c8d..7d39ff691a8 100644 --- a/source/blender/blenkernel/BKE_edithair.h +++ b/source/blender/blenkernel/BKE_edithair.h @@ -54,11 +54,18 @@ typedef struct BMEditStrands { struct Object *ob; struct DerivedMesh *root_dm; + int flag; + unsigned int vertex_glbuf; unsigned int elem_glbuf; unsigned int dot_glbuf; } BMEditStrands; +/* BMEditStrands->flag */ +typedef enum BMEditStrandsFlag { + BM_STRANDS_DIRTY_SEGLEN = 1, +} BMEditStrandsFlag; + struct BMEditStrands *BKE_editstrands_create(struct BMesh *bm, struct DerivedMesh *root_dm); struct BMEditStrands *BKE_editstrands_copy(struct BMEditStrands *es); struct BMEditStrands *BKE_editstrands_from_object(struct Object *ob); @@ -67,9 +74,8 @@ 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); +void BKE_editstrands_ensure(struct BMEditStrands *es); /* === particle conversion === */ diff --git a/source/blender/blenkernel/BKE_mesh_sample.h b/source/blender/blenkernel/BKE_mesh_sample.h index e43b162a7b8..6b489550847 100644 --- a/source/blender/blenkernel/BKE_mesh_sample.h +++ b/source/blender/blenkernel/BKE_mesh_sample.h @@ -33,7 +33,7 @@ struct MSurfaceSample; /* ==== Evaluate ==== */ -bool BKE_mesh_sample_eval(struct DerivedMesh *dm, const struct MSurfaceSample *sample, float loc[3], float nor[3]); +bool BKE_mesh_sample_eval(struct DerivedMesh *dm, const struct MSurfaceSample *sample, float loc[3], float nor[3], float tang[3]); bool BKE_mesh_sample_shapekey(struct Key *key, struct KeyBlock *kb, const struct MSurfaceSample *sample, float loc[3]); diff --git a/source/blender/blenkernel/intern/edithair.c b/source/blender/blenkernel/intern/edithair.c index e1064d95946..2da64f18dc0 100644 --- a/source/blender/blenkernel/intern/edithair.c +++ b/source/blender/blenkernel/intern/edithair.c @@ -101,7 +101,7 @@ void BKE_editstrands_free(BMEditStrands *es) /* === constraints === */ -void BKE_editstrands_calc_segment_lengths(BMesh *bm) +static void editstrands_calc_segment_lengths(BMesh *bm) { BMVert *root, *v, *vprev; BMIter iter, iter_strand; @@ -128,10 +128,10 @@ static void editstrands_apply_root_locations(BMesh *bm, DerivedMesh *root_dm) BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) { MSurfaceSample root_sample; - float loc[3], nor[3]; + 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)) { + if (BKE_mesh_sample_eval(root_dm, &root_sample, loc, nor, tang)) { copy_v3_v3(root->co, loc); } } @@ -167,10 +167,23 @@ static void editstrands_solve_segment_lengths(BMesh *bm) void BKE_editstrands_solve_constraints(BMEditStrands *es) { + BKE_editstrands_ensure(es); + editstrands_apply_root_locations(es->bm, es->root_dm); editstrands_solve_segment_lengths(es->bm); } +void BKE_editstrands_ensure(BMEditStrands *es) +{ + BM_strands_cd_flag_ensure(es->bm, 0); + + if (es->flag & BM_STRANDS_DIRTY_SEGLEN) { + editstrands_calc_segment_lengths(es->bm); + + es->flag &= ~BM_STRANDS_DIRTY_SEGLEN; + } +} + /* === particle conversion === */ @@ -188,7 +201,7 @@ BMesh *BKE_particles_to_bmesh(Object *ob, ParticleSystem *psys) BM_strands_bm_from_psys(bm, ob, psys, psmd->dm, true, psys->shapenr); - BKE_editstrands_calc_segment_lengths(bm); + editstrands_calc_segment_lengths(bm); } return bm; diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index b4c59037f88..c36d2adde8b 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -43,15 +43,15 @@ /* ==== Evaluate ==== */ -bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float loc[3], float nor[3]) +bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float loc[3], float nor[3], float tang[3]) { MVert *mverts = dm->getVertArray(dm); unsigned int totverts = (unsigned int)dm->getNumVerts(dm); MVert *v1, *v2, *v3; - float vnor[3]; zero_v3(loc); zero_v3(nor); + zero_v3(tang); if (sample->orig_verts[0] >= totverts || sample->orig_verts[1] >= totverts || @@ -62,18 +62,39 @@ bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float l v2 = &mverts[sample->orig_verts[1]]; v3 = &mverts[sample->orig_verts[2]]; - madd_v3_v3fl(loc, v1->co, sample->orig_weights[0]); - madd_v3_v3fl(loc, v2->co, sample->orig_weights[1]); - madd_v3_v3fl(loc, v3->co, sample->orig_weights[2]); + { /* location */ + madd_v3_v3fl(loc, v1->co, sample->orig_weights[0]); + madd_v3_v3fl(loc, v2->co, sample->orig_weights[1]); + madd_v3_v3fl(loc, v3->co, sample->orig_weights[2]); + } - normal_short_to_float_v3(vnor, v1->no); - madd_v3_v3fl(nor, vnor, sample->orig_weights[0]); - normal_short_to_float_v3(vnor, v2->no); - madd_v3_v3fl(nor, vnor, sample->orig_weights[1]); - normal_short_to_float_v3(vnor, v3->no); - madd_v3_v3fl(nor, vnor, sample->orig_weights[2]); + { /* normal */ + float vnor[3]; + + normal_short_to_float_v3(vnor, v1->no); + madd_v3_v3fl(nor, vnor, sample->orig_weights[0]); + normal_short_to_float_v3(vnor, v2->no); + madd_v3_v3fl(nor, vnor, sample->orig_weights[1]); + normal_short_to_float_v3(vnor, v3->no); + madd_v3_v3fl(nor, vnor, sample->orig_weights[2]); + + normalize_v3(nor); + } - normalize_v3(nor); + { /* tangent */ + float edge[3]; + + /* XXX simply using the v1-v2 edge as a tangent vector for now ... + * Eventually mikktspace generated tangents (CD_TANGENT tessface layer) + * should be used for consistency, but requires well-defined tessface + * indices for the mesh surface samples. + */ + + sub_v3_v3v3(edge, v2->co, v1->co); + /* make edge orthogonal to nor */ + madd_v3_v3fl(edge, nor, -dot_v3v3(edge, nor)); + normalize_v3_v3(tang, edge); + } return true; } @@ -329,9 +350,9 @@ bool BKE_mesh_sample_from_particle(MSurfaceSample *sample, ParticleSystem *psys, bool BKE_mesh_sample_to_particle(MSurfaceSample *sample, ParticleSystem *UNUSED(psys), DerivedMesh *dm, BVHTreeFromMesh *bvhtree, ParticleData *pa) { BVHTreeNearest nearest; - float vec[3], nor[3]; + float vec[3], nor[3], tang[3]; - BKE_mesh_sample_eval(dm, sample, vec, nor); + BKE_mesh_sample_eval(dm, sample, vec, nor, tang); nearest.index = -1; nearest.dist_sq = FLT_MAX; diff --git a/source/blender/bmesh/intern/bmesh_strands.c b/source/blender/bmesh/intern/bmesh_strands.c index ae8fd7ae4f1..ec1b7781dd6 100644 --- a/source/blender/bmesh/intern/bmesh_strands.c +++ b/source/blender/bmesh/intern/bmesh_strands.c @@ -27,6 +27,7 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" +#include "BLI_math.h" #include "BLI_mempool.h" #include "bmesh.h" @@ -115,3 +116,30 @@ int BM_strands_keys_count(BMVert *root) return count; } +/* ------------------------------------------------------------------------- */ + +/* Create a new strand */ +BMVert *BM_strands_create(BMesh *bm, int len, bool set_defaults) +{ + float co[3] = {0.0f, 0.0f, 0.0f}; + + BMVert *root, *v, *vprev; + int k; + + for (k = 0; k < len; ++k) { + vprev = v; + v = BM_vert_create(bm, co, NULL, set_defaults ? BM_CREATE_NOP : BM_CREATE_SKIP_CD); + + zero_v3(v->no); + + /* root */ + if (k == 0) { + root = v; + } + else { + /*BMEdge *e =*/ BM_edge_create(bm, vprev, v, NULL, set_defaults ? BM_CREATE_NOP : BM_CREATE_SKIP_CD); + } + } + + return root; +} diff --git a/source/blender/bmesh/intern/bmesh_strands.h b/source/blender/bmesh/intern/bmesh_strands.h index 8410bfd8443..66284ee62f8 100644 --- a/source/blender/bmesh/intern/bmesh_strands.h +++ b/source/blender/bmesh/intern/bmesh_strands.h @@ -72,6 +72,9 @@ BLI_INLINE bool BM_strands_vert_is_tip(BMVert *v) int BM_strands_count(BMesh *bm); int BM_strands_keys_count(BMVert *root); +/* Create a new strand */ +struct BMVert *BM_strands_create(struct BMesh *bm, int len, bool set_defaults); + /* ==== Iterators ==== */ typedef enum BMStrandsIterType { diff --git a/source/blender/bmesh/intern/bmesh_strands_conv.c b/source/blender/bmesh/intern/bmesh_strands_conv.c index 786b35b486a..b23dbbdf1fe 100644 --- a/source/blender/bmesh/intern/bmesh_strands_conv.c +++ b/source/blender/bmesh/intern/bmesh_strands_conv.c @@ -76,13 +76,10 @@ void BM_strands_cd_validate(BMesh *UNUSED(bm)) { } -void BM_strands_cd_flag_ensure(BMesh *bm, ParticleSystem *psys, const char cd_flag) +void BM_strands_cd_flag_ensure(BMesh *bm, const char cd_flag) { const char cd_flag_all = BM_strands_cd_flag_from_bmesh(bm) | cd_flag; BM_strands_cd_flag_apply(bm, cd_flag_all); - if (psys) { -// psys->cd_flag = cd_flag_all; - } } void BM_strands_cd_flag_apply(BMesh *bm, const char UNUSED(cd_flag)) diff --git a/source/blender/bmesh/intern/bmesh_strands_conv.h b/source/blender/bmesh/intern/bmesh_strands_conv.h index 30bf139c4de..683c1e998ad 100644 --- a/source/blender/bmesh/intern/bmesh_strands_conv.h +++ b/source/blender/bmesh/intern/bmesh_strands_conv.h @@ -45,7 +45,7 @@ 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); +void BM_strands_cd_flag_ensure(struct BMesh *bm, const char cd_flag); void BM_strands_cd_flag_apply(struct BMesh *bm, const char cd_flag); char BM_strands_cd_flag_from_bmesh(struct BMesh *bm); diff --git a/source/blender/editors/hair/hair_edit.c b/source/blender/editors/hair/hair_edit.c index fa7e914b5ee..4912adde524 100644 --- a/source/blender/editors/hair/hair_edit.c +++ b/source/blender/editors/hair/hair_edit.c @@ -308,7 +308,6 @@ static bool hair_stroke_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) HairEditSettings *settings = &scene->toolsettings->hair_edit; ARegion *ar = CTX_wm_region(C); - float imat[4][4]; float mouse[2], mdelta[2], zvec[3], delta_max; int totsteps, step; HairToolData tool_data; @@ -316,8 +315,6 @@ static bool hair_stroke_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) RNA_float_get_array(itemptr, "mouse", mouse); - invert_m4_m4(imat, ob->obmat); - if (stroke->first) { copy_v2_v2(stroke->lastmouse, mouse); stroke->first = false; @@ -338,6 +335,7 @@ static bool hair_stroke_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) tool_data.edit = edit; tool_data.settings = settings; + invert_m4_m4(tool_data.imat, ob->obmat); copy_v2_v2(tool_data.mval, mouse); tool_data.mdepth = stroke->zfac; @@ -345,8 +343,8 @@ static bool hair_stroke_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) ED_view3d_win_to_3d(ar, zvec, mouse, tool_data.loc); ED_view3d_win_to_delta(ar, mdelta, tool_data.delta, stroke->zfac); /* tools work in object space */ - mul_m4_v3(imat, tool_data.loc); - mul_mat3_m4_v3(imat, tool_data.delta); + mul_m4_v3(tool_data.imat, tool_data.loc); + mul_mat3_m4_v3(tool_data.imat, tool_data.delta); for (step = 0; step < totsteps; ++step) { bool step_updated = hair_brush_step(&tool_data); diff --git a/source/blender/editors/hair/hair_intern.h b/source/blender/editors/hair/hair_intern.h index 7218fa08483..92b40fd083f 100644 --- a/source/blender/editors/hair/hair_intern.h +++ b/source/blender/editors/hair/hair_intern.h @@ -73,6 +73,7 @@ typedef struct HairToolData { float mdepth; /* mouse z depth */ /* object space */ + float imat[4][4]; /* obmat inverse */ float loc[3]; /* start location */ float delta[3]; /* stroke step */ } HairToolData; diff --git a/source/blender/editors/hair/hair_stroke.c b/source/blender/editors/hair/hair_stroke.c index e7b095e9c85..ec34475fc94 100644 --- a/source/blender/editors/hair/hair_stroke.c +++ b/source/blender/editors/hair/hair_stroke.c @@ -37,12 +37,15 @@ #include "BLI_math.h" #include "DNA_brush_types.h" +#include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_view3d_types.h" #include "BKE_brush.h" +#include "BKE_DerivedMesh.h" #include "BKE_edithair.h" +#include "BKE_mesh_sample.h" #include "bmesh.h" @@ -163,10 +166,102 @@ static void hair_vertex_comb(HairToolData *data, void *userdata, BMVert *v, floa madd_v3_v3fl(v->co, data->delta, combfactor); } + +BLI_INLINE void construct_m4_loc_nor_tan(float mat[4][4], const float loc[3], const float nor[3], const float tang[3]) +{ + float cotang[3]; + + cross_v3_v3v3(cotang, nor, tang); + + copy_v3_v3(mat[0], tang); + copy_v3_v3(mat[1], cotang); + copy_v3_v3(mat[2], nor); + copy_v3_v3(mat[3], loc); + mat[0][3] = 0.0f; + mat[1][3] = 0.0f; + mat[2][3] = 0.0f; + mat[3][3] = 1.0f; +} + +static void grow_hair(BMEditStrands *edit, MSurfaceSample *sample) +{ + DerivedMesh *dm = edit->root_dm; + const float len = 1.5f; + + float root_mat[4][4]; + BMVert *root, *v; + BMIter iter; + int i; + + { + float co[3], nor[3], tang[3]; + BKE_mesh_sample_eval(dm, sample, co, nor, tang); + construct_m4_loc_nor_tan(root_mat, co, nor, tang); + } + + root = BM_strands_create(edit->bm, 5, true); + + BM_elem_meshsample_data_named_set(&edit->bm->vdata, root, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION, sample); + + BM_ITER_STRANDS_ELEM_INDEX(v, &iter, root, BM_VERTS_OF_STRAND, i) { + float co[3]; + + co[0] = co[1] = 0.0f; + co[2] = len * (float)i / (float)(len - 1); + + mul_m4_v3(root_mat, co); + + copy_v3_v3(v->co, co); + } + + BM_mesh_elem_index_ensure(edit->bm, BM_ALL); +} + +static bool hair_add_ray_cb(void *vdata, float ray_start[3], float ray_end[3]) +{ + HairToolData *data = vdata; + ViewContext *vc = &data->viewdata.vc; + + ED_view3d_win_to_segment(vc->ar, vc->v3d, data->mval, ray_start, ray_end, true); + + mul_m4_v3(data->imat, ray_start); + mul_m4_v3(data->imat, ray_end); + + return true; +} + +static bool hair_get_surface_sample(HairToolData *data, MSurfaceSample *sample) +{ + DerivedMesh *dm = data->edit->root_dm; + + MSurfaceSampleStorage dst; + int tot; + + BKE_mesh_sample_storage_single(&dst, sample); + tot = BKE_mesh_sample_generate_raycast(&dst, dm, hair_add_ray_cb, data, 1); + BKE_mesh_sample_storage_release(&dst); + + return tot > 0; +} + +static bool hair_add(HairToolData *data) +{ + MSurfaceSample sample; + + if (!hair_get_surface_sample(data, &sample)) + return false; + + grow_hair(data->edit, &sample); + + return true; +} + + bool hair_brush_step(HairToolData *data) { Brush *brush = data->settings->brush; BrushHairTool hair_tool = brush->hair_tool; + BMEditStrands *edit = data->edit; int tot = 0; switch (hair_tool) { @@ -181,12 +276,20 @@ bool hair_brush_step(HairToolData *data) tot = hair_tool_apply_vertex(data, hair_vertex_comb, &combdata); break; } - case HAIR_TOOL_CUT: break; - case HAIR_TOOL_LENGTH: break; - case HAIR_TOOL_PUFF: break; - case HAIR_TOOL_ADD: break; - case HAIR_TOOL_SMOOTH: break; - case HAIR_TOOL_WEIGHT: break; + case HAIR_TOOL_CUT: + break; + case HAIR_TOOL_LENGTH: + break; + case HAIR_TOOL_PUFF: + break; + case HAIR_TOOL_ADD: + if (hair_add(data)) + edit->flag |= BM_STRANDS_DIRTY_SEGLEN; + break; + case HAIR_TOOL_SMOOTH: + break; + case HAIR_TOOL_WEIGHT: + break; } return tot > 0; |