From e9587a89faf33aa0c1383b59f006be4cc7443a5a Mon Sep 17 00:00:00 2001 From: Janne Karhu Date: Thu, 10 Sep 2009 22:32:33 +0000 Subject: Hair dynamics with cloth simulation - Hair dynamics have their own panel in particle settings with the settings from cloth panel that apply to hair. - Basic internal friction force to quickly emulate self collisions and volume preservation. (Still very early code, but gives some idea of what's possible). - Softbody simulation is no longer used for hair. * Old files with sb dynamics should just load the hair without dynamics so new dynamics can be applied. * Invasion of particles exceptions in sb code is finally over. - Collisions with other objects are disabled for now and will be worked out in the future. Other changes/fixes: - Particle mode editing flag wasn't saved properly. - Some old files with edited hair didn't load correctly. - Disabled delete & specials menu in particle mode for non-hair editing. - Fixed yet one more cloth & softbody pointcache update issue. - Disconnect/connect hair now uses only the deformed mesh so it works correctly also for subsurfed emitters. - Hair editing now updates correctly with a moving emitter. --- source/blender/blenkernel/BKE_cloth.h | 3 +- source/blender/blenkernel/BKE_particle.h | 2 +- source/blender/blenkernel/intern/cloth.c | 45 ++- source/blender/blenkernel/intern/implicit.c | 88 +++++- source/blender/blenkernel/intern/object.c | 7 +- source/blender/blenkernel/intern/particle.c | 209 +++++++------- source/blender/blenkernel/intern/particle_system.c | 305 ++++++++++++-------- source/blender/blenkernel/intern/pointcache.c | 33 +-- source/blender/blenkernel/intern/softbody.c | 307 ++++----------------- source/blender/blenloader/intern/readfile.c | 32 ++- source/blender/blenloader/intern/writefile.c | 9 +- source/blender/editors/physics/editparticle.c | 48 +++- source/blender/editors/space_buttons/buttons_ops.c | 26 +- source/blender/editors/space_view3d/drawobject.c | 6 + source/blender/makesdna/DNA_cloth_types.h | 2 +- source/blender/makesdna/DNA_object_force.h | 2 - source/blender/makesdna/DNA_particle_types.h | 15 +- source/blender/makesrna/intern/rna_cloth.c | 10 +- source/blender/makesrna/intern/rna_particle.c | 39 ++- 19 files changed, 620 insertions(+), 568 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index bc4585106e6..e5b3adbd0c0 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -176,7 +176,8 @@ typedef enum CLOTH_SIMSETTINGS_FLAG_GOAL = ( 1 << 3 ), // we have goals enabled CLOTH_SIMSETTINGS_FLAG_TEARING = ( 1 << 4 ),// true if tearing is enabled CLOTH_SIMSETTINGS_FLAG_SCALING = ( 1 << 8 ), /* is advanced scaling active? */ - CLOTH_SIMSETTINGS_FLAG_CCACHE_EDIT = (1 << 12) /* edit cache in editmode */ + CLOTH_SIMSETTINGS_FLAG_CCACHE_EDIT = (1 << 12), /* edit cache in editmode */ + CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS = (1 << 13) /* don't allow spring compression */ } CLOTH_SIMSETTINGS_FLAGS; /* COLLISION FLAGS */ diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 15896477a6a..c22778f5a30 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -208,7 +208,7 @@ void psys_free_boid_rules(struct ListBase *list); void psys_free_settings(struct ParticleSettings *part); void free_child_path_cache(struct ParticleSystem *psys); void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit); -void free_hair(struct ParticleSystem *psys, int softbody); +void free_hair(struct Object *ob, struct ParticleSystem *psys, int dynamics); void free_keyed_keys(struct ParticleSystem *psys); void psys_free_particles(struct ParticleSystem *psys); void psys_free(struct Object * ob, struct ParticleSystem * psys); diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 8be8df8e63b..d25c329f49f 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -496,9 +496,11 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, if(!do_init_cloth(ob, clmd, result, framenr)) return result; - if(framenr == startframe && cache->flag & PTCACHE_REDO_NEEDED) { + if(framenr == startframe) { BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); + do_init_cloth(ob, clmd, result, framenr); cache->simframe= framenr; + cache->flag |= PTCACHE_SIMULATION_VALID; cache->flag &= ~PTCACHE_REDO_NEEDED; return result; } @@ -530,36 +532,25 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, return result; } - if(framenr == startframe) { - implicit_set_positions(clmd); + /* if on second frame, write cache for first frame */ + if(cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) + BKE_ptcache_write_cache(&pid, startframe); - cache->simframe= framenr; - cache->flag |= PTCACHE_SIMULATION_VALID; + clmd->sim_parms->timescale *= framenr - cache->simframe; - /* don't write cache on first frame, but on second frame write - * cache for frame 1 and 2 */ - } - else { - /* if on second frame, write cache for first frame */ - if(cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) - BKE_ptcache_write_cache(&pid, startframe); + /* do simulation */ + cache->flag |= PTCACHE_SIMULATION_VALID; + cache->simframe= framenr; - clmd->sim_parms->timescale *= framenr - cache->simframe; - - /* do simulation */ - cache->flag |= PTCACHE_SIMULATION_VALID; - cache->simframe= framenr; - - if(!do_step_cloth(ob, clmd, result, framenr)) { - cache->flag &= ~PTCACHE_SIMULATION_VALID; - cache->simframe= 0; - cache->last_exact= 0; - } - else - BKE_ptcache_write_cache(&pid, framenr); - - cloth_to_object (ob, clmd, result); + if(!do_step_cloth(ob, clmd, result, framenr)) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + cache->last_exact= 0; } + else + BKE_ptcache_write_cache(&pid, framenr); + + cloth_to_object (ob, clmd, result); return result; } diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c index fc5213d5532..0bce71b57eb 100644 --- a/source/blender/blenkernel/intern/implicit.c +++ b/source/blender/blenkernel/intern/implicit.c @@ -1183,7 +1183,8 @@ DO_INLINE void dfdx_spring(float to[3][3], float dir[3],float length,float L,fl //return ( (I-outerprod(dir,dir))*Min(1.0f,rest/length) - I) * -k; mul_fvectorT_fvector(to, dir, dir); sub_fmatrix_fmatrix(to, I, to); - mul_fmatrix_S(to, (((L/length)> 1.0f) ? (1.0f): (L/length))); + + mul_fmatrix_S(to, (L/length)); sub_fmatrix_fmatrix(to, to, I); mul_fmatrix_S(to, -k); } @@ -1218,6 +1219,8 @@ DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, float nulldfdx[3][3]={ {0,0,0}, {0,0,0}, {0,0,0}}; float scaling = 0.0; + + int no_compress = clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS; VECCOPY(s->f, nullf); cp_fmatrix(s->dfdx, nulldfdx); @@ -1254,7 +1257,7 @@ DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, // calculate force of structural + shear springs if((s->type & CLOTH_SPRING_TYPE_STRUCTURAL) || (s->type & CLOTH_SPRING_TYPE_SHEAR)) { - if(length > L) // only on elonglation + if(length > L || no_compress) { s->flags |= CLOTH_SPRING_FLAG_NEEDED; @@ -1393,6 +1396,84 @@ float calculateVertexWindForce(float wind[3], float vertexnormal[3]) return (INPR(wind, vertexnormal)); } +typedef struct HairGridVert { + float velocity[3]; + float density; +} HairGridVert; +/* Smoothing of hair velocities: + * adapted from + Volumetric Methods for Simulation and Rendering of Hair + by Lena Petrovic, Mark Henne and John Anderson + * Pixar Technical Memo #06-08, Pixar Animation Studios + */ +static void hair_velocity_smoothing(float smoothfac, lfVector *lF, lfVector *lX, lfVector *lV, int numverts) +{ + /* TODO: this is an initial implementation and should be made much better in due time */ + + /* 10x10x10 grid gives nice initial results */ + HairGridVert grid[10][10][10]; + float gmin[3], gmax[3], density; + int v = 0; + int i = 0; + int j = 0; + int k = 0; + lfVector temp; + + INIT_MINMAX(gmin, gmax); + + for(i = 0; i < numverts; i++) + DO_MINMAX(lX[i], gmin, gmax); + + /* initialize grid */ + for(i = 0; i < 10; i++) { + for(j = 0; j < 10; j++) { + for(k = 0; k < 10; k++) { + grid[i][j][k].velocity[0] = 0.0f; + grid[i][j][k].velocity[1] = 0.0f; + grid[i][j][k].velocity[2] = 0.0f; + grid[i][j][k].density = 0.0f; + } + } + } + + /* gather velocities & density */ + for(v = 0; v < numverts; v++) { + i = (int)( (lX[v][0] - gmin[0]) / (gmax[0] - gmin[0]) * 9.99f ); + j = (int)( (lX[v][1] - gmin[1]) / (gmax[1] - gmin[1]) * 9.99f ); + k = (int)( (lX[v][2] - gmin[2]) / (gmax[2] - gmin[2]) * 9.99f ); + + grid[i][j][k].velocity[0] += lV[v][0]; + grid[i][j][k].velocity[1] += lV[v][1]; + grid[i][j][k].velocity[2] += lV[v][2]; + grid[i][j][k].density += 1.0f; + } + + /* divide velocity with density */ + for(i = 0; i < 10; i++) { + for(j = 0; j < 10; j++) { + for(k = 0; k < 10; k++) { + density = grid[i][j][k].density; + if(density > 0.0f) { + grid[i][j][k].velocity[0] /= density; + grid[i][j][k].velocity[1] /= density; + grid[i][j][k].velocity[2] /= density; + } + } + } + } + + /* calculate forces */ + for(v = 0; v < numverts; v++) { + i = (int)( (lX[v][0] - gmin[0]) / (gmax[0] - gmin[0]) * 9.99f ); + j = (int)( (lX[v][1] - gmin[1]) / (gmax[1] - gmin[1]) * 9.99f ); + k = (int)( (lX[v][2] - gmin[2]) / (gmax[2] - gmin[2]) * 9.99f ); + + /* 2.0f is an experimental value that seems to give good results */ + lF[v][0] += 2.0f * smoothfac * (grid[i][j][k].velocity[0] - lV[v][0]); + lF[v][1] += 2.0f * smoothfac * (grid[i][j][k].velocity[1] - lV[v][1]); + lF[v][2] += 2.0f * smoothfac * (grid[i][j][k].velocity[2] - lV[v][2]); + } +} static void cloth_calc_force(ClothModifierData *clmd, float frame, lfVector *lF, lfVector *lX, lfVector *lV, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, ListBase *effectors, float time, fmatrix3x3 *M) { /* Collect forces and derivatives: F,dFdX,dFdV */ @@ -1416,6 +1497,9 @@ static void cloth_calc_force(ClothModifierData *clmd, float frame, lfVector *lF, init_lfvector(lF, gravity, numverts); + if(clmd->sim_parms->velocity_smooth > 0.0f) + hair_velocity_smoothing(clmd->sim_parms->velocity_smooth, lF, lX, lV, numverts); + /* multiply lF with mass matrix // force = mass * acceleration (in this case: gravity) */ diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index f10226f6f6b..a0004aaae49 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1113,9 +1113,10 @@ ParticleSystem *copy_particlesystem(ParticleSystem *psys) } } - if(psys->soft) { - psysn->soft= copy_softbody(psys->soft); - psysn->soft->particles = psysn; + if(psys->clmd) { + ClothModifierData *nclmd = modifier_new(eModifierType_Cloth); + modifier_copyData((ModifierData*)psys->clmd, (ModifierData*)nclmd); + psys->hair_in_dm = psys->hair_out_dm = NULL; } BLI_duplicatelist(&psysn->targets, &psys->targets); diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 0ba2f357a1f..3b2125a7973 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -366,7 +366,7 @@ void psys_free_settings(ParticleSettings *part) boid_free_settings(part->boids); } -void free_hair(ParticleSystem *psys, int softbody) +void free_hair(Object *ob, ParticleSystem *psys, int dynamics) { PARTICLE_P; @@ -382,10 +382,28 @@ void free_hair(ParticleSystem *psys, int softbody) psys->flag &= ~PSYS_HAIR_DONE; - if(softbody && psys->soft) { - sbFree(psys->soft); - psys->soft = NULL; + if(psys->clmd) { + if(dynamics) { + BKE_ptcache_free_list(&psys->ptcaches); + psys->clmd->point_cache = psys->pointcache = NULL; + psys->clmd->ptcaches.first = psys->clmd->ptcaches.first = NULL; + + modifier_free((ModifierData*)psys->clmd); + + psys->clmd = NULL; + } + else { + cloth_free_modifier(ob, psys->clmd); + } } + + if(psys->hair_in_dm) + psys->hair_in_dm->release(psys->hair_in_dm); + psys->hair_in_dm = NULL; + + if(psys->hair_out_dm) + psys->hair_out_dm->release(psys->hair_out_dm); + psys->hair_out_dm = NULL; } void free_keyed_keys(ParticleSystem *psys) { @@ -468,6 +486,8 @@ void psys_free(Object *ob, ParticleSystem * psys) psys_free_path_cache(psys, NULL); + free_hair(ob, psys, 1); + psys_free_particles(psys); if(psys->edit && psys->free_edit) @@ -976,11 +996,11 @@ void psys_interpolate_particle(short type, ParticleKey keys[4], float dt, Partic typedef struct ParticleInterpolationData { HairKey *hkey[2]; + DerivedMesh *dm; + MVert *mvert[2]; + int keyed; ParticleKey *kkey[2]; - - SoftBody *soft; - BodyPoint *bp[2]; PointCache *cache; @@ -1049,12 +1069,12 @@ static void init_particle_interpolation(Object *ob, ParticleSystem *psys, Partic pind->birthtime = key->time; pind->dietime = (key + pa->totkey - 1)->time; - } - //if(pind->soft) { - // pind->bp[0] = pind->soft->bpoint + pa->bpi; - // pind->bp[1] = pind->soft->bpoint + pa->bpi + 1; - //} + if(pind->dm) { + pind->mvert[0] = CDDM_get_vert(pind->dm, pa->hair_index); + pind->mvert[1] = pind->mvert[0] + 1; + } + } } static void edit_to_particle(ParticleKey *key, PTCacheEditKey *ekey) { @@ -1069,9 +1089,10 @@ static void hair_to_particle(ParticleKey *key, HairKey *hkey) VECCOPY(key->co, hkey->co); key->time = hkey->time; } -static void bp_to_particle(ParticleKey *key, BodyPoint *bp, HairKey *hkey) + +static void mvert_to_particle(ParticleKey *key, MVert *mvert, HairKey *hkey) { - VECCOPY(key->co, bp->pos); + VECCOPY(key->co, mvert->co); key->time = hkey->time; } @@ -1145,7 +1166,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData while(pind->hkey[1]->time < real_t) { pind->hkey[1]++; - pind->bp[1]++; + pind->mvert[1]++; } pind->hkey[0] = pind->hkey[1] - 1; @@ -1156,10 +1177,10 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData edit_to_particle(keys + 1, pind->ekey[0]); edit_to_particle(keys + 2, pind->ekey[1]); } - else if(pind->soft) { - pind->bp[0] = pind->bp[1] - 1; - bp_to_particle(keys + 1, pind->bp[0], pind->hkey[0]); - bp_to_particle(keys + 2, pind->bp[1], pind->hkey[1]); + else if(pind->dm) { + pind->mvert[0] = pind->mvert[1] - 1; + mvert_to_particle(keys + 1, pind->mvert[0], pind->hkey[0]); + mvert_to_particle(keys + 2, pind->mvert[1], pind->hkey[1]); } else if(pind->keyed) { memcpy(keys + 1, pind->kkey[0], sizeof(ParticleKey)); @@ -1181,11 +1202,11 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData else edit_to_particle(keys, pind->ekey[0]); } - else if(pind->soft) { + else if(pind->dm) { if(pind->hkey[0] != pa->hair) - bp_to_particle(keys, pind->bp[0] - 1, pind->hkey[0] - 1); + mvert_to_particle(keys, pind->mvert[0] - 1, pind->hkey[0] - 1); else - bp_to_particle(keys, pind->bp[0], pind->hkey[0]); + mvert_to_particle(keys, pind->mvert[0], pind->hkey[0]); } else { if(pind->hkey[0] != pa->hair) @@ -1200,11 +1221,11 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData else edit_to_particle(keys + 3, pind->ekey[1]); } - else if(pind->soft) { + else if(pind->dm) { if(pind->hkey[1] != pa->hair + pa->totkey - 1) - bp_to_particle(keys + 3, pind->bp[1] + 1, pind->hkey[1] + 1); + mvert_to_particle(keys + 3, pind->mvert[1] + 1, pind->hkey[1] + 1); else - bp_to_particle(keys + 3, pind->bp[1], pind->hkey[1]); + mvert_to_particle(keys + 3, pind->mvert[1], pind->hkey[1]); } else { if(pind->hkey[1] != pa->hair + pa->totkey - 1) @@ -2110,7 +2131,11 @@ float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup) { float *vg=0; - if(psys->vgroup[vgroup]){ + if(vgroup < 0) { + /* hair dynamics pinning vgroup */ + + } + else if(psys->vgroup[vgroup]){ MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); if(dvert){ int totvert=dm->getNumVerts(dm), i; @@ -2639,12 +2664,11 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); ParticleSettings *part = psys->part; ParticleEditSettings *pset = &scene->toolsettings->particle; + + DerivedMesh *hair_dm = psys->hair_out_dm; ParticleData *pa = psys->particles; ParticleKey result; - - SoftBody *soft = NULL; - BodyPoint *bp[2] = {NULL, NULL}; Material *ma; ParticleInterpolationData pind; @@ -2663,7 +2687,7 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra int keyed, baked; /* we don't have anything valid to create paths from so let's quit here */ - if(!(psys->flag & PSYS_HAIR_DONE) && !(psys->flag & PSYS_KEYED) && !(psys->pointcache->flag & PTCACHE_BAKED)) + if((psys->flag & PSYS_HAIR_DONE || psys->flag & PSYS_KEYED || psys->pointcache->flag & PTCACHE_BAKED)==0) return; if(psys_in_edit_mode(scene, psys)) @@ -2673,24 +2697,18 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra BLI_srandom(psys->seed); keyed = psys->flag & PSYS_KEYED; - baked = psys->pointcache->flag & PTCACHE_BAKED; + baked = !hair_dm && psys->pointcache->flag & PTCACHE_BAKED; /* 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); - if(psys->soft && psys->softflag & OB_SB_ENABLE) { - soft = psys->soft; - if(!soft->bpoint) - soft= NULL; - } - psys->lattice = psys_get_lattice(scene, ob, psys); ma= give_current_material(ob, psys->part->omat); if(ma && (psys->part->draw & PART_DRAW_MAT_COL)) VECCOPY(col, &ma->r) - if(psys->part->from!=PART_FROM_PARTICLE) { + if(psys->part->from!=PART_FROM_PARTICLE && !(psys->flag & PSYS_GLOBAL_HAIR)) { if(!(psys->part->flag & PART_CHILD_EFFECT)) vg_effector = psys_cache_vgroup(psmd->dm, psys, PSYS_VG_EFFECTOR); @@ -2700,11 +2718,8 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra /*---first main loop: create all actual particles' paths---*/ for(i=0; iflag & PARS_NO_DISP || pa->flag & PARS_UNEXIST) { - if(soft) - bp[0] += pa->totkey; /* TODO use of initialized value? */ + if(pa->flag & PARS_NO_DISP || pa->flag & PARS_UNEXIST) continue; - } if(!psys->totchild) { BLI_srandom(psys->seed + i); @@ -2715,9 +2730,9 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra pind.keyed = keyed; pind.cache = baked ? psys->pointcache : NULL; - pind.soft = soft; pind.epoint = NULL; pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE); + pind.dm = hair_dm; memset(cache[i], 0, sizeof(*cache[i])*(steps+1)); @@ -2759,10 +2774,12 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra do_particle_interpolation(psys, i, pa, t, frs_sec, &pind, &result); - /* keyed, baked and softbody are allready in global space */ - if(!keyed && !baked && !soft && !(psys->flag & PSYS_GLOBAL_HAIR)) { + /* dynamic hair is in object space */ + /* keyed and baked are allready in global space */ + if(hair_dm) + Mat4MulVecfl(ob->obmat, result.co); + else if(!keyed && !baked && !(psys->flag & PSYS_GLOBAL_HAIR)) Mat4MulVecfl(hairmat, result.co); - } VECCOPY(ca->co, result.co); VECCOPY(ca->col, col); @@ -2778,64 +2795,66 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra effector*= psys_particle_value_from_verts(psmd->dm,psys->part->from,pa,vg_effector); for(k=0, ca=cache[i]; k<=steps; k++, ca++) { + if(!(psys->flag & PSYS_GLOBAL_HAIR)) { /* apply effectors */ - if(!(psys->part->flag & PART_CHILD_EFFECT) && k) - do_path_effectors(scene, ob, psys, i, ca, k, steps, cache[i]->co, effector, dfra, cfra, &length, vec); + if(!(psys->part->flag & PART_CHILD_EFFECT) && k) + do_path_effectors(scene, ob, psys, i, ca, k, steps, cache[i]->co, effector, dfra, cfra, &length, vec); - /* apply guide curves to path data */ - if(psys->effectors.first && (psys->part->flag & PART_CHILD_EFFECT)==0) - /* ca is safe to cast, since only co and vel are used */ - do_guide(scene, (ParticleKey*)ca, i, (float)k/(float)steps, &psys->effectors); + /* apply guide curves to path data */ + if(psys->effectors.first && (psys->part->flag & PART_CHILD_EFFECT)==0) + /* ca is safe to cast, since only co and vel are used */ + do_guide(scene, (ParticleKey*)ca, i, (float)k/(float)steps, &psys->effectors); - /* apply lattice */ - if(psys->lattice) - calc_latt_deform(psys->lattice, ca->co, 1.0f); + /* apply lattice */ + if(psys->lattice) + calc_latt_deform(psys->lattice, ca->co, 1.0f); - /* figure out rotation */ - - if(k) { - float cosangle, angle, tangent[3], normal[3], q[4]; - - if(k == 1) { - /* calculate initial tangent for incremental rotations */ - VECSUB(tangent, ca->co, (ca - 1)->co); - VECCOPY(prev_tangent, tangent); - Normalize(prev_tangent); - - /* First rotation is based on emitting face orientation. */ - /* This is way better than having flipping rotations resulting */ - /* from using a global axis as a rotation pole (vec_to_quat()). */ - /* It's not an ideal solution though since it disregards the */ - /* initial tangent, but taking that in to account will allow */ - /* the possibility of flipping again. -jahka */ - Mat3ToQuat_is_ok(rotmat, (ca-1)->rot); - } - else { - VECSUB(tangent, ca->co, (ca - 1)->co); - Normalize(tangent); - - cosangle= Inpf(tangent, prev_tangent); - - /* note we do the comparison on cosangle instead of - * angle, since floating point accuracy makes it give - * different results across platforms */ - if(cosangle > 0.999999f) { - QUATCOPY((ca - 1)->rot, (ca - 2)->rot); + /* figure out rotation */ + + if(k) { + float cosangle, angle, tangent[3], normal[3], q[4]; + + if(k == 1) { + /* calculate initial tangent for incremental rotations */ + VECSUB(tangent, ca->co, (ca - 1)->co); + VECCOPY(prev_tangent, tangent); + Normalize(prev_tangent); + + /* First rotation is based on emitting face orientation. */ + /* This is way better than having flipping rotations resulting */ + /* from using a global axis as a rotation pole (vec_to_quat()). */ + /* It's not an ideal solution though since it disregards the */ + /* initial tangent, but taking that in to account will allow */ + /* the possibility of flipping again. -jahka */ + Mat3ToQuat_is_ok(rotmat, (ca-1)->rot); } else { - angle= saacos(cosangle); - Crossf(normal, prev_tangent, tangent); - VecRotToQuat(normal, angle, q); - QuatMul((ca - 1)->rot, q, (ca - 2)->rot); + VECSUB(tangent, ca->co, (ca - 1)->co); + Normalize(tangent); + + cosangle= Inpf(tangent, prev_tangent); + + /* note we do the comparison on cosangle instead of + * angle, since floating point accuracy makes it give + * different results across platforms */ + if(cosangle > 0.999999f) { + QUATCOPY((ca - 1)->rot, (ca - 2)->rot); + } + else { + angle= saacos(cosangle); + Crossf(normal, prev_tangent, tangent); + VecRotToQuat(normal, angle, q); + QuatMul((ca - 1)->rot, q, (ca - 2)->rot); + } + + VECCOPY(prev_tangent, tangent); } - VECCOPY(prev_tangent, tangent); + if(k == steps) + QUATCOPY(ca->rot, (ca - 1)->rot); } - if(k == steps) - QUATCOPY(ca->rot, (ca - 1)->rot); } - /* set velocity */ @@ -2913,9 +2932,9 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf pind.keyed = 0; pind.cache = NULL; - pind.soft = NULL; pind.epoint = point; pind.bspline = psys ? (psys->part->flag & PART_HAIR_BSPLINE) : 0; + pind.dm = NULL; memset(cache[i], 0, sizeof(*cache[i])*(steps+1)); @@ -3783,8 +3802,8 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i pa = psys->particles + p; pind.keyed = keyed; pind.cache = cached ? psys->pointcache : NULL; - pind.soft = NULL; pind.epoint = NULL; + pind.dm = psys->hair_out_dm; init_particle_interpolation(ob, psys, pa, &pind); do_particle_interpolation(psys, p, pa, t, frs_sec, &pind, state); diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 1931b89af38..88b85bcfa29 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -73,7 +73,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_object.h" #include "BKE_material.h" -#include "BKE_softbody.h" +#include "BKE_cloth.h" #include "BKE_depsgraph.h" #include "BKE_lattice.h" #include "BKE_pointcache.h" @@ -126,7 +126,7 @@ void psys_reset(ParticleSystem *psys, int mode) PARTICLE_P; if(ELEM(mode, PSYS_RESET_ALL, PSYS_RESET_DEPSGRAPH)) { - if(mode == PSYS_RESET_ALL || !(part->type == PART_HAIR && (psys->edit && psys->edit->edited))) { + if(mode == PSYS_RESET_ALL || !(psys->flag & PSYS_EDITED)) { psys_free_particles(psys); psys->totpart= 0; @@ -3432,6 +3432,190 @@ static void deflect_particle(Scene *scene, Object *pob, ParticleSystemModifierDa /************************************************/ /* Hair */ /************************************************/ +/* check if path cache or children need updating and do it if needed */ +static void psys_update_path_cache(Scene *scene, Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) +{ + ParticleSettings *part=psys->part; + ParticleEditSettings *pset=&scene->toolsettings->particle; + int distr=0,alloc=0,skip=0; + + if((psys->part->childtype && psys->totchild != get_psys_tot_child(scene, psys)) || psys->recalc&PSYS_RECALC_RESET) + alloc=1; + + if(alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))) + distr=1; + + if(distr){ + if(alloc) + realloc_particles(ob,psys,psys->totpart); + + if(get_psys_tot_child(scene, psys)) { + /* don't generate children while computing the hair keys */ + if(!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) { + distribute_particles(scene, ob, psys, PART_FROM_CHILD); + + if(part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES && part->parents!=0.0) + psys_find_parents(ob,psmd,psys); + } + } + } + + if((part->type==PART_HAIR || psys->flag&PSYS_KEYED || psys->pointcache->flag & PTCACHE_BAKED)==0) + skip = 1; /* only hair, keyed and baked stuff can have paths */ + else if(part->ren_as != PART_DRAW_PATH) + skip = 1; /* particle visualization must be set as path */ + else if(!psys->renderdata) { + if(part->draw_as != PART_DRAW_REND) + skip = 1; /* draw visualization */ + else if(psys->pointcache->flag & PTCACHE_BAKING) + skip = 1; /* no need to cache paths while baking dynamics */ + else if(psys_in_edit_mode(scene, psys)) { + if((pset->flag & PE_DRAW_PART)==0) + skip = 1; + else if(part->childtype==0 && (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED)==0) + skip = 1; /* in edit mode paths are needed for child particles and dynamic hair */ + } + } + + if(!skip) { + psys_cache_paths(scene, ob, psys, cfra); + + /* for render, child particle paths are computed on the fly */ + if(part->childtype) { + if(!psys->totchild) + skip = 1; + else if((psys->part->type == PART_HAIR && psys->flag & PSYS_HAIR_DONE)==0) + skip = 1; + + if(!skip) + psys_cache_child_paths(scene, ob, psys, cfra, 0); + } + } + else if(psys->pathcache) + psys_free_path_cache(psys, NULL); +} + +static void do_hair_dynamics(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd) +{ + DerivedMesh *dm = psys->hair_in_dm; + MVert *mvert = NULL; + MEdge *medge = NULL; + MDeformVert *dvert = NULL; + HairKey *key; + PARTICLE_P; + int totpoint = 0; + int totedge; + int k; + float hairmat[4][4]; + + if(!psys->clmd) { + psys->clmd = (ClothModifierData*)modifier_new(eModifierType_Cloth); + psys->clmd->sim_parms->goalspring = 0.0f; + psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_GOAL|CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS; + psys->clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF; + } + + /* create a dm from hair vertices */ + LOOP_PARTICLES + totpoint += pa->totkey; + + totedge = totpoint - psys->totpart; + + if(dm && (totpoint != dm->getNumVerts(dm) || totedge != dm->getNumEdges(dm))) { + dm->release(dm); + dm = psys->hair_in_dm = NULL; + } + + if(!dm) { + dm = psys->hair_in_dm = CDDM_new(totpoint, totedge, 0); + DM_add_vert_layer(dm, CD_MDEFORMVERT, CD_CALLOC, NULL); + } + + mvert = CDDM_get_verts(dm); + medge = CDDM_get_edges(dm); + dvert = DM_get_vert_data_layer(dm, CD_MDEFORMVERT); + + psys->clmd->sim_parms->vgroup_mass = 1; + + /* make vgroup for pin roots etc.. */ + psys->particles->hair_index = 0; + LOOP_PARTICLES { + if(p) + pa->hair_index = (pa-1)->hair_index + (pa-1)->totkey; + + psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, hairmat); + + for(k=0, key=pa->hair; ktotkey; k++,key++) { + VECCOPY(mvert->co, key->co); + Mat4MulVecfl(hairmat, mvert->co); + mvert++; + + if(k) { + medge->v1 = pa->hair_index + k - 1; + medge->v2 = pa->hair_index + k; + medge++; + } + + if(dvert) { + if(!dvert->totweight) { + dvert->dw = MEM_callocN (sizeof(MDeformWeight), "deformWeight"); + dvert->totweight = 1; + } + + /* no special reason for the 0.5 */ + /* just seems like a nice value from experiments */ + dvert->dw->weight = k ? 0.5f : 1.0f; + dvert++; + } + } + } + + if(psys->hair_out_dm) + psys->hair_out_dm->release(psys->hair_out_dm); + + psys->clmd->point_cache = psys->pointcache; + + psys->hair_out_dm = clothModifier_do(psys->clmd, scene, ob, dm, 0, 0); +} +static void hair_step(Scene *scene, Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) +{ + ParticleSettings *part = psys->part; + PARTICLE_P; + float disp = (float)get_current_display_percentage(psys)/100.0f; + + BLI_srandom(psys->seed); + + LOOP_PARTICLES { + if(BLI_frand() > disp) + pa->flag |= PARS_NO_DISP; + else + pa->flag &= ~PARS_NO_DISP; + } + + if(psys->recalc & PSYS_RECALC_RESET) { + /* need this for changing subsurf levels */ + psys_calc_dmcache(ob, psmd->dm, psys); + + if(psys->clmd) + cloth_free_modifier(ob, psys->clmd); + } + + if(psys->effectors.first) + psys_end_effectors(psys); + + /* dynamics with cloth simulation */ + if(psys->part->type==PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) + do_hair_dynamics(scene, ob, psys, psmd); + + psys_init_effectors(scene, ob, part->eff_group, psys); + if(psys->effectors.first) + precalc_effectors(scene, ob,psys,psmd,cfra); + + psys_update_path_cache(scene, ob,psmd,psys,cfra); + + psys->flag |= PSYS_HAIR_UPDATED; +} + static void save_hair(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra){ HairKey *key, *root; PARTICLE_P; @@ -3692,79 +3876,6 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic BLI_kdtree_free(tree); } -/* check if path cache or children need updating and do it if needed */ -static void psys_update_path_cache(Scene *scene, Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) -{ - ParticleSettings *part=psys->part; - ParticleEditSettings *pset=&scene->toolsettings->particle; - int distr=0,alloc=0; - - if((psys->part->childtype && psys->totchild != get_psys_tot_child(scene, psys)) || psys->recalc&PSYS_RECALC_RESET) - alloc=1; - - if(alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))) - distr=1; - - if(distr){ - if(alloc) - realloc_particles(ob,psys,psys->totpart); - - if(get_psys_tot_child(scene, psys)) { - /* don't generate children while computing the hair keys */ - if(!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) { - distribute_particles(scene, ob, psys, PART_FROM_CHILD); - - if(part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES && part->parents!=0.0) - psys_find_parents(ob,psmd,psys); - } - } - } - - if((part->type==PART_HAIR || psys->flag&PSYS_KEYED || psys->pointcache->flag & PTCACHE_BAKED) && ( psys_in_edit_mode(scene, psys) || (part->type==PART_HAIR - || (part->ren_as == PART_DRAW_PATH && (part->draw_as == PART_DRAW_REND || psys->renderdata))))){ - - psys_cache_paths(scene, ob, psys, cfra); - - /* for render, child particle paths are computed on the fly */ - if(part->childtype) { - if(((psys->totchild!=0)) || (psys_in_edit_mode(scene, psys) && (pset->flag&PE_DRAW_PART))) - if(!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) - psys_cache_child_paths(scene, ob, psys, cfra, 0); - } - } - else if(psys->pathcache) - psys_free_path_cache(psys, NULL); -} - -static void hair_step(Scene *scene, Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) -{ - ParticleSettings *part = psys->part; - PARTICLE_P; - float disp = (float)get_current_display_percentage(psys)/100.0f; - - BLI_srandom(psys->seed); - - LOOP_PARTICLES { - if(BLI_frand() > disp) - pa->flag |= PARS_NO_DISP; - else - pa->flag &= ~PARS_NO_DISP; - } - - if(psys->recalc & PSYS_RECALC_RESET) - /* need this for changing subsurf levels */ - psys_calc_dmcache(ob, psmd->dm, psys); - - if(psys->effectors.first) - psys_end_effectors(psys); - - psys_init_effectors(scene, ob, part->eff_group, psys); - if(psys->effectors.first) - precalc_effectors(scene, ob,psys,psmd,cfra); - - psys_update_path_cache(scene, ob,psmd,psys,cfra); -} - /* updates cached particles' alive & other flags etc..*/ static void cached_step(Scene *scene, Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) { @@ -3889,14 +4000,12 @@ static void psys_changed_type(Object *ob, ParticleSystem *psys) BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0); } else { - free_hair(psys, 1); + free_hair(ob, psys, 1); CLAMP(part->path_start, 0.0f, MAX2(100.0f, part->end + part->lifetime)); CLAMP(part->path_end, 0.0f, MAX2(100.0f, part->end + part->lifetime)); } - psys->softflag= 0; - psys_reset(psys, PSYS_RESET_ALL); } void psys_check_boid_data(ParticleSystem *psys) @@ -4082,7 +4191,7 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle framedelta= framenr - cache->simframe; /* set suitable cache range automatically */ - if((cache->flag & (PTCACHE_BAKING|PTCACHE_BAKED))==0) + if((cache->flag & (PTCACHE_BAKING|PTCACHE_BAKED))==0 && !(psys->flag & PSYS_HAIR_DYNAMICS)) psys_get_pointcache_start_end(scene, psys, &cache->startframe, &cache->endframe); BKE_ptcache_id_from_particles(&pid, ob, psys); @@ -4307,39 +4416,9 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle } } -static void psys_to_softbody(Scene *scene, Object *ob, ParticleSystem *psys) -{ - SoftBody *sb; - short softflag; - - if(!(psys->softflag & OB_SB_ENABLE)) - return; - - /* let's replace the object's own softbody with the particle softbody */ - /* a temporary solution before cloth simulation is implemented, jahka */ - - /* save these */ - sb= ob->soft; - softflag= ob->softflag; - - /* swich to new ones */ - ob->soft= psys->soft; - ob->softflag= psys->softflag; - - /* do softbody */ - sbObjectStep(scene, ob, (float)scene->r.cfra, NULL, psys_count_keys(psys)); - - /* return things back to normal */ - psys->soft= ob->soft; - psys->softflag= ob->softflag; - - ob->soft= sb; - ob->softflag= softflag; -} - static int hair_needs_recalc(ParticleSystem *psys) { - if((!psys->edit || !psys->edit->edited) && + if(!(psys->flag & PSYS_EDITED) && (!psys->edit || !psys->edit->edited) && ((psys->flag & PSYS_HAIR_DONE)==0 || psys->recalc & PSYS_RECALC_RESET)) { return 1; } @@ -4380,7 +4459,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) float hcfra=0.0f; int i; - free_hair(psys, 0); + free_hair(ob, psys, 0); /* first step is negative so particles get killed and reset */ psys->cfra= 1.0f; @@ -4394,10 +4473,6 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) psys->flag |= PSYS_HAIR_DONE; } - /* handle softbody hair */ - if(psys->part->type==PART_HAIR && psys->soft) - psys_to_softbody(scene, ob, psys); - /* the main particle system step */ system_step(scene, ob, psys, psmd, cfra); diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 5a14277d63b..f351f8a4335 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -382,8 +382,6 @@ static int ptcache_totpoint_cloth(void *cloth_v) /* Creating ID's */ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) { - ParticleSystemModifierData *psmd; - memset(pid, 0, sizeof(PTCacheID)); pid->ob= ob; @@ -406,12 +404,7 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) pid->data_types= (1<info_types= 0; - if(sb->particles) { - psmd= psys_get_modifier(ob, sb->particles); - // pid->stack_index= modifiers_indexInObject(ob, (ModifierData*)psmd); XXX TODO - get other index DG - } - else - pid->stack_index = pid->cache->index; + pid->stack_index = pid->cache->index; } void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *psys) @@ -426,7 +419,8 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p pid->cache_ptr= &psys->pointcache; pid->ptcaches= &psys->ptcaches; - pid->flag |= PTCACHE_VEL_PER_SEC; + if(psys->part->type != PART_HAIR) + pid->flag |= PTCACHE_VEL_PER_SEC; pid->write_elem= ptcache_write_particle; pid->write_stream = NULL; @@ -816,12 +810,6 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob) pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); BKE_ptcache_id_from_particles(pid, ob, psys); BLI_addtail(lb, pid); - - if(psys->soft) { - pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); - BKE_ptcache_id_from_softbody(pid, ob, psys->soft); - BLI_addtail(lb, pid); - } } } @@ -1828,9 +1816,10 @@ int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode) else if(mode == PTCACHE_RESET_OUTDATED) { reset = 1; - if(cache->flag & PTCACHE_OUTDATED) - if(!(cache->flag & PTCACHE_BAKED)) - clear= 1; + if(cache->flag & PTCACHE_OUTDATED && !(cache->flag & PTCACHE_BAKED)) { + clear= 1; + cache->flag &= ~PTCACHE_OUTDATED; + } } if(reset) { @@ -1873,10 +1862,10 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode) } for(psys=ob->particlesystem.first; psys; psys=psys->next) { - /* Baked softbody hair has to be checked first, because we don't want to reset */ - /* particles or softbody in that case -jahka */ - if(psys->soft) { - BKE_ptcache_id_from_softbody(&pid, ob, psys->soft); + /* Baked cloth hair has to be checked first, because we don't want to reset */ + /* particles or cloth in that case -jahka */ + if(psys->clmd) { + BKE_ptcache_id_from_cloth(&pid, ob, psys->clmd); if(mode == PSYS_RESET_ALL || !(psys->part->type == PART_HAIR && (pid.cache->flag & PTCACHE_BAKED))) reset |= BKE_ptcache_id_reset(scene, &pid, mode); else diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index fdbfe154fae..450a64d72eb 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -58,7 +58,6 @@ variables on the UI for now #include "DNA_curve_types.h" #include "DNA_object_types.h" #include "DNA_object_force.h" /* here is the softbody struct */ -#include "DNA_particle_types.h" #include "DNA_key_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -76,7 +75,6 @@ variables on the UI for now #include "BKE_global.h" #include "BKE_key.h" #include "BKE_object.h" -#include "BKE_particle.h" #include "BKE_softbody.h" #include "BKE_utildefines.h" #include "BKE_DerivedMesh.h" @@ -494,32 +492,21 @@ static void ccd_build_deflector_hash(Scene *scene, Object *vertexowner, GHash *h while (base) { /*Only proceed for mesh object in same layer */ if(base->object->type==OB_MESH && (base->lay & vertexowner->lay)) { - int particles=0; ob= base->object; if((vertexowner) && (ob == vertexowner)) { - if(vertexowner->soft->particles){ - particles=1; - } - else { - /* if vertexowner is given we don't want to check collision with owner object */ - base = base->next; - continue; - } + /* if vertexowner is given we don't want to check collision with owner object */ + base = base->next; + continue; } /*+++ only with deflecting set */ if(ob->pd && ob->pd->deflect && BLI_ghash_lookup(hash, ob) == 0) { DerivedMesh *dm= NULL; - if(particles) { - dm = psys_get_modifier(ob,psys_get_current(ob))->dm; - } - else { - if(ob->softflag & OB_SB_COLLFINAL) /* so maybe someone wants overkill to collide with subsurfed */ - dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - else - dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); - } + if(ob->softflag & OB_SB_COLLFINAL) /* so maybe someone wants overkill to collide with subsurfed */ + dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); + else + dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); if(dm){ ccd_Mesh *ccdmesh = ccd_mesh_make(ob, dm); @@ -3571,107 +3558,6 @@ static void curve_surf_to_softbody(Scene *scene, Object *ob) } } - -static void springs_from_particles(Object *ob) -{ - ParticleSystem *psys; - ParticleSystemModifierData *psmd=0; - ParticleData *pa=0; - HairKey *key=0; - SoftBody *sb; - BodyPoint *bp; - BodySpring *bs; - int a,k; - float hairmat[4][4]; - - if(ob && ob->soft && ob->soft->particles) { - psys= ob->soft->particles; - sb= ob->soft; - psmd = psys_get_modifier(ob, psys); - - bp= sb->bpoint; - for(a=0, pa=psys->particles; atotpart; a++, pa++) { - for(k=0, key=pa->hair; ktotkey; k++, bp++, key++) { - VECCOPY(bp->origS, key->co); - - psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); - - Mat4MulVecfl(hairmat, bp->origS); - } - } - - for(a=0, bs=sb->bspring; atotspring; a++, bs++) - bs->len= VecLenf(sb->bpoint[bs->v1].origS, sb->bpoint[bs->v2].origS); - } -} - -static void particles_to_softbody(Scene *scene, Object *ob) -{ - SoftBody *sb; - BodyPoint *bp; - BodySpring *bs; - ParticleData *pa; - HairKey *key; - ParticleSystem *psys= ob->soft->particles; - float goalfac; - int a, k, curpoint; - int totpoint= psys_count_keys(psys); - int totedge= totpoint-psys->totpart; - - /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */ - renew_softbody(scene, ob, totpoint, totedge); - - /* find first BodyPoint index for each particle */ - if(psys->totpart > 0) { -// psys->particles->bpi = 0; -// for(a=1, pa=psys->particles+1; atotpart; a++, pa++) -// pa->bpi = (pa-1)->bpi + (pa-1)->totkey; - } - - /* we always make body points */ - sb= ob->soft; - bp= sb->bpoint; - bs= sb->bspring; - goalfac= ABS(sb->maxgoal - sb->mingoal); - - if((ob->softflag & OB_SB_GOAL)) { - for(a=0, pa=psys->particles; atotpart; a++, pa++) { - for(k=0, key=pa->hair; ktotkey; k++,bp++,key++) { - if(k) { - bp->goal= key->weight; - bp->goal= sb->mingoal + bp->goal*goalfac; - bp->goal= (float)pow(bp->goal, 4.0f); - } - else{ - /* hair roots are allways fixed fully to goal */ - bp->goal= 1.0f; - } - } - } - } - - bp= sb->bpoint; - curpoint=0; - for(a=0, pa=psys->particles; atotpart; a++, curpoint++, pa++) { - for(k=0; ktotkey-1; k++,bs++,curpoint++) { - bs->v1=curpoint; - bs->v2=curpoint+1; - bs->strength= 1.0; - bs->order=1; - } - } - - build_bps_springlist(ob); /* scan for springs attached to bodypoints ONCE */ - /* insert *other second order* springs if desired */ - if(sb->secondspring > 0.0000001f) { - add_2nd_order_springs(ob,sb->secondspring*10.0); /* exploits the the first run of build_bps_springlist(ob);*/ - build_bps_springlist(ob); /* yes we need to do it again*/ - } - springs_from_particles(ob); /* write the 'rest'-lenght of the springs */ - if(ob->softflag & OB_SB_SELF) - calculate_collision_balls(ob); -} - /* copies softbody result back in object */ static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts, int local) { @@ -3795,44 +3681,16 @@ void sbSetInterruptCallBack(int (*f)(void)) static void softbody_update_positions(Object *ob, SoftBody *sb, float (*vertexCos)[3], int numVerts) { - ParticleSystemModifierData *psmd= NULL; - ParticleData *pa= NULL; - HairKey *key= NULL; BodyPoint *bp; - float hairmat[4][4]; int a; - /* update the vertex locations */ - if(sb->particles && sb->particles->totpart>0) { - psmd= psys_get_modifier(ob,sb->particles); - - pa= sb->particles->particles; - key= pa->hair; - - psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); - } - for(a=0,bp=sb->bpoint; aorigS, bp->origE); /* copy the position of the goals at desired end time */ - if(sb->particles) { - if(key == pa->hair + pa->totkey) { - pa++; - key = pa->hair; - - psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); - } - VECCOPY(bp->origE, key->co); - Mat4MulVecfl(hairmat,bp->origE); - - key++; - } - else{ - VECCOPY(bp->origE, vertexCos[a]); - /* vertexCos came from local world, go global */ - Mat4MulVecfl(ob->obmat, bp->origE); - } + VECCOPY(bp->origE, vertexCos[a]); + /* vertexCos came from local world, go global */ + Mat4MulVecfl(ob->obmat, bp->origE); /* just to be save give bp->origT a defined value will be calulated in interpolate_exciter()*/ VECCOPY(bp->origT, bp->origE); @@ -3841,37 +3699,12 @@ static void softbody_update_positions(Object *ob, SoftBody *sb, float (*vertexCo static void softbody_reset(Object *ob, SoftBody *sb, float (*vertexCos)[3], int numVerts) { - ParticleSystemModifierData *psmd= NULL; - HairKey *key= NULL; - ParticleData *pa= NULL; BodyPoint *bp; - float hairmat[4][4]; int a; - if(sb->particles && sb->particles->totpart>0) { - psmd= psys_get_modifier(ob, sb->particles); - pa= sb->particles->particles; - key= pa->hair; - - psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); - } - for(a=0,bp=sb->bpoint; aparticles) { - if(key == pa->hair + pa->totkey) { - pa++; - key = pa->hair; - - psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); - } - VECCOPY(bp->pos, key->co); - Mat4MulVecfl(hairmat, bp->pos); - key++; - } - else { - VECCOPY(bp->pos, vertexCos[a]); - Mat4MulVecfl(ob->obmat, bp->pos); /* yep, sofbody is global coords*/ - } + VECCOPY(bp->pos, vertexCos[a]); + Mat4MulVecfl(ob->obmat, bp->pos); /* yep, sofbody is global coords*/ VECCOPY(bp->origS, bp->pos); VECCOPY(bp->origE, bp->pos); VECCOPY(bp->origT, bp->pos); @@ -3900,20 +3733,18 @@ static void softbody_reset(Object *ob, SoftBody *sb, float (*vertexCos)[3], int sb_new_scratch(sb); /* make a new */ sb->scratch->needstobuildcollider=1; - if((sb->particles)==0) { - /* copy some info to scratch */ - switch(ob->type) { - case OB_MESH: - if (ob->softflag & OB_SB_FACECOLL) mesh_faces_to_scratch(ob); - break; - case OB_LATTICE: - break; - case OB_CURVE: - case OB_SURF: - break; - default: - break; - } + /* copy some info to scratch */ + switch(ob->type) { + case OB_MESH: + if (ob->softflag & OB_SB_FACECOLL) mesh_faces_to_scratch(ob); + break; + case OB_LATTICE: + break; + case OB_CURVE: + case OB_SURF: + break; + default: + break; } } @@ -4049,8 +3880,6 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime) /* simulates one step. framenr is in frames */ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], int numVerts) { - ParticleSystemModifierData *psmd=0; - ParticleData *pa=0; SoftBody *sb= ob->soft; PointCache *cache; PTCacheID pid; @@ -4091,25 +3920,20 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i if(sb->bpoint == NULL || ((ob->softflag & OB_SB_EDGES) && !ob->soft->bspring && object_has_edges(ob))) { - if(sb->particles){ - particles_to_softbody(scene, ob); - } - else { - switch(ob->type) { - case OB_MESH: - mesh_to_softbody(scene, ob); - break; - case OB_LATTICE: - lattice_to_softbody(scene, ob); - break; - case OB_CURVE: - case OB_SURF: - curve_surf_to_softbody(scene, ob); - break; - default: - renew_softbody(scene, ob, numVerts, 0); - break; - } + switch(ob->type) { + case OB_MESH: + mesh_to_softbody(scene, ob); + break; + case OB_LATTICE: + lattice_to_softbody(scene, ob); + break; + case OB_CURVE: + case OB_SURF: + curve_surf_to_softbody(scene, ob); + break; + default: + renew_softbody(scene, ob, numVerts, 0); + break; } softbody_update_positions(ob, sb, vertexCos, numVerts); @@ -4127,8 +3951,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i softbody_update_positions(ob, sb, vertexCos, numVerts); softbody_step(scene, ob, sb, dtime); - if(sb->particles==0) - softbody_to_object(ob, vertexCos, numVerts, 0); + softbody_to_object(ob, vertexCos, numVerts, 0); return; } @@ -4136,14 +3959,14 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i /* still no points? go away */ if(sb->totpoint==0) return; - if(sb->particles){ - psmd= psys_get_modifier(ob, sb->particles); - pa= sb->particles->particles; - } - - if(framenr == startframe && cache->flag & PTCACHE_REDO_NEEDED) { + if(framenr == startframe) { BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); + + /* first frame, no simulation to do, just set the positions */ + softbody_update_positions(ob, sb, vertexCos, numVerts); + cache->simframe= framenr; + cache->flag |= PTCACHE_SIMULATION_VALID; cache->flag &= ~PTCACHE_REDO_NEEDED; return; } @@ -4152,8 +3975,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i cache_result = BKE_ptcache_read_cache(&pid, framenr, scene->r.frs_sec); if(cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED) { - if(sb->particles==0) - softbody_to_object(ob, vertexCos, numVerts, sb->local); + softbody_to_object(ob, vertexCos, numVerts, sb->local); cache->simframe= framenr; cache->flag |= PTCACHE_SIMULATION_VALID; @@ -4174,36 +3996,23 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i return; } - if(framenr == startframe) { - /* first frame, no simulation to do, just set the positions */ - softbody_update_positions(ob, sb, vertexCos, numVerts); - - cache->simframe= framenr; - cache->flag |= PTCACHE_SIMULATION_VALID; + /* if on second frame, write cache for first frame */ + if(cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) + BKE_ptcache_write_cache(&pid, startframe); - /* don't write cache on first frame, but on second frame write - * cache for frame 1 and 2 */ - } - else { - /* if on second frame, write cache for first frame */ - if(cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) - BKE_ptcache_write_cache(&pid, startframe); + softbody_update_positions(ob, sb, vertexCos, numVerts); - softbody_update_positions(ob, sb, vertexCos, numVerts); + /* checking time: */ + dtime = framedelta*timescale; - /* checking time: */ - dtime = framedelta*timescale; + softbody_step(scene, ob, sb, dtime); - softbody_step(scene, ob, sb, dtime); - - if(sb->particles==0) - softbody_to_object(ob, vertexCos, numVerts, 0); + softbody_to_object(ob, vertexCos, numVerts, 0); - /* do simulation */ - cache->simframe= framenr; - cache->flag |= PTCACHE_SIMULATION_VALID; + /* do simulation */ + cache->simframe= framenr; + cache->flag |= PTCACHE_SIMULATION_VALID; - BKE_ptcache_write_cache(&pid, framenr); - } + BKE_ptcache_write_cache(&pid, framenr); } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 37031f4f82a..5b45a4219c7 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -3114,17 +3114,6 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles) psys->child=newdataadr(fd,psys->child); psys->effectors.first=psys->effectors.last=0; - psys->soft= newdataadr(fd, psys->soft); - if(psys->soft) { - SoftBody *sb = psys->soft; - sb->particles = psys; - sb->bpoint= NULL; // init pointers so it gets rebuilt nicely - sb->bspring= NULL; - sb->scratch= NULL; - - direct_link_pointcache_list(fd, &sb->ptcaches, &sb->pointcache); - } - link_list(fd, &psys->targets); psys->edit = NULL; @@ -3137,6 +3126,23 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles) direct_link_pointcache_list(fd, &psys->ptcaches, &psys->pointcache); + if(psys->clmd) { + psys->clmd = newdataadr(fd, psys->clmd); + psys->clmd->clothObject = NULL; + + psys->clmd->sim_parms= newdataadr(fd, psys->clmd->sim_parms); + psys->clmd->coll_parms= newdataadr(fd, psys->clmd->coll_parms); + + if(psys->clmd->sim_parms) { + if(psys->clmd->sim_parms->presets > 10) + psys->clmd->sim_parms->presets = 0; + } + + psys->hair_in_dm = psys->hair_out_dm = NULL; + + psys->clmd->point_cache = psys->pointcache; + } + psys->tree = NULL; } return; @@ -8342,8 +8348,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main) ob->soft->pointcache= BKE_ptcache_add(&ob->soft->ptcaches); for(psys=ob->particlesystem.first; psys; psys=psys->next) { - if(psys->soft && !psys->soft->pointcache) - psys->soft->pointcache= BKE_ptcache_add(&psys->soft->ptcaches); + //if(psys->soft && !psys->soft->pointcache) + // psys->soft->pointcache= BKE_ptcache_add(&psys->soft->ptcaches); if(!psys->pointcache) psys->pointcache= BKE_ptcache_add(&psys->ptcaches); } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 46cc62fff1c..98db27182ab 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -660,8 +660,13 @@ static void write_particlesystems(WriteData *wd, ListBase *particles) writestruct(wd, DATA, "ParticleTarget", 1, pt); if(psys->child) writestruct(wd, DATA, "ChildParticle", psys->totchild ,psys->child); - writestruct(wd, DATA, "SoftBody", 1, psys->soft); - if(psys->soft) write_pointcaches(wd, &psys->soft->ptcaches); + + if(psys->clmd) { + writestruct(wd, DATA, "ClothModifierData", 1, psys->clmd); + writestruct(wd, DATA, "ClothSimSettings", 1, psys->clmd->sim_parms); + writestruct(wd, DATA, "ClothCollSettings", 1, psys->clmd->coll_parms); + } + write_pointcaches(wd, &psys->ptcaches); } } diff --git a/source/blender/editors/physics/editparticle.c b/source/blender/editors/physics/editparticle.c index 0f5e677b912..5acdcb40613 100644 --- a/source/blender/editors/physics/editparticle.c +++ b/source/blender/editors/physics/editparticle.c @@ -120,6 +120,20 @@ static int PE_poll(bContext *C) return (edit && (ob->mode & OB_MODE_PARTICLE_EDIT)); } +static int PE_hair_poll(bContext *C) +{ + Scene *scene= CTX_data_scene(C); + Object *ob= CTX_data_active_object(C); + PTCacheEdit *edit; + + if(!scene || !ob) + return 0; + + edit= PE_get_current(scene, ob); + + return (edit && edit->psys && (ob->mode & OB_MODE_PARTICLE_EDIT)); +} + static int PE_poll_3dview(bContext *C) { return PE_poll(C) && CTX_wm_area(C)->spacetype == SPACE_VIEW3D && @@ -169,6 +183,8 @@ int PE_start_edit(PTCacheEdit *edit) { if(edit) { edit->edited = 1; + if(edit->psys) + edit->psys->flag |= PSYS_EDITED; return 1; } @@ -218,9 +234,16 @@ PTCacheEdit *PE_get_current(Scene *scene, Object *ob) if(psys->flag & PSYS_CURRENT) { if(psys->part && psys->part->type == PART_HAIR) { - if(!psys->edit && psys->flag & PSYS_HAIR_DONE) - PE_create_particle_edit(scene, ob, NULL, psys); - edit = psys->edit; + if(psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) { + if(!psys->pointcache->edit) + PE_create_particle_edit(scene, ob, pid->cache, NULL); + edit = pid->cache->edit; + } + else { + if(!psys->edit && psys->flag & PSYS_HAIR_DONE) + PE_create_particle_edit(scene, ob, NULL, psys); + edit = psys->edit; + } } else { if(pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) @@ -2387,7 +2410,7 @@ void PARTICLE_OT_delete(wmOperatorType *ot) /* api callbacks */ ot->exec= delete_exec; ot->invoke= WM_menu_invoke; - ot->poll= PE_poll; + ot->poll= PE_hair_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; @@ -3858,6 +3881,7 @@ static int clear_edited_exec(bContext *C, wmOperator *op) psys->recalc |= PSYS_RECALC_RESET; psys->flag &= ~PSYS_GLOBAL_HAIR; + psys->flag &= ~PSYS_EDITED; psys_reset(psys, PSYS_RESET_DEPSGRAPH); DAG_id_flush_update(&ob->id, OB_RECALC_DATA); @@ -3894,15 +3918,13 @@ static int specials_menu_invoke(bContext *C, wmOperator *op, wmEvent *event) pup= uiPupMenuBegin(C, "Specials", 0); layout= uiPupMenuLayout(pup); - if(edit->psys) { - uiItemO(layout, NULL, 0, "PARTICLE_OT_rekey"); - if(pset->selectmode & SCE_SELECT_POINT) { - uiItemO(layout, NULL, 0, "PARTICLE_OT_subdivide"); - uiItemO(layout, NULL, 0, "PARTICLE_OT_select_first"); - uiItemO(layout, NULL, 0, "PARTICLE_OT_select_last"); - } - uiItemO(layout, NULL, 0, "PARTICLE_OT_remove_doubles"); + uiItemO(layout, NULL, 0, "PARTICLE_OT_rekey"); + if(pset->selectmode & SCE_SELECT_POINT) { + uiItemO(layout, NULL, 0, "PARTICLE_OT_subdivide"); + uiItemO(layout, NULL, 0, "PARTICLE_OT_select_first"); + uiItemO(layout, NULL, 0, "PARTICLE_OT_select_last"); } + uiItemO(layout, NULL, 0, "PARTICLE_OT_remove_doubles"); uiPupMenuEnd(C, pup); @@ -3917,7 +3939,7 @@ void PARTICLE_OT_specials_menu(wmOperatorType *ot) /* api callbacks */ ot->invoke= specials_menu_invoke; - ot->poll= PE_poll; + ot->poll= PE_hair_poll; } /**************************** registration **********************************/ diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index 0df6f6250ff..bc9b05dc12e 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -54,6 +54,7 @@ #include "BKE_library.h" #include "BKE_main.h" #include "BKE_material.h" +#include "BKE_modifier.h" #include "BKE_node.h" #include "BKE_particle.h" #include "BKE_pointcache.h" @@ -728,6 +729,7 @@ static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys) PTCacheEdit *edit = psys->edit; PTCacheEditPoint *point = edit ? edit->points : NULL; PTCacheEditKey *ekey = NULL; + DerivedMesh *dm = NULL; HairKey *key; int i, k; float hairmat[4][4]; @@ -738,13 +740,18 @@ static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys) if(!psys->part || psys->part->type != PART_HAIR) return; + if(psmd->dm->deformedOnly) + dm= psmd->dm; + else + dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); + for(i=0; itotpart; i++,pa++) { if(point) { ekey = point->keys; point++; } - psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); + psys_mat_hair_to_global(ob, dm, psys->part->from, pa, hairmat); for(k=0,key=pa->hair; ktotkey; k++,key++) { Mat4MulVecfl(hairmat,key->co); @@ -758,6 +765,9 @@ static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys) psys_free_path_cache(psys, psys->edit); + if(!psmd->dm->deformedOnly) + dm->release(dm); + psys->flag |= PSYS_GLOBAL_HAIR; PE_update_object(scene, ob, 0); @@ -814,8 +824,8 @@ static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) BVHTreeFromMesh bvhtree; BVHTreeNearest nearest; MFace *mface; - DerivedMesh *dm = CDDM_copy(psmd->dm); - int numverts = dm->getNumVerts (dm); + DerivedMesh *dm = NULL; + int numverts; int i, k; float hairmat[4][4], imat[4][4]; float v[4][3], vec[3]; @@ -823,6 +833,13 @@ static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) if(!psys || !psys->part || psys->part->type != PART_HAIR) return; + if(psmd->dm->deformedOnly) + dm= psmd->dm; + else + dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); + + numverts = dm->getNumVerts (dm); + memset( &bvhtree, 0, sizeof(bvhtree) ); /* convert to global coordinates */ @@ -881,7 +898,8 @@ static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) } free_bvhtree_from_mesh(&bvhtree); - dm->release(dm); + if(!psmd->dm->deformedOnly) + dm->release(dm); psys_free_path_cache(psys, psys->edit); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 7ed029f3eaf..aa9c28dbef2 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -3727,6 +3727,12 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obj float nosel_col[3]; float *pathcol = NULL, *pcol; + + if(edit->psys && edit->psys->flag & PSYS_HAIR_UPDATED) { + PE_update_object(scene, ob, 0); + edit->psys->flag &= ~PSYS_HAIR_UPDATED; + } + /* create path and child path cache if it doesn't exist already */ if(edit->pathcache==0) psys_cache_edit_paths(scene, ob, edit, CFRA); diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h index 33984582d7f..5cfecf7cc01 100644 --- a/source/blender/makesdna/DNA_cloth_types.h +++ b/source/blender/makesdna/DNA_cloth_types.h @@ -68,6 +68,7 @@ typedef struct ClothSimSettings float defgoal; float goalspring; float goalfrict; + float velocity_smooth; /* smoothing of velocities for hair */ int stepsPerFrame; /* Number of time steps per frame. */ int flags; /* flags, see CSIMSETT_FLAGS enum above. */ int preroll; /* How many frames of simulation to do before we start. */ @@ -78,7 +79,6 @@ typedef struct ClothSimSettings short vgroup_struct; /* vertex group for scaling structural stiffness */ short presets; /* used for presets on GUI */ short pad; - int pad2; } ClothSimSettings; diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h index 5696f82ab0d..986a75f1a96 100644 --- a/source/blender/makesdna/DNA_object_force.h +++ b/source/blender/makesdna/DNA_object_force.h @@ -184,8 +184,6 @@ typedef struct BulletSoftBody { typedef struct SoftBody { - struct ParticleSystem *particles; /* particlesystem softbody */ - /* dynamic data */ int totpoint, totspring; struct BodyPoint *bpoint; /* not saved in file */ diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index d4dc3df0965..6a0a0e1d912 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -105,7 +105,7 @@ typedef struct ParticleData { short flag; short alive; /* the life state of a particle */ short loop; /* how many times particle life has looped */ - short rt; + short hair_index; } ParticleData; typedef struct ParticleSettings { @@ -202,7 +202,8 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in struct ParticleCacheKey **childcache; /* child cache (runtime) */ ListBase pathcachebufs, childcachebufs; /* buffers for the above */ - struct SoftBody *soft; /* hair softbody */ + struct ClothModifierData *clmd; /* cloth simulation for hair */ + struct DerivedMesh *hair_in_dm, *hair_out_dm; /* input/output for cloth simulation */ struct Object *target_ob; struct Object *lattice; @@ -216,9 +217,9 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in float imat[4][4]; /* used for duplicators */ float cfra, tree_frame; - int seed; + int seed, rt; int flag, totpart, totchild, totcached, totchildcache; - short recalc, target_psys, totkeyed, softflag, bakespace, rt2; + short recalc, target_psys, totkeyed, bakespace; char bb_uvname[3][32]; /* billboard uv name */ @@ -411,16 +412,16 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in /* psys->flag */ #define PSYS_CURRENT 1 #define PSYS_GLOBAL_HAIR 2 -//#define PSYS_BAKE_UI 4 +#define PSYS_HAIR_DYNAMICS 4 #define PSYS_KEYED_TIMING 8 #define PSYS_ENABLED 16 /* deprecated */ -//#define PSYS_FIRST_KEYED 32 +#define PSYS_HAIR_UPDATED 32 /* signal for updating hair particle mode */ #define PSYS_DRAWING 64 //#define PSYS_SOFT_BAKE 128 #define PSYS_DELETE 256 /* remove particlesystem as soon as possible */ #define PSYS_HAIR_DONE 512 #define PSYS_KEYED 1024 -//#define PSYS_EDITED 2048 +#define PSYS_EDITED 2048 //#define PSYS_PROTECT_CACHE 4096 #define PSYS_DISABLED 8192 diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c index 38086502d6f..22cc2e2c9c3 100644 --- a/source/blender/makesrna/intern/rna_cloth.c +++ b/source/blender/makesrna/intern/rna_cloth.c @@ -152,7 +152,7 @@ static char *rna_ClothSettings_path(PointerRNA *ptr) Object *ob= (Object*)ptr->id.data; ModifierData *md= modifiers_findByType(ob, eModifierType_Cloth); - return BLI_sprintfN("modifiers[%s].settings", md->name); + return md ? BLI_sprintfN("modifiers[%s].settings", md->name) : NULL; } static char *rna_ClothCollisionSettings_path(PointerRNA *ptr) @@ -160,7 +160,7 @@ static char *rna_ClothCollisionSettings_path(PointerRNA *ptr) Object *ob= (Object*)ptr->id.data; ModifierData *md= modifiers_findByType(ob, eModifierType_Cloth); - return BLI_sprintfN("modifiers[%s].collision_settings", md->name); + return md ? BLI_sprintfN("modifiers[%s].collision_settings", md->name) : NULL; } #else @@ -207,6 +207,12 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Goal Damping", "Goal (vertex target position) friction."); RNA_def_property_update(prop, 0, "rna_cloth_update"); + prop= RNA_def_property(srna, "internal_friction", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "velocity_smooth"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Internal Friction", ""); + RNA_def_property_update(prop, 0, "rna_cloth_update"); + /* mass */ prop= RNA_def_property(srna, "mass", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 719e6f43eed..e6f0a462f03 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -33,6 +33,7 @@ #include "rna_internal.h" +#include "DNA_modifier_types.h" #include "DNA_particle_types.h" #include "DNA_object_force.h" #include "DNA_object_types.h" @@ -96,7 +97,9 @@ EnumPropertyItem part_hair_ren_as_items[] = { #ifdef RNA_RUNTIME #include "BKE_context.h" +#include "BKE_cloth.h" #include "BKE_depsgraph.h" +#include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_pointcache.h" @@ -249,6 +252,21 @@ static void rna_Particle_redo_child(bContext *C, PointerRNA *ptr) WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, NULL); } +static void rna_Particle_hair_dynamics(bContext *C, PointerRNA *ptr) +{ + Scene *scene = CTX_data_scene(C); + ParticleSystem *psys = (ParticleSystem*)ptr->data; + + if(psys && !psys->clmd) { + psys->clmd = (ClothModifierData*)modifier_new(eModifierType_Cloth); + psys->clmd->sim_parms->goalspring = 0.0f; + psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_GOAL|CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS; + psys->clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF; + rna_Particle_redo(C, ptr); + } + else + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, NULL); +} static PointerRNA rna_particle_settings_get(PointerRNA *ptr) { Object *ob= (Object*)ptr->id.data; @@ -467,7 +485,7 @@ static int rna_ParticleSystem_edited_get(PointerRNA *ptr) ParticleSystem *psys= (ParticleSystem*)ptr->data; if(psys->part && psys->part->type==PART_HAIR) - return (psys->edit && psys->edit->edited); + return (psys->flag & PSYS_EDITED || (psys->edit && psys->edit->edited)); else return (psys->pointcache->edit && psys->pointcache->edit->edited); } @@ -1876,19 +1894,22 @@ static void rna_def_particle_system(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Particle_reset"); /* hair */ - prop= RNA_def_property(srna, "softbody", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "soft"); - RNA_def_property_ui_text(prop, "Soft Body", "Soft body settings for hair physics simulation."); - - prop= RNA_def_property(srna, "use_softbody", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "softflag", OB_SB_ENABLE); - RNA_def_property_ui_text(prop, "Use Soft Body", "Enable use of soft body for hair physics simulation."); - prop= RNA_def_property(srna, "global_hair", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_GLOBAL_HAIR); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Global Hair", "Hair keys are in global coordinate space"); + prop= RNA_def_property(srna, "hair_dynamics", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_HAIR_DYNAMICS); + RNA_def_property_ui_text(prop, "Hair Dynamics", "Enable hair dynamics using cloth simulation."); + RNA_def_property_update(prop, 0, "rna_Particle_hair_dynamics"); + + prop= RNA_def_property(srna, "cloth", PROP_POINTER, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "clmd"); + RNA_def_property_struct_type(prop, "ClothModifier"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Cloth", "Cloth dynamics for hair"); + /* reactor */ prop= RNA_def_property(srna, "reactor_target_object", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "target_ob"); -- cgit v1.2.3