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.c300
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),