diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2015-01-12 18:03:12 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2015-01-20 11:30:10 +0300 |
commit | c2306919b7cafdf4dbca876a4fea2f9f0681ef78 (patch) | |
tree | eb1c285d902d0723ab190a2a0108fdd7ce772f70 /source/blender/blenkernel | |
parent | 7f219137cf13003143f5d671b6c59bc500b53f75 (diff) |
Optional clumping noise feature for simulating twisted hair strands.
This adds another level of clumping on child hairs. When enabled, child
hairs chose a secondary clumping target using a Voronoi pattern. This
adds visual detail on a smaller scale, which is useful particularly when
the number of parents is relatively small.
Natural fibres behave in a similar way when they become sticky and
intertwined. Hairs close to each other form a first twisted strand, then
combine into larger strands. Similar features can be found in ropes:
http://en.wikipedia.org/wiki/Hair_twists
http://en.wikipedia.org/wiki/Rope
Conflicts:
source/blender/blenloader/intern/versioning_270.c
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/BKE_particle.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/particle.c | 75 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/particle_child.c | 61 |
3 files changed, 99 insertions, 39 deletions
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index b0b605e40ca..35e89eeef9e 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -343,7 +343,7 @@ void BKE_particlesettings_clump_curve_init(struct ParticleSettings *part); void BKE_particlesettings_rough_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); + struct ParticleCacheKey *keys, struct ParticleCacheKey *parent_keys, const float parent_orco[3]); void psys_sph_init(struct ParticleSimulationData *sim, struct SPHData *sphdata); void psys_sph_finalise(struct SPHData *sphdata); diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 2f0fbbb45ea..856388ce33c 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -104,8 +104,8 @@ void psys_init_rng(void) static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx, ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex); extern void do_child_modifiers(ParticleSimulationData *sim, - ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, - const float orco[3], float mat[4][4], ParticleKey *state, float t); + ParticleTexture *ptex, ParticleKey *par, float *par_rot, const float par_orco[3], + ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t); /* few helpers for countall etc. */ int count_particles(ParticleSystem *psys) @@ -1672,7 +1672,8 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in extern void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, float flat, short type, short axis, float obmat[4][4], int smooth_start); -extern float do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump, CurveMapping *clumpcurve); +extern float do_clump(ParticleKey *state, ParticleKey *par, float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump, + bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve); void precalc_guides(ParticleSimulationData *sim, ListBase *effectors) { @@ -1720,7 +1721,6 @@ int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, i EffectorCache *eff; PartDeflect *pd; Curve *cu; - ParticleKey key, par; GuideEffectorData *data; float effect[3] = {0.0f, 0.0f, 0.0f}, veffect[3] = {0.0f, 0.0f, 0.0f}; @@ -1790,11 +1790,17 @@ int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, i if (part->roughcurve) curvemapping_changed_all(part->roughcurve); - par.co[0] = par.co[1] = par.co[2] = 0.0f; - copy_v3_v3(key.co, vec_to_point); - do_kink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, 0.f, pd->kink, pd->kink_axis, 0, 0); - do_clump(&key, &par, guidetime, pd->clump_fac, pd->clump_pow, 1.0f, part->clumpcurve); - copy_v3_v3(vec_to_point, key.co); + { + ParticleKey key, par; + float orco_offset[3] = {0.0f, 0.0f, 0.0f}; + + par.co[0] = par.co[1] = par.co[2] = 0.0f; + copy_v3_v3(key.co, vec_to_point); + do_kink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, 0.f, pd->kink, pd->kink_axis, 0, 0); + do_clump(&key, &par, guidetime, orco_offset, pd->clump_fac, pd->clump_pow, 1.0f, + part->child_flag & PART_CHILD_USE_CLUMP_NOISE, part->clump_noise_size, part->clumpcurve); + copy_v3_v3(vec_to_point, key.co); + } add_v3_v3(vec_to_point, guidevec); @@ -2018,7 +2024,7 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp ParticleSettings *part = psys->part; ParticleCacheKey **cache = psys->childcache; ParticleCacheKey **pcache = psys_in_edit_mode(ctx->sim.scene, psys) && psys->edit ? psys->edit->pathcache : psys->pathcache; - ParticleCacheKey *child, *par = NULL, *key[4]; + ParticleCacheKey *child, *key[4]; ParticleTexture ptex; float *cpa_fuv = 0, *par_rot = 0, rot[4]; float orco[3], ornor[3], hairmat[4][4], dvec[3], off1[4][3], off2[4][3]; @@ -2219,16 +2225,35 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp } } - if (ctx->totparent) - /* this is now threadsafe, virtual parents are calculated before rest of children */ - par = (i >= ctx->totparent) ? cache[cpa->parent] : NULL; - else if (cpa->parent >= 0) - par = pcache[cpa->parent]; - { - ListBase modifiers; - BLI_listbase_clear(&modifiers); - psys_apply_child_modifiers(ctx, &modifiers, cpa, &ptex, orco, ornor, hairmat, child_keys, par); + ParticleData *pa = NULL; + ParticleCacheKey *par = NULL; + float par_co[3]; + float par_orco[3]; + + if (ctx->totparent) { + if (i >= ctx->totparent) { + pa = &psys->particles[cpa->parent]; + /* this is now threadsafe, virtual parents are calculated before rest of children */ + par = cache[cpa->parent]; + } + } + else if (cpa->parent >= 0) { + pa = &psys->particles[cpa->parent]; + par = pcache[cpa->parent]; + } + + if (pa) + psys_particle_on_emitter(ctx->sim.psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, + par_co, NULL, NULL, NULL, par_orco, NULL); + else + zero_v3(par_orco); + + { + ListBase modifiers; + BLI_listbase_clear(&modifiers); + psys_apply_child_modifiers(ctx, &modifiers, cpa, &ptex, orco, ornor, hairmat, child_keys, par, par_orco); + } } #if 0 for (k = 0, child = child_keys; k <= ctx->steps; k++, child++) { @@ -3093,6 +3118,7 @@ static void default_particle_settings(ParticleSettings *part) part->adapt_pix = 3; part->kink_axis = 2; part->kink_amp_clump = 1.f; + part->clump_noise_size = 1.0f; part->reactevent = PART_EVENT_DEATH; part->disp = 100; part->from = PART_FROM_FACE; @@ -3674,6 +3700,8 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey * copy_qt_qt(state->rot, result.rot); } else { + float par_co[3], par_orco[3]; + cpa = psys->child + p - totpart; if (state->time < 0.0f) @@ -3710,6 +3738,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey * pa = psys->particles + cpa->parent; + psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0); if (part->type == PART_HAIR) psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat); else @@ -3729,8 +3758,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey * cpa_num = pa->num; cpa_fuv = pa->fuv; - - + psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0); if (part->type == PART_HAIR) { psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco, 0); psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat); @@ -3788,7 +3816,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey * copy_particle_key(&tstate, state, 1); /* apply different deformations to the child path */ - do_child_modifiers(sim, &ptex, par, par->rot, cpa, orco, hairmat, state, t); + do_child_modifiers(sim, &ptex, par, par->rot, par_orco, cpa, orco, hairmat, state, t); /* try to estimate correct velocity */ if (vel) { @@ -3883,6 +3911,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta float mat[4][4]; ParticleKey *key1; float t = (cfra - pa->time) / pa->lifetime; + float par_orco[3] = {0.0f, 0.0f, 0.0f}; key1 = &pa->state; offset_child(cpa, key1, key1->rot, state, part->childflat, part->childrad); @@ -3890,7 +3919,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta CLAMP(t, 0.0f, 1.0f); unit_m4(mat); - do_child_modifiers(sim, NULL, key1, key1->rot, cpa, cpa->fuv, mat, state, t); + do_child_modifiers(sim, NULL, key1, key1->rot, par_orco, cpa, cpa->fuv, mat, state, t); if (psys->lattice_deform_data) calc_latt_deform(psys->lattice_deform_data, state->co, 1.0f); diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c index d7976699011..b11196e74f0 100644 --- a/source/blender/blenkernel/intern/particle_child.c +++ b/source/blender/blenkernel/intern/particle_child.c @@ -41,10 +41,11 @@ struct Material; void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, float flat, short type, short axis, float obmat[4][4], int smooth_start); -float do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump, CurveMapping *clumpcurve); +float do_clump(ParticleKey *state, ParticleKey *par, float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump, + bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve); void do_child_modifiers(ParticleSimulationData *sim, - ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, - const float orco[3], float mat[4][4], ParticleKey *state, float t); + ParticleTexture *ptex, ParticleKey *par, float *par_rot, const float par_orco[3], + ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t); static void get_strand_normal(Material *ma, const float surfnor[3], float surfdist, float nor[3]) { @@ -89,7 +90,8 @@ typedef struct ParticlePathIterator { float parent_rotation[4]; } ParticlePathIterator; -static void psys_path_iter_get(ParticlePathIterator *iter, ParticleCacheKey *keys, int totkeys, ParticleCacheKey *parent, int index) +static void psys_path_iter_get(ParticlePathIterator *iter, ParticleCacheKey *keys, int totkeys, + ParticleCacheKey *parent, int index) { BLI_assert(index >= 0 && index < totkeys); @@ -136,7 +138,7 @@ static bool check_path_length(int k, ParticleCacheKey *keys, ParticleCacheKey *k void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *modifiers, ChildParticle *cpa, ParticleTexture *ptex, const float orco[3], const float ornor[3], float hairmat[4][4], - ParticleCacheKey *keys, ParticleCacheKey *parent_keys) + ParticleCacheKey *keys, ParticleCacheKey *parent_keys, const float parent_orco[3]) { struct ParticleSettings *part = ctx->sim.psys->part; struct Material *ma = ctx->ma; @@ -165,7 +167,7 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod psys_path_iter_get(&iter, keys, totkeys, parent_keys, k); /* apply different deformations to the child path */ - do_child_modifiers(&ctx->sim, ptex, (ParticleKey *)iter.parent_key, iter.parent_rotation, cpa, orco, hairmat, (ParticleKey *)key, iter.time); + do_child_modifiers(&ctx->sim, ptex, (ParticleKey *)iter.parent_key, iter.parent_rotation, parent_orco, cpa, orco, hairmat, (ParticleKey *)key, iter.time); } } #endif @@ -360,17 +362,15 @@ void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, f copy_v3_v3(state->co, result); } -float do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump, CurveMapping *clumpcurve) +static float do_clump_level(float result[3], const float co[3], const float par_co[3], float time, + float clumpfac, float clumppow, float pa_clump, CurveMapping *clumpcurve) { - float clump = 0.f; - - if (!par) - return 0.0f; + float clump = 0.0f; if (clumpcurve) { clump = pa_clump * (1.0f - CLAMPIS(curvemapping_evaluateF(clumpcurve, 0, time), 0.0f, 1.0f)); - interp_v3_v3v3(state->co, state->co, par->co, clump); + interp_v3_v3v3(result, co, par_co, clump); } else if (clumpfac != 0.0f) { float cpow; @@ -385,9 +385,34 @@ float do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, else clump = clumpfac * pa_clump * (float)pow((double)time, (double)cpow); - interp_v3_v3v3(state->co, state->co, par->co, clump); + interp_v3_v3v3(result, co, par_co, clump); } + + return clump; +} +float do_clump(ParticleKey *state, ParticleKey *par, float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump, + bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve) +{ + float clump; + + if (!par) + return 0.0f; + + if (use_clump_noise && clump_noise_size != 0.0f) { + float center[3], noisevec[3]; + float da[4], pa[12]; + + mul_v3_v3fl(noisevec, orco_offset, 1.0f / clump_noise_size); + voronoi(noisevec[0], noisevec[1], noisevec[2], da, pa, 1.0f, 0); + mul_v3_fl(&pa[0], clump_noise_size); + add_v3_v3v3(center, par->co, &pa[0]); + + do_clump_level(state->co, state->co, center, time, clumpfac, clumppow, pa_clump, clumpcurve); + } + + clump = do_clump_level(state->co, state->co, par->co, time, clumpfac, clumppow, pa_clump, clumpcurve); + return clump; } @@ -449,7 +474,8 @@ 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]); } -void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t) +void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, ParticleKey *par, float *par_rot, const float par_orco[3], + ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t) { ParticleSettings *part = sim->psys->part; int i = cpa - sim->psys->child; @@ -472,7 +498,12 @@ void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, Part guided = do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t); if (guided == 0) { - float clump = do_clump(state, par, t, part->clumpfac, part->clumppow, ptex ? ptex->clump : 1.f, part->clumpcurve); + float orco_offset[3]; + float clump; + + sub_v3_v3v3(orco_offset, orco, par_orco); + clump = do_clump(state, par, t, orco_offset, part->clumpfac, part->clumppow, ptex ? ptex->clump : 1.f, + part->child_flag & PART_CHILD_USE_CLUMP_NOISE, part->clump_noise_size, part->clumpcurve); if (kink_freq != 0.f) { float kink_amp = part->kink_amp * (1.f - part->kink_amp_clump * clump); |