[Bf-blender-cvs] [ffde74a8788] master: Simple hair children: Initial implementation of twist control

Sergey Sharybin noreply at git.blender.org
Thu Feb 15 12:27:55 CET 2018


Commit: ffde74a878882618ab4d4179ba8dd9b98aab15e2
Author: Sergey Sharybin
Date:   Wed Feb 14 14:33:53 2018 +0100
Branches: master
https://developer.blender.org/rBffde74a878882618ab4d4179ba8dd9b98aab15e2

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.

===================================================================

M	release/scripts/startup/bl_ui/properties_particle.py
M	source/blender/blenkernel/BKE_particle.h
M	source/blender/blenkernel/intern/particle.c
M	source/blender/blenkernel/intern/particle_child.c
M	source/blender/blenkernel/intern/particle_system.c
M	source/blender/blenkernel/intern/smoke.c
M	source/blender/blenkernel/particle_private.h
M	source/blender/blenloader/intern/readfile.c
M	source/blender/blenloader/intern/writefile.c
M	source/blender/editors/space_view3d/drawobject.c
M	source/blender/makesdna/DNA_particle_types.h
M	source/blender/makesrna/intern/rna_particle.c

===================================================================

diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py
index b01d1ebbfa3..e552ff35ffa 100644
--- a/release/scripts/startup/bl_ui/properties_particle.py
+++ b/release/scripts/startup/bl_ui/properties_particle.py
@@ -1198,6 +1198,12 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel):
         col.label(text="Effects:")
 
         sub = col.column(align=True)
+        if part.child_type == 'SIMPLE':
+            sub.prop(part, "twist")
+            sub.prop(part, "use_twist_curve")
+            if part.use_twist_curve:
+                sub.template_curve_mapping(part, "twist_curve")
+
         sub.prop(part, "use_clump_curve")
         if part.use_clump_curve:
             sub.template_curve_mapping(part, "clump_curve")
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) {
di

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list