From 272700728f411fa8099883e4866dc65d837d23ce Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 12 Sep 2012 16:42:24 +0000 Subject: Fix #32338: particle instance modifier did not work well when the mesh had only vertices. Previously it would hide particles by creating invalid faces, but this didn't make the vertices actually disappear. Also found that it could generated corrupt geometry for cases with faces, which gave wrong subsurf and could crash in edit mode. --- .../modifiers/intern/MOD_particleinstance.c | 238 ++++++++++++--------- 1 file changed, 133 insertions(+), 105 deletions(-) (limited to 'source') diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index c034832bfb4..d46ef3c3fc4 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -105,6 +105,41 @@ static void foreachObjectLink(ModifierData *md, Object *ob, walk(userData, ob, &pimd->ob); } +static int particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *psys, int p) +{ + ParticleData *pa; + + if (pimd->flag & eParticleInstanceFlag_Parents) { + if (p >= psys->totpart) { + if (psys->part->childtype == PART_CHILD_PARTICLES) { + pa = psys->particles + (psys->child + p - psys->totpart)->parent; + } + else { + pa = NULL; + } + } + else { + pa = psys->particles + p; + } + } + else { + if (psys->part->childtype == PART_CHILD_PARTICLES) { + pa = psys->particles + (psys->child + p)->parent; + } + else { + pa = NULL; + } + } + + if (pa) { + if (pa->alive == PARS_UNBORN && (pimd->flag & eParticleInstanceFlag_Unborn) == 0) return 1; + if (pa->alive == PARS_ALIVE && (pimd->flag & eParticleInstanceFlag_Alive) == 0) return 1; + if (pa->alive == PARS_DEAD && (pimd->flag & eParticleInstanceFlag_Dead) == 0) return 1; + } + + return 0; +} + static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) @@ -113,11 +148,13 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md; ParticleSimulationData sim; ParticleSystem *psys = NULL; - ParticleData *pa = NULL, *pars = NULL; + ParticleData *pa = NULL; MPoly *mpoly, *orig_mpoly; MLoop *mloop, *orig_mloop; MVert *mvert, *orig_mvert; - int i, totvert, totpoly, totloop, maxvert, maxpoly, maxloop, totpart = 0, first_particle = 0; + int totvert, totpoly, totloop, totedge; + int maxvert, maxpoly, maxloop, totpart = 0, first_particle = 0; + int k, p, p_skip; short track = ob->trackflag % 3, trackneg, axis = pimd->axis; float max_co = 0.0, min_co = 0.0, temp_co[3], cross[3]; float *size = NULL; @@ -153,7 +190,6 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, sim.psmd = psys_get_modifier(pimd->ob, psys); if (pimd->flag & eParticleInstanceFlag_UseSize) { - int p; float *si; si = size = MEM_callocN(totpart * sizeof(float), "particle size array"); @@ -171,15 +207,24 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, } } - pars = psys->particles; - totvert = dm->getNumVerts(dm); totpoly = dm->getNumPolys(dm); totloop = dm->getNumLoops(dm); + totedge = dm->getNumEdges(dm); - maxvert = totvert * totpart; - maxpoly = totpoly * totpart; - maxloop = totloop * totpart; + /* count particles */ + maxvert = 0; + maxpoly = 0; + maxloop = 0; + + for (p = 0; p < totpart; p++) { + if (particle_skip(pimd, psys, p)) + continue; + + maxvert += totvert; + maxpoly += totpoly; + maxloop += totloop; + } psys->lattice = psys_get_lattice(&sim); @@ -191,127 +236,110 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, max_co = max_r[track]; } - result = CDDM_from_template(dm, maxvert, dm->getNumEdges(dm) * totpart, 0, maxloop, maxpoly); + result = CDDM_from_template(dm, maxvert, 0, 0, maxloop, maxpoly); mvert = result->getVertArray(result); orig_mvert = dm->getVertArray(dm); - for (i = 0; i < maxvert; i++) { - MVert *inMV; - MVert *mv = mvert + i; - ParticleKey state; - - inMV = orig_mvert + i % totvert; - DM_copy_vert_data(dm, result, i % totvert, i, 1); - *mv = *inMV; - - /*change orientation based on object trackflag*/ - copy_v3_v3(temp_co, mv->co); - mv->co[axis] = temp_co[track]; - mv->co[(axis + 1) % 3] = temp_co[(track + 1) % 3]; - mv->co[(axis + 2) % 3] = temp_co[(track + 2) % 3]; - - if ((psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) && - (pimd->flag & eParticleInstanceFlag_Path)) - { - float ran = 0.0f; - if (pimd->random_position != 0.0f) { - BLI_srandom(psys->seed + (i / totvert) % totpart); - ran = pimd->random_position * BLI_frand(); - } - - if (pimd->flag & eParticleInstanceFlag_KeepShape) { - state.time = pimd->position * (1.0f - ran); - } - else { - state.time = (mv->co[axis] - min_co) / (max_co - min_co) * pimd->position * (1.0f - ran); - - if (trackneg) - state.time = 1.0f - state.time; - - mv->co[axis] = 0.0; - } - - psys_get_particle_on_path(&sim, first_particle + i / totvert, &state, 1); - - normalize_v3(state.vel); + mpoly = result->getPolyArray(result); + orig_mpoly = dm->getPolyArray(dm); + mloop = result->getLoopArray(result); + orig_mloop = dm->getLoopArray(dm); - /* TODO: incremental rotations somehow */ - if (state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) { - unit_qt(state.rot); - } - else { - float temp[3] = {0.0f, 0.0f, 0.0f}; - temp[axis] = 1.0f; + for (p = 0, p_skip = 0; p < totpart; p++) { + /* skip particle? */ + if (particle_skip(pimd, psys, p)) + continue; + + /* set vertices coordinates */ + for (k = 0; k < totvert; k++) { + ParticleKey state; + MVert *inMV; + MVert *mv = mvert + p_skip * totvert + k; + + inMV = orig_mvert + k; + DM_copy_vert_data(dm, result, k, p_skip * totvert + k, 1); + *mv = *inMV; + + /*change orientation based on object trackflag*/ + copy_v3_v3(temp_co, mv->co); + mv->co[axis] = temp_co[track]; + mv->co[(axis + 1) % 3] = temp_co[(track + 1) % 3]; + mv->co[(axis + 2) % 3] = temp_co[(track + 2) % 3]; + + /* get particle state */ + if ((psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) && + (pimd->flag & eParticleInstanceFlag_Path)) + { + float ran = 0.0f; + if (pimd->random_position != 0.0f) { + BLI_srandom(psys->seed + p); + ran = pimd->random_position * BLI_frand(); + } - cross_v3_v3v3(cross, temp, state.vel); + if (pimd->flag & eParticleInstanceFlag_KeepShape) { + state.time = pimd->position * (1.0f - ran); + } + else { + state.time = (mv->co[axis] - min_co) / (max_co - min_co) * pimd->position * (1.0f - ran); - /* state.vel[axis] is the only component surviving from a dot product with the axis */ - axis_angle_to_quat(state.rot, cross, saacos(state.vel[axis])); - } - } - else { - state.time = -1.0; - psys_get_particle_state(&sim, first_particle + i / totvert, &state, 1); - } + if (trackneg) + state.time = 1.0f - state.time; - mul_qt_v3(state.rot, mv->co); - if (pimd->flag & eParticleInstanceFlag_UseSize) - mul_v3_fl(mv->co, size[i / totvert]); - add_v3_v3(mv->co, state.co); - } + mv->co[axis] = 0.0; + } - mpoly = result->getPolyArray(result); - orig_mpoly = dm->getPolyArray(dm); - mloop = result->getLoopArray(result); - orig_mloop = dm->getLoopArray(dm); + psys_get_particle_on_path(&sim, first_particle + p, &state, 1); - for (i = 0; i < maxpoly; i++) { - MPoly *inMP = orig_mpoly + i % totpoly; - MPoly *mp = mpoly + i; + normalize_v3(state.vel); - if (pimd->flag & eParticleInstanceFlag_Parents) { - if (i / totpoly >= psys->totpart) { - if (psys->part->childtype == PART_CHILD_PARTICLES) { - pa = psys->particles + (psys->child + i / totpoly - psys->totpart)->parent; + /* TODO: incremental rotations somehow */ + if (state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) { + unit_qt(state.rot); } else { - pa = NULL; + float temp[3] = {0.0f, 0.0f, 0.0f}; + temp[axis] = 1.0f; + + cross_v3_v3v3(cross, temp, state.vel); + + /* state.vel[axis] is the only component surviving from a dot product with the axis */ + axis_angle_to_quat(state.rot, cross, saacos(state.vel[axis])); } } else { - pa = pars + i / totpoly; - } - } - else { - if (psys->part->childtype == PART_CHILD_PARTICLES) { - pa = psys->particles + (psys->child + i / totpoly)->parent; - } - else { - pa = NULL; + state.time = -1.0; + psys_get_particle_state(&sim, first_particle + p, &state, 1); } - } - if (pa) { - if (pa->alive == PARS_UNBORN && (pimd->flag & eParticleInstanceFlag_Unborn) == 0) continue; - if (pa->alive == PARS_ALIVE && (pimd->flag & eParticleInstanceFlag_Alive) == 0) continue; - if (pa->alive == PARS_DEAD && (pimd->flag & eParticleInstanceFlag_Dead) == 0) continue; + mul_qt_v3(state.rot, mv->co); + if (pimd->flag & eParticleInstanceFlag_UseSize) + mul_v3_fl(mv->co, size[p]); + add_v3_v3(mv->co, state.co); } - DM_copy_poly_data(dm, result, i % totpoly, i, 1); - *mp = *inMP; - mp->loopstart += (i / totpoly) * totloop; + /* create polys and loops */ + for (k = 0; k < totpoly; k++) { + MPoly *inMP = orig_mpoly + k; + MPoly *mp = mpoly + p_skip * totpoly + k; + + DM_copy_poly_data(dm, result, k, p_skip * totpoly + k, 1); + *mp = *inMP; + mp->loopstart += p_skip * totloop; - { - MLoop *inML = orig_mloop + inMP->loopstart; - MLoop *ml = mloop + mp->loopstart; - int j = mp->totloop; + { + MLoop *inML = orig_mloop + inMP->loopstart; + MLoop *ml = mloop + mp->loopstart; + int j = mp->totloop; - DM_copy_loop_data(dm, result, inMP->loopstart, mp->loopstart, j); - for (; j; j--, ml++, inML++) { - ml->v = inML->v + ((i / totpoly) * totvert); + DM_copy_loop_data(dm, result, inMP->loopstart, mp->loopstart, j); + for (; j; j--, ml++, inML++) { + ml->v = inML->v + (p_skip * totvert); + } } } + + p_skip++; } CDDM_calc_edges(result); -- cgit v1.2.3