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:
authorSergey Sharybin <sergey.vfx@gmail.com>2018-02-14 16:33:53 +0300
committerSergey Sharybin <sergey.vfx@gmail.com>2018-02-15 13:53:58 +0300
commitffde74a878882618ab4d4179ba8dd9b98aab15e2 (patch)
tree9feb87aff52fc5cfa7191d79113d9f634a043ed2 /source/blender
parentbb3efe61276346f7ee12d24308d95d447941b0ec (diff)
Simple hair children: Initial implementation of twist control
It allows to have children hair to be twisted around parent curve, which is quite an essential feature when creating hair braids. There are currently two controls: - Number of turns around parent children. - Influence curve, which allows to modify "twistness" along the strand.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_particle.h2
-rw-r--r--source/blender/blenkernel/intern/particle.c26
-rw-r--r--source/blender/blenkernel/intern/particle_child.c87
-rw-r--r--source/blender/blenkernel/intern/particle_system.c3
-rw-r--r--source/blender/blenkernel/intern/smoke.c2
-rw-r--r--source/blender/blenkernel/particle_private.h1
-rw-r--r--source/blender/blenloader/intern/readfile.c3
-rw-r--r--source/blender/blenloader/intern/writefile.c3
-rw-r--r--source/blender/editors/space_view3d/drawobject.c2
-rw-r--r--source/blender/makesdna/DNA_particle_types.h5
-rw-r--r--source/blender/makesrna/intern/rna_particle.c32
11 files changed, 166 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index 2c72373c2a9..747a6b65bb0 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -162,6 +162,7 @@ typedef struct ParticleThreadContext {
struct CurveMapping *clumpcurve;
struct CurveMapping *roughcurve;
+ struct CurveMapping *twistcurve;
} ParticleThreadContext;
typedef struct ParticleTask {
@@ -349,6 +350,7 @@ int psys_get_particle_state(struct ParticleSimulationData *sim, int p, struct Pa
/* child paths */
void BKE_particlesettings_clump_curve_init(struct ParticleSettings *part);
void BKE_particlesettings_rough_curve_init(struct ParticleSettings *part);
+void BKE_particlesettings_twist_curve_init(struct ParticleSettings *part);
void psys_apply_child_modifiers(struct ParticleThreadContext *ctx, struct ListBase *modifiers,
struct ChildParticle *cpa, struct ParticleTexture *ptex, const float orco[3], const float ornor[3], float hairmat[4][4],
struct ParticleCacheKey *keys, struct ParticleCacheKey *parent_keys, const float parent_orco[3]);
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 8aa7b167b85..ea27e23ed2f 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -405,6 +405,8 @@ void BKE_particlesettings_free(ParticleSettings *part)
curvemapping_free(part->clumpcurve);
if (part->roughcurve)
curvemapping_free(part->roughcurve);
+ if (part->twistcurve)
+ curvemapping_free(part->twistcurve);
free_partdeflect(part->pd);
free_partdeflect(part->pd2);
@@ -2152,6 +2154,13 @@ static bool psys_thread_context_init_path(
else {
ctx->roughcurve = NULL;
}
+ if ((part->child_flag & PART_CHILD_USE_TWIST_CURVE) && part->twistcurve) {
+ ctx->twistcurve = curvemapping_copy(part->twistcurve);
+ curvemapping_changed_all(ctx->twistcurve);
+ }
+ else {
+ ctx->twistcurve = NULL;
+ }
return true;
}
@@ -3337,6 +3346,18 @@ void BKE_particlesettings_rough_curve_init(ParticleSettings *part)
part->roughcurve = cumap;
}
+void BKE_particlesettings_twist_curve_init(ParticleSettings *part)
+{
+ CurveMapping *cumap = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+
+ cumap->cm[0].curve[0].x = 0.0f;
+ cumap->cm[0].curve[0].y = 1.0f;
+ cumap->cm[0].curve[1].x = 1.0f;
+ cumap->cm[0].curve[1].y = 1.0f;
+
+ part->twistcurve = cumap;
+}
+
/**
* Only copy internal data of ParticleSettings ID from source to already allocated/initialized destination.
* You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
@@ -3359,6 +3380,9 @@ void BKE_particlesettings_copy_data(
if (part_src->roughcurve) {
part_dst->roughcurve = curvemapping_copy(part_src->roughcurve);
}
+ if (part_src->twistcurve) {
+ part_dst->twistcurve = curvemapping_copy(part_src->twistcurve);
+ }
part_dst->boids = boid_copy_settings(part_src->boids);
@@ -3935,6 +3959,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
modifier_ctx.par_vel = par->vel;
modifier_ctx.par_rot = par->rot;
modifier_ctx.par_orco = par_orco;
+ modifier_ctx.parent_keys = psys->childcache ? psys->childcache[p - totpart] : NULL;
do_child_modifiers(&modifier_ctx, hairmat, state, t);
/* try to estimate correct velocity */
@@ -4048,6 +4073,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
modifier_ctx.par_vel = key1->vel;
modifier_ctx.par_rot = key1->rot;
modifier_ctx.par_orco = par_orco;
+ modifier_ctx.parent_keys = psys->childcache ? psys->childcache[p - totpart] : NULL;
do_child_modifiers(&modifier_ctx, mat, state, t);
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
index 70e635e16cf..53bf577d4f4 100644
--- a/source/blender/blenkernel/intern/particle_child.c
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -242,6 +242,7 @@ static void do_kink_spiral(ParticleThreadContext *ctx, ParticleTexture *ptex, co
modifier_ctx.ptex = ptex;
modifier_ctx.cpa = cpa;
modifier_ctx.orco = orco;
+ modifier_ctx.parent_keys = parent_keys;
for (k = 0, key = keys; k < end_index; k++, key++) {
float par_time;
@@ -352,6 +353,7 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
modifier_ctx.ptex = ptex;
modifier_ctx.cpa = cpa;
modifier_ctx.orco = orco;
+ modifier_ctx.parent_keys = parent_keys;
totkeys = ctx->segments + 1;
max_length = ptex->length;
@@ -688,6 +690,89 @@ static void do_rough_curve(const float loc[3], float mat[4][4], float time, floa
madd_v3_v3fl(state->co, mat[2], fac * rough[2]);
}
+static int twist_num_segments(const ParticleChildModifierContext *modifier_ctx)
+{
+ ParticleThreadContext *thread_ctx = modifier_ctx->thread_ctx;
+ return (thread_ctx != NULL) ? thread_ctx->segments
+ : modifier_ctx->sim->psys->part->draw_step;
+}
+
+static void twist_get_axis(const ParticleChildModifierContext *modifier_ctx,
+ const float time, float r_axis[3])
+{
+ const int num_segments = twist_num_segments(modifier_ctx);
+ const int index = clamp_i(time * num_segments, 0, num_segments);
+ if (index > 0) {
+ sub_v3_v3v3(r_axis,
+ modifier_ctx->parent_keys[index].co,
+ modifier_ctx->parent_keys[index - 1].co);
+ }
+ else {
+ sub_v3_v3v3(r_axis,
+ modifier_ctx->parent_keys[index + 1].co,
+ modifier_ctx->parent_keys[index].co);
+ }
+}
+
+static float curvemapping_integrate_clamped(CurveMapping *curve,
+ float start, float end, float step)
+{
+ float integral = 0.0f;
+ float x = start;
+ while (x < end) {
+ float y = curvemapping_evaluateF(curve, 0, x);
+ y = clamp_f(y, 0.0f, 1.0f);
+ /* TODO(sergey): Clamp last step to end. */
+ integral += y * step;
+ x += step;
+ }
+ return integral;
+}
+
+static void do_twist(const ParticleChildModifierContext *modifier_ctx,
+ ParticleKey *state, const float time)
+{
+ ParticleThreadContext *thread_ctx = modifier_ctx->thread_ctx;
+ ParticleSimulationData *sim = modifier_ctx->sim;
+ ParticleSettings *part = sim->psys->part;
+ /* Early output checks. */
+ if (part->childtype != PART_CHILD_PARTICLES) {
+ /* Interpolated children behave weird with twist. */
+ return;
+ }
+ if (part->twist == 0.0f) {
+ /* No twist along the strand. */
+ return;
+ }
+ /* Dependent on whether it's threaded update or not, curve comes
+ * from different places.
+ */
+ CurveMapping *twist_curve = NULL;
+ if (part->child_flag & PART_CHILD_USE_TWIST_CURVE) {
+ twist_curve = (thread_ctx != NULL) ? thread_ctx->twistcurve
+ : part->twistcurve;
+ }
+ /* Axis of rotation. */
+ float axis[3];
+ twist_get_axis(modifier_ctx, time, axis);
+ /* Angle of rotation. */
+ float angle = part->twist;
+ if (twist_curve != NULL) {
+ const int num_segments = twist_num_segments(modifier_ctx);
+ angle *= curvemapping_integrate_clamped(twist_curve,
+ 0.0f, time,
+ 1.0f / num_segments);
+ }
+ else {
+ angle *= time;
+ }
+ /* Perform rotation around parent curve. */
+ float vec[3];
+ sub_v3_v3v3(vec, state->co, modifier_ctx->par_co);
+ rotate_v3_v3v3fl(state->co, vec, axis, angle * 2.0f * M_PI);
+ add_v3_v3(state->co, modifier_ctx->par_co);
+}
+
void do_child_modifiers(const ParticleChildModifierContext *modifier_ctx,
float mat[4][4], ParticleKey *state, float t)
{
@@ -723,6 +808,8 @@ void do_child_modifiers(const ParticleChildModifierContext *modifier_ctx,
rough_end *= ptex->roughe;
}
+ do_twist(modifier_ctx, state, t);
+
if (part->flag & PART_CHILD_EFFECT)
/* state is safe to cast, since only co and vel are used */
guided = do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t);
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index dfc732dcb74..bae76354705 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -519,6 +519,9 @@ void psys_thread_context_free(ParticleThreadContext *ctx)
if (ctx->roughcurve != NULL) {
curvemapping_free(ctx->roughcurve);
}
+ if (ctx->twistcurve != NULL) {
+ curvemapping_free(ctx->twistcurve);
+ }
}
static void initialize_particle_texture(ParticleSimulationData *sim, ParticleData *pa, int p)
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 3cf98b284b1..34ff9a155b4 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -1285,6 +1285,8 @@ static void emit_from_particles(
curvemapping_changed_all(psys->part->clumpcurve);
if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve)
curvemapping_changed_all(psys->part->roughcurve);
+ if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve)
+ curvemapping_changed_all(psys->part->twistcurve);
/* initialize particle cache */
if (psys->part->type == PART_HAIR) {
diff --git a/source/blender/blenkernel/particle_private.h b/source/blender/blenkernel/particle_private.h
index 00a7637e246..2189527118b 100644
--- a/source/blender/blenkernel/particle_private.h
+++ b/source/blender/blenkernel/particle_private.h
@@ -41,6 +41,7 @@ typedef struct ParticleChildModifierContext {
const float *par_rot; /* float4 */
const float *par_orco; /* float3 */
const float *orco; /* float3 */
+ ParticleCacheKey *parent_keys;
} ParticleChildModifierContext;
void do_kink(ParticleKey *state, const float par_co[3], const float par_vel[3], const float par_rot[4], float time, float freq, float shape, float amplitude, float flat,
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 2a25de121b3..9aa67e8651f 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -4253,6 +4253,9 @@ static void direct_link_particlesettings(FileData *fd, ParticleSettings *part)
part->roughcurve = newdataadr(fd, part->roughcurve);
if (part->roughcurve)
direct_link_curvemapping(fd, part->roughcurve);
+ part->twistcurve = newdataadr(fd, part->twistcurve);
+ if (part->twistcurve)
+ direct_link_curvemapping(fd, part->twistcurve);
part->effector_weights = newdataadr(fd, part->effector_weights);
if (!part->effector_weights)
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index ceb1233596a..5941f96041c 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -1304,6 +1304,9 @@ static void write_particlesettings(WriteData *wd, ParticleSettings *part)
if (part->roughcurve) {
write_curvemapping(wd, part->roughcurve);
}
+ if (part->twistcurve) {
+ write_curvemapping(wd, part->twistcurve);
+ }
for (ParticleDupliWeight *dw = part->dupliweights.first; dw; dw = dw->next) {
/* update indices, but only if dw->ob is set (can be NULL after loading e.g.) */
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 828617d1447..c3823627009 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -5044,6 +5044,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
curvemapping_changed_all(psys->part->clumpcurve);
if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve)
curvemapping_changed_all(psys->part->roughcurve);
+ if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve)
+ curvemapping_changed_all(psys->part->twistcurve);
/* 2. */
sim.scene = scene;
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index f6bed37dfa2..371b53567a6 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -261,6 +261,10 @@ typedef struct ParticleSettings {
short use_modifier_stack;
short pad5[3];
+ float twist;
+ float pad6;
+ struct CurveMapping *twistcurve;
+ void *pad7;
} ParticleSettings;
typedef struct ParticleSystem {
@@ -435,6 +439,7 @@ typedef enum eParticleChildFlag {
PART_CHILD_USE_CLUMP_NOISE = (1<<0),
PART_CHILD_USE_CLUMP_CURVE = (1<<1),
PART_CHILD_USE_ROUGH_CURVE = (1<<2),
+ PART_CHILD_USE_TWIST_CURVE = (1<<3),
} eParticleChildFlag;
/* part->draw_col */
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 9e52457d32a..e9bbc981a13 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -944,6 +944,19 @@ static void rna_ParticleSettings_use_roughness_curve_update(Main *bmain, Scene *
rna_Particle_redo_child(bmain, scene, ptr);
}
+static void rna_ParticleSettings_use_twist_curve_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ ParticleSettings *part = ptr->data;
+
+ if (part->child_flag & PART_CHILD_USE_TWIST_CURVE) {
+ if (!part->twistcurve) {
+ BKE_particlesettings_twist_curve_init(part);
+ }
+ }
+
+ rna_Particle_redo_child(bmain, scene, ptr);
+}
+
static void rna_ParticleSystem_name_set(PointerRNA *ptr, const char *value)
{
Object *ob = ptr->id.data;
@@ -3170,6 +3183,25 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "FieldSettings");
RNA_def_property_pointer_funcs(prop, "rna_Particle_field2_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Force Field 2", "");
+
+ /* twist */
+ prop = RNA_def_property(srna, "twist", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, -100000.0f, 100000.0f);
+ RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Twist", "Number of turns around parent allong the strand");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+
+ prop = RNA_def_property(srna, "use_twist_curve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "child_flag", PART_CHILD_USE_TWIST_CURVE);
+ RNA_def_property_ui_text(prop, "Use Twist Curve", "Use a curve to define twist");
+ RNA_def_property_update(prop, 0, "rna_ParticleSettings_use_twist_curve_update");
+
+ prop = RNA_def_property(srna, "twist_curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "twistcurve");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Twist Curve", "Curve defining twist");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
}
static void rna_def_particle_target(BlenderRNA *brna)