From 9bf763393603a987aa95033b2da78cea501d699b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 12 Jan 2015 20:24:50 +0100 Subject: Spiral kink mode for particles. This is BAD code, but the particle kinking does not make it easy to write a non-local modifier that requires neighboring positions, curvature, etc. The feature is needed for Gooseberry. --- source/blender/blenkernel/intern/particle.c | 175 +++++++++++----------- source/blender/blenkernel/intern/particle_child.c | 91 +++++++++-- 2 files changed, 171 insertions(+), 95 deletions(-) (limited to 'source/blender/blenkernel') diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 856388ce33c..3f8d694aa44 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -105,7 +105,7 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread 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, const float par_orco[3], - ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t); + ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t, float spiral_start[3], float *time_prev, float *co_prev); /* few helpers for countall etc. */ int count_particles(ParticleSystem *psys) @@ -1671,7 +1671,7 @@ 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); + short type, short axis, float obmat[4][4], int smooth_start, float spiral_start[3], float *time_prev, float *co_prev); 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); @@ -1729,90 +1729,91 @@ int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, i float vec_to_point[3]; if (effectors) for (eff = effectors->first; eff; eff = eff->next) { - pd = eff->pd; - - if (pd->forcefield != PFIELD_GUIDE) - continue; - - data = eff->guide_data + index; - - if (data->strength <= 0.0f) - continue; - - guidetime = time / (1.0f - pd->free_end); - - if (guidetime > 1.0f) - continue; - - cu = (Curve *)eff->ob->data; - - if (pd->flag & PFIELD_GUIDE_PATH_ADD) { - if (where_on_path(eff->ob, data->strength * guidetime, guidevec, guidedir, NULL, &radius, &weight) == 0) - return 0; - } - else { - if (where_on_path(eff->ob, guidetime, guidevec, guidedir, NULL, &radius, &weight) == 0) - return 0; - } - - mul_m4_v3(eff->ob->obmat, guidevec); - mul_mat3_m4_v3(eff->ob->obmat, guidedir); - - normalize_v3(guidedir); - - copy_v3_v3(vec_to_point, data->vec_to_point); - - if (guidetime != 0.0f) { - /* curve direction */ - cross_v3_v3v3(temp, eff->guide_dir, guidedir); - angle = dot_v3v3(eff->guide_dir, guidedir) / (len_v3(eff->guide_dir)); - angle = saacos(angle); - axis_angle_to_quat(rot2, temp, angle); - mul_qt_v3(rot2, vec_to_point); - - /* curve tilt */ - axis_angle_to_quat(rot2, guidedir, guidevec[3] - eff->guide_loc[3]); - mul_qt_v3(rot2, vec_to_point); - } - - /* curve taper */ - if (cu->taperobj) - mul_v3_fl(vec_to_point, BKE_displist_calc_taper(eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100)); - - else { /* curve size*/ - if (cu->flag & CU_PATH_RADIUS) { - mul_v3_fl(vec_to_point, radius); - } - } - - if (part->clumpcurve) - curvemapping_changed_all(part->clumpcurve); - if (part->roughcurve) - curvemapping_changed_all(part->roughcurve); + pd = eff->pd; + + if (pd->forcefield != PFIELD_GUIDE) + continue; + + data = eff->guide_data + index; + + if (data->strength <= 0.0f) + continue; + + guidetime = time / (1.0f - pd->free_end); + + if (guidetime > 1.0f) + continue; + + cu = (Curve *)eff->ob->data; + + if (pd->flag & PFIELD_GUIDE_PATH_ADD) { + if (where_on_path(eff->ob, data->strength * guidetime, guidevec, guidedir, NULL, &radius, &weight) == 0) + return 0; + } + else { + if (where_on_path(eff->ob, guidetime, guidevec, guidedir, NULL, &radius, &weight) == 0) + return 0; + } + + mul_m4_v3(eff->ob->obmat, guidevec); + mul_mat3_m4_v3(eff->ob->obmat, guidedir); + + normalize_v3(guidedir); + + copy_v3_v3(vec_to_point, data->vec_to_point); + + if (guidetime != 0.0f) { + /* curve direction */ + cross_v3_v3v3(temp, eff->guide_dir, guidedir); + angle = dot_v3v3(eff->guide_dir, guidedir) / (len_v3(eff->guide_dir)); + angle = saacos(angle); + axis_angle_to_quat(rot2, temp, angle); + mul_qt_v3(rot2, vec_to_point); - { - 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); + /* curve tilt */ + axis_angle_to_quat(rot2, guidedir, guidevec[3] - eff->guide_loc[3]); + mul_qt_v3(rot2, vec_to_point); + } + + /* curve taper */ + if (cu->taperobj) + mul_v3_fl(vec_to_point, BKE_displist_calc_taper(eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100)); + + else { /* curve size*/ + if (cu->flag & CU_PATH_RADIUS) { + mul_v3_fl(vec_to_point, radius); } - - add_v3_v3(vec_to_point, guidevec); - - //sub_v3_v3v3(pa_loc, pa_loc, pa_zero); - madd_v3_v3fl(effect, vec_to_point, data->strength); - madd_v3_v3fl(veffect, guidedir, data->strength); - totstrength += data->strength; - - if (pd->flag & PFIELD_GUIDE_PATH_WEIGHT) - totstrength *= weight; } - + + if (part->clumpcurve) + curvemapping_changed_all(part->clumpcurve); + if (part->roughcurve) + curvemapping_changed_all(part->roughcurve); + + { + ParticleKey key, par; + float orco_offset[3] = {0.0f, 0.0f, 0.0f}; + float spiral_start[3], time_prev = 0.0f, co_prev[3] = {0,0,0}; + + 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, spiral_start, &time_prev, co_prev); + 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); + + //sub_v3_v3v3(pa_loc, pa_loc, pa_zero); + madd_v3_v3fl(effect, vec_to_point, data->strength); + madd_v3_v3fl(veffect, guidedir, data->strength); + totstrength += data->strength; + + if (pd->flag & PFIELD_GUIDE_PATH_WEIGHT) + totstrength *= weight; + } + if (totstrength != 0.0f) { if (totstrength > 1.0f) mul_v3_fl(effect, 1.0f / totstrength); @@ -3816,7 +3817,10 @@ 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, par_orco, cpa, orco, hairmat, state, t); + { + float spiral_start[3], time_prev = 0.0f, co_prev[3] = {0,0,0}; + do_child_modifiers(sim, &ptex, par, par->rot, par_orco, cpa, orco, hairmat, state, t, spiral_start, &time_prev, co_prev); + } /* try to estimate correct velocity */ if (vel) { @@ -3912,6 +3916,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta ParticleKey *key1; float t = (cfra - pa->time) / pa->lifetime; float par_orco[3] = {0.0f, 0.0f, 0.0f}; + float spiral_start[3], time_prev = 0.0f, co_prev[3] = {0,0,0}; key1 = &pa->state; offset_child(cpa, key1, key1->rot, state, part->childflat, part->childrad); @@ -3919,7 +3924,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, par_orco, cpa, cpa->fuv, mat, state, t); + do_child_modifiers(sim, NULL, key1, key1->rot, par_orco, cpa, cpa->fuv, mat, state, t, spiral_start, &time_prev, co_prev); 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 b11196e74f0..ef4a41fc3b5 100644 --- a/source/blender/blenkernel/intern/particle_child.c +++ b/source/blender/blenkernel/intern/particle_child.c @@ -40,12 +40,12 @@ 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); + short type, short axis, float obmat[4][4], int smooth_start, float spiral_start[3], float *time_prev, float *co_prev); 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, const float par_orco[3], - ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t); + ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t, float spiral_start[3], float *time_prev, float *co_prev); static void get_strand_normal(Material *ma, const float surfnor[3], float surfdist, float nor[3]) { @@ -163,11 +163,15 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod { ParticlePathIterator iter; + float spiral_start[3]; + float time_prev = 0.0f; + float co_prev[3] = {0.0f, 0.0f, 0.0f}; + for (k = 0, key = keys; k < totkeys; k++, key++) { 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, parent_orco, 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, spiral_start, &time_prev, co_prev); } } #endif @@ -203,7 +207,9 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod /* ------------------------------------------------------------------------- */ -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) +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 spiral_start[3], float *time_prev, float *co_prev) { float kink[3] = {1.f, 0.f, 0.f}, par_vec[3], q1[4] = {1.f, 0.f, 0.f, 0.f}; float t, dt = 1.f, result[3]; @@ -213,7 +219,7 @@ void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, f CLAMP(time, 0.f, 1.f); - if (shape != 0.0f && type != PART_KINK_BRAID) { + if (shape != 0.0f && !ELEM(type, PART_KINK_BRAID, PART_KINK_SPIRAL)) { if (shape < 0.0f) time = (float)pow(time, 1.f + shape); else @@ -222,14 +228,14 @@ void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, f t = time * freq * (float)M_PI; - if (smooth_start) { + if (smooth_start && !ELEM(type, PART_KINK_SPIRAL)) { dt = fabsf(t); /* smooth the beginning of kink */ CLAMP(dt, 0.f, (float)M_PI); dt = sinf(dt / 2.f); } - if (type != PART_KINK_RADIAL) { + if (!ELEM(type, PART_KINK_RADIAL, PART_KINK_SPIRAL)) { float temp[3]; kink[axis] = 1.f; @@ -353,6 +359,65 @@ void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, f } break; } + case PART_KINK_SPIRAL: + { + if (time <= flat) { + /* nothing to do for the flat section */ + } + else { +#if 0 + /* Creates a logarithmic spiral: + * r(theta) = a * exp(b * theta) + * + * For now chose the golden spiral for the "density" parameter b: + * http://en.wikipedia.org/wiki/Golden_spiral + * This could be configurable, but the golden spiral is quite pleasant and natural + */ + const float b = (1.0f + sqrtf(5.0f)) / (2.0f * M_PI); + const float arc_factor = sqrtf(1.0f + b*b) / b; + + /* Relation to amplitude (spiral radius): + * a*exp(b*theta0) = sqrt(2) * R + * + * Arc length of the logarithmic spiral: + * s(theta) = a*exp(b*theta) * (1 + b^2)/b + */ + + const float a = arc_length / (sqrtf(2.0f) * amplitude * arc_factor); + const float theta0 = logf(sqrtf(2.0f) * amplitude / a) / b; + + float arc = max_length - time; + float theta = logf(arc / (a * arc_factor)) / b; +#else +// float theta = (time - flat) / amplitude; +#endif + + float dir[3], up[3], rot[3][3]; + float vec[3]; + + float theta = freq * (time - flat) / (1.0f - flat); +// float arc = theta * amplitude; + float radius = amplitude * expf(shape * theta); + + normalize_v3_v3(dir, par->vel); + cross_v3_v3v3(up, dir, kink); + axis_angle_normalized_to_mat3(rot, kink, theta); + + if (*time_prev <= flat) { + interp_v3_v3v3(spiral_start, co_prev, state->co, (flat - *time_prev) / (time - *time_prev)); + } + + mul_v3_v3fl(vec, up, radius); + mul_v3_m3v3(result, rot, vec); + + madd_v3_v3fl(result, up, -radius); + add_v3_v3(result, spiral_start); + } + + *time_prev = time; + copy_v3_v3(co_prev, state->co); + break; + } } /* blend the start of the kink */ @@ -475,7 +540,7 @@ static void do_rough_curve(const float loc[3], float mat[4][4], float time, floa } 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) + ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t, float spiral_start[3], float *time_prev, float *co_prev) { ParticleSettings *part = sim->psys->part; int i = cpa - sim->psys->child; @@ -506,11 +571,17 @@ void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, Part 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); + float kink_amp; + /* seriously ... */ + if (ELEM(part->kink, PART_KINK_SPIRAL)) + kink_amp = part->kink_amp; + else + kink_amp = part->kink_amp * (1.f - part->kink_amp_clump * clump); do_kink(state, par, par_rot, t, kink_freq, part->kink_shape, kink_amp, part->kink_flat, part->kink, part->kink_axis, - sim->ob->obmat, sim->psys->part->childtype == PART_CHILD_FACES); + sim->ob->obmat, sim->psys->part->childtype == PART_CHILD_FACES, + spiral_start, time_prev, co_prev); } } -- cgit v1.2.3