diff options
-rw-r--r-- | release/scripts/ui/properties_particle.py | 33 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_pointcache.h | 17 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/particle.c | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/particle_system.c | 178 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pointcache.c | 70 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 7 | ||||
-rw-r--r-- | source/blender/blenloader/intern/writefile.c | 12 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_object_force.h | 5 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_particle_types.h | 15 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_particle.c | 63 |
10 files changed, 340 insertions, 63 deletions
diff --git a/release/scripts/ui/properties_particle.py b/release/scripts/ui/properties_particle.py index 2c5cfeaca63..cc4b974e6b6 100644 --- a/release/scripts/ui/properties_particle.py +++ b/release/scripts/ui/properties_particle.py @@ -445,24 +445,32 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, bpy.types.Panel): split = layout.split() sub = split.column() sub.label(text="Fluid Interaction:") - sub.prop(fluid, "fluid_radius", slider=True) - sub.prop(fluid, "stiffness") - sub.prop(fluid, "stiffness_near") - sub.prop(fluid, "rest_density") + sub.prop(fluid, "fluid_radius") + sub.prop(fluid, "repulsion_force") + subsub = sub.column(align=True) + subsub.prop(fluid, "rest_density") + subsub.prop(fluid, "density_force", text="Force") sub.label(text="Viscosity:") - sub.prop(fluid, "viscosity_omega", text="Linear") - sub.prop(fluid, "viscosity_beta", text="Square") + subsub = sub.column(align=True) + subsub.prop(fluid, "linear_viscosity", text="Linear") + subsub.prop(fluid, "square_viscosity", text="Square") sub = split.column() sub.label(text="Springs:") - sub.prop(fluid, "spring_force", text="Force", slider=True) - sub.prop(fluid, "rest_length", slider=True) - layout.label(text="Multiple fluids interactions:") + sub.prop(fluid, "spring_force", text="Force") + #Hidden to make ui a bit lighter, can be unhidden for a bit more control + #sub.prop(fluid, "rest_length", slider=True) + sub.prop(fluid, "use_viscoelastic_springs") + subsub = sub.column(align=True) + subsub.active = fluid.use_viscoelastic_springs + subsub.prop(fluid, "yield_ratio", slider=True) + subsub.prop(fluid, "plasticity", slider=True) + subsub.prop(fluid, "use_initial_rest_length") sub.label(text="Buoyancy:") - sub.prop(fluid, "buoyancy", slider=True) + sub.prop(fluid, "buoyancy", text="Strength", slider=True) elif part.physics_type == 'KEYED': split = layout.split() @@ -526,6 +534,8 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, bpy.types.Panel): if part.physics_type == 'KEYED' or part.physics_type == 'BOIDS' or part.physics_type == 'FLUID': if part.physics_type == 'BOIDS': layout.label(text="Relations:") + elif part.physics_type == 'FLUID': + layout.label(text="Fluid interaction:") row = layout.row() row.template_list(psys, "targets", psys, "active_particle_target_index") @@ -886,6 +896,9 @@ class PARTICLE_PT_draw(ParticleButtonsPanel, bpy.types.Panel): col.prop(part, "show_number") if part.physics_type == 'BOIDS': col.prop(part, "show_health") + + + col = row.column() col.prop(part, "show_material_color", text="Use material color") diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index 68c4177fe3a..a4ce46409a1 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -32,6 +32,7 @@ #include "DNA_ID.h" #include "DNA_object_force.h" #include "DNA_boid_types.h" +#include "DNA_particle_types.h" #include <stdio.h> /* for FILE */ /* Point cache clearing option, for BKE_ptcache_id_clear, before @@ -110,6 +111,16 @@ static char *ptcache_datastruct[] = { "BoidData" // case BPHYS_DATA_BOIDS: }; +static char *ptcache_extra_datastruct[] = { + "", + "ParticleSpring" +}; + +static int ptcache_extra_datasize[] = { + 0, + sizeof(ParticleSpring) +}; + typedef struct PTCacheFile { FILE *fp; @@ -149,11 +160,11 @@ typedef struct PTCacheID { void (*read_stream)(PTCacheFile *pf, void *calldata); /* copies custom extradata to cache data */ - int (*write_extra_data)(void *calldata, struct PTCacheMem *pm, int cfra); + void (*write_extra_data)(void *calldata, struct PTCacheMem *pm, int cfra); /* copies custom extradata to cache data */ - int (*read_extra_data)(void *calldata, struct PTCacheMem *pm, float cfra); + void (*read_extra_data)(void *calldata, struct PTCacheMem *pm, float cfra); /* copies custom extradata to cache data */ - int (*interpolate_extra_data)(void *calldata, struct PTCacheMem *pm, float cfra, float cfra1, float cfra2); + void (*interpolate_extra_data)(void *calldata, struct PTCacheMem *pm, float cfra, float cfra1, float cfra2); /* total number of simulated points (the cfra parameter is just for using same function pointer with totwrite) */ int (*totpoint)(void *calldata, int cfra); diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 26f96d0c304..279190b9f9c 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -561,6 +561,9 @@ void psys_free(Object *ob, ParticleSystem * psys) BLI_freelistN(&psys->targets); BLI_kdtree_free(psys->tree); + + if(psys->fluid_springs) + MEM_freeN(psys->fluid_springs); pdEndEffectors(&psys->effectors); diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 3534a7dba37..fac79270bc1 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -54,6 +54,7 @@ #include "DNA_ipo_types.h" // XXX old animation system stuff... to be removed! #include "DNA_listBase.h" +#include "BLI_edgehash.h" #include "BLI_rand.h" #include "BLI_jitter.h" #include "BLI_math.h" @@ -182,6 +183,13 @@ void psys_reset(ParticleSystem *psys, int mode) /* reset point cache */ BKE_ptcache_invalidate(psys->pointcache); + + if(psys->fluid_springs) { + MEM_freeN(psys->fluid_springs); + psys->fluid_springs = NULL; + } + + psys->tot_fluidsprings = psys->alloc_fluidsprings = 0; } static void realloc_particles(ParticleSimulationData *sim, int new_totpart) @@ -2228,32 +2236,79 @@ static void psys_update_effectors(ParticleSimulationData *sim) Presented at Siggraph, (2005) ***********************************************************************************************************/ -static void particle_fluidsim(ParticleSystem *psys, int own_psys, ParticleData *pa, float dtime, float mass, float *gravity) +#define PSYS_FLUID_SPRINGS_INITIAL_SIZE 256 +ParticleSpring *add_fluid_spring(ParticleSystem *psys, ParticleSpring *spring) +{ + /* Are more refs required? */ + if(psys->alloc_fluidsprings == 0 || psys->fluid_springs == NULL) { + psys->alloc_fluidsprings = PSYS_FLUID_SPRINGS_INITIAL_SIZE; + psys->fluid_springs = (ParticleSpring*)MEM_callocN(psys->alloc_fluidsprings * sizeof(ParticleSpring), "Particle Fluid Springs"); + } + else if(psys->tot_fluidsprings == psys->alloc_fluidsprings) { + /* Double the number of refs allocated */ + psys->alloc_fluidsprings *= 2; + psys->fluid_springs = (ParticleSpring*)MEM_reallocN(psys->fluid_springs, psys->alloc_fluidsprings * sizeof(ParticleSpring)); + } + + memcpy(psys->fluid_springs + psys->tot_fluidsprings, spring, sizeof(ParticleSpring)); + psys->tot_fluidsprings++; + + return psys->fluid_springs + psys->tot_fluidsprings - 1; +} + +void delete_fluid_spring(ParticleSystem *psys, int j) +{ + if (j != psys->tot_fluidsprings - 1) + psys->fluid_springs[j] = psys->fluid_springs[psys->tot_fluidsprings - 1]; + + psys->tot_fluidsprings--; + + if (psys->tot_fluidsprings < psys->alloc_fluidsprings/2 && psys->alloc_fluidsprings > PSYS_FLUID_SPRINGS_INITIAL_SIZE){ + psys->alloc_fluidsprings /= 2; + psys->fluid_springs = (ParticleSpring*)MEM_reallocN(psys->fluid_springs, psys->alloc_fluidsprings * sizeof(ParticleSpring)); + } +} + +EdgeHash *build_fluid_springhash(ParticleSystem *psys) +{ + EdgeHash *springhash = NULL; + ParticleSpring *spring = psys->fluid_springs; + int i = 0; + + springhash = BLI_edgehash_new(); + + for(i=0, spring=psys->fluid_springs; i<psys->tot_fluidsprings; i++, spring++) + BLI_edgehash_insert(springhash, spring->particle_index[0], spring->particle_index[1], SET_INT_IN_POINTER(i+1)); + + return springhash; +} +static void particle_fluidsim(ParticleSystem *psys, int own_psys, ParticleData *pa, float dtime, float mass, float *gravity, EdgeHash *springhash) { SPHFluidSettings *fluid = psys->part->fluid; KDTreeNearest *ptn = NULL; ParticleData *npa; + ParticleSpring *spring = NULL; float temp[3]; - float q, q1, u, I, D; + float q, q1, u, I, D, rij, d, Lij; float pressure_near, pressure; float p=0, pnear=0; - float radius = fluid->radius; float omega = fluid->viscosity_omega; float beta = fluid->viscosity_beta; float massfactor = 1.0f/mass; float spring_k = fluid->spring_k; - float L = fluid->rest_length; + float h = fluid->radius; + float L = fluid->rest_length * fluid->radius; - int n, neighbours = BLI_kdtree_range_search(psys->tree, radius, pa->prev_state.co, NULL, &ptn); - int index = own_psys ? pa - psys->particles : -1; + int n, neighbours = BLI_kdtree_range_search(psys->tree, h, pa->prev_state.co, NULL, &ptn); + int spring_index = 0, index = own_psys ? pa - psys->particles : -1; /* pressure and near pressure */ for(n=own_psys?1:0; n<neighbours; n++) { sub_v3_v3(ptn[n].co, pa->prev_state.co); mul_v3_fl(ptn[n].co, 1.f/ptn[n].dist); - q = ptn[n].dist/radius; + q = ptn[n].dist/h; if(q < 1.f) { q1 = 1.f - q; @@ -2272,7 +2327,8 @@ static void particle_fluidsim(ParticleSystem *psys, int own_psys, ParticleData * for(n=own_psys?1:0; n<neighbours; n++) { npa = psys->particles + ptn[n].index; - q = ptn[n].dist/radius; + rij = ptn[n].dist; + q = rij/h; q1 = 1.f-q; /* Double Density Relaxation - Algorithm 2 (can't be thread safe!)*/ @@ -2296,14 +2352,40 @@ static void particle_fluidsim(ParticleSystem *psys, int own_psys, ParticleData * } } - /* Hooke's spring force */ if(spring_k > 0.f) { - /* L is a factor of radius */ - D = 0.5 * dtime * dtime * 10.f * fluid->spring_k * (1.f - L) * (L - q); + /* Viscoelastic spring force - Algorithm 4*/ + if (fluid->flag & SPH_VISCOELASTIC_SPRINGS && springhash){ + spring_index = GET_INT_FROM_POINTER(BLI_edgehash_lookup(springhash, index, ptn[n].index)); + + if(spring_index) { + spring = psys->fluid_springs + spring_index - 1; + } + else { + ParticleSpring temp_spring; + temp_spring.particle_index[0] = index; + temp_spring.particle_index[1] = ptn[n].index; + temp_spring.rest_length = (fluid->flag & SPH_CURRENT_REST_LENGTH) ? rij : L; + temp_spring.delete_flag = 0; + + spring = add_fluid_spring(psys, &temp_spring); + } + + Lij = spring->rest_length; + d = fluid->yield_ratio * Lij; - madd_v3_v3fl(pa->state.co, ptn[n].co, -D * massfactor); - if(own_psys) - madd_v3_v3fl(npa->state.co, ptn[n].co, D * massfactor); + if (rij > Lij + d) // Stretch, 25 is just a multiplier for plasticity_constant value to counter default dtime of 1/25 + spring->rest_length += dtime * 25.f * fluid->plasticity_constant * (rij - Lij - d); + else if(rij < Lij - d) // Compress + spring->rest_length -= dtime * 25.f * fluid->plasticity_constant * (Lij - d - rij); + } + else { /* PART_SPRING_HOOKES - Hooke's spring force */ + /* L is a factor of radius */ + D = 0.5 * dtime * dtime * 10.f * fluid->spring_k * (1.f - L/h) * (L - rij); + + madd_v3_v3fl(pa->state.co, ptn[n].co, -D * massfactor); + if(own_psys) + madd_v3_v3fl(npa->state.co, ptn[n].co, D * massfactor); + } } } } @@ -2318,21 +2400,63 @@ static void particle_fluidsim(ParticleSystem *psys, int own_psys, ParticleData * MEM_freeN(ptn); } -static void apply_particle_fluidsim(Object *ob, ParticleSystem *psys, ParticleData *pa, float dtime, float *gravity){ +static void apply_particle_fluidsim(Object *ob, ParticleSystem *psys, ParticleData *pa, float dtime, float *gravity, EdgeHash *springhash){ ParticleTarget *pt; - particle_fluidsim(psys, 1, pa, dtime, psys->part->mass, gravity); + particle_fluidsim(psys, 1, pa, dtime, psys->part->mass, gravity, springhash); /*----check other SPH systems (Multifluids) , each fluid has its own parameters---*/ for(pt=psys->targets.first; pt; pt=pt->next) { ParticleSystem *epsys = psys_get_target_system(ob, pt); if(epsys) - particle_fluidsim(epsys, 0, pa, dtime, psys->part->mass, gravity); + particle_fluidsim(epsys, 0, pa, dtime, psys->part->mass, gravity, NULL); } /*----------------------------------------------------------------*/ } +static void apply_fluid_springs(ParticleSystem *psys, ParticleSettings *part, float timestep){ + SPHFluidSettings *fluid = psys->part->fluid; + ParticleData *pa1, *pa2; + ParticleSpring *spring = psys->fluid_springs; + + float h = fluid->radius; + float massfactor = 1.0f/psys->part->mass; + float D, Rij[3], rij, Lij; + int i; + + if((fluid->flag & SPH_VISCOELASTIC_SPRINGS)==0 || fluid->spring_k == 0.f) + return; + + /* Loop through the springs */ + for(i=0; i<psys->tot_fluidsprings; i++, spring++) { + Lij = spring->rest_length; + + if (Lij > h) { + spring->delete_flag = 1; + } + else { + pa1 = psys->particles + spring->particle_index[0]; + pa2 = psys->particles + spring->particle_index[1]; + + sub_v3_v3v3(Rij, pa2->prev_state.co, pa1->prev_state.co); + rij = normalize_v3(Rij); + + /* Calculate displacement and apply value */ + D = 0.5f * timestep * timestep * 10.f * fluid->spring_k * (1.f - Lij/h) * (Lij - rij); + + madd_v3_v3fl(pa1->state.co, Rij, -D * pa1->state.time * pa1->state.time * massfactor); + madd_v3_v3fl(pa2->state.co, Rij, D * pa2->state.time * pa2->state.time * massfactor); + } + } + + /* Loop through springs backwaqrds - for efficient delete function */ + for (i=psys->tot_fluidsprings-1; i >= 0; i--) { + if(psys->fluid_springs[i].delete_flag) + delete_fluid_spring(psys, i); + } +} + /************************************************/ /* Newtonian physics */ /************************************************/ @@ -3420,6 +3544,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) } case PART_PHYS_FLUID: { + EdgeHash *springhash = build_fluid_springhash(psys); float *gravity = NULL; if(psys_uses_gravity(sim)) @@ -3434,9 +3559,12 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) /* actual fluids calculations (not threadsafe!) */ LOOP_DYNAMIC_PARTICLES { - apply_particle_fluidsim(sim->ob, psys, pa, pa->state.time*timestep, gravity); + apply_particle_fluidsim(sim->ob, psys, pa, pa->state.time*timestep, gravity, springhash); } + /* Apply springs to particles */ + apply_fluid_springs(psys, part, timestep); + /* apply velocity, collisions and rotation */ LOOP_DYNAMIC_PARTICLES { /* velocity holds forces and viscosity, so apply them before collisions */ @@ -3452,6 +3580,11 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) /* SPH particles are not physical particles, just interpolation particles, thus rotation has not a direct sense for them */ rotate_particle(part, pa, pa->state.time, timestep); } + + if(springhash) { + BLI_edgehash_free(springhash, NULL); + springhash = NULL; + } break; } } @@ -3696,6 +3829,13 @@ static void system_step(ParticleSimulationData *sim, float cfra) /* reset only just created particles (on startframe all particles are recreated) */ reset_all_particles(sim, 0.0, cfra, oldtotpart); + if (psys->fluid_springs) { + MEM_freeN(psys->fluid_springs); + psys->fluid_springs = NULL; + } + + psys->tot_fluidsprings = psys->alloc_fluidsprings = 0; + /* flag for possible explode modifiers after this system */ sim->psmd->flag |= eParticleSystemFlag_Pars; @@ -3851,6 +3991,8 @@ static void fluid_default_settings(ParticleSettings *part){ fluid->radius = 0.5f; fluid->spring_k = 0.f; + fluid->plasticity_constant = 0.1f; + fluid->yield_ratio = 0.1f; fluid->rest_length = 0.5f; fluid->viscosity_omega = 2.f; fluid->viscosity_beta = 0.f; diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index eb0601b413e..5408e57f10d 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -390,6 +390,48 @@ static int ptcache_particle_totwrite(void *psys_v, int cfra) return totwrite; } +static void ptcache_particle_extra_write(void *psys_v, PTCacheMem *pm, int UNUSED(cfra)) +{ + ParticleSystem *psys = psys_v; + PTCacheExtra *extra = NULL; + + if(psys->part->phystype == PART_PHYS_FLUID && + psys->part->fluid && psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS && + psys->tot_fluidsprings && psys->fluid_springs) { + + extra = MEM_callocN(sizeof(PTCacheExtra), "Point cache: fluid extra data"); + + extra->type = BPHYS_EXTRA_FLUID_SPRINGS; + extra->totdata = psys->tot_fluidsprings; + + extra->data = MEM_callocN(extra->totdata * ptcache_extra_datasize[extra->type], "Point cache: extra data"); + memcpy(extra->data, psys->fluid_springs, extra->totdata * ptcache_extra_datasize[extra->type]); + + BLI_addtail(&pm->extradata, extra); + } +} + +static int ptcache_particle_extra_read(void *psys_v, PTCacheMem *pm, float UNUSED(cfra)) +{ + ParticleSystem *psys = psys_v; + PTCacheExtra *extra = pm->extradata.first; + + for(; extra; extra=extra->next) { + switch(extra->type) { + case BPHYS_EXTRA_FLUID_SPRINGS: + { + if(psys->fluid_springs) + MEM_freeN(psys->fluid_springs); + + psys->fluid_springs = MEM_dupallocN(extra->data); + psys->tot_fluidsprings = psys->alloc_fluidsprings = extra->totdata; + break; + } + } + } + return 1; +} + /* Cloth functions */ static int ptcache_cloth_write(int index, void *cloth_v, void **data, int UNUSED(cfra)) { @@ -667,6 +709,10 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p if(psys->part->phystype == PART_PHYS_BOIDS) pid->data_types|= (1<<BPHYS_DATA_AVELOCITY) | (1<<BPHYS_DATA_ROTATION) | (1<<BPHYS_DATA_BOIDS); + else if(psys->part->phystype == PART_PHYS_FLUID && psys->part->fluid && psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS) { + pid->write_extra_data = ptcache_particle_extra_write; + pid->read_extra_data = ptcache_particle_extra_read; + } if(psys->part->rotmode!=PART_ROT_VEL || psys->part->avemode!=PART_AVE_SPIN || psys->part->avefac!=0.0f) @@ -1261,9 +1307,13 @@ static void ptcache_extra_free(PTCacheMem *pm) { PTCacheExtra *extra = pm->extradata.first; - for(; extra; extra=extra->next) { - if(extra->data) - MEM_freeN(extra->data); + if(extra) { + for(; extra; extra=extra->next) { + if(extra->data) + MEM_freeN(extra->data); + } + + BLI_freelistN(&pm->extradata); } } static int ptcache_old_elemsize(PTCacheID *pid) @@ -1383,16 +1433,14 @@ static PTCacheMem *ptcache_disk_frame_to_mem(PTCacheID *pid, int cfra) extra->type = extratype; - ptcache_file_read(pf, &extra->flag, 1, sizeof(unsigned int)); ptcache_file_read(pf, &extra->totdata, 1, sizeof(unsigned int)); - ptcache_file_read(pf, &extra->datasize, 1, sizeof(unsigned int)); - extra->data = MEM_callocN(extra->totdata * extra->datasize, "Pointcache extradata->data"); + extra->data = MEM_callocN(extra->totdata * ptcache_extra_datasize[extra->type], "Pointcache extradata->data"); if(pf->flag & PTCACHE_TYPEFLAG_COMPRESS) - ptcache_file_compressed_read(pf, (unsigned char*)(extra->data), extra->totdata*extra->datasize); + ptcache_file_compressed_read(pf, (unsigned char*)(extra->data), extra->totdata*ptcache_extra_datasize[extra->type]); else - ptcache_file_read(pf, extra->data, extra->totdata, extra->datasize); + ptcache_file_read(pf, extra->data, extra->totdata, ptcache_extra_datasize[extra->type]); BLI_addtail(&pm->extradata, extra); } @@ -1475,18 +1523,16 @@ static int ptcache_mem_frame_to_disk(PTCacheID *pid, PTCacheMem *pm) continue; ptcache_file_write(pf, &extra->type, 1, sizeof(unsigned int)); - ptcache_file_write(pf, &extra->flag, 1, sizeof(unsigned int)); ptcache_file_write(pf, &extra->totdata, 1, sizeof(unsigned int)); - ptcache_file_write(pf, &extra->datasize, 1, sizeof(unsigned int)); if(pid->cache->compression) { - unsigned int in_len = extra->totdata * extra->datasize; + unsigned int in_len = extra->totdata * ptcache_extra_datasize[extra->type]; unsigned char *out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len)*4, "pointcache_lzo_buffer"); ptcache_file_compressed_write(pf, (unsigned char*)(extra->data), in_len, out, pid->cache->compression); MEM_freeN(out); } else { - ptcache_file_write(pf, extra->data, extra->totdata, extra->datasize); + ptcache_file_write(pf, extra->data, extra->totdata, ptcache_extra_datasize[extra->type]); } } } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index cc2b73d87f5..a86363cf7ad 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2929,6 +2929,7 @@ static void direct_link_pointcache(FileData *fd, PointCache *cache) { if((cache->flag & PTCACHE_DISK_CACHE)==0) { PTCacheMem *pm; + PTCacheExtra *extra; int i; link_list(fd, &cache->mem_cache); @@ -2948,6 +2949,11 @@ static void direct_link_pointcache(FileData *fd, PointCache *cache) SWITCH_INT(poin[j]); } } + + link_list(fd, &pm->extradata); + + for(extra=pm->extradata.first; extra; extra=extra->next) + extra->data = newdataadr(fd, extra->data); } } else @@ -3156,6 +3162,7 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles) pa->boid = NULL; } + psys->fluid_springs = newdataadr(fd, psys->fluid_springs); psys->child = newdataadr(fd,psys->child); psys->effectors = NULL; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 8230050fc2f..fd8fb8ad8a6 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -780,6 +780,8 @@ static void write_pointcaches(WriteData *wd, ListBase *ptcaches) PTCacheMem *pm = cache->mem_cache.first; for(; pm; pm=pm->next) { + PTCacheExtra *extra = pm->extradata.first; + writestruct(wd, DATA, "PTCacheMem", 1, pm); for(i=0; i<BPHYS_TOT_DATA; i++) { @@ -790,6 +792,13 @@ static void write_pointcaches(WriteData *wd, ListBase *ptcaches) writestruct(wd, DATA, ptcache_datastruct[i], pm->totpoint, pm->data[i]); } } + + for(; extra; extra=extra->next) { + if(strcmp(ptcache_extra_datastruct[extra->type], "")==0) + continue; + writestruct(wd, DATA, "PTCacheExtra", 1, extra); + writestruct(wd, DATA, ptcache_extra_datastruct[extra->type], extra->totdata, extra->data); + } } } } @@ -850,6 +859,9 @@ static void write_particlesystems(WriteData *wd, ListBase *particles) if(psys->particles->boid && psys->part->phystype == PART_PHYS_BOIDS) writestruct(wd, DATA, "BoidParticle", psys->totpart, psys->particles->boid); + + if(psys->part->fluid && psys->part->phystype == PART_PHYS_FLUID && (psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS)) + writestruct(wd, DATA, "ParticleSpring", psys->tot_fluidsprings, psys->fluid_springs); } pt = psys->targets.first; for(; pt; pt=pt->next) diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h index a6898279a1d..89d31586f6b 100644 --- a/source/blender/makesdna/DNA_object_force.h +++ b/source/blender/makesdna/DNA_object_force.h @@ -141,10 +141,11 @@ typedef struct EffectorWeights { #define BPHYS_TOT_DATA 8 +#define BPHYS_EXTRA_FLUID_SPRINGS 1 + typedef struct PTCacheExtra { struct PTCacheExtra *next, *prev; - unsigned int type, flag; - unsigned int totdata, datasize; + unsigned int type, totdata; void *data; } PTCacheExtra; diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index cbc9e0f1c29..f140d60d3e9 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -61,6 +61,11 @@ typedef struct BoidParticle { float rt; } BoidParticle; +typedef struct ParticleSpring { + float rest_length; + unsigned int particle_index[2], delete_flag; +}ParticleSpring; + /* Child particles are created around or between parent particles */ typedef struct ChildParticle { int num, parent; /* num is face index on the final derived mesh */ @@ -116,12 +121,17 @@ typedef struct ParticleData { typedef struct SPHFluidSettings { /*Particle Fluid*/ - float spring_k, radius, rest_length; + float spring_k, radius, rest_length, plasticity_constant, yield_ratio; float viscosity_omega, viscosity_beta; float stiffness_k, stiffness_knear, rest_density; float buoyancy; + int flag, pad; } SPHFluidSettings; +/* fluid->flag */ +#define SPH_VISCOELASTIC_SPRINGS 1 +#define SPH_CURRENT_REST_LENGTH 2 + typedef struct ParticleSettings { ID id; struct AnimData *adt; @@ -254,6 +264,9 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in struct ListBase *effectors; + ParticleSpring *fluid_springs; + int tot_fluidsprings, alloc_fluidsprings; + struct KDTree *tree; /* used for interactions with self and other systems */ struct ParticleDrawData *pdd; diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index cb17893ce0d..aa5f69e7164 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -989,59 +989,88 @@ static void rna_def_fluid_settings(BlenderRNA *brna) /* Fluid settings */ prop= RNA_def_property(srna, "spring_force", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "spring_k"); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Spring", "Spring force constant"); + RNA_def_property_range(prop, 0.0f, 100.0f); + RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3); + RNA_def_property_ui_text(prop, "Spring Force", "Spring force"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop= RNA_def_property(srna, "fluid_radius", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "radius"); - RNA_def_property_range(prop, 0.0f, 2.0f); - RNA_def_property_ui_text(prop, "Radius", "Fluid interaction Radius"); + RNA_def_property_range(prop, 0.0f, 20.0f); + RNA_def_property_ui_range(prop, 0.0f, 2.0f, 1, 3); + RNA_def_property_ui_text(prop, "Interaction Radius", "Fluid interaction radius"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); + /* Hidden in ui to give a little easier user experience. */ prop= RNA_def_property(srna, "rest_length", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "rest_length"); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Rest Length", "The Spring Rest Length (factor of interaction radius)"); - RNA_def_property_update(prop, 0, "rna_Particle_reset"); + RNA_def_property_ui_text(prop, "Rest Length", "Spring rest length (factor of interaction radius)"); + RNA_def_property_update(prop, 0, "rna_Particle_reset"); + + prop= RNA_def_property(srna, "use_viscoelastic_springs", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SPH_VISCOELASTIC_SPRINGS); + RNA_def_property_ui_text(prop, "Viscoelastic Springs", "Use viscoelastic springs instead of Hooke's springs"); + RNA_def_property_update(prop, 0, "rna_Particle_reset"); + + prop= RNA_def_property(srna, "use_initial_rest_length", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SPH_CURRENT_REST_LENGTH); + RNA_def_property_ui_text(prop, "Initial Rest Length", "Use the initial length as spring rest length instead of interaction radius/2"); + RNA_def_property_update(prop, 0, "rna_Particle_reset"); + + prop= RNA_def_property(srna, "plasticity", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "plasticity_constant"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Plasticity", "How much the spring rest length can change after the elastic limit is crossed"); + RNA_def_property_update(prop, 0, "rna_Particle_reset"); + + prop= RNA_def_property(srna, "yield_ratio", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "yield_ratio"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Elastic Limit", "How much the spring has to be stretched/compressed in order to change it's rest length"); + RNA_def_property_update(prop, 0, "rna_Particle_reset"); /* Viscosity */ - prop= RNA_def_property(srna, "viscosity_omega", PROP_FLOAT, PROP_NONE); + prop= RNA_def_property(srna, "linear_viscosity", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "viscosity_omega"); RNA_def_property_range(prop, 0.0f, 100.0f); + RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3); RNA_def_property_ui_text(prop, "Viscosity", "Linear viscosity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); - prop= RNA_def_property(srna, "viscosity_beta", PROP_FLOAT, PROP_NONE); + prop= RNA_def_property(srna, "square_viscosity", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "viscosity_beta"); RNA_def_property_range(prop, 0.0f, 100.0f); - RNA_def_property_ui_text(prop, "Square viscosity", "Square viscosity factor"); + RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3); + RNA_def_property_ui_text(prop, "Square viscosity", "Square viscosity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); /* Double density relaxation */ - prop= RNA_def_property(srna, "stiffness", PROP_FLOAT, PROP_NONE); + prop= RNA_def_property(srna, "density_force", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "stiffness_k"); RNA_def_property_range(prop, 0.0f, 100.0f); - RNA_def_property_ui_text(prop, "Stiffness ", "Constant K - Stiffness"); + RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3); + RNA_def_property_ui_text(prop, "Density Force", "How strongly the fluid tends to rest density"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); - prop= RNA_def_property(srna, "stiffness_near", PROP_FLOAT, PROP_NONE); + prop= RNA_def_property(srna, "repulsion_force", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "stiffness_knear"); RNA_def_property_range(prop, 0.0f, 100.0f); - RNA_def_property_ui_text(prop, "Repulsion", "Repulsion factor: stiffness_knear"); + RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3); + RNA_def_property_ui_text(prop, "Repulsion", "How strongly the fluid tries to keep from clustering"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop= RNA_def_property(srna, "rest_density", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "rest_density"); - RNA_def_property_range(prop, 0.0f, 100.0f); - RNA_def_property_ui_text(prop, "Rest Density", "Density"); + RNA_def_property_range(prop, 0.0f, 1000.0f); + RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); + RNA_def_property_ui_text(prop, "Rest Density", "Rest density of the fluid"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); /* Buoyancy */ prop= RNA_def_property(srna, "buoyancy", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "buoyancy"); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Buoyancy", ""); + RNA_def_property_ui_text(prop, "Buoyancy", "Artificial buoyancy force in negative gravity direction based on pressure differences inside the fluid"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); } |