diff options
Diffstat (limited to 'source/blender/blenkernel/intern/particle_system.c')
-rw-r--r-- | source/blender/blenkernel/intern/particle_system.c | 300 |
1 files changed, 212 insertions, 88 deletions
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index a3e61bb3681..a859de40910 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -40,10 +40,6 @@ #include <math.h> #include <string.h> -#ifdef _OPENMP -#include <omp.h> -#endif - #include "MEM_guardedalloc.h" #include "DNA_anim_types.h" @@ -76,7 +72,9 @@ #include "BKE_boids.h" #include "BKE_cdderivedmesh.h" #include "BKE_collision.h" +#include "BKE_colortools.h" #include "BKE_effect.h" +#include "BKE_library_query.h" #include "BKE_particle.h" #include "BKE_global.h" @@ -310,7 +308,7 @@ int psys_get_tot_child(Scene *scene, ParticleSystem *psys) /* Distribution */ /************************************************/ -void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys) +void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deformed, ParticleSystem *psys) { /* use for building derived mesh mapping info: * @@ -323,13 +321,13 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys) PARTICLE_P; /* CACHE LOCATIONS */ - if (!dm->deformedOnly) { + if (!dm_final->deformedOnly) { /* Will use later to speed up subsurf/derivedmesh */ LinkNode *node, *nodedmelem, **nodearray; int totdmelem, totelem, i, *origindex, *origindex_poly = NULL; if (psys->part->from == PART_FROM_VERT) { - totdmelem= dm->getNumVerts(dm); + totdmelem= dm_final->getNumVerts(dm_final); if (use_modifier_stack) { totelem= totdmelem; @@ -337,11 +335,11 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys) } else { totelem= me->totvert; - origindex= dm->getVertDataArray(dm, CD_ORIGINDEX); + origindex= dm_final->getVertDataArray(dm_final, CD_ORIGINDEX); } } else { /* FROM_FACE/FROM_VOLUME */ - totdmelem= dm->getNumTessFaces(dm); + totdmelem= dm_final->getNumTessFaces(dm_final); if (use_modifier_stack) { totelem= totdmelem; @@ -349,20 +347,20 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys) origindex_poly= NULL; } else { - totelem= me->totpoly; - origindex= dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + totelem = dm_deformed->getNumTessFaces(dm_deformed); + origindex = dm_final->getTessFaceDataArray(dm_final, CD_ORIGINDEX); /* for face lookups we need the poly origindex too */ - origindex_poly= dm->getPolyDataArray(dm, CD_ORIGINDEX); + origindex_poly= dm_final->getPolyDataArray(dm_final, CD_ORIGINDEX); if (origindex_poly == NULL) { origindex= NULL; } } } - + nodedmelem= MEM_callocN(sizeof(LinkNode)*totdmelem, "psys node elems"); nodearray= MEM_callocN(sizeof(LinkNode *)*totelem, "psys node array"); - + for (i=0, node=nodedmelem; i<totdmelem; i++, node++) { int origindex_final; node->link = SET_INT_IN_POINTER(i); @@ -391,7 +389,7 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys) } } } - + /* cache the verts/faces! */ LOOP_PARTICLES { if (pa->num < 0) { @@ -413,9 +411,7 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys) pa->num_dmcache = DMCACHE_NOTFOUND; } else { /* FROM_FACE/FROM_VOLUME */ - /* 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); + pa->num_dmcache = psys_particle_dm_face_lookup(dm_final, dm_deformed, pa->num, pa->fuv, nodearray); } } } @@ -428,8 +424,9 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys) * should know to use the num or num_dmcache, set the num_dmcache to * an invalid value, just in case */ - LOOP_PARTICLES + LOOP_PARTICLES { pa->num_dmcache = DMCACHE_NOTFOUND; + } } } @@ -438,7 +435,7 @@ void psys_thread_context_init(ParticleThreadContext *ctx, ParticleSimulationData { memset(ctx, 0, sizeof(ParticleThreadContext)); ctx->sim = *sim; - ctx->dm = ctx->sim.psmd->dm; + ctx->dm = ctx->sim.psmd->dm_final; ctx->ma = give_current_material(sim->ob, sim->psys->part->omat); } @@ -515,6 +512,13 @@ void psys_thread_context_free(ParticleThreadContext *ctx) if (ctx->seams) MEM_freeN(ctx->seams); //if (ctx->vertpart) MEM_freeN(ctx->vertpart); BLI_kdtree_free(ctx->tree); + + if (ctx->clumpcurve != NULL) { + curvemapping_free(ctx->clumpcurve); + } + if (ctx->roughcurve != NULL) { + curvemapping_free(ctx->roughcurve); + } } static void initialize_particle_texture(ParticleSimulationData *sim, ParticleData *pa, int p) @@ -893,7 +897,7 @@ void psys_get_birth_coords(ParticleSimulationData *sim, ParticleData *pa, Partic float q_imat[4]; mat4_to_quat(q_obmat, ob->obmat); - invert_qt_qt(q_imat, q_obmat); + invert_qt_qt_normalized(q_imat, q_obmat); if (part->rotmode != PART_ROT_NOR_TAN) { @@ -1214,8 +1218,8 @@ void psys_get_pointcache_start_end(Scene *scene, ParticleSystem *psys, int *sfra { ParticleSettings *part = psys->part; - *sfra = MAX2(1, (int)part->sta); - *efra = MIN2((int)(part->end + part->lifetime + 1.0f), MAX2(scene->r.pefra, scene->r.efra)); + *sfra = max_ii(1, (int)part->sta); + *efra = min_ii((int)(part->end + part->lifetime + 1.0f), max_ii(scene->r.pefra, scene->r.efra)); } /************************************************/ @@ -1580,13 +1584,15 @@ static void sph_evaluate_func(BVHTree *tree, ParticleSystem **psys, float co[3], } } } -static void sph_density_accum_cb(void *userdata, int index, float squared_dist) +static void sph_density_accum_cb(void *userdata, int index, const float co[3], float squared_dist) { SPHRangeData *pfr = (SPHRangeData *)userdata; ParticleData *npa = pfr->npsys->particles + index; float q; float dist; + UNUSED_VARS(co); + if (npa == pfr->pa || squared_dist < FLT_EPSILON) return; @@ -1745,7 +1751,6 @@ static void sph_force_cb(void *sphdata_v, ParticleKey *state, float *force, floa temp_spring.delete_flag = 0; /* sph_spring_add is not thread-safe. - z0r */ -#pragma omp critical sph_spring_add(psys[0], &temp_spring); } } @@ -1764,7 +1769,7 @@ static void sph_force_cb(void *sphdata_v, ParticleKey *state, float *force, floa sphdata->pass++; } -static void sphclassical_density_accum_cb(void *userdata, int index, float UNUSED(squared_dist)) +static void sphclassical_density_accum_cb(void *userdata, int index, const float co[3], float UNUSED(squared_dist)) { SPHRangeData *pfr = (SPHRangeData *)userdata; ParticleData *npa = pfr->npsys->particles + index; @@ -1776,7 +1781,7 @@ static void sphclassical_density_accum_cb(void *userdata, int index, float UNUSE /* Exclude particles that are more than 2h away. Can't use squared_dist here * because it is not accurate enough. Use current state, i.e. the output of * basic_integrate() - z0r */ - sub_v3_v3v3(vec, npa->state.co, pfr->pa->state.co); + sub_v3_v3v3(vec, npa->state.co, co); rij = len_v3(vec); rij_h = rij / pfr->h; if (rij_h > 2.0f) @@ -1795,7 +1800,7 @@ static void sphclassical_density_accum_cb(void *userdata, int index, float UNUSE pfr->data[1] += q / npa->sphdensity; } -static void sphclassical_neighbour_accum_cb(void *userdata, int index, float UNUSED(squared_dist)) +static void sphclassical_neighbour_accum_cb(void *userdata, int index, const float co[3], float UNUSED(squared_dist)) { SPHRangeData *pfr = (SPHRangeData *)userdata; ParticleData *npa = pfr->npsys->particles + index; @@ -1808,7 +1813,7 @@ static void sphclassical_neighbour_accum_cb(void *userdata, int index, float UNU /* Exclude particles that are more than 2h away. Can't use squared_dist here * because it is not accurate enough. Use current state, i.e. the output of * basic_integrate() - z0r */ - sub_v3_v3v3(vec, npa->state.co, pfr->pa->state.co); + sub_v3_v3v3(vec, npa->state.co, co); rij = len_v3(vec); rij_h = rij / pfr->h; if (rij_h > 2.0f) @@ -1938,7 +1943,7 @@ static void sphclassical_calc_dens(ParticleData *pa, float UNUSED(dfra), SPHData pfr.mass = sphdata->mass; sph_evaluate_func( NULL, psys, pa->state.co, &pfr, interaction_radius, sphclassical_density_accum_cb); - pa->sphdensity = MIN2(MAX2(data[0], fluid->rest_density * 0.9f), fluid->rest_density * 1.1f); + pa->sphdensity = min_ff(max_ff(data[0], fluid->rest_density * 0.9f), fluid->rest_density * 1.1f); } void psys_sph_init(ParticleSimulationData *sim, SPHData *sphdata) @@ -3053,7 +3058,7 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int pa->hair_index = hair_index; use_hair = psys_hair_use_simulation(pa, max_length); - psys_mat_hair_to_object(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat); + psys_mat_hair_to_object(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat); mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat); normalize_m4(root_mat); @@ -3208,7 +3213,7 @@ static void hair_step(ParticleSimulationData *sim, float cfra) if (psys->recalc & PSYS_RECALC_RESET) { /* need this for changing subsurf levels */ - psys_calc_dmcache(sim->ob, sim->psmd->dm, psys); + psys_calc_dmcache(sim->ob, sim->psmd->dm_final, sim->psmd->dm_deformed, psys); if (psys->clmd) cloth_free_modifier(psys->clmd); @@ -3255,7 +3260,7 @@ static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra)) if (pa->totkey) { sub_v3_v3(key->co, root->co); - psys_vec_rot_to_face(sim->psmd->dm, pa, key->co); + psys_vec_rot_to_face(sim->psmd->dm_final, pa, key->co); } key->time = pa->state.time; @@ -3286,15 +3291,20 @@ static const float TIMESTEP_EXPANSION_TOLERANCE = 1.5f; * step, after the velocity has been updated. element_size defines the scale of * the simulation, and is typically the distance to neighboring particles. */ static void update_courant_num(ParticleSimulationData *sim, ParticleData *pa, - float dtime, SPHData *sphdata) + float dtime, SPHData *sphdata, SpinLock *spin) { float relative_vel[3]; - float speed; sub_v3_v3v3(relative_vel, pa->prev_state.vel, sphdata->flow); - speed = len_v3(relative_vel); - if (sim->courant_num < speed * dtime / sphdata->element_size) - sim->courant_num = speed * dtime / sphdata->element_size; + + const float courant_num = len_v3(relative_vel) * dtime / sphdata->element_size; + if (sim->courant_num < courant_num) { + BLI_spin_lock(spin); + if (sim->courant_num < courant_num) { + sim->courant_num = courant_num; + } + BLI_spin_unlock(spin); + } } static float get_base_time_step(ParticleSettings *part) { @@ -3334,6 +3344,116 @@ static float update_timestep(ParticleSystem *psys, ParticleSimulationData *sim, /************************************************/ /* System Core */ /************************************************/ + +typedef struct DynamicStepSolverTaskData { + ParticleSimulationData *sim; + + float cfra; + float timestep; + float dtime; + + SpinLock spin; +} DynamicStepSolverTaskData; + +static void dynamics_step_sph_ddr_task_cb_ex( + void *userdata, void *userdata_chunk, const int p, const int UNUSED(thread_id)) +{ + DynamicStepSolverTaskData *data = userdata; + ParticleSimulationData *sim = data->sim; + ParticleSystem *psys = sim->psys; + ParticleSettings *part = psys->part; + + SPHData *sphdata = userdata_chunk; + + ParticleData *pa; + + if ((pa = psys->particles + p)->state.time <= 0.0f) { + return; + } + + /* do global forces & effectors */ + basic_integrate(sim, p, pa->state.time, data->cfra); + + /* actual fluids calculations */ + sph_integrate(sim, pa, pa->state.time, sphdata); + + if (sim->colliders) + collision_check(sim, p, pa->state.time, data->cfra); + + /* SPH particles are not physical particles, just interpolation + * particles, thus rotation has not a direct sense for them */ + basic_rotate(part, pa, pa->state.time, data->timestep); + + if (part->time_flag & PART_TIME_AUTOSF) { + update_courant_num(sim, pa, data->dtime, sphdata, &data->spin); + } +} + +static void dynamics_step_sph_classical_basic_integrate_task_cb_ex( + void *userdata, void *UNUSED(userdata_chunk), const int p, const int UNUSED(thread_id)) +{ + DynamicStepSolverTaskData *data = userdata; + ParticleSimulationData *sim = data->sim; + ParticleSystem *psys = sim->psys; + + ParticleData *pa; + + if ((pa = psys->particles + p)->state.time <= 0.0f) { + return; + } + + basic_integrate(sim, p, pa->state.time, data->cfra); +} + +static void dynamics_step_sph_classical_calc_density_task_cb_ex( + void *userdata, void *userdata_chunk, const int p, const int UNUSED(thread_id)) +{ + DynamicStepSolverTaskData *data = userdata; + ParticleSimulationData *sim = data->sim; + ParticleSystem *psys = sim->psys; + + SPHData *sphdata = userdata_chunk; + + ParticleData *pa; + + if ((pa = psys->particles + p)->state.time <= 0.0f) { + return; + } + + sphclassical_calc_dens(pa, pa->state.time, sphdata); +} + +static void dynamics_step_sph_classical_integrate_task_cb_ex( + void *userdata, void *userdata_chunk, const int p, const int UNUSED(thread_id)) +{ + DynamicStepSolverTaskData *data = userdata; + ParticleSimulationData *sim = data->sim; + ParticleSystem *psys = sim->psys; + ParticleSettings *part = psys->part; + + SPHData *sphdata = userdata_chunk; + + ParticleData *pa; + + if ((pa = psys->particles + p)->state.time <= 0.0f) { + return; + } + + /* actual fluids calculations */ + sph_integrate(sim, pa, pa->state.time, sphdata); + + if (sim->colliders) + collision_check(sim, p, pa->state.time, data->cfra); + + /* SPH particles are not physical particles, just interpolation + * particles, thus rotation has not a direct sense for them */ + basic_rotate(part, pa, pa->state.time, data->timestep); + + if (part->time_flag & PART_TIME_AUTOSF) { + update_courant_num(sim, pa, data->dtime, sphdata, &data->spin); + } +} + /* unbaked particles are calculated dynamically */ static void dynamics_step(ParticleSimulationData *sim, float cfra) { @@ -3392,8 +3512,10 @@ static void dynamics_step(ParticleSimulationData *sim, float 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); + ParticleSystem *psys_target = psys_get_target_system(sim->ob, pt); + if (psys_target && psys_target != psys) { + psys_update_particle_tree(psys_target, cfra); + } } break; } @@ -3488,34 +3610,23 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) case PART_PHYS_FLUID: { SPHData sphdata; - ParticleSettings *part = sim->psys->part; psys_sph_init(sim, &sphdata); + DynamicStepSolverTaskData task_data = { + .sim = sim, .cfra = cfra, .timestep = timestep, .dtime = dtime, + }; + + BLI_spin_init(&task_data.spin); + if (part->fluid->solver == SPH_SOLVER_DDR) { /* Apply SPH forces using double-density relaxation algorithm * (Clavat et. al.) */ -#pragma omp parallel for firstprivate (sphdata) private (pa) schedule(dynamic,5) - LOOP_DYNAMIC_PARTICLES { - /* do global forces & effectors */ - basic_integrate(sim, p, pa->state.time, cfra); - /* actual fluids calculations */ - sph_integrate(sim, pa, pa->state.time, &sphdata); - - if (sim->colliders) - collision_check(sim, p, pa->state.time, cfra); - - /* SPH particles are not physical particles, just interpolation - * particles, thus rotation has not a direct sense for them */ - basic_rotate(part, pa, pa->state.time, timestep); - -#pragma omp critical - if (part->time_flag & PART_TIME_AUTOSF) - update_courant_num(sim, pa, dtime, &sphdata); - } + BLI_task_parallel_range_ex( + 0, psys->totpart, &task_data, &sphdata, sizeof(sphdata), + dynamics_step_sph_ddr_task_cb_ex, psys->totpart > 100, true); sph_springs_modify(psys, timestep); - } else { /* SPH_SOLVER_CLASSICAL */ @@ -3523,36 +3634,25 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) * and Monaghan). Note that, unlike double-density relaxation, * this algorithm is separated into distinct loops. */ -#pragma omp parallel for private (pa) schedule(dynamic,5) - LOOP_DYNAMIC_PARTICLES { - basic_integrate(sim, p, pa->state.time, cfra); - } + BLI_task_parallel_range_ex( + 0, psys->totpart, &task_data, NULL, 0, + dynamics_step_sph_classical_basic_integrate_task_cb_ex, psys->totpart > 100, true); /* calculate summation density */ -#pragma omp parallel for firstprivate (sphdata) private (pa) schedule(dynamic,5) - LOOP_DYNAMIC_PARTICLES { - sphclassical_calc_dens(pa, pa->state.time, &sphdata); - } + /* Note that we could avoid copying sphdata for each thread here (it's only read here), + * but doubt this would gain us anything except confusion... */ + BLI_task_parallel_range_ex( + 0, psys->totpart, &task_data, &sphdata, sizeof(sphdata), + dynamics_step_sph_classical_calc_density_task_cb_ex, psys->totpart > 100, true); /* do global forces & effectors */ -#pragma omp parallel for firstprivate (sphdata) private (pa) schedule(dynamic,5) - LOOP_DYNAMIC_PARTICLES { - /* actual fluids calculations */ - sph_integrate(sim, pa, pa->state.time, &sphdata); - - if (sim->colliders) - collision_check(sim, p, pa->state.time, cfra); - - /* SPH particles are not physical particles, just interpolation - * particles, thus rotation has not a direct sense for them */ - basic_rotate(part, pa, pa->state.time, timestep); - -#pragma omp critical - if (part->time_flag & PART_TIME_AUTOSF) - update_courant_num(sim, pa, dtime, &sphdata); - } + BLI_task_parallel_range_ex( + 0, psys->totpart, &task_data, &sphdata, sizeof(sphdata), + dynamics_step_sph_classical_integrate_task_cb_ex, psys->totpart > 100, true); } + BLI_spin_end(&task_data.spin); + psys_sph_finalise(&sphdata); break; } @@ -3780,8 +3880,8 @@ static void system_step(ParticleSimulationData *sim, float cfra) BKE_ptcache_id_time(pid, sim->scene, 0.0f, &startframe, &endframe, NULL); - /* clear everythin on start frame */ - if (cfra == startframe) { + /* clear everything on start frame, or when psys needs full reset! */ + if ((cfra == startframe) || (psys->recalc & PSYS_RECALC_RESET)) { BKE_ptcache_id_reset(sim->scene, pid, PTCACHE_RESET_OUTDATED); BKE_ptcache_validate(cache, startframe); cache->flag &= ~PTCACHE_REDO_NEEDED; @@ -4064,11 +4164,11 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) return; } - if (!sim.psmd->dm) + if (!sim.psmd->dm_final) return; if (part->from != PART_FROM_VERT) { - DM_ensure_tessface(sim.psmd->dm); + DM_ensure_tessface(sim.psmd->dm_final); } /* execute drivers only, as animation has already been done */ @@ -4209,6 +4309,30 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) invert_m4_m4(psys->imat, ob->obmat); } +/* ID looper */ + +void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func, void *userdata) +{ + ParticleTarget *pt; + + func(psys, (ID **)&psys->part, userdata, IDWALK_USER | IDWALK_NEVER_NULL); + func(psys, (ID **)&psys->target_ob, userdata, IDWALK_NOP); + func(psys, (ID **)&psys->parent, userdata, IDWALK_NOP); + + for (pt = psys->targets.first; pt; pt = pt->next) { + func(psys, (ID **)&pt->ob, userdata, IDWALK_NOP); + } + + if (psys->part->phystype == PART_PHYS_BOIDS) { + ParticleData *pa; + int p; + + for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) { + func(psys, (ID **)&pa->boid->ground, userdata, IDWALK_NOP); + } + } +} + /* **** Depsgraph evaluation **** */ void BKE_particle_system_eval(EvaluationContext *UNUSED(eval_ctx), |