diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2012-09-12 20:42:24 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2012-09-12 20:42:24 +0400 |
commit | 272700728f411fa8099883e4866dc65d837d23ce (patch) | |
tree | b5c48c803f985e379ec51e38d23096d879e1441c /source/blender/modifiers | |
parent | ab77d11bdbc45955988b5e77c1ce6899c86a2882 (diff) |
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.
Diffstat (limited to 'source/blender/modifiers')
-rw-r--r-- | source/blender/modifiers/intern/MOD_particleinstance.c | 238 |
1 files changed, 133 insertions, 105 deletions
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); |