Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Tönne <lukas.toenne@gmail.com>2014-12-05 16:42:22 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2015-04-20 13:23:15 +0300
commit56a09434c533e5ca72d2f8ff6e144bfcdd88886c (patch)
tree9ca26e1fc412da4c3cd21fba2334af8a89103105
parent8672304e30a207767888b75ebe9015ad7f3210a3 (diff)
Basic Add tool for creating new strands in hair edit mode.
-rw-r--r--source/blender/blenkernel/BKE_edithair.h10
-rw-r--r--source/blender/blenkernel/BKE_mesh_sample.h2
-rw-r--r--source/blender/blenkernel/intern/edithair.c21
-rw-r--r--source/blender/blenkernel/intern/mesh_sample.c49
-rw-r--r--source/blender/bmesh/intern/bmesh_strands.c28
-rw-r--r--source/blender/bmesh/intern/bmesh_strands.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_strands_conv.c5
-rw-r--r--source/blender/bmesh/intern/bmesh_strands_conv.h2
-rw-r--r--source/blender/editors/hair/hair_edit.c8
-rw-r--r--source/blender/editors/hair/hair_intern.h1
-rw-r--r--source/blender/editors/hair/hair_stroke.c115
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;