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:
Diffstat (limited to 'source/blender/blenkernel/intern/particle_system.c')
-rw-r--r--source/blender/blenkernel/intern/particle_system.c1036
1 files changed, 598 insertions, 438 deletions
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 47a220dcefb..2e2decdf84d 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"
@@ -62,7 +63,10 @@
#include "BLI_kdopbvh.h"
#include "BLI_listbase.h"
#include "BLI_threads.h"
+#include "BLI_storage.h" /* For _LARGEFILE64_SOURCE; zlib needs this on some systems */
+#include "BLI_utildefines.h"
+#include "BKE_main.h"
#include "BKE_animsys.h"
#include "BKE_boids.h"
#include "BKE_cdderivedmesh.h"
@@ -71,7 +75,7 @@
#include "BKE_effect.h"
#include "BKE_particle.h"
#include "BKE_global.h"
-#include "BKE_utildefines.h"
+
#include "BKE_DerivedMesh.h"
#include "BKE_object.h"
#include "BKE_material.h"
@@ -128,15 +132,28 @@ int psys_get_current_display_percentage(ParticleSystem *psys)
return psys->part->disp;
}
+static int tot_particles(ParticleSystem *psys, PTCacheID *pid)
+{
+ if(pid && psys->pointcache->flag & PTCACHE_EXTERNAL)
+ return pid->cache->totpoint;
+ else if(psys->part->distr == PART_DISTR_GRID && psys->part->from != PART_FROM_VERT)
+ return psys->part->grid_res * psys->part->grid_res * psys->part->grid_res - psys->totunexist;
+ else
+ return psys->part->totpart - psys->totunexist;
+}
+
void psys_reset(ParticleSystem *psys, int mode)
{
PARTICLE_P;
if(ELEM(mode, PSYS_RESET_ALL, PSYS_RESET_DEPSGRAPH)) {
if(mode == PSYS_RESET_ALL || !(psys->flag & PSYS_EDITED)) {
- psys_free_particles(psys);
+ /* don't free if not absolutely necessary */
+ if(psys->totpart != tot_particles(psys, NULL)) {
+ psys_free_particles(psys);
+ psys->totpart= 0;
+ }
- psys->totpart= 0;
psys->totkeyed= 0;
psys->flag &= ~(PSYS_HAIR_DONE|PSYS_KEYED);
@@ -166,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)
@@ -197,8 +221,19 @@ static void realloc_particles(ParticleSimulationData *sim, int new_totpart)
if(totpart) {
newpars= MEM_callocN(totpart*sizeof(ParticleData), "particles");
- if(psys->part->phystype == PART_PHYS_BOIDS)
+ if(newpars == NULL)
+ return;
+
+ if(psys->part->phystype == PART_PHYS_BOIDS) {
newboids= MEM_callocN(totpart*sizeof(BoidParticle), "boid particles");
+
+ if(newboids == NULL) {
+ /* allocation error! */
+ if(newpars)
+ MEM_freeN(newpars);
+ return;
+ }
+ }
}
if(psys->particles) {
@@ -335,12 +370,17 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys)
/* cache the verts/faces! */
LOOP_PARTICLES {
+ if(pa->num < 0) {
+ pa->num_dmcache = -1;
+ continue;
+ }
+
if(psys->part->from == PART_FROM_VERT) {
if(nodearray[pa->num])
pa->num_dmcache= GET_INT_FROM_POINTER(nodearray[pa->num]->link);
}
else { /* FROM_FACE/FROM_VOLUME */
- /* Note that somtimes the pa->num is over the nodearray size, this is bad, maybe there is a better place to fix this,
+ /* Note that sometimes the pa->num is over the nodearray size, this is bad, maybe there is a better place to fix this,
* but for now passing NULL is OK. every face will be searched for the particle so its slower - Campbell */
pa->num_dmcache= psys_particle_dm_face_lookup(ob, dm, pa->num, pa->fuv, pa->num < totelem ? nodearray[pa->num] : NULL);
}
@@ -399,9 +439,14 @@ static void distribute_particles_in_grid(DerivedMesh *dm, ParticleSystem *psys)
size[(axis+1)%3] = MIN2(size[(axis+1)%3],res);
size[(axis+2)%3] = MIN2(size[(axis+2)%3],res);
- min[0]+=d/2.0f;
- min[1]+=d/2.0f;
- min[2]+=d/2.0f;
+ size[0] = MAX2(size[0], 1);
+ size[1] = MAX2(size[1], 1);
+ size[2] = MAX2(size[2], 1);
+
+ /* no full offset for flat/thin objects */
+ min[0]+= d < delta[0] ? d/2.f : delta[0]/2.f;
+ min[1]+= d < delta[1] ? d/2.f : delta[1]/2.f;
+ min[2]+= d < delta[2] ? d/2.f : delta[2]/2.f;
for(i=0,p=0,pa=psys->particles; i<res; i++){
for(j=0; j<res; j++){
@@ -438,13 +483,13 @@ static void distribute_particles_in_grid(DerivedMesh *dm, ParticleSystem *psys)
else if(ELEM(from,PART_FROM_FACE,PART_FROM_VOLUME)){
float co1[3], co2[3];
- MFace *mface=0;
+ MFace *mface= NULL, *mface_array;
float v1[3], v2[3], v3[3], v4[4], lambda;
int a, a1, a2, a0mul, a1mul, a2mul, totface;
int amax= from==PART_FROM_FACE ? 3 : 1;
totface=dm->getNumFaces(dm);
- mface=dm->getFaceDataArray(dm,CD_MFACE);
+ mface_array= dm->getFaceDataArray(dm,CD_MFACE);
for(a=0; a<amax; a++){
if(a==0){ a0mul=res*res; a1mul=res; a2mul=1; }
@@ -453,11 +498,11 @@ static void distribute_particles_in_grid(DerivedMesh *dm, ParticleSystem *psys)
for(a1=0; a1<size[(a+1)%3]; a1++){
for(a2=0; a2<size[(a+2)%3]; a2++){
- mface=dm->getFaceDataArray(dm,CD_MFACE);
+ mface= mface_array;
pa=psys->particles + a1*a1mul + a2*a2mul;
VECCOPY(co1,pa->fuv);
- co1[a]-=d/2.0f;
+ co1[a]-= d < delta[a] ? d/2.f : delta[a]/2.f;
VECCOPY(co2,co1);
co2[a]+=delta[a] + 0.001f*d;
co1[a]-=0.001f*d;
@@ -504,7 +549,7 @@ static void distribute_particles_in_grid(DerivedMesh *dm, ParticleSystem *psys)
}
if(psys->part->flag & PART_GRID_INVERT){
- for(i=0,pa=psys->particles; i<size[0]; i++){
+ for(i=0; i<size[0]; i++){
for(j=0; j<size[1]; j++){
pa=psys->particles + res*(i*res + j);
for(k=0; k<size[2]; k++, pa++){
@@ -513,6 +558,18 @@ static void distribute_particles_in_grid(DerivedMesh *dm, ParticleSystem *psys)
}
}
}
+
+ if(psys->part->grid_rand > 0.f) {
+ float rfac = d * psys->part->grid_rand;
+ for(p=0,pa=psys->particles; p<psys->totpart; p++,pa++){
+ if(pa->flag & PARS_UNEXIST)
+ continue;
+
+ pa->fuv[0] += rfac * (PSYS_FRAND(p + 31) - 0.5f);
+ pa->fuv[1] += rfac * (PSYS_FRAND(p + 32) - 0.5f);
+ pa->fuv[2] += rfac * (PSYS_FRAND(p + 33) - 0.5f);
+ }
+ }
}
/* modified copy from rayshade.c */
@@ -606,15 +663,21 @@ static void psys_uv_to_w(float u, float v, int quad, float *w)
}
}
+/* Find the index in "sum" array before "value" is crossed. */
static int binary_search_distribution(float *sum, int n, float value)
{
int mid, low=0, high=n;
+ if(value == 0.f)
+ return 0;
+
while(low <= high) {
mid= (low + high)/2;
- if(sum[mid] <= value && value <= sum[mid+1])
+
+ if(sum[mid] < value && value <= sum[mid+1])
return mid;
- else if(sum[mid] > value)
+
+ if(sum[mid] >= value)
high= mid - 1;
else if(sum[mid] < value)
low= mid + 1;
@@ -638,7 +701,7 @@ static void psys_thread_distribute_particle(ParticleThread *thread, ParticleData
DerivedMesh *dm= ctx->dm;
ParticleData *tpa;
/* ParticleSettings *part= ctx->sim.psys->part; */
- float *v1, *v2, *v3, *v4, nor[3], orco1[3], co1[3], co2[3], nor1[3], ornor1[3];
+ float *v1, *v2, *v3, *v4, nor[3], orco1[3], co1[3], co2[3], nor1[3];
float cur_d, min_d, randu, randv;
int from= ctx->from;
int cfrom= ctx->cfrom;
@@ -775,20 +838,17 @@ static void psys_thread_distribute_particle(ParticleThread *thread, ParticleData
if(ctx->tree){
KDTreeNearest ptn[10];
int w,maxw;//, do_seams;
- float maxd,mind,dd,totw=0.0;
+ float maxd,mind,/*dd,*/totw=0.0;
int parent[10];
float pweight[10];
- /*do_seams= (part->flag&PART_CHILD_SEAMS && ctx->seams);*/
-
- psys_particle_on_dm(dm,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,0,0,orco1,ornor1);
+ psys_particle_on_dm(dm,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,NULL,NULL,orco1,NULL);
transform_mesh_orco_verts((Mesh*)ob->data, &orco1, 1, 1);
- //maxw = BLI_kdtree_find_n_nearest(ctx->tree,(do_seams)?10:4,orco1,ornor1,ptn);
- maxw = BLI_kdtree_find_n_nearest(ctx->tree,4,orco1,ornor1,ptn);
+ maxw = BLI_kdtree_find_n_nearest(ctx->tree,4,orco1,NULL,ptn);
maxd=ptn[maxw-1].dist;
mind=ptn[0].dist;
- dd=maxd-mind;
+ /*dd=maxd-mind;*/ /*UNUSED*/
/* the weights here could be done better */
for(w=0; w<maxw; w++){
@@ -799,63 +859,6 @@ static void psys_thread_distribute_particle(ParticleThread *thread, ParticleData
parent[w]=-1;
pweight[w]=0.0f;
}
- //if(do_seams){
- // ParticleSeam *seam=ctx->seams;
- // float temp[3],temp2[3],tan[3];
- // float inp,cur_len,min_len=10000.0f;
- // int min_seam=0, near_vert=0;
- // /* find closest seam */
- // for(i=0; i<ctx->totseam; i++, seam++){
- // sub_v3_v3v3(temp,co1,seam->v0);
- // inp=dot_v3v3(temp,seam->dir)/seam->length2;
- // if(inp<0.0f){
- // cur_len=len_v3v3(co1,seam->v0);
- // }
- // else if(inp>1.0f){
- // cur_len=len_v3v3(co1,seam->v1);
- // }
- // else{
- // copy_v3_v3(temp2,seam->dir);
- // mul_v3_fl(temp2,inp);
- // cur_len=len_v3v3(temp,temp2);
- // }
- // if(cur_len<min_len){
- // min_len=cur_len;
- // min_seam=i;
- // if(inp<0.0f) near_vert=-1;
- // else if(inp>1.0f) near_vert=1;
- // else near_vert=0;
- // }
- // }
- // seam=ctx->seams+min_seam;
- //
- // copy_v3_v3(temp,seam->v0);
- //
- // if(near_vert){
- // if(near_vert==-1)
- // sub_v3_v3v3(tan,co1,seam->v0);
- // else{
- // sub_v3_v3v3(tan,co1,seam->v1);
- // copy_v3_v3(temp,seam->v1);
- // }
-
- // normalize_v3(tan);
- // }
- // else{
- // copy_v3_v3(tan,seam->tan);
- // sub_v3_v3v3(temp2,co1,temp);
- // if(dot_v3v3(tan,temp2)<0.0f)
- // negate_v3(tan);
- // }
- // for(w=0; w<maxw; w++){
- // sub_v3_v3v3(temp2,ptn[w].co,temp);
- // if(dot_v3v3(tan,temp2)<0.0f){
- // parent[w]=-1;
- // pweight[w]=0.0f;
- // }
- // }
-
- //}
for(w=0,i=0; w<maxw && i<4; w++){
if(parent[w]>=0){
@@ -966,7 +969,7 @@ static int psys_threads_init_distribution(ParticleThread *threads, Scene *scene,
DerivedMesh *dm= NULL;
float *jit= NULL;
int i, seed, p=0, totthread= threads[0].tot;
- int no_distr=0, cfrom=0;
+ int /*no_distr=0,*/ cfrom=0;
int tot=0, totpart, *index=0, children=0, totseam=0;
//int *vertpart=0;
int jitlevel= 1, distr;
@@ -991,6 +994,8 @@ static int psys_threads_init_distribution(ParticleThread *threads, Scene *scene,
if(from==PART_FROM_CHILD){
distr=PART_DISTR_RAND;
+ BLI_srandom(31415926 + psys->seed + psys->child_seed);
+
if(part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){
dm= finaldm;
children=1;
@@ -1007,50 +1012,6 @@ static int psys_threads_init_distribution(ParticleThread *threads, Scene *scene,
totpart=get_psys_tot_child(scene, psys);
cfrom=from=PART_FROM_FACE;
-
- //if(part->flag&PART_CHILD_SEAMS){
- // MEdge *ed, *medge=dm->getEdgeDataArray(dm,CD_MEDGE);
- // MVert *mvert=dm->getVertDataArray(dm,CD_MVERT);
- // int totedge=dm->getNumEdges(dm);
-
- // for(p=0, ed=medge; p<totedge; p++,ed++)
- // if(ed->flag&ME_SEAM)
- // totseam++;
-
- // if(totseam){
- // ParticleSeam *cur_seam=seams=MEM_callocN(totseam*sizeof(ParticleSeam),"Child Distribution Seams");
- // float temp[3],temp2[3];
-
- // for(p=0, ed=medge; p<totedge; p++,ed++){
- // if(ed->flag&ME_SEAM){
- // copy_v3_v3(cur_seam->v0,(mvert+ed->v1)->co);
- // copy_v3_v3(cur_seam->v1,(mvert+ed->v2)->co);
-
- // sub_v3_v3v3(cur_seam->dir,cur_seam->v1,cur_seam->v0);
-
- // cur_seam->length2=len_v3(cur_seam->dir);
- // cur_seam->length2*=cur_seam->length2;
-
- // temp[0]=(float)((mvert+ed->v1)->no[0]);
- // temp[1]=(float)((mvert+ed->v1)->no[1]);
- // temp[2]=(float)((mvert+ed->v1)->no[2]);
- // temp2[0]=(float)((mvert+ed->v2)->no[0]);
- // temp2[1]=(float)((mvert+ed->v2)->no[1]);
- // temp2[2]=(float)((mvert+ed->v2)->no[2]);
-
- // add_v3_v3v3(cur_seam->nor,temp,temp2);
- // normalize_v3(cur_seam->nor);
-
- // cross_v3_v3v3(cur_seam->tan,cur_seam->dir,cur_seam->nor);
-
- // normalize_v3(cur_seam->tan);
-
- // cur_seam++;
- // }
- // }
- // }
- //
- //}
}
else{
/* no need to figure out distribution */
@@ -1095,7 +1056,7 @@ static int psys_threads_init_distribution(ParticleThread *threads, Scene *scene,
DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, get_mesh_orco_verts(ob));
distr=part->distr;
- pa=psys->particles;
+
if(from==PART_FROM_VERT){
MVert *mv= dm->getVertDataArray(dm, CD_MVERT);
float (*orcodata)[3]= dm->getVertDataArray(dm, CD_ORCO);
@@ -1140,7 +1101,7 @@ static int psys_threads_init_distribution(ParticleThread *threads, Scene *scene,
}
if(tot==0){
- no_distr=1;
+ /*no_distr=1;*/ /*UNUSED*/
if(children){
if(G.f & G_DEBUG)
fprintf(stderr,"Particle child distribution error: Nothing to emit from!\n");
@@ -1287,7 +1248,8 @@ static int psys_threads_init_distribution(ParticleThread *threads, Scene *scene,
float pos;
for(p=0; p<totpart; p++) {
- pos= BLI_frand();
+ /* In theory sys[tot] should be 1.0, but due to float errors this is not necessarily always true, so scale pos accordingly. */
+ pos= BLI_frand() * sum[tot];
index[p]= binary_search_distribution(sum, tot, pos);
index[p]= MIN2(tot-1, index[p]);
jitoff[index[p]]= pos;
@@ -1437,7 +1399,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
}
/* ready for future use, to emit particles without geometry */
-static void distribute_particles_on_shape(ParticleSimulationData *sim, int from)
+static void distribute_particles_on_shape(ParticleSimulationData *sim, int UNUSED(from))
{
ParticleSystem *psys = sim->psys;
PARTICLE_P;
@@ -1609,8 +1571,51 @@ static void initialize_all_particles(ParticleSimulationData *sim)
ParticleSystem *psys = sim->psys;
PARTICLE_P;
- LOOP_PARTICLES
+ psys->totunexist = 0;
+
+ LOOP_PARTICLES {
initialize_particle(sim, pa, p);
+ if(pa->flag & PARS_UNEXIST)
+ psys->totunexist++;
+ }
+
+ /* Free unexisting particles. */
+ if(psys->totpart && psys->totunexist == psys->totpart) {
+ if(psys->particles->boid)
+ MEM_freeN(psys->particles->boid);
+
+ MEM_freeN(psys->particles);
+ psys->particles = NULL;
+ psys->totpart = psys->totunexist = 0;
+ }
+
+ if(psys->totunexist) {
+ int newtotpart = psys->totpart - psys->totunexist;
+ ParticleData *npa, *newpars;
+
+ npa = newpars = MEM_callocN(newtotpart * sizeof(ParticleData), "particles");
+
+ for(p=0, pa=psys->particles; p<newtotpart; p++, pa++, npa++) {
+ while(pa->flag & PARS_UNEXIST)
+ pa++;
+
+ memcpy(npa, pa, sizeof(ParticleData));
+ }
+
+ if(psys->particles->boid)
+ MEM_freeN(psys->particles->boid);
+ MEM_freeN(psys->particles);
+ psys->particles = newpars;
+ psys->totpart -= psys->totunexist;
+
+ if(psys->particles->boid) {
+ BoidParticle *newboids = MEM_callocN(psys->totpart * sizeof(BoidParticle), "boid particles");
+
+ LOOP_PARTICLES
+ pa->boid = newboids++;
+
+ }
+ }
if(psys->part->type != PART_FLUID) {
#if 0 // XXX old animation system
@@ -1703,9 +1708,10 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime,
r_phase = PSYS_FRAND(p + 20);
if(part->from==PART_FROM_PARTICLE){
- ParticleSimulationData tsim = {sim->scene, psys->target_ob ? psys->target_ob : ob, NULL, NULL};
float speed;
-
+ ParticleSimulationData tsim= {0};
+ tsim.scene= sim->scene;
+ tsim.ob= psys->target_ob ? psys->target_ob : ob;
tsim.psys = BLI_findlink(&tsim.ob->particlesystem, sim->psys->target_psys-1);
state.time = pa->time;
@@ -2055,12 +2061,14 @@ void psys_count_keyed_targets(ParticleSimulationData *sim)
static void set_keyed_keys(ParticleSimulationData *sim)
{
ParticleSystem *psys = sim->psys;
- ParticleSimulationData ksim = {sim->scene, NULL, NULL, NULL};
+ ParticleSimulationData ksim= {0};
ParticleTarget *pt;
PARTICLE_P;
ParticleKey *key;
int totpart = psys->totpart, k, totkeys = psys->totkeyed;
+ ksim.scene= sim->scene;
+
/* no proper targets so let's clear and bail out */
if(psys->totkeyed==0) {
free_keyed_keys(psys);
@@ -2231,7 +2239,9 @@ void psys_make_temp_pointcache(Object *ob, ParticleSystem *psys)
if(cache->flag & PTCACHE_DISK_CACHE && cache->mem_cache.first == NULL) {
PTCacheID pid;
BKE_ptcache_id_from_particles(&pid, ob, psys);
+ cache->flag &= ~PTCACHE_DISK_CACHE;
BKE_ptcache_disk_to_mem(&pid);
+ cache->flag |= PTCACHE_DISK_CACHE;
}
}
static void psys_clear_temp_pointcache(ParticleSystem *psys)
@@ -2283,136 +2293,241 @@ static void psys_update_effectors(ParticleSimulationData *sim)
precalc_guides(sim, sim->psys->effectors);
}
-/*************************************************
+/*********************************************************************************************************
SPH fluid physics
- In theory, there could be unlimited implementation
- of SPH simulators
-**************************************************/
-void particle_fluidsim(ParticleSystem *psys, ParticleData *pa, ParticleSettings *part, ParticleSimulationData *sim, float dfra, float cfra, float mass){
-/****************************************************************************************************************
-* This code uses in some parts adapted algorithms from the pseduo code as outlined in the Research paper
-* Titled: Particle-based Viscoelastic Fluid Simulation.
-* Authors: Simon Clavet, Philippe Beaudoin and Pierre Poulin
-*
-* Website: http://www.iro.umontreal.ca/labs/infographie/papers/Clavet-2005-PVFS/
-* Presented at Siggraph, (2005)
-*
-*****************************************************************************************************************/
- KDTree *tree = psys->tree;
+ In theory, there could be unlimited implementation of SPH simulators
+
+ This code uses in some parts adapted algorithms from the pseudo code as outlined in the Research paper:
+
+ Titled: Particle-based Viscoelastic Fluid Simulation.
+ Authors: Simon Clavet, Philippe Beaudoin and Pierre Poulin
+ Website: http://www.iro.umontreal.ca/labs/infographie/papers/Clavet-2005-PVFS/
+
+ Presented at Siggraph, (2005)
+
+***********************************************************************************************************/
+#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;
+ 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;
-
- SPHFluidSettings *fluid = part->fluid;
- ParticleData *second_particle;
+ ParticleData *npa;
+ ParticleSpring *spring = NULL;
- float start[3], end[3], v[3];
float temp[3];
- float q, radius, D;
- float p, pnear, pressure_near, pressure;
- float dtime = dfra * psys_get_timestep(sim);
+ float q, q1, u, I, D, rij, d, Lij;
+ float pressure_near, pressure;
+ float p=0, pnear=0;
+
float omega = fluid->viscosity_omega;
- float beta = fluid->viscosity_omega;
+ float beta = fluid->viscosity_beta;
float massfactor = 1.0f/mass;
- int n, neighbours;
+ float spring_k = fluid->spring_k;
+ float h = fluid->radius;
+ float L = fluid->rest_length * fluid->radius;
-
- radius = fluid->radius;
+ 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;
- VECCOPY(start, pa->prev_state.co);
- VECCOPY(end, pa->state.co);
+ /* 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/h;
- VECCOPY(v, pa->state.vel);
+ if(q < 1.f) {
+ q1 = 1.f - q;
- neighbours = BLI_kdtree_range_search(tree, radius, start, NULL, &ptn);
-
- /* use ptn[n].co to store relative direction */
- for(n=1; n<neighbours; n++) {
- sub_v3_v3(ptn[n].co, start);
- normalize_v3(ptn[n].co);
- }
-
- /* Viscosity - Algorithm 5 */
- if (omega > 0.f || beta > 0.f) {
- float u, I;
-
- for(n=1; n<neighbours; n++) {
- second_particle = psys->particles + ptn[n].index;
- q = ptn[n].dist/radius;
-
- sub_v3_v3v3(temp, v, second_particle->prev_state.vel);
-
- u = dot_v3v3(ptn[n].co, temp);
-
- if (u > 0){
- I = dtime * ((1-q) * (omega * u + beta * u*u)) * 0.5f;
- madd_v3_v3fl(v, ptn[n].co, -I * massfactor);
- }
- }
- }
-
- /* Hooke's spring force */
- if (fluid->spring_k > 0.f) {
- float D, L = fluid->rest_length;
- for(n=1; n<neighbours; n++) {
- /* L is a factor of radius */
- D = dtime * 10.f * fluid->spring_k * (1.f - L) * (L - ptn[n].dist/radius);
- madd_v3_v3fl(v, ptn[n].co, -D * massfactor);
+ p += q1*q1;
+ pnear += q1*q1*q1;
}
}
- /* Update particle position */
- VECADDFAC(end, start, v, dtime);
- /* Double Density Relaxation - Algorithm 2 */
- p = 0;
- pnear = 0;
- for(n=1; n<neighbours; n++) {
- q = ptn[n].dist/radius;
- p += ((1-q)*(1-q));
- pnear += ((1-q)*(1-q)*(1-q));
- }
- p *= part->mass;
- pnear *= part->mass;
+ p *= mass;
+ pnear *= mass;
pressure = fluid->stiffness_k * (p - fluid->rest_density);
pressure_near = fluid->stiffness_knear * pnear;
- for(n=1; n<neighbours; n++) {
- q = ptn[n].dist/radius;
+ /* main calculations */
+ for(n=own_psys?1:0; n<neighbours; n++) {
+ npa = psys->particles + ptn[n].index;
+
+ rij = ptn[n].dist;
+ q = rij/h;
+ q1 = 1.f-q;
- D = dtime * dtime * (pressure*(1-q) + pressure_near*(1-q)*(1-q))* 0.5f;
- madd_v3_v3fl(end, ptn[n].co, -D * massfactor);
- }
+ /* Double Density Relaxation - Algorithm 2 (can't be thread safe!)*/
+ D = dtime * dtime * (pressure + pressure_near*q1)*q1 * 0.5f;
+ 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(index < ptn[n].index) {
+ /* Viscosity - Algorithm 5 */
+ if(omega > 0.f || beta > 0.f) {
+ sub_v3_v3v3(temp, pa->state.vel, npa->state.vel);
+ u = dot_v3v3(ptn[n].co, temp);
+
+ if (u > 0){
+ I = dtime * (q1 * (omega * u + beta * u*u)) * 0.5f;
+ madd_v3_v3fl(pa->state.vel, ptn[n].co, -I * massfactor);
+
+ if(own_psys)
+ madd_v3_v3fl(npa->state.vel, ptn[n].co, I * massfactor);
+ }
+ }
+
+ if(spring_k > 0.f) {
+ /* 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;
+
+ 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);
+ }
+ }
+ }
+ }
/* Artificial buoyancy force in negative gravity direction */
- if (fluid->buoyancy >= 0.f && psys_uses_gravity(sim)) {
+ if (fluid->buoyancy >= 0.f && gravity) {
float B = -dtime * dtime * fluid->buoyancy * (p - fluid->rest_density) * 0.5f;
- madd_v3_v3fl(end, sim->scene->physics_settings.gravity, -B * massfactor);
+ madd_v3_v3fl(pa->state.co, gravity, -B * massfactor);
}
- /* apply final result and recalculate velocity */
- VECCOPY(pa->state.co, end);
- sub_v3_v3v3(pa->state.vel, end, start);
- mul_v3_fl(pa->state.vel, 1.f/dtime);
-
- if(ptn){ MEM_freeN(ptn); ptn=NULL;}
+ if(ptn)
+ MEM_freeN(ptn);
}
-static void apply_particle_fluidsim(ParticleSystem *psys, ParticleData *pa, ParticleSettings *part, ParticleSimulationData *sim, float dfra, float cfra){
+static void apply_particle_fluidsim(Object *ob, ParticleSystem *psys, ParticleData *pa, float dtime, float *gravity, EdgeHash *springhash){
ParticleTarget *pt;
-// float dtime = dfra*psys_get_timestep(sim);
- float particle_mass = part->mass;
- particle_fluidsim(psys, pa, part, sim, dfra, cfra, particle_mass);
+ particle_fluidsim(psys, 1, pa, dtime, psys->part->mass, gravity, springhash);
/*----check other SPH systems (Multifluids) , each fluid has its own parameters---*/
- for(pt=sim->psys->targets.first; pt; pt=pt->next) {
- ParticleSystem *epsys = psys_get_target_system(sim->ob, pt);
+ for(pt=psys->targets.first; pt; pt=pt->next) {
+ ParticleSystem *epsys = psys_get_target_system(ob, pt);
if(epsys)
- particle_fluidsim(epsys, pa, epsys->part, sim, dfra, cfra, particle_mass);
+ particle_fluidsim(epsys, 0, pa, dtime, psys->part->mass, gravity, NULL);
}
/*----------------------------------------------------------------*/
}
+static void apply_fluid_springs(ParticleSystem *psys, 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 */
/************************************************/
@@ -2425,7 +2540,7 @@ static void apply_particle_forces(ParticleSimulationData *sim, int p, float dfra
ParticleKey states[5], tkey;
float timestep = psys_get_timestep(sim);
float force[3],impulse[3],dx[4][3],dv[4][3],oldpos[3];
- float dtime=dfra*timestep, time, pa_mass=part->mass, fac, fra=sim->psys->cfra;
+ float dtime=dfra*timestep, time, pa_mass=part->mass, fac /*, fra=sim->psys->cfra*/;
int i, steps=1;
/* maintain angular velocity */
@@ -2498,7 +2613,7 @@ static void apply_particle_forces(ParticleSimulationData *sim, int p, float dfra
if(i==0){
VECADDFAC(states[1].co,states->co,states->vel,dtime*0.5f);
VECADDFAC(states[1].vel,states->vel,force,dtime*0.5f);
- fra=sim->psys->cfra+0.5f*dfra;
+ /*fra=sim->psys->cfra+0.5f*dfra;*/
}
else{
VECADDFAC(pa->state.co,states->co,states[1].vel,dtime);
@@ -2515,7 +2630,7 @@ static void apply_particle_forces(ParticleSimulationData *sim, int p, float dfra
VECADDFAC(states[1].co,states->co,dx[0],0.5f);
VECADDFAC(states[1].vel,states->vel,dv[0],0.5f);
- fra=sim->psys->cfra+0.5f*dfra;
+ /*fra=sim->psys->cfra+0.5f*dfra;*/
break;
case 1:
VECADDFAC(dx[1],states->vel,dv[0],0.5f);
@@ -2534,7 +2649,7 @@ static void apply_particle_forces(ParticleSimulationData *sim, int p, float dfra
VECADD(states[3].co,states->co,dx[2]);
VECADD(states[3].vel,states->vel,dv[2]);
- fra=cfra;
+ /*fra=cfra;*/
break;
case 3:
VECADD(dx[3],states->vel,dv[2]);
@@ -2775,23 +2890,26 @@ void particle_intersect_face(void *userdata, int index, const BVHTreeRay *ray, B
MVert *x = col->md->x;
MVert *v = col->md->current_v;
float vel[3], co1[3], co2[3], uv[2], ipoint[3], temp[3], t;
+ float x0[3], x1[3], x2[3], x3[3];
+ float *t0=x0, *t1=x1, *t2=x2, *t3=(face->v4 ? x3 : NULL);
- float *t0, *t1, *t2, *t3;
- t0 = x[ face->v1 ].co;
- t1 = x[ face->v2 ].co;
- t2 = x[ face->v3 ].co;
- t3 = face->v4 ? x[ face->v4].co : NULL;
+ /* move collision face to start of timestep */
+ madd_v3_v3v3fl(t0, x[face->v1].co, v[face->v1].co, col->cfra);
+ madd_v3_v3v3fl(t1, x[face->v2].co, v[face->v2].co, col->cfra);
+ madd_v3_v3v3fl(t2, x[face->v3].co, v[face->v3].co, col->cfra);
+ if(t3)
+ madd_v3_v3v3fl(t3, x[face->v4].co, v[face->v4].co, col->cfra);
/* calculate average velocity of face */
- VECCOPY(vel, v[ face->v1 ].co);
- VECADD(vel, vel, v[ face->v2 ].co);
- VECADD(vel, vel, v[ face->v3 ].co);
- mul_v3_fl(vel, 0.33334f);
+ copy_v3_v3(vel, v[ face->v1 ].co);
+ add_v3_v3(vel, v[ face->v2 ].co);
+ add_v3_v3(vel, v[ face->v3 ].co);
+ mul_v3_fl(vel, 0.33334f*col->dfra);
/* substract face velocity, in other words convert to
a coordinate system where only the particle moves */
- VECADDFAC(co1, col->co1, vel, -col->t);
- VECSUB(co2, col->co2, vel);
+ madd_v3_v3v3fl(co1, col->co1, vel, -col->f);
+ sub_v3_v3v3(co2, col->co2, vel);
do
{
@@ -2873,7 +2991,7 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo
copy_v3_v3(col.co2, pa->state.co);
copy_v3_v3(col.ve1, pa->prev_state.vel);
copy_v3_v3(col.ve2, pa->state.vel);
- col.t = 0.0f;
+ col.f = 0.0f;
/* override for boids */
if(part->phystype == PART_PHYS_BOIDS) {
@@ -2891,6 +3009,9 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo
hit.index = -1;
hit.dist = col.ray_len = len_v3(ray_dir);
+ col.cfra = fmod(cfra-dfra, 1.0f);
+ col.dfra = dfra;
+
/* even if particle is stationary we want to check for moving colliders */
/* if hit.dist is zero the bvhtree_ray_cast will just ignore everything */
if(hit.dist == 0.0f)
@@ -2915,11 +3036,11 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo
/* 2. */
if(hit.index>=0) {
PartDeflect *pd = col.hit_ob->pd;
- float co[3]; /* point of collision */
- float x = hit.dist/col.ray_len; /* location of collision between this iteration */
- float df = col.t + x * (1.0f - col.t); /* time of collision between frame change*/
- float dt1 = (df - col.t) * timestep; /* iteration time of collision (in seconds) */
- float dt2 = (1.0f - df) * timestep; /* time left after collision (in seconds) */
+ float co[3]; /* point of collision */
+ float x = hit.dist/col.ray_len; /* location factor of collision between this iteration */
+ float f = col.f + x * (1.0f - col.f); /* time factor of collision between timestep */
+ float dt1 = (f - col.f) * timestep; /* time since previous collision (in seconds) */
+ float dt2 = (1.0f - f) * timestep; /* time left after collision (in seconds) */
int through = (BLI_frand() < pd->pdef_perm) ? 1 : 0; /* did particle pass through the collision surface? */
deflections++;
@@ -2933,12 +3054,12 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo
/* particle dies in collision */
if(through == 0 && (part->flag & PART_DIE_ON_COL || pd->flag & PDEFLE_KILL_PART)) {
pa->alive = PARS_DYING;
- pa->dietime = pa->state.time + (cfra - pa->state.time) * df;
+ pa->dietime = sim->psys->cfra + (cfra - sim->psys->cfra) * f;
copy_v3_v3(pa->state.co, co);
- interp_v3_v3v3(pa->state.vel, pa->prev_state.vel, pa->state.vel, df);
- interp_qt_qtqt(pa->state.rot, pa->prev_state.rot, pa->state.rot, df);
- interp_v3_v3v3(pa->state.ave, pa->prev_state.ave, pa->state.ave, df);
+ interp_v3_v3v3(pa->state.vel, pa->prev_state.vel, pa->state.vel, f);
+ interp_qt_qtqt(pa->state.rot, pa->prev_state.rot, pa->state.rot, f);
+ interp_v3_v3v3(pa->state.ave, pa->prev_state.ave, pa->state.ave, f);
/* particle is dead so we don't need to calculate further */
return;
@@ -3071,11 +3192,11 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo
copy_v3_v3(col.ve1, v0);
copy_v3_v3(col.ve2, pa->state.vel);
- col.t = df;
+ col.f = f;
}
else {
- /* final chance to prevent failure, so don't do anything fancy */
- copy_v3_v3(pa->state.co, co);
+ /* final chance to prevent failure, so stick to the surface and hope for the best */
+ madd_v3_v3v3fl(pa->state.co, co, col.vel, dt2);
copy_v3_v3(pa->state.vel, v0);
}
}
@@ -3259,7 +3380,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
psys->clmd->point_cache = psys->pointcache;
psys->clmd->sim_parms->effector_weights = psys->part->effector_weights;
- psys->hair_out_dm = clothModifier_do(psys->clmd, sim->scene, sim->ob, dm, 0, 0);
+ psys->hair_out_dm = clothModifier_do(psys->clmd, sim->scene, sim->ob, dm);
psys->clmd->sim_parms->effector_weights = NULL;
}
@@ -3284,11 +3405,11 @@ static void hair_step(ParticleSimulationData *sim, float cfra)
psys_calc_dmcache(sim->ob, sim->psmd->dm, psys);
if(psys->clmd)
- cloth_free_modifier(sim->ob, psys->clmd);
+ cloth_free_modifier(psys->clmd);
}
- /* dynamics with cloth simulation */
- if(psys->part->type==PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS)
+ /* dynamics with cloth simulation, psys->particles can be NULL with 0 particles [#25519] */
+ if(psys->part->type==PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS && psys->particles)
do_hair_dynamics(sim);
/* following lines were removed r29079 but cause bug [#22811], see report for details */
@@ -3298,20 +3419,17 @@ static void hair_step(ParticleSimulationData *sim, float cfra)
psys->flag |= PSYS_HAIR_UPDATED;
}
-static void save_hair(ParticleSimulationData *sim, float cfra){
+static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra)){
Object *ob = sim->ob;
ParticleSystem *psys = sim->psys;
HairKey *key, *root;
PARTICLE_P;
- int totpart;
invert_m4_m4(ob->imat, ob->obmat);
psys->lattice= psys_get_lattice(sim);
if(psys->totpart==0) return;
-
- totpart=psys->totpart;
/* save new keys for elements if needed */
LOOP_PARTICLES {
@@ -3355,20 +3473,15 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
BoidBrainData bbd;
PARTICLE_P;
float timestep;
- /* current time */
- float ctime;
/* frame & time changes */
- float dfra, dtime, pa_dtime, pa_dfra=0.0;
+ float dfra, dtime;
float birthtime, dietime;
-
- int invalidParticles=0;
/* where have we gone in time since last time */
dfra= cfra - psys->cfra;
timestep = psys_get_timestep(sim);
dtime= dfra*timestep;
- ctime= cfra*timestep;
if(dfra<0.0){
LOOP_EXISTING_PARTICLES {
@@ -3386,35 +3499,42 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
psys_update_effectors(sim);
if(part->type != PART_HAIR)
- sim->colliders = get_collider_cache(sim->scene, NULL, NULL);
+ sim->colliders = get_collider_cache(sim->scene, sim->ob, NULL);
- if(part->phystype==PART_PHYS_BOIDS){
- ParticleTarget *pt = psys->targets.first;
- bbd.sim = sim;
- bbd.part = part;
- bbd.cfra = cfra;
- bbd.dfra = dfra;
- bbd.timestep = timestep;
+ /* initialize physics type specific stuff */
+ switch(part->phystype) {
+ case PART_PHYS_BOIDS:
+ {
+ ParticleTarget *pt = psys->targets.first;
+ bbd.sim = sim;
+ bbd.part = part;
+ bbd.cfra = cfra;
+ bbd.dfra = dfra;
+ bbd.timestep = timestep;
- psys_update_particle_tree(psys, cfra);
+ psys_update_particle_tree(psys, cfra);
- boids_precalc_rules(part, cfra);
+ boids_precalc_rules(part, cfra);
- for(; pt; pt=pt->next) {
- if(pt->ob)
- psys_update_particle_tree(BLI_findlink(&pt->ob->particlesystem, pt->psys-1), cfra);
+ for(; pt; pt=pt->next) {
+ if(pt->ob)
+ psys_update_particle_tree(BLI_findlink(&pt->ob->particlesystem, pt->psys-1), cfra);
+ }
+ break;
}
- }
- else if(part->phystype==PART_PHYS_FLUID){
- ParticleTarget *pt = psys->targets.first;
- psys_update_particle_tree(psys, cfra);
-
- for(; pt; pt=pt->next) { /* Updating others systems particle tree for fluid-fluid interaction */
- if(pt->ob) psys_update_particle_tree(BLI_findlink(&pt->ob->particlesystem, pt->psys-1), cfra);
+ case PART_PHYS_FLUID:
+ {
+ ParticleTarget *pt = psys->targets.first;
+ psys_update_particle_tree(psys, cfra);
+
+ for(; pt; pt=pt->next) { /* Updating others systems particle tree for fluid-fluid interaction */
+ if(pt->ob)
+ psys_update_particle_tree(BLI_findlink(&pt->ob->particlesystem, pt->psys-1), cfra);
+ }
+ break;
}
}
-
- /* main loop: calculate physics for all particles */
+ /* initialize all particles for dynamics */
LOOP_SHOWN_PARTICLES {
copy_particle_key(&pa->prev_state,&pa->state,1);
@@ -3422,29 +3542,22 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
if(part->randsize > 0.0)
pa->size *= 1.0f - part->randsize * PSYS_FRAND(p + 1);
- ///* reactions can change birth time so they need to be checked first */
- //if(psys->reactevents.first && ELEM(pa->alive,PARS_DEAD,PARS_KILLED)==0)
- // react_to_events(psys,p);
-
birthtime = pa->time;
dietime = birthtime + pa->lifetime;
- pa_dfra = dfra;
- pa_dtime = dtime;
-
+ /* store this, so we can do multiple loops over particles */
+ pa->state.time = dfra;
if(dietime <= cfra && psys->cfra < dietime){
/* particle dies some time between this and last step */
- pa_dfra = dietime - ((birthtime > psys->cfra) ? birthtime : psys->cfra);
- pa_dtime = pa_dfra * timestep;
+ pa->state.time = dietime - ((birthtime > psys->cfra) ? birthtime : psys->cfra);
pa->alive = PARS_DYING;
}
else if(birthtime <= cfra && birthtime >= psys->cfra){
/* particle is born some time between this and last step*/
- reset_particle(sim, pa, dtime, cfra);
+ reset_particle(sim, pa, dfra*timestep, cfra);
pa->alive = PARS_ALIVE;
- pa_dfra = cfra - birthtime;
- pa_dtime = pa_dfra*timestep;
+ pa->state.time = cfra - birthtime;
}
else if(dietime < cfra){
/* nothing to be done when particle is dead */
@@ -3457,62 +3570,98 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
else if(part->phystype == PART_PHYS_NO)
reset_particle(sim, pa, dtime, cfra);
- if(pa_dfra>0.0 && ELEM(pa->alive,PARS_ALIVE,PARS_DYING)){
- switch(part->phystype){
- case PART_PHYS_NEWTON:
- /* do global forces & effectors */
- apply_particle_forces(sim, p, pa_dfra, cfra);
-
+ if(ELEM(pa->alive, PARS_ALIVE, PARS_DYING)==0 || (pa->flag & (PARS_UNEXIST|PARS_NO_DISP)))
+ pa->state.time = -1.f;
+ }
+
+ switch(part->phystype) {
+ case PART_PHYS_NEWTON:
+ {
+ LOOP_DYNAMIC_PARTICLES {
+ /* do global forces & effectors */
+ apply_particle_forces(sim, p, pa->state.time, cfra);
+
+ /* deflection */
+ if(sim->colliders)
+ deflect_particle(sim, p, pa->state.time, cfra);
+
+ /* rotations */
+ rotate_particle(part, pa, pa->state.time, timestep);
+ }
+ break;
+ }
+ case PART_PHYS_BOIDS:
+ {
+ LOOP_DYNAMIC_PARTICLES {
+ bbd.goal_ob = NULL;
+
+ boid_brain(&bbd, p, pa);
+
+ if(pa->alive != PARS_DYING) {
+ boid_body(&bbd, pa);
+
/* deflection */
if(sim->colliders)
- deflect_particle(sim, p, pa_dfra, cfra);
-
- /* rotations */
- rotate_particle(part, pa, pa_dfra, timestep);
- break;
- case PART_PHYS_BOIDS:
- {
- bbd.goal_ob = NULL;
- boid_brain(&bbd, p, pa);
- if(pa->alive != PARS_DYING) {
- boid_body(&bbd, pa);
-
- /* deflection */
- if(sim->colliders)
- deflect_particle(sim, p, pa_dfra, cfra);
- }
- break;
+ deflect_particle(sim, p, pa->state.time, cfra);
}
- case PART_PHYS_FLUID:
- {
- /* do global forces & effectors */
- apply_particle_forces(sim, p, pa_dfra, cfra);
+ }
+ break;
+ }
+ case PART_PHYS_FLUID:
+ {
+ EdgeHash *springhash = build_fluid_springhash(psys);
+ float *gravity = NULL;
- /* do fluid sim */
- apply_particle_fluidsim(psys, pa, part, sim, pa_dfra, cfra);
+ if(psys_uses_gravity(sim))
+ gravity = sim->scene->physics_settings.gravity;
- /* deflection */
- if(sim->colliders)
- deflect_particle(sim, p, pa_dfra, cfra);
-
- /* rotations, SPH particles are not physical particles, just interpolation particles, thus rotation has not a direct sense for them */
- rotate_particle(part, pa, pa_dfra, timestep);
- break;
- }
+ /* do global forces & effectors */
+ LOOP_DYNAMIC_PARTICLES {
+ apply_particle_forces(sim, p, pa->state.time, cfra);
+ /* in fluids forces only effect velocity */
+ copy_v3_v3(pa->state.co, pa->prev_state.co);
+ }
+
+ /* actual fluids calculations (not threadsafe!) */
+ LOOP_DYNAMIC_PARTICLES {
+ apply_particle_fluidsim(sim->ob, psys, pa, pa->state.time*timestep, gravity, springhash);
}
- if(pa->alive == PARS_DYING){
- //push_reaction(ob,psys,p,PART_EVENT_DEATH,&pa->state);
+ /* Apply springs to particles */
+ apply_fluid_springs(psys, timestep);
- pa->alive=PARS_DEAD;
- pa->state.time=pa->dietime;
+ /* apply velocity, collisions and rotation */
+ LOOP_DYNAMIC_PARTICLES {
+ /* velocity holds forces and viscosity, so apply them before collisions */
+ madd_v3_v3fl(pa->state.co, pa->state.vel, pa->state.time*timestep);
+
+ /* calculate new velocity based on new-old location */
+ sub_v3_v3v3(pa->state.vel, pa->state.co, pa->prev_state.co);
+ mul_v3_fl(pa->state.vel, 1.f/(pa->state.time*timestep));
+
+ if(sim->colliders)
+ deflect_particle(sim, p, pa->state.time, 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);
}
- else
- pa->state.time=cfra;
- //push_reaction(ob,psys,p,PART_EVENT_NEAR,&pa->state);
+ if(springhash) {
+ BLI_edgehash_free(springhash, NULL);
+ springhash = NULL;
+ }
+ break;
}
- if (isnan(pa->state.co[0]) || isnan(pa->state.co[1]) || isnan(pa->state.co[2])) {invalidParticles++;}
+ }
+
+ /* finalize particle state and time after dynamics */
+ LOOP_DYNAMIC_PARTICLES {
+ if(pa->alive == PARS_DYING){
+ pa->alive=PARS_DEAD;
+ pa->state.time=pa->dietime;
+ }
+ else
+ pa->state.time=cfra;
}
free_collider_cache(&sim->colliders);
@@ -3522,8 +3671,12 @@ static void update_children(ParticleSimulationData *sim)
if((sim->psys->part->type == PART_HAIR) && (sim->psys->flag & PSYS_HAIR_DONE)==0)
/* don't generate children while growing hair - waste of time */
psys_free_children(sim->psys);
- else if(sim->psys->part->childtype && sim->psys->totchild != get_psys_tot_child(sim->scene, sim->psys))
- distribute_particles(sim, PART_FROM_CHILD);
+ else if(sim->psys->part->childtype) {
+ if(sim->psys->totchild != get_psys_tot_child(sim->scene, sim->psys))
+ distribute_particles(sim, PART_FROM_CHILD);
+ else
+ ; /* Children are up to date, nothing to do. */
+ }
else
psys_free_children(sim->psys);
}
@@ -3533,7 +3686,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra)
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
PARTICLE_P;
- float disp, birthtime, dietime;
+ float disp, dietime;
BLI_srandom(psys->seed);
@@ -3548,7 +3701,6 @@ static void cached_step(ParticleSimulationData *sim, float cfra)
psys->lattice= psys_get_lattice(sim);
- birthtime = pa->time;
dietime = pa->dietime;
/* update alive status and push events */
@@ -3574,7 +3726,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra)
}
}
-static void particles_fluid_step(ParticleSimulationData *sim, int cfra)
+static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra))
{
ParticleSystem *psys = sim->psys;
if(psys->particles){
@@ -3591,26 +3743,23 @@ static void particles_fluid_step(ParticleSimulationData *sim, int cfra)
if( fluidmd && fluidmd->fss) {
FluidsimSettings *fss= fluidmd->fss;
ParticleSettings *part = psys->part;
- ParticleData *pa=0;
- char *suffix = "fluidsurface_particles_####";
- char *suffix2 = ".gz";
+ ParticleData *pa=NULL;
char filename[256];
char debugStrBuffer[256];
int curFrame = sim->scene->r.cfra -1; // warning - sync with derived mesh fsmesh loading
- int p, j, numFileParts, totpart;
+ int p, j, totpart;
int readMask, activeParts = 0, fileParts = 0;
gzFile gzf;
// XXX if(ob==G.obedit) // off...
// return;
-
+
// ok, start loading
- strcpy(filename, fss->surfdataPath);
- strcat(filename, suffix);
- BLI_path_abs(filename, G.sce);
+ BLI_snprintf(filename, sizeof(filename), "%sfluidsurface_particles_####.gz", fss->surfdataPath);
+
+ BLI_path_abs(filename, G.main->name);
BLI_path_frame(filename, curFrame, 0); // fixed #frame-no
- strcat(filename, suffix2);
-
+
gzf = gzopen(filename, "rb");
if (!gzf) {
snprintf(debugStrBuffer,256,"readFsPartData::error - Unable to open file for reading '%s' \n", filename);
@@ -3619,16 +3768,14 @@ static void particles_fluid_step(ParticleSimulationData *sim, int cfra)
}
gzread(gzf, &totpart, sizeof(totpart));
- numFileParts = totpart;
totpart = (G.rendering)?totpart:(part->disp*totpart)/100;
part->totpart= totpart;
part->sta=part->end = 1.0f;
part->lifetime = sim->scene->r.efra + 1;
- /* initialize particles */
+ /* allocate particles */
realloc_particles(sim, part->totpart);
- initialize_all_particles(sim);
// set up reading mask
readMask = fss->typeFlags;
@@ -3660,6 +3807,9 @@ static void particles_fluid_step(ParticleSimulationData *sim, int cfra)
pa->state.rot[0] = 1.0;
pa->state.rot[1] = pa->state.rot[2] = pa->state.rot[3] = 0.0;
+ pa->time = 1.f;
+ pa->dietime = sim->scene->r.efra + 1;
+ pa->lifetime = sim->scene->r.efra;
pa->alive = PARS_ALIVE;
//if(a<25) fprintf(stderr,"FSPARTICLE debug set %s , a%d = %f,%f,%f , life=%f \n", filename, a, pa->co[0],pa->co[1],pa->co[2], pa->lifetime );
} else {
@@ -3682,19 +3832,11 @@ static void particles_fluid_step(ParticleSimulationData *sim, int cfra)
#endif // DISABLE_ELBEEM
}
-static int emit_particles(ParticleSimulationData *sim, PTCacheID *pid, float cfra)
+static int emit_particles(ParticleSimulationData *sim, PTCacheID *pid, float UNUSED(cfra))
{
ParticleSystem *psys = sim->psys;
- ParticleSettings *part = psys->part;
int oldtotpart = psys->totpart;
- int totpart = oldtotpart;
-
- if(pid && psys->pointcache->flag & PTCACHE_EXTERNAL)
- totpart = pid->cache->totpoint;
- else if(part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT)
- totpart = part->grid_res*part->grid_res*part->grid_res;
- else
- totpart = psys->part->totpart;
+ int totpart = tot_particles(psys, pid);
if(totpart != oldtotpart)
realloc_particles(sim, totpart);
@@ -3712,94 +3854,84 @@ static void system_step(ParticleSimulationData *sim, float cfra)
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
PointCache *cache = psys->pointcache;
- PTCacheID pid, *use_cache = NULL;
+ PTCacheID ptcacheid, *pid = NULL;
PARTICLE_P;
- int oldtotpart;
- float disp; /*, *vg_vel= 0, *vg_tan= 0, *vg_rot= 0, *vg_size= 0; */
- int init= 0, emit= 0; //, only_children_changed= 0;
- int framenr, framedelta, startframe = 0, endframe = 100;
-
- framenr= (int)sim->scene->r.cfra;
- framedelta= framenr - cache->simframe;
+ float disp, cache_cfra = cfra; /*, *vg_vel= 0, *vg_tan= 0, *vg_rot= 0, *vg_size= 0; */
+ int startframe = 0, endframe = 100, oldtotpart = 0;
/* cache shouldn't be used for hair or "continue physics" */
if(part->type != PART_HAIR && BKE_ptcache_get_continue_physics() == 0) {
- BKE_ptcache_id_from_particles(&pid, sim->ob, psys);
- use_cache = &pid;
- }
-
- if(use_cache) {
- psys_clear_temp_pointcache(sim->psys);
+ psys_clear_temp_pointcache(psys);
/* set suitable cache range automatically */
if((cache->flag & (PTCACHE_BAKING|PTCACHE_BAKED))==0)
- psys_get_pointcache_start_end(sim->scene, sim->psys, &cache->startframe, &cache->endframe);
-
- BKE_ptcache_id_time(&pid, sim->scene, 0.0f, &startframe, &endframe, NULL);
+ psys_get_pointcache_start_end(sim->scene, psys, &cache->startframe, &cache->endframe);
- /* simulation is only active during a specific period */
- if(framenr < startframe) {
- psys_reset(psys, PSYS_RESET_CACHE_MISS);
- return;
- }
- else if(framenr > endframe) {
- framenr= endframe;
- }
+ pid = &ptcacheid;
+ BKE_ptcache_id_from_particles(pid, sim->ob, psys);
- if(framenr == startframe) {
- BKE_ptcache_id_reset(sim->scene, use_cache, PTCACHE_RESET_OUTDATED);
- BKE_ptcache_validate(cache, framenr);
+ BKE_ptcache_id_time(pid, sim->scene, 0.0f, &startframe, &endframe, NULL);
+
+ /* clear everythin on start frame */
+ if((int)cfra == startframe) {
+ BKE_ptcache_id_reset(sim->scene, pid, PTCACHE_RESET_OUTDATED);
+ BKE_ptcache_validate(cache, startframe);
cache->flag &= ~PTCACHE_REDO_NEEDED;
}
+
+ CLAMP(cache_cfra, startframe, endframe);
}
-/* 1. emit particles */
-
- /* verify if we need to reallocate */
+/* 1. emit particles and redo particles if needed */
oldtotpart = psys->totpart;
-
- emit = emit_particles(sim, use_cache, cfra);
- if(use_cache && emit > 0)
- BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, cfra);
- init = emit*emit + (psys->recalc & PSYS_RECALC_RESET);
-
- if(init) {
+ if(emit_particles(sim, pid, cfra) || psys->recalc & PSYS_RECALC_RESET) {
distribute_particles(sim, part->from);
initialize_all_particles(sim);
+ /* 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;
+
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, cfra);
}
/* 2. try to read from the cache */
- if(use_cache) {
- int cache_result = BKE_ptcache_read_cache(use_cache, cfra, sim->scene->r.frs_sec);
+ if(pid) {
+ int cache_result = BKE_ptcache_read(pid, cache_cfra);
if(ELEM(cache_result, PTCACHE_READ_EXACT, PTCACHE_READ_INTERPOLATED)) {
cached_step(sim, cfra);
update_children(sim);
psys_update_path_cache(sim, cfra);
- BKE_ptcache_validate(cache, framenr);
+ BKE_ptcache_validate(cache, (int)cache_cfra);
if(cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED)
- BKE_ptcache_write_cache(use_cache, framenr);
+ BKE_ptcache_write(pid, (int)cache_cfra);
return;
}
+ /* Cache is supposed to be baked, but no data was found so bail out */
+ else if(cache->flag & PTCACHE_BAKED) {
+ psys_reset(psys, PSYS_RESET_CACHE_MISS);
+ return;
+ }
else if(cache_result == PTCACHE_READ_OLD) {
psys->cfra = (float)cache->simframe;
cached_step(sim, psys->cfra);
}
- else if(cfra != startframe && ( /*sim->ob->id.lib ||*/ (cache->flag & PTCACHE_BAKED))) { /* 2.4x disabled lib, but this can be used in some cases, testing further - campbell */
- psys_reset(psys, PSYS_RESET_CACHE_MISS);
- return;
- }
/* if on second frame, write cache for first frame */
if(psys->cfra == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0))
- BKE_ptcache_write_cache(use_cache, startframe);
+ BKE_ptcache_write(pid, startframe);
}
else
BKE_ptcache_invalidate(cache);
@@ -3822,7 +3954,7 @@ static void system_step(ParticleSimulationData *sim, float cfra)
/* handle negative frame start at the first frame by doing
* all the steps before the first frame */
- if(framenr == startframe && part->sta < startframe)
+ if((int)cfra == startframe && part->sta < startframe)
totframesback = (startframe - (int)part->sta);
for(dframe=-totframesback; dframe<=0; dframe++) {
@@ -3837,14 +3969,13 @@ static void system_step(ParticleSimulationData *sim, float cfra)
}
/* 4. only write cache starting from second frame */
- if(use_cache) {
- BKE_ptcache_validate(cache, framenr);
- if(framenr != startframe)
- BKE_ptcache_write_cache(use_cache, framenr);
+ if(pid) {
+ BKE_ptcache_validate(cache, (int)cache_cfra);
+ if((int)cache_cfra != startframe)
+ BKE_ptcache_write(pid, (int)cache_cfra);
}
- if(init)
- update_children(sim);
+ update_children(sim);
/* cleanup */
if(psys->lattice){
@@ -3922,6 +4053,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;
@@ -3931,7 +4064,7 @@ static void fluid_default_settings(ParticleSettings *part){
fluid->buoyancy = 0.f;
}
-static void psys_changed_physics(ParticleSimulationData *sim)
+static void psys_prepare_physics(ParticleSimulationData *sim)
{
ParticleSettings *part = sim->psys->part;
@@ -3970,7 +4103,7 @@ static void psys_changed_physics(ParticleSimulationData *sim)
static int hair_needs_recalc(ParticleSystem *psys)
{
if(!(psys->flag & PSYS_EDITED) && (!psys->edit || !psys->edit->edited) &&
- ((psys->flag & PSYS_HAIR_DONE)==0 || psys->recalc & PSYS_RECALC_RESET)) {
+ ((psys->flag & PSYS_HAIR_DONE)==0 || psys->recalc & PSYS_RECALC_RESET || (psys->part->flag & PART_HAIR_REGROW && !psys->edit))) {
return 1;
}
@@ -3981,7 +4114,7 @@ static int hair_needs_recalc(ParticleSystem *psys)
* then advances in to actual particle calculations depending on particle type */
void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
{
- ParticleSimulationData sim = {scene, ob, psys, NULL, NULL};
+ ParticleSimulationData sim= {0};
ParticleSettings *part = psys->part;
float cfra;
@@ -3992,6 +4125,10 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
return;
cfra= BKE_curframe(scene);
+
+ sim.scene= scene;
+ sim.ob= ob;
+ sim.psys= psys;
sim.psmd= psys_get_modifier(ob, psys);
/* system was already updated from modifier stack */
@@ -4010,19 +4147,34 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
if(psys->recalc & PSYS_RECALC_TYPE)
psys_changed_type(&sim);
- else if(psys->recalc & PSYS_RECALC_PHYS)
- psys_changed_physics(&sim);
+
+ if(psys->recalc & PSYS_RECALC_RESET)
+ psys->totunexist = 0;
+
+ /* setup necessary physics type dependent additional data if it doesn't yet exist */
+ psys_prepare_physics(&sim);
switch(part->type) {
case PART_HAIR:
{
+ /* nothing to do so bail out early */
+ if(psys->totpart == 0 && part->totpart == 0) {
+ psys_free_path_cache(psys, NULL);
+ free_hair(ob, psys, 0);
+ }
/* (re-)create hair */
- if(hair_needs_recalc(psys)) {
+ else if(hair_needs_recalc(psys)) {
float hcfra=0.0f;
int i, recalc = psys->recalc;
free_hair(ob, psys, 0);
+ if(psys->edit && psys->free_edit) {
+ psys->free_edit(psys->edit);
+ psys->edit = NULL;
+ psys->free_edit = NULL;
+ }
+
/* first step is negative so particles get killed and reset */
psys->cfra= 1.0f;
@@ -4038,6 +4190,8 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
psys->flag |= PSYS_HAIR_DONE;
psys->recalc = recalc;
}
+ else if(psys->flag & PSYS_EDITED)
+ psys->flag |= PSYS_HAIR_DONE;
if(psys->flag & PSYS_HAIR_DONE)
hair_step(&sim, cfra);
@@ -4055,12 +4209,13 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
case PART_PHYS_KEYED:
{
PARTICLE_P;
+ float disp = (float)psys_get_current_display_percentage(psys)/100.0f;
/* Particles without dynamics haven't been reset yet because they don't use pointcache */
if(psys->recalc & PSYS_RECALC_RESET)
psys_reset(psys, PSYS_RESET_ALL);
- if(emit_particles(&sim, NULL, cfra)) {
+ if(emit_particles(&sim, NULL, cfra) || (psys->recalc & PSYS_RECALC_RESET)) {
free_keyed_keys(psys);
distribute_particles(&sim, part->from);
initialize_all_particles(&sim);
@@ -4072,6 +4227,11 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
pa->size *= 1.0f - part->randsize * PSYS_FRAND(p + 1);
reset_particle(&sim, pa, 0.0, cfra);
+
+ if(PSYS_FRAND(p) > disp)
+ pa->flag |= PARS_NO_DISP;
+ else
+ pa->flag &= ~PARS_NO_DISP;
}
if(part->phystype == PART_PHYS_KEYED) {