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:
authorLukas Tönne <lukas.toenne@gmail.com>2015-01-13 19:24:20 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2015-01-20 11:30:10 +0300
commit307c4a4df92cdde64b39e7fe28ab2db80355025f (patch)
treedef751e2e620e0172bf3c386b1300f60366c5c13 /source/blender/blenkernel
parent9bf763393603a987aa95033b2da78cea501d699b (diff)
Another crappy approach to spirals on hairs, crazy expensive though.
Conflicts: source/blender/blenkernel/intern/particle.c
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_particle.h4
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c4
-rw-r--r--source/blender/blenkernel/intern/particle.c119
-rw-r--r--source/blender/blenkernel/intern/particle_child.c317
4 files changed, 274 insertions, 170 deletions
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index 35e89eeef9e..a2b283a4f70 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -126,7 +126,7 @@ typedef struct ParticleCacheKey {
float rot[4];
float col[3];
float time;
- int steps;
+ int segments;
} ParticleCacheKey;
typedef struct ParticleThreadContext {
@@ -150,7 +150,7 @@ typedef struct ParticleThreadContext {
struct ParticleData *tpars;
/* path caching */
- int editupdate, between, steps;
+ int editupdate, between, segments, extra_segments;
int totchild, totparent, parent_pass;
float cfra;
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 2bee6b76ad6..057f9999fac 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -970,8 +970,8 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
/* some hair paths might be non-existent so they can't be used for duplication */
if (hair &&
- ((a < totpart && psys->pathcache[a]->steps < 0) ||
- (a >= totpart && psys->childcache[a - totpart]->steps < 0)))
+ ((a < totpart && psys->pathcache[a]->segments < 0) ||
+ (a >= totpart && psys->childcache[a - totpart]->segments < 0)))
{
continue;
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 3f8d694aa44..15afd36d4ba 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, float spiral_start[3], float *time_prev, float *co_prev);
+ ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t);
/* few helpers for countall etc. */
int count_particles(ParticleSystem *psys)
@@ -139,7 +139,7 @@ int count_particles_mod(ParticleSystem *psys, int totgr, int cur)
#define PATH_CACHE_BUF_SIZE 1024
-static ParticleCacheKey **psys_alloc_path_cache_buffers(ListBase *bufs, int tot, int steps)
+static ParticleCacheKey **psys_alloc_path_cache_buffers(ListBase *bufs, int tot, int totkeys)
{
LinkData *buf;
ParticleCacheKey **cache;
@@ -152,10 +152,10 @@ static ParticleCacheKey **psys_alloc_path_cache_buffers(ListBase *bufs, int tot,
while (totkey < tot) {
totbufkey = MIN2(tot - totkey, PATH_CACHE_BUF_SIZE);
buf = MEM_callocN(sizeof(LinkData), "PathCacheLinkData");
- buf->data = MEM_callocN(sizeof(ParticleCacheKey) * totbufkey * steps, "ParticleCacheKey");
+ buf->data = MEM_callocN(sizeof(ParticleCacheKey) * totbufkey * totkeys, "ParticleCacheKey");
for (i = 0; i < totbufkey; i++)
- cache[totkey + i] = ((ParticleCacheKey *)buf->data) + i * steps;
+ cache[totkey + i] = ((ParticleCacheKey *)buf->data) + i * totkeys;
totkey += totbufkey;
BLI_addtail(bufs, buf);
@@ -1139,9 +1139,9 @@ static void interpolate_pathcache(ParticleCacheKey *first, float t, ParticleCach
ParticleCacheKey *cur = first;
/* scale the requested time to fit the entire path even if the path is cut early */
- t *= (first + first->steps)->time;
+ t *= (first + first->segments)->time;
- while (i < first->steps && cur->time < t)
+ while (i < first->segments && cur->time < t)
cur++;
if (cur->time == t)
@@ -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, float spiral_start[3], float *time_prev, float *co_prev);
+ short type, short axis, float obmat[4][4], int smooth_start);
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);
@@ -1793,11 +1793,10 @@ int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, i
{
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_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);
@@ -1943,7 +1942,7 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
int totparent = 0, between = 0;
- int steps = 1 << part->draw_step;
+ int segments = 1 << part->draw_step;
int totchild = psys->totchild;
psys_thread_context_init(ctx, sim);
@@ -1955,7 +1954,7 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi
if (psys->renderdata == 0 && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
totchild = 0;
- steps = 1 << pset->draw_step;
+ segments = 1 << pset->draw_step;
}
if (totchild && part->childtype == PART_CHILD_FACES) {
@@ -1969,7 +1968,7 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi
}
if (psys->renderdata)
- steps = (int)pow(2.0, (double)part->ren_step);
+ segments = 1 << part->ren_step;
else {
totchild = (int)((float)totchild * (float)part->disp / 100.0f);
totparent = MIN2(totparent, totchild);
@@ -1980,7 +1979,11 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi
/* fill context values */
ctx->between = between;
- ctx->steps = steps;
+ ctx->segments = segments;
+ if (ELEM(part->kink, PART_KINK_SPIRAL))
+ ctx->extra_segments = max_ii(part->kink_extra_steps, 1);
+ else
+ ctx->extra_segments = 0;
ctx->totchild = totchild;
ctx->totparent = totparent;
ctx->parent_pass = 0;
@@ -2060,7 +2063,7 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
if (!needupdate)
return;
else
- memset(child_keys, 0, sizeof(*child_keys) * (ctx->steps + 1));
+ memset(child_keys, 0, sizeof(*child_keys) * (ctx->segments + 1));
}
/* get parent paths */
@@ -2083,14 +2086,14 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
if (part->flag & PART_CHILD_LONG_HAIR) {
/* For long hair use tip distance/root distance as parting factor instead of root to tip angle. */
float d1 = len_v3v3(key[0]->co, key[w]->co);
- float d2 = len_v3v3((key[0] + key[0]->steps - 1)->co, (key[w] + key[w]->steps - 1)->co);
+ float d2 = len_v3v3((key[0] + key[0]->segments - 1)->co, (key[w] + key[w]->segments - 1)->co);
d = d1 > 0.f ? d2 / d1 - 1.f : 10000.f;
}
else {
float v1[3], v2[3];
- sub_v3_v3v3(v1, (key[0] + key[0]->steps - 1)->co, key[0]->co);
- sub_v3_v3v3(v2, (key[w] + key[w]->steps - 1)->co, key[w]->co);
+ sub_v3_v3v3(v1, (key[0] + key[0]->segments - 1)->co, key[0]->co);
+ sub_v3_v3v3(v2, (key[w] + key[w]->segments - 1)->co, key[w]->co);
normalize_v3(v1);
normalize_v3(v2);
@@ -2138,7 +2141,7 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
if (!(psys->edit->points[cpa->parent].flag & PEP_EDIT_RECALC))
return;
- memset(child_keys, 0, sizeof(*child_keys) * (ctx->steps + 1));
+ memset(child_keys, 0, sizeof(*child_keys) * (ctx->segments + 1));
}
/* get the parent path */
@@ -2157,18 +2160,18 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
psys_mat_hair_to_global(ob, ctx->sim.psmd->dm, psys->part->from, pa, hairmat);
}
- child_keys->steps = ctx->steps;
+ child_keys->segments = ctx->segments;
/* get different child parameters from textures & vgroups */
get_child_modifier_parameters(part, ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex);
if (ptex.exist < psys_frand(psys, i + 24)) {
- child_keys->steps = -1;
+ child_keys->segments = -1;
return;
}
/* create the child path */
- for (k = 0, child = child_keys; k <= ctx->steps; k++, child++) {
+ for (k = 0, child = child_keys; k <= ctx->segments; k++, child++) {
if (ctx->between) {
int w = 0;
@@ -2186,7 +2189,7 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
/* Fade the effect of rotation for even lengths in the end */
project_v3_v3v3(dvec, off2[w], (key[w] + k)->vel);
- madd_v3_v3fl(off2[w], dvec, -(float)k / (float)ctx->steps);
+ madd_v3_v3fl(off2[w], dvec, -(float)k / (float)ctx->segments);
}
add_v3_v3(off2[w], (key[w] + k)->co);
@@ -2210,14 +2213,14 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
offset_child(cpa, (ParticleKey *)(key[0] + k), par_rot, (ParticleKey *)child, part->childflat, part->childrad);
}
- child->time = (float)k / (float)ctx->steps;
+ child->time = (float)k / (float)ctx->segments;
}
/* apply effectors */
if (part->flag & PART_CHILD_EFFECT) {
- for (k = 0, child = child_keys; k <= ctx->steps; k++, child++) {
+ for (k = 0, child = child_keys; k <= ctx->segments; k++, child++) {
if (k) {
- do_path_effectors(&ctx->sim, cpa->pa[0], child, k, ctx->steps, child_keys->co, ptex.effector, 0.0f, ctx->cfra, &eff_length, eff_vec);
+ do_path_effectors(&ctx->sim, cpa->pa[0], child, k, ctx->segments, child_keys->co, ptex.effector, 0.0f, ctx->cfra, &eff_length, eff_vec);
}
else {
sub_v3_v3v3(eff_vec, (child + 1)->co, child->co);
@@ -2313,7 +2316,7 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
/* Hide virtual parents */
if (i < ctx->totparent)
- child_keys->steps = -1;
+ child_keys->segments = -1;
}
static void exec_child_path_cache(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
@@ -2358,7 +2361,8 @@ void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupd
else {
/* clear out old and create new empty path cache */
free_child_path_cache(sim->psys);
- sim->psys->childcache = psys_alloc_path_cache_buffers(&sim->psys->childcachebufs, totchild, ctx.steps + 1);
+
+ sim->psys->childcache = psys_alloc_path_cache_buffers(&sim->psys->childcachebufs, totchild, ctx.segments + ctx.extra_segments + 1);
sim->psys->totchildcache = totchild;
}
@@ -2459,7 +2463,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4];
float rotmat[3][3];
int k;
- int steps = (int)pow(2.0, (double)(psys->renderdata ? part->ren_step : part->draw_step));
+ int segments = (int)pow(2.0, (double)(psys->renderdata ? part->ren_step : part->draw_step));
int totpart = psys->totpart;
float length, vec[3];
float *vg_effector = NULL;
@@ -2479,7 +2483,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
/* clear out old and create new empty path cache */
psys_free_path_cache(psys, psys->edit);
- cache = psys->pathcache = psys_alloc_path_cache_buffers(&psys->pathcachebufs, totpart, steps + 1);
+ cache = psys->pathcache = psys_alloc_path_cache_buffers(&psys->pathcachebufs, totpart, segments + 1);
psys->lattice_deform_data = psys_create_lattice_deform_data(sim);
ma = give_current_material(sim->ob, psys->part->omat);
@@ -2514,9 +2518,9 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE);
pind.dm = hair_dm;
- memset(cache[p], 0, sizeof(*cache[p]) * (steps + 1));
+ memset(cache[p], 0, sizeof(*cache[p]) * (segments + 1));
- cache[p]->steps = steps;
+ cache[p]->segments = segments;
/*--get the first data points--*/
init_particle_interpolation(sim->ob, sim->psys, pa, &pind);
@@ -2538,15 +2542,15 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
}
if (birthtime >= dietime) {
- cache[p]->steps = -1;
+ cache[p]->segments = -1;
continue;
}
dietime = birthtime + pa_length * (dietime - birthtime);
/*--interpolate actual path from data points--*/
- for (k = 0, ca = cache[p]; k <= steps; k++, ca++) {
- time = (float)k / (float)steps;
+ for (k = 0, ca = cache[p]; k <= segments; k++, ca++) {
+ time = (float)k / (float)segments;
t = birthtime + time * (dietime - birthtime);
result.time = -t;
do_particle_interpolation(psys, p, pa, t, &pind, &result);
@@ -2582,29 +2586,29 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
sub_v3_v3v3(vec, (cache[p] + 1)->co, cache[p]->co);
length = len_v3(vec);
- for (k = 1, ca = cache[p] + 1; k <= steps; k++, ca++)
- do_path_effectors(sim, p, ca, k, steps, cache[p]->co, effector, dfra, cfra, &length, vec);
+ for (k = 1, ca = cache[p] + 1; k <= segments; k++, ca++)
+ do_path_effectors(sim, p, ca, k, segments, cache[p]->co, effector, dfra, cfra, &length, vec);
}
/* apply guide curves to path data */
if (sim->psys->effectors && (psys->part->flag & PART_CHILD_EFFECT) == 0) {
- for (k = 0, ca = cache[p]; k <= steps; k++, ca++)
+ for (k = 0, ca = cache[p]; k <= segments; k++, ca++)
/* ca is safe to cast, since only co and vel are used */
- do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)ca, p, (float)k / (float)steps);
+ do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)ca, p, (float)k / (float)segments);
}
/* lattices have to be calculated separately to avoid mixups between effector calculations */
if (psys->lattice_deform_data) {
- for (k = 0, ca = cache[p]; k <= steps; k++, ca++)
+ for (k = 0, ca = cache[p]; k <= segments; k++, ca++)
calc_latt_deform(psys->lattice_deform_data, ca->co, 1.0f);
}
}
/* finally do rotation & velocity */
- for (k = 1, ca = cache[p] + 1; k <= steps; k++, ca++) {
+ for (k = 1, ca = cache[p] + 1; k <= segments; k++, ca++) {
cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k);
- if (k == steps)
+ if (k == segments)
copy_qt_qt(ca->rot, (ca - 1)->rot);
/* set velocity */
@@ -2613,7 +2617,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
if (k == 1)
copy_v3_v3((ca - 1)->vel, ca->vel);
- ca->time = (float)k / (float)steps;
+ ca->time = (float)k / (float)segments;
}
/* First rotation is based on emitting face orientation.
* This is way better than having flipping rotations resulting
@@ -2657,17 +2661,17 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
float t, time = 0.0f, keytime = 0.0f /*, frs_sec */;
float hairmat[4][4], rotmat[3][3], prev_tangent[3] = {0.0f, 0.0f, 0.0f};
int k, i;
- int steps = (int)pow(2.0, (double)pset->draw_step);
+ int segments = 1 << pset->draw_step;
int totpart = edit->totpoint, recalc_set = 0;
float sel_col[3];
float nosel_col[3];
- steps = MAX2(steps, 4);
+ segments = MAX2(segments, 4);
if (!cache || edit->totpoint != edit->totcached) {
/* clear out old and create new empty path cache */
psys_free_path_cache(edit->psys, edit);
- cache = edit->pathcache = psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, steps + 1);
+ cache = edit->pathcache = psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, segments + 1);
/* set flag for update (child particles check this too) */
for (i = 0, point = edit->points; i < totpart; i++, point++)
@@ -2714,9 +2718,9 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
}
- memset(cache[i], 0, sizeof(*cache[i]) * (steps + 1));
+ memset(cache[i], 0, sizeof(*cache[i]) * (segments + 1));
- cache[i]->steps = steps;
+ cache[i]->segments = segments;
/*--get the first data points--*/
init_particle_interpolation(ob, psys, pa, &pind);
@@ -2732,13 +2736,13 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
dietime = pind.dietime;
if (birthtime >= dietime) {
- cache[i]->steps = -1;
+ cache[i]->segments = -1;
continue;
}
/*--interpolate actual path from data points--*/
- for (k = 0, ca = cache[i]; k <= steps; k++, ca++) {
- time = (float)k / (float)steps;
+ for (k = 0, ca = cache[i]; k <= segments; k++, ca++) {
+ time = (float)k / (float)segments;
t = birthtime + time * (dietime - birthtime);
result.time = -t;
do_particle_interpolation(psys, i, pa, t, &pind, &result);
@@ -2751,7 +2755,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
if (k) {
cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k);
- if (k == steps)
+ if (k == segments)
copy_qt_qt(ca->rot, (ca - 1)->rot);
/* set velocity */
@@ -2785,7 +2789,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
/* at the moment this is only used for weight painting.
* will need to move out of this check if its used elsewhere. */
- t2 = birthtime + ((float)k / (float)steps) * (dietime - birthtime);
+ t2 = birthtime + ((float)k / (float)segments) * (dietime - birthtime);
while (pind.hkey[1]->time < t2) pind.hkey[1]++;
pind.hkey[0] = pind.hkey[1] - 1;
@@ -3119,6 +3123,7 @@ static void default_particle_settings(ParticleSettings *part)
part->adapt_pix = 3;
part->kink_axis = 2;
part->kink_amp_clump = 1.f;
+ part->kink_extra_steps = 4;
part->clump_noise_size = 1.0f;
part->reactevent = PART_EVENT_DEATH;
part->disp = 100;
@@ -3817,10 +3822,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 */
- {
- 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);
- }
+ do_child_modifiers(sim, &ptex, par, par->rot, par_orco, cpa, orco, hairmat, state, t);
/* try to estimate correct velocity */
if (vel) {
@@ -3916,7 +3918,6 @@ 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);
@@ -3924,7 +3925,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, spiral_start, &time_prev, co_prev);
+ 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);
@@ -4052,7 +4053,7 @@ void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa
float loc[3], nor[3], vec[3], side[3], len;
float xvec[3] = {-1.0, 0.0, 0.0}, nmat[3][3];
- sub_v3_v3v3(vec, (cache + cache->steps)->co, cache->co);
+ sub_v3_v3v3(vec, (cache + cache->segments)->co, cache->co);
len = normalize_v3(vec);
if (pa == NULL && psys->part->childflat != PART_CHILD_FACES)
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
index ef4a41fc3b5..ea95255a313 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, float spiral_start[3], float *time_prev, float *co_prev);
+ short type, short axis, float obmat[4][4], int smooth_start);
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, float spiral_start[3], float *time_prev, float *co_prev);
+ 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])
{
@@ -120,13 +120,171 @@ typedef struct ParticlePathModifier {
/* ------------------------------------------------------------------------- */
+static void do_kink_spiral_deform(ParticleKey *state, const float dir[3],
+ float time, float freq, float shape, float amplitude,
+ const float spiral_start[3])
+{
+ float kink[3] = {1.f, 0.f, 0.f};
+ float result[3];
+
+ CLAMP(time, 0.f, 1.f);
+
+#if 0
+ {
+ float temp[3];
+
+ kink[axis] = 1.f;
+
+ if (obmat)
+ mul_mat3_m4_v3(obmat, kink);
+
+ mul_qt_v3(par_rot, kink);
+
+ /* make sure kink is normal to strand */
+ project_v3_v3v3(temp, kink, par_vel);
+ sub_v3_v3(kink, temp);
+ normalize_v3(kink);
+ }
+#endif
+
+ copy_v3_v3(result, state->co);
+
+ {
+ /* Creates a logarithmic spiral:
+ * r(theta) = a * exp(b * theta)
+ *
+ * The "density" parameter b is defined by the shape parameter
+ * and goes up to the Golden Spiral for 1.0
+ * http://en.wikipedia.org/wiki/Golden_spiral
+ */
+ const float b = shape * (1.0f + sqrtf(5.0f)) / M_PI * 0.25f;
+ /* angle of the spiral against the curve (rotated opposite to make a smooth transition) */
+ const float start_angle = (b != 0.0f ? atanf(1.0f / b) : -M_PI*0.5f) + (b > 0.0f ? -M_PI*0.5f : M_PI*0.5f);
+
+ float up[3], rot[3][3];
+ float vec[3];
+
+ float theta = freq * time * 2.0f*M_PI;
+ float radius = amplitude * expf(b * theta);
+
+ cross_v3_v3v3(up, dir, kink);
+
+ mul_v3_v3fl(vec, up, radius);
+
+ axis_angle_normalized_to_mat3(rot, kink, theta);
+ mul_m3_v3(rot, vec);
+
+ madd_v3_v3fl(vec, up, -amplitude);
+
+ axis_angle_normalized_to_mat3(rot, kink, -start_angle);
+ mul_m3_v3(rot, vec);
+
+ add_v3_v3v3(result, spiral_start, vec);
+ }
+
+ copy_v3_v3(state->co, result);
+}
+
+static void do_kink_spiral(ParticleThreadContext *ctx, ParticleTexture *ptex, const float parent_orco[3],
+ ChildParticle *cpa, const float orco[3], float hairmat[4][4],
+ ParticleCacheKey *keys, int *r_totkeys, float *r_max_length)
+{
+ struct ParticleSettings *part = ctx->sim.psys->part;
+ const int totkeys = ctx->segments + 1;
+ const int extrakeys = ctx->extra_segments;
+
+ float kink_amp = part->kink_amp;
+ float kink_freq = part->kink_freq;
+ float kink_shape = part->kink_shape;
+ float rough1 = part->rough1;
+ float rough2 = part->rough2;
+ float rough_end = part->rough_end;
+
+ ParticlePathIterator iter;
+ ParticleCacheKey *key;
+ int k;
+
+ float dir[3];
+ float spiral_start[3];
+ float len, totlen, cutlen;
+ int start_index = 0, end_index = 0;
+
+ if (ptex) {
+ kink_freq *= ptex->kink;
+ rough1 *= ptex->rough1;
+ rough2 *= ptex->rough2;
+ rough_end *= ptex->roughe;
+ }
+
+ totlen = 0.0f;
+ for (k = 0, key = keys; k < totkeys-1; k++, key++)
+ totlen += len_v3v3((key+1)->co, key->co);
+
+ cutlen = totlen - kink_amp;
+ zero_v3(spiral_start);
+
+ len = 0.0f;
+ for (k = 0, key = keys; k < totkeys-1; k++, key++) {
+ float seglen = len_v3v3((key+1)->co, key->co);
+
+ if (seglen > 0.0f && len + seglen >= cutlen) {
+ float fac = (cutlen - len) / seglen;
+ start_index = k + 1;
+ end_index = start_index + extrakeys;
+ interp_v3_v3v3(spiral_start, key->co, (key+1)->co, fac);
+
+ break;
+ }
+ len += seglen;
+ }
+
+#if 0
+ /* use the last segment's direction for the spiral orientation
+ * this is more consistent and stable than the last flat segment
+ * when changing the amplitude
+ */
+ if (totkeys > 1) {
+ sub_v3_v3v3(dir, (keys+totkeys-1)->co, (keys+totkeys-2)->co);
+ normalize_v3(dir);
+ }
+ else
+ zero_v3(dir);
+#endif
+
+ zero_v3(dir);
+ for (k = 0, key = keys; k < end_index; k++, key++) {
+ psys_path_iter_get(&iter, keys, end_index, NULL, k);
+ if (k < start_index) {
+ sub_v3_v3v3(dir, (key+1)->co, key->co);
+ normalize_v3(dir);
+ }
+ else {
+ float spiral_time = (float)(k - start_index) / (float)(extrakeys-1);
+ do_kink_spiral_deform((ParticleKey *)key, dir, spiral_time, kink_freq, kink_shape, kink_amp, spiral_start);
+ }
+
+ /* apply different deformations to the child path */
+ /* XXX TODO does not work without parent key, replace by explicit loc, rot, dir arguments! */
+ do_child_modifiers(&ctx->sim, ptex, (ParticleKey *)iter.parent_key, iter.parent_rotation, parent_orco, cpa, orco, hairmat, (ParticleKey *)key, iter.time);
+ }
+
+ totlen = 0.0f;
+ for (k = 0, key = keys; k < end_index-1; k++, key++)
+ totlen += len_v3v3((key+1)->co, key->co);
+
+ *r_totkeys = end_index;
+ *r_max_length = totlen;
+}
+
+/* ------------------------------------------------------------------------- */
+
static bool check_path_length(int k, ParticleCacheKey *keys, ParticleCacheKey *key, float max_length, float step_length, float *cur_length, float dvec[3])
{
if (*cur_length + step_length > max_length) {
sub_v3_v3v3(dvec, key->co, (key-1)->co);
mul_v3_fl(dvec, (max_length - *cur_length) / step_length);
add_v3_v3v3(key->co, (key-1)->co, dvec);
- keys->steps = k;
+ keys->segments = k;
/* something over the maximum step value */
return false;
}
@@ -144,14 +302,10 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
struct Material *ma = ctx->ma;
const bool draw_col_ma = (part->draw_col == PART_DRAW_COL_MAT);
- const int totkeys = ctx->steps + 1;
- const float step_length = 1.0f / (float)ctx->steps;
- const float max_length = ptex->length;
-
ParticlePathModifier *mod;
ParticleCacheKey *key;
- int k;
- float cur_length;
+ int totkeys, k;
+ float max_length;
#if 0 /* TODO for the future: use true particle modifiers that work on the whole curve */
for (mod = modifiers->first; mod; mod = mod->next) {
@@ -161,65 +315,73 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
(void)modifiers;
(void)mod;
- {
+ if (part->kink == PART_KINK_SPIRAL) {
+ do_kink_spiral(ctx, ptex, parent_orco, cpa, orco, hairmat, keys, &totkeys, &max_length);
+ keys->segments = totkeys - 1;
+ }
+ else {
ParticlePathIterator iter;
- float spiral_start[3];
- float time_prev = 0.0f;
- float co_prev[3] = {0.0f, 0.0f, 0.0f};
+
+ totkeys = ctx->segments + 1;
+ max_length = ptex->length;
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, spiral_start, &time_prev, co_prev);
+ do_child_modifiers(&ctx->sim, ptex, (ParticleKey *)iter.parent_key, iter.parent_rotation, parent_orco, cpa, orco, hairmat, (ParticleKey *)key, iter.time);
}
}
-#endif
-
- cur_length = 0.0f;
- /* we have to correct velocity because of kink & clump */
- for (k = 0, key = keys; k < totkeys; ++k, ++key) {
- if (k >= 2) {
- sub_v3_v3v3((key-1)->vel, key->co, (key-2)->co);
- mul_v3_fl((key-1)->vel, 0.5);
-
- if (ma && draw_col_ma)
- get_strand_normal(ma, ornor, cur_length, (key-1)->vel);
- }
- else if (k == totkeys-1) {
- /* last key */
- sub_v3_v3v3(key->vel, key->co, (key-1)->co);
- }
+
+ {
+ const float step_length = 1.0f / (float)(totkeys - 1);
- if (k > 1) {
- float dvec[3];
- /* check if path needs to be cut before actual end of data points */
- if (!check_path_length(k, keys, key, max_length, step_length, &cur_length, dvec))
- break;
- }
+ float cur_length = 0.0f;
- if (ma && draw_col_ma) {
- copy_v3_v3(key->col, &ma->r);
- get_strand_normal(ma, ornor, cur_length, key->vel);
+ /* we have to correct velocity because of kink & clump */
+ for (k = 0, key = keys; k < totkeys; ++k, ++key) {
+ if (k >= 2) {
+ sub_v3_v3v3((key-1)->vel, key->co, (key-2)->co);
+ mul_v3_fl((key-1)->vel, 0.5);
+
+ if (ma && draw_col_ma)
+ get_strand_normal(ma, ornor, cur_length, (key-1)->vel);
+ }
+ else if (k == totkeys-1) {
+ /* last key */
+ sub_v3_v3v3(key->vel, key->co, (key-1)->co);
+ }
+
+ if (k > 1) {
+ float dvec[3];
+ /* check if path needs to be cut before actual end of data points */
+ if (!check_path_length(k, keys, key, max_length, step_length, &cur_length, dvec))
+ break;
+ }
+
+ if (ma && draw_col_ma) {
+ copy_v3_v3(key->col, &ma->r);
+ get_strand_normal(ma, ornor, cur_length, key->vel);
+ }
}
}
+#endif
}
/* ------------------------------------------------------------------------- */
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 amplitude, float flat, short type, short axis, float obmat[4][4], int smooth_start)
{
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];
- if (par == NULL || type == PART_KINK_NO)
+ if (par == NULL || ELEM(type, PART_KINK_NO, PART_KINK_SPIRAL))
return;
CLAMP(time, 0.f, 1.f);
- if (shape != 0.0f && !ELEM(type, PART_KINK_BRAID, PART_KINK_SPIRAL)) {
+ if (shape != 0.0f && !ELEM(type, PART_KINK_BRAID)) {
if (shape < 0.0f)
time = (float)pow(time, 1.f + shape);
else
@@ -228,14 +390,14 @@ void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, f
t = time * freq * (float)M_PI;
- if (smooth_start && !ELEM(type, PART_KINK_SPIRAL)) {
+ if (smooth_start) {
dt = fabsf(t);
/* smooth the beginning of kink */
CLAMP(dt, 0.f, (float)M_PI);
dt = sinf(dt / 2.f);
}
- if (!ELEM(type, PART_KINK_RADIAL, PART_KINK_SPIRAL)) {
+ if (!ELEM(type, PART_KINK_RADIAL)) {
float temp[3];
kink[axis] = 1.f;
@@ -359,65 +521,6 @@ 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 */
@@ -540,7 +643,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, float spiral_start[3], float *time_prev, float *co_prev)
+ 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;
@@ -550,6 +653,7 @@ void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, Part
float rough1 = part->rough1;
float rough2 = part->rough2;
float rough_end = part->rough_end;
+ const bool smooth_start = (sim->psys->part->childtype == PART_CHILD_FACES);
if (ptex) {
kink_freq *= ptex->kink;
@@ -580,8 +684,7 @@ void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, Part
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,
- spiral_start, time_prev, co_prev);
+ sim->ob->obmat, smooth_start);
}
}