Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/ui/properties_particle.py33
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h17
-rw-r--r--source/blender/blenkernel/intern/particle.c3
-rw-r--r--source/blender/blenkernel/intern/particle_system.c178
-rw-r--r--source/blender/blenkernel/intern/pointcache.c70
-rw-r--r--source/blender/blenloader/intern/readfile.c7
-rw-r--r--source/blender/blenloader/intern/writefile.c12
-rw-r--r--source/blender/makesdna/DNA_object_force.h5
-rw-r--r--source/blender/makesdna/DNA_particle_types.h15
-rw-r--r--source/blender/makesrna/intern/rna_particle.c63
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");
}