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/blenkernel/intern/particle_child.c
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/blenkernel/intern/particle_child.c')
-rw-r--r--source/blender/blenkernel/intern/particle_child.c87
1 files changed, 87 insertions, 0 deletions
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);