Depsgraph: cache effector relations, for performance and stability.

To find all effectors in the scene, we need to loop over all objects.
Doing this during depsgraph evaluation caused crashes because not all
objects are guaranteed to be evaluated yet.

To fix this, we now cache the relations as part of the dependency graph
build. As a bonus this also makes evaluation faster for big scenes,
since looping over all objects for each particle system is slow.

Fixes T55156.
This commit is contained in:
Brecht Van Lommel 2018-06-21 19:45:39 +02:00
parent 79615c5adb
commit cc4dc2dce2
19 changed files with 432 additions and 228 deletions

@ -45,6 +45,7 @@ struct ParticleSimulationData;
struct ParticleData;
struct ParticleKey;
struct Depsgraph;
struct ViewLayer;
struct EffectorWeights *BKE_add_effector_weights(struct Collection *collection);
struct PartDeflect *object_add_collision_fields(int type);
@ -111,13 +112,36 @@ typedef struct EffectorCache {
int flag;
} EffectorCache;
typedef struct EffectorRelation {
struct EffectorRelation *next, *prev;
struct Object *ob;
struct ParticleSystem *psys;
struct PartDeflect *pd;
} EffectorRelation;
void free_partdeflect(struct PartDeflect *pd);
struct ListBase *pdInitEffectors(
struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob_src, struct ParticleSystem *psys_src,
struct EffectorWeights *weights, bool for_simulation);
void pdEndEffectors(struct ListBase **effectors);
void pdPrecalculateEffectors(struct Depsgraph *depsgraph, struct ListBase *effectors);
void pdDoEffectors(struct ListBase *effectors, struct ListBase *colliders, struct EffectorWeights *weights, struct EffectedPoint *point, float *force, float *impulse);
struct ListBase *BKE_effector_relations_create(
struct Depsgraph *depsgraph,
struct ViewLayer *view_layer,
struct Collection *collection);
void BKE_effector_relations_free(struct ListBase *lb);
struct ListBase *BKE_effectors_create(
struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_src,
struct ParticleSystem *psys_src,
struct EffectorWeights *weights);
void BKE_effectors_apply(
struct ListBase *effectors,
struct ListBase *colliders,
struct EffectorWeights *weights,
struct EffectedPoint *point,
float *force,
float *impulse);
void BKE_effectors_free(struct ListBase *lb);
void pd_point_from_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, struct EffectedPoint *point);
void pd_point_from_loc(struct Scene *scene, float *loc, float *vel, int index, struct EffectedPoint *point);

@ -1265,7 +1265,7 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa)
/* account for effectors */
pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
pdDoEffectors(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL);
BKE_effectors_apply(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL);
if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
float length = normalize_v3(force);

@ -375,7 +375,7 @@ static int do_step_cloth(struct Depsgraph *depsgraph, Scene *scene, Object *ob,
mul_m4_v3(ob->obmat, verts->xconst);
}
effectors = pdInitEffectors(depsgraph, scene, ob, NULL, clmd->sim_parms->effector_weights, true);
effectors = BKE_effectors_create(depsgraph, scene, ob, NULL, clmd->sim_parms->effector_weights);
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH )
cloth_update_verts ( ob, clmd, result );
@ -395,7 +395,7 @@ static int do_step_cloth(struct Depsgraph *depsgraph, Scene *scene, Object *ob,
// TIMEIT_END(cloth_step)
pdEndEffectors(&effectors);
BKE_effectors_free(effectors);
// printf ( "%f\n", ( float ) tval() );

@ -4886,7 +4886,7 @@ static void dynamic_paint_prepare_effect_cb(
EffectedPoint epoint;
pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
epoint.vel_to_sec = 1.0f;
pdDoEffectors(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
BKE_effectors_apply(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
}
/* if global gravity is enabled, add it too */
@ -4926,7 +4926,7 @@ static int dynamicPaint_prepareEffectStep(
/* Init force data if required */
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
ListBase *effectors = pdInitEffectors(depsgraph, scene, ob, NULL, surface->effector_weights, true);
ListBase *effectors = BKE_effectors_create(depsgraph, scene, ob, NULL, surface->effector_weights);
/* allocate memory for force data (dir vector + strength) */
*force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces");
@ -4950,7 +4950,7 @@ static int dynamicPaint_prepareEffectStep(
}
average_force /= sData->total_points;
}
pdEndEffectors(&effectors);
BKE_effectors_free(effectors);
}
/* Get number of required steps using average point distance

@ -74,6 +74,7 @@
#include "BKE_smoke.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_physics.h"
#include "DEG_depsgraph_query.h"
#include "RE_render_ext.h"
@ -135,9 +136,8 @@ PartDeflect *object_add_collision_fields(int type)
return pd;
}
/* ***************** PARTICLES ***************** */
/************************ PARTICLES ***************************/
/* -------------------------- Effectors ------------------ */
void free_partdeflect(PartDeflect *pd)
{
if (!pd)
@ -149,114 +149,7 @@ void free_partdeflect(PartDeflect *pd)
MEM_freeN(pd);
}
static EffectorCache *new_effector_cache(struct Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys, PartDeflect *pd)
{
EffectorCache *eff = MEM_callocN(sizeof(EffectorCache), "EffectorCache");
eff->depsgraph = depsgraph;
eff->scene = scene;
eff->ob = ob;
eff->psys = psys;
eff->pd = pd;
eff->frame = -1;
return eff;
}
static void add_object_to_effectors(ListBase **effectors, struct Depsgraph *depsgraph, Scene *scene, EffectorWeights *weights, Object *ob, Object *ob_src, bool for_simulation)
{
EffectorCache *eff = NULL;
if ( ob == ob_src )
return;
if (for_simulation) {
if (weights->weight[ob->pd->forcefield] == 0.0f )
return;
if (ob->pd->shape == PFIELD_SHAPE_POINTS && !ob->derivedFinal )
return;
}
if (*effectors == NULL)
*effectors = MEM_callocN(sizeof(ListBase), "effectors list");
eff = new_effector_cache(depsgraph, scene, ob, NULL, ob->pd);
/* make sure imat is up to date */
invert_m4_m4(ob->imat, ob->obmat);
BLI_addtail(*effectors, eff);
}
static void add_particles_to_effectors(ListBase **effectors, struct Depsgraph *depsgraph, Scene *scene, EffectorWeights *weights, Object *ob, ParticleSystem *psys, ParticleSystem *psys_src, bool for_simulation)
{
ParticleSettings *part= psys->part;
const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
if ( !psys_check_enabled(ob, psys, for_render) )
return;
if ( psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0)
return;
if ( part->pd && part->pd->forcefield && (!for_simulation || weights->weight[part->pd->forcefield] != 0.0f)) {
if (*effectors == NULL)
*effectors = MEM_callocN(sizeof(ListBase), "effectors list");
BLI_addtail(*effectors, new_effector_cache(depsgraph, scene, ob, psys, part->pd));
}
if (part->pd2 && part->pd2->forcefield && (!for_simulation || weights->weight[part->pd2->forcefield] != 0.0f)) {
if (*effectors == NULL)
*effectors = MEM_callocN(sizeof(ListBase), "effectors list");
BLI_addtail(*effectors, new_effector_cache(depsgraph, scene, ob, psys, part->pd2));
}
}
/* returns ListBase handle with objects taking part in the effecting */
ListBase *pdInitEffectors(
struct Depsgraph *depsgraph, Scene *scene, Object *ob_src, ParticleSystem *psys_src,
EffectorWeights *weights, bool for_simulation)
{
/* For dependency building, we get objects from the scene.
* For simulation, we get objects from the depsgraph. */
Base *base = BKE_collection_or_layer_objects((for_simulation) ? depsgraph : NULL, scene, NULL, weights->group);
ListBase *effectors = NULL;
for (; base; base = base->next) {
if (base->object->pd && base->object->pd->forcefield) {
add_object_to_effectors(&effectors, depsgraph, scene, weights, base->object, ob_src, for_simulation);
}
if (base->object->particlesystem.first) {
ParticleSystem *psys= base->object->particlesystem.first;
for (; psys; psys=psys->next) {
add_particles_to_effectors(&effectors, depsgraph, scene, weights, base->object, psys, psys_src, for_simulation);
}
}
}
if (for_simulation) {
pdPrecalculateEffectors(depsgraph, effectors);
}
return effectors;
}
void pdEndEffectors(ListBase **effectors)
{
if (*effectors) {
EffectorCache *eff = (*effectors)->first;
for (; eff; eff=eff->next) {
if (eff->guide_data)
MEM_freeN(eff->guide_data);
}
BLI_freelistN(*effectors);
MEM_freeN(*effectors);
*effectors = NULL;
}
}
/******************** EFFECTOR RELATIONS ***********************/
static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *eff)
{
@ -299,12 +192,144 @@ static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *ef
}
}
void pdPrecalculateEffectors(struct Depsgraph *depsgraph, ListBase *effectors)
static void add_effector_relation(ListBase *relations, Object *ob, ParticleSystem *psys, PartDeflect *pd)
{
if (effectors) {
EffectorCache *eff = effectors->first;
for (; eff; eff=eff->next)
EffectorRelation *relation = MEM_callocN(sizeof(EffectorRelation), "EffectorRelation");
relation->ob = ob;
relation->psys = psys;
relation->pd = pd;
BLI_addtail(relations, relation);
}
static void add_effector_evaluation(ListBase **effectors, Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys, PartDeflect *pd)
{
if (*effectors == NULL) {
*effectors = MEM_callocN(sizeof(ListBase), "effector effectors");
}
EffectorCache *eff = MEM_callocN(sizeof(EffectorCache), "EffectorCache");
eff->depsgraph = depsgraph;
eff->scene = scene;
eff->ob = ob;
eff->psys = psys;
eff->pd = pd;
eff->frame = -1;
BLI_addtail(*effectors, eff);
precalculate_effector(depsgraph, eff);
}
/* Create list of effector relations in the collection or entire scene.
* This is used by the depsgraph to build relations, as well as faster
* lookup of effectors during evaluation. */
ListBase *BKE_effector_relations_create(
Depsgraph *depsgraph,
ViewLayer *view_layer,
Collection *collection)
{
const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
Base *base = BKE_collection_or_layer_objects(NULL, NULL, view_layer, collection);
ListBase *relations = MEM_callocN(sizeof(ListBase), "effector relations");
for (; base; base = base->next) {
Object *ob = base->object;
if (ob->pd && ob->pd->forcefield) {
add_effector_relation(relations, ob, NULL, ob->pd);
}
for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
ParticleSettings *part = psys->part;
if (psys_check_enabled(ob, psys, for_render)) {
if (part->pd && part->pd->forcefield) {
add_effector_relation(relations, ob, psys, part->pd);
}
if (part->pd2 && part->pd2->forcefield) {
add_effector_relation(relations, ob, psys, part->pd2);
}
}
}
}
return relations;
}
void BKE_effector_relations_free(ListBase *lb)
{
if (lb) {
BLI_freelistN(lb);
MEM_freeN(lb);
}
}
/* Create effective list of effectors from relations built beforehand. */
ListBase *BKE_effectors_create(
Depsgraph *depsgraph,
Scene *scene,
Object *ob_src,
ParticleSystem *psys_src,
EffectorWeights *weights)
{
ListBase *relations = DEG_get_effector_relations(depsgraph, weights->group);
ListBase *effectors = NULL;
if (!relations) {
return NULL;
}
for (EffectorRelation *relation = relations->first; relation; relation = relation->next) {
/* Get evaluated object. */
Object *ob = (Object*)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
if (relation->psys) {
/* Get evaluated particle system. */
ParticleSystem *psys = BLI_findstring(&ob->particlesystem,
relation->psys->name, offsetof(ParticleSystem, name));
ParticleSettings *part = psys->part;
if (psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0) {
continue;
}
PartDeflect *pd = (relation->pd == relation->psys->part->pd) ? part->pd : part->pd2;
if (weights->weight[pd->forcefield] == 0.0f) {
continue;
}
add_effector_evaluation(&effectors, depsgraph, scene, ob, psys, pd);
}
else {
/* Object effector. */
if (ob == ob_src) {
continue;
}
else if (weights->weight[ob->pd->forcefield] == 0.0f) {
continue;
}
else if (ob->pd->shape == PFIELD_SHAPE_POINTS && !ob->derivedFinal) {
continue;
}
add_effector_evaluation(&effectors, depsgraph, scene, ob, NULL, ob->pd);
}
}
return effectors;
}
void BKE_effectors_free(ListBase *lb)
{
if (lb) {
for (EffectorCache *eff = lb->first; eff; eff = eff->next) {
if (eff->guide_data) {
MEM_freeN(eff->guide_data);
}
}
BLI_freelistN(lb);
MEM_freeN(lb);
}
}
@ -963,7 +988,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
}
}
/* -------- pdDoEffectors() --------
/* -------- BKE_effectors_apply() --------
* generic force/speed system, now used for particles and softbodies
* scene = scene where it runs in, for time and stuff
* lb = listbase with objects that take part in effecting
@ -976,7 +1001,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
* flags = only used for softbody wind now
* guide = old speed of particle
*/
void pdDoEffectors(ListBase *effectors, ListBase *colliders, EffectorWeights *weights, EffectedPoint *point, float *force, float *impulse)
void BKE_effectors_apply(ListBase *effectors, ListBase *colliders, EffectorWeights *weights, EffectedPoint *point, float *force, float *impulse)
{
/*
* Modifies the force on a particle according to its

@ -641,7 +641,7 @@ void psys_free(Object *ob, ParticleSystem *psys)
if (psys->fluid_springs)
MEM_freeN(psys->fluid_springs);
pdEndEffectors(&psys->effectors);
BKE_effectors_free(psys->effectors);
if (psys->pdd) {
psys_free_pdd(psys);
@ -1842,7 +1842,7 @@ static void do_path_effectors(ParticleSimulationData *sim, int i, ParticleCacheK
copy_qt_qt(eff_key.rot, (ca - 1)->rot);
pd_point_from_particle(sim, sim->psys->particles + i, &eff_key, &epoint);
pdDoEffectors(sim->psys->effectors, sim->colliders, sim->psys->part->effector_weights, &epoint, force, NULL);
BKE_effectors_apply(sim->psys->effectors, sim->colliders, sim->psys->part->effector_weights, &epoint, force, NULL);
mul_v3_fl(force, effector * powf((float)k / (float)steps, 100.0f * sim->psys->part->eff_hair) / (float)steps);

@ -93,6 +93,7 @@
#include "BKE_bvhutils.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_physics.h"
#include "DEG_depsgraph_query.h"
#include "PIL_time.h"
@ -1307,9 +1308,10 @@ void psys_update_particle_tree(ParticleSystem *psys, float cfra)
static void psys_update_effectors(ParticleSimulationData *sim)
{
pdEndEffectors(&sim->psys->effectors);
sim->psys->effectors = pdInitEffectors(sim->depsgraph, sim->scene, sim->ob, sim->psys,
sim->psys->part->effector_weights, true);
BKE_effectors_free(sim->psys->effectors);
sim->psys->effectors = BKE_effectors_create(sim->depsgraph,
sim->scene, sim->ob, sim->psys,
sim->psys->part->effector_weights);
precalc_guides(sim, sim->psys->effectors);
}
@ -2066,7 +2068,7 @@ static void basic_force_cb(void *efdata_v, ParticleKey *state, float *force, flo
/* add effectors */
pd_point_from_particle(efdata->sim, efdata->pa, state, &epoint);
if (part->type != PART_HAIR || part->effector_weights->flag & EFF_WEIGHT_DO_HAIR)
pdDoEffectors(sim->psys->effectors, sim->colliders, part->effector_weights, &epoint, force, impulse);
BKE_effectors_apply(sim->psys->effectors, sim->colliders, part->effector_weights, &epoint, force, impulse);
mul_v3_fl(force, efdata->ptex.field);
mul_v3_fl(impulse, efdata->ptex.field);
@ -2957,6 +2959,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
/* particle instance modifier with "path" option need cached paths even if particle system doesn't */
if (skip) {
FOREACH_SCENE_OBJECT_BEGIN(sim->scene, ob)
{
ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleInstance);
@ -2969,6 +2972,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
}
}
FOREACH_SCENE_OBJECT_END;
}
if (!skip) {
psys_cache_paths(sim, cfra, use_render_params);

@ -1278,7 +1278,7 @@ static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Scene *scene, RigidBod
ListBase *effectors;
/* get effectors present in the group specified by effector_weights */
effectors = pdInitEffectors(depsgraph, scene, ob, NULL, effector_weights, true);
effectors = BKE_effectors_create(depsgraph, scene, ob, NULL, effector_weights);
if (effectors) {
float eff_force[3] = {0.0f, 0.0f, 0.0f};
float eff_loc[3], eff_vel[3];
@ -1293,7 +1293,7 @@ static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Scene *scene, RigidBod
/* calculate net force of effectors, and apply to sim object
* - we use 'central force' since apply force requires a "relative position" which we don't have...
*/
pdDoEffectors(effectors, NULL, effector_weights, &epoint, eff_force, NULL);
BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL);
if (G.f & G_DEBUG)
printf("\tapplying force (%f,%f,%f) to '%s'\n", eff_force[0], eff_force[1], eff_force[2], ob->id.name + 2);
/* activate object in case it is deactivated */
@ -1305,7 +1305,7 @@ static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Scene *scene, RigidBod
printf("\tno forces to apply to '%s'\n", ob->id.name + 2);
/* cleanup */
pdEndEffectors(&effectors);
BKE_effectors_free(effectors);
}
/* NOTE: passive objects don't need to be updated since they don't move */

@ -2512,7 +2512,7 @@ static void update_effectors_task_cb(
mul_m4_v3(sds->obmat, voxelCenter);
pd_point_from_loc(data->scene, voxelCenter, vel, index, &epoint);
pdDoEffectors(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
BKE_effectors_apply(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
/* convert retvel to local space */
mag = len_v3(retvel);
@ -2533,7 +2533,7 @@ static void update_effectors(struct Depsgraph *depsgraph, Scene *scene, Object *
ListBase *effectors;
/* make sure smoke flow influence is 0.0f */
sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
effectors = pdInitEffectors(depsgraph, scene, ob, NULL, sds->effector_weights, true);
effectors = BKE_effectors_create(depsgraph, scene, ob, NULL, sds->effector_weights);
if (effectors) {
// precalculate wind forces
@ -2560,7 +2560,7 @@ static void update_effectors(struct Depsgraph *depsgraph, Scene *scene, Object *
&settings);
}
pdEndEffectors(&effectors);
BKE_effectors_free(effectors);
}
static void step(

@ -139,7 +139,7 @@ typedef struct SB_thread_context {
float timenow;
int ifirst;
int ilast;
ListBase *do_effector;
ListBase *effectors;
int do_deflector;
float fieldfactor;
float windfactor;
@ -1444,7 +1444,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], fl
return deflected;
}
static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow, int ifirst, int ilast, struct ListBase *do_effector)
static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow, int ifirst, int ilast, struct ListBase *effectors)
{
SoftBody *sb = ob->soft;
int a;
@ -1478,14 +1478,14 @@ static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow,
float vel[3], sp[3], pr[3], force[3];
float f, windfactor = 0.25f;
/*see if we have wind*/
if (do_effector) {
if (effectors) {
EffectedPoint epoint;
float speed[3] = {0.0f, 0.0f, 0.0f};
float pos[3];
mid_v3_v3v3(pos, sb->bpoint[bs->v1].pos, sb->bpoint[bs->v2].pos);
mid_v3_v3v3(vel, sb->bpoint[bs->v1].vec, sb->bpoint[bs->v2].vec);
pd_point_from_soft(scene, pos, vel, -1, &epoint);
pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed);
BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
mul_v3_fl(speed, windfactor);
add_v3_v3(vel, speed);
@ -1521,29 +1521,27 @@ static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow,
static void scan_for_ext_spring_forces(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float timenow)
{
SoftBody *sb = ob->soft;
ListBase *do_effector = NULL;
do_effector = pdInitEffectors(depsgraph, scene, ob, NULL, sb->effector_weights, true);
_scan_for_ext_spring_forces(scene, ob, timenow, 0, sb->totspring, do_effector);
pdEndEffectors(&do_effector);
ListBase *effectors = BKE_effectors_create(depsgraph, scene, ob, NULL, sb->effector_weights);
_scan_for_ext_spring_forces(scene, ob, timenow, 0, sb->totspring, effectors);
BKE_effectors_free(effectors);
}
static void *exec_scan_for_ext_spring_forces(void *data)
{
SB_thread_context *pctx = (SB_thread_context*)data;
_scan_for_ext_spring_forces(pctx->scene, pctx->ob, pctx->timenow, pctx->ifirst, pctx->ilast, pctx->do_effector);
_scan_for_ext_spring_forces(pctx->scene, pctx->ob, pctx->timenow, pctx->ifirst, pctx->ilast, pctx->effectors);
return NULL;
}
static void sb_sfesf_threads_run(struct Depsgraph *depsgraph, Scene *scene, struct Object *ob, float timenow, int totsprings, int *UNUSED(ptr_to_break_func(void)))
{
ListBase *do_effector = NULL;
ListBase threads;
SB_thread_context *sb_threads;
int i, totthread, left, dec;
int lowsprings =100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */
do_effector= pdInitEffectors(depsgraph, scene, ob, NULL, ob->soft->effector_weights, true);
ListBase *effectors = BKE_effectors_create(depsgraph, scene, ob, NULL, ob->soft->effector_weights);
/* figure the number of threads while preventing pretty pointless threading overhead */
totthread= BKE_scene_num_threads(scene);
@ -1568,7 +1566,7 @@ static void sb_sfesf_threads_run(struct Depsgraph *depsgraph, Scene *scene, stru
}
else
sb_threads[i].ifirst = 0;
sb_threads[i].do_effector = do_effector;
sb_threads[i].effectors = effectors;
sb_threads[i].do_deflector = false;// not used here
sb_threads[i].fieldfactor = 0.0f;// not used here
sb_threads[i].windfactor = 0.0f;// not used here
@ -1588,7 +1586,7 @@ static void sb_sfesf_threads_run(struct Depsgraph *depsgraph, Scene *scene, stru
/* clean up */
MEM_freeN(sb_threads);
pdEndEffectors(&do_effector);
BKE_effectors_free(effectors);
}
@ -1941,7 +1939,7 @@ static void sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, floa
/* since this is definitely the most CPU consuming task here .. try to spread it */
/* core function _softbody_calc_forces_slice_in_a_thread */
/* result is int to be able to flag user break */
static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, float forcetime, float timenow, int ifirst, int ilast, int *UNUSED(ptr_to_break_func(void)), ListBase *do_effector, int do_deflector, float fieldfactor, float windfactor)
static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, float forcetime, float timenow, int ifirst, int ilast, int *UNUSED(ptr_to_break_func(void)), ListBase *effectors, int do_deflector, float fieldfactor, float windfactor)
{
float iks;
int bb, do_selfcollision, do_springcollision, do_aero;
@ -2060,14 +2058,14 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
}
/* particle field & vortex */
if (do_effector) {
if (effectors) {
EffectedPoint epoint;
float kd;
float force[3] = {0.0f, 0.0f, 0.0f};
float speed[3] = {0.0f, 0.0f, 0.0f};
float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */
pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint-bp, &epoint);
pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed);
BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
/* apply forcefield*/
mul_v3_fl(force, fieldfactor* eval_sb_fric_force_scale);
@ -2142,11 +2140,11 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
static void *exec_softbody_calc_forces(void *data)
{
SB_thread_context *pctx = (SB_thread_context*)data;
_softbody_calc_forces_slice_in_a_thread(pctx->scene, pctx->ob, pctx->forcetime, pctx->timenow, pctx->ifirst, pctx->ilast, NULL, pctx->do_effector, pctx->do_deflector, pctx->fieldfactor, pctx->windfactor);
_softbody_calc_forces_slice_in_a_thread(pctx->scene, pctx->ob, pctx->forcetime, pctx->timenow, pctx->ifirst, pctx->ilast, NULL, pctx->effectors, pctx->do_deflector, pctx->fieldfactor, pctx->windfactor);
return NULL;
}
static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float timenow, int totpoint, int *UNUSED(ptr_to_break_func(void)), struct ListBase *do_effector, int do_deflector, float fieldfactor, float windfactor)
static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float timenow, int totpoint, int *UNUSED(ptr_to_break_func(void)), struct ListBase *effectors, int do_deflector, float fieldfactor, float windfactor)
{
ListBase threads;
SB_thread_context *sb_threads;
@ -2178,7 +2176,7 @@ static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float t
}
else
sb_threads[i].ifirst = 0;
sb_threads[i].do_effector = do_effector;
sb_threads[i].effectors = effectors;
sb_threads[i].do_deflector = do_deflector;
sb_threads[i].fieldfactor = fieldfactor;
sb_threads[i].windfactor = windfactor;
@ -2208,7 +2206,6 @@ static void softbody_calc_forcesEx(struct Depsgraph *depsgraph, Scene *scene, Ob
*/
SoftBody *sb= ob->soft; /* is supposed to be there */
/*BodyPoint *bproot;*/ /* UNUSED */
ListBase *do_effector = NULL;
/* float gravity; */ /* UNUSED */
/* float iks; */
float fieldfactor = -1.0f, windfactor = 0.25;
@ -2229,20 +2226,20 @@ static void softbody_calc_forcesEx(struct Depsgraph *depsgraph, Scene *scene, Ob
sb_sfesf_threads_run(depsgraph, scene, ob, timenow, sb->totspring, NULL);
/* after spring scan because it uses Effoctors too */
do_effector= pdInitEffectors(depsgraph, scene, ob, NULL, sb->effector_weights, true);
ListBase *effectors = BKE_effectors_create(depsgraph, scene, ob, NULL, sb->effector_weights);
if (do_deflector) {
float defforce[3];
do_deflector = sb_detect_aabb_collisionCached(defforce, ob->lay, ob, timenow);
}
sb_cf_threads_run(scene, ob, forcetime, timenow, sb->totpoint, NULL, do_effector, do_deflector, fieldfactor, windfactor);
sb_cf_threads_run(scene, ob, forcetime, timenow, sb->totpoint, NULL, effectors, do_deflector, fieldfactor, windfactor);
/* finally add forces caused by face collision */
if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob, timenow);
/* finish matrix and solve */
pdEndEffectors(&do_effector);
BKE_effectors_free(effectors);
}
@ -2269,7 +2266,6 @@ static void softbody_calc_forces(struct Depsgraph *depsgraph, Scene *scene, Obje
BodyPoint *bp;
/* BodyPoint *bproot; */ /* UNUSED */
BodySpring *bs;
ListBase *do_effector = NULL;
float iks, ks, kd, gravity[3] = {0.0f, 0.0f, 0.0f};
float fieldfactor = -1.0f, windfactor = 0.25f;
float tune = sb->ballstiff;
@ -2291,7 +2287,7 @@ static void softbody_calc_forces(struct Depsgraph *depsgraph, Scene *scene, Obje
if (do_springcollision || do_aero) scan_for_ext_spring_forces(depsgraph, scene, ob, timenow);
/* after spring scan because it uses Effoctors too */
do_effector= pdInitEffectors(depsgraph, scene, ob, NULL, ob->soft->effector_weights, true);
ListBase *effectors = BKE_effectors_create(depsgraph, scene, ob, NULL, ob->soft->effector_weights);
if (do_deflector) {
float defforce[3];
@ -2394,13 +2390,13 @@ static void softbody_calc_forces(struct Depsgraph *depsgraph, Scene *scene, Obje
/* particle field & vortex */
if (do_effector) {
if (effectors) {
EffectedPoint epoint;
float force[3] = {0.0f, 0.0f, 0.0f};
float speed[3] = {0.0f, 0.0f, 0.0f};
float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */
pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint-bp, &epoint);
pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed);
BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
/* apply forcefield*/
mul_v3_fl(force, fieldfactor* eval_sb_fric_force_scale);
@ -2492,7 +2488,7 @@ static void softbody_calc_forces(struct Depsgraph *depsgraph, Scene *scene, Obje
/* finally add forces caused by face collision */
if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob, timenow);
pdEndEffectors(&do_effector);
BKE_effectors_free(effectors);
}
}

@ -67,6 +67,7 @@ set(SRC
intern/depsgraph_build.cc
intern/depsgraph_debug.cc
intern/depsgraph_eval.cc
intern/depsgraph_physics.cc
intern/depsgraph_query.cc
intern/depsgraph_query_foreach.cc
intern/depsgraph_query_iter.cc
@ -76,6 +77,7 @@ set(SRC
DEG_depsgraph.h
DEG_depsgraph_build.h
DEG_depsgraph_debug.h
DEG_depsgraph_physics.h
DEG_depsgraph_query.h
intern/builder/deg_builder.h

@ -0,0 +1,51 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2018 Blender Foundation.
* All rights reserved.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/depsgraph/DEG_depsgraph_physics.h
* \ingroup depsgraph
*
* Physics utilities for effectors and collision.
*/
#ifndef __DEG_DEPSGRAPH_PHYSICS_H__
#define __DEG_DEPSGRAPH_PHYSICS_H__
#include "DEG_depsgraph.h"
struct Colllection;
struct Depsgraph;
#ifdef __cplusplus
extern "C" {
#endif
/* Get effector relations from collection or entire scene during evaluation,
* these are created during depsgraph relations building. */
struct ListBase *DEG_get_effector_relations(const struct Depsgraph *depsgraph,
struct Collection *collection);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __DEG_DEPSGRAPH_PHYSICS_H__ */

@ -333,43 +333,22 @@ void DepsgraphRelationBuilder::add_forcefield_relations(
bool add_absorption,
const char *name)
{
::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph*>(graph_);
ListBase *effectors = pdInitEffectors(depsgraph, scene, object, psys, eff, false);
if (effectors == NULL) {
return;
}
LISTBASE_FOREACH (EffectorCache *, eff, effectors) {
if (eff->ob != object) {
ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_TRANSFORM);
ListBase *relations = deg_build_effector_relations(graph_, eff->group);
LISTBASE_FOREACH (EffectorRelation *, relation, relations) {
if (relation->ob != object) {
ComponentKey eff_key(&relation->ob->id, DEG_NODE_TYPE_TRANSFORM);
add_relation(eff_key, key, name);
}
if (eff->psys != NULL) {
if (eff->ob != object) {
ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_EVAL_PARTICLES);
add_relation(eff_key, key, name);
/* TODO: remove this when/if EVAL_PARTICLES is sufficient
* for up to date particles.
*/
ComponentKey mod_key(&eff->ob->id, DEG_NODE_TYPE_GEOMETRY);
add_relation(mod_key, key, name);
}
else if (eff->psys != psys) {
OperationKey eff_key(&eff->ob->id,
DEG_NODE_TYPE_EVAL_PARTICLES,
DEG_OPCODE_PARTICLE_SYSTEM_EVAL,
eff->psys->name);
add_relation(eff_key, key, name);
}
}
if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
ComponentKey trf_key(&eff->pd->f_source->id,
if (relation->pd->forcefield == PFIELD_SMOKEFLOW && relation->pd->f_source) {
ComponentKey trf_key(&relation->pd->f_source->id,
DEG_NODE_TYPE_TRANSFORM);
add_relation(trf_key, key, "Smoke Force Domain");
ComponentKey eff_key(&eff->pd->f_source->id,
ComponentKey eff_key(&relation->pd->f_source->id,
DEG_NODE_TYPE_GEOMETRY);
add_relation(eff_key, key, "Smoke Force Domain");
}
if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
if (add_absorption && (relation->pd->flag & PFIELD_VISIBILITY)) {
add_collision_relations(key,
scene,
object,
@ -378,7 +357,25 @@ void DepsgraphRelationBuilder::add_forcefield_relations(
"Force Absorption");
}
}
pdEndEffectors(&effectors);
if (relation->psys) {
if (relation->ob != object) {
ComponentKey eff_key(&relation->ob->id, DEG_NODE_TYPE_EVAL_PARTICLES);
add_relation(eff_key, key, name);
/* TODO: remove this when/if EVAL_PARTICLES is sufficient
* for up to date particles.
*/
ComponentKey mod_key(&relation->ob->id, DEG_NODE_TYPE_GEOMETRY);
add_relation(mod_key, key, name);
}
else if (relation->psys != psys) {
OperationKey eff_key(&relation->ob->id,
DEG_NODE_TYPE_EVAL_PARTICLES,
DEG_OPCODE_PARTICLE_SYSTEM_EVAL,
relation->psys->name);
add_relation(eff_key, key, name);
}
}
}
}
Depsgraph *DepsgraphRelationBuilder::getGraph()

@ -93,7 +93,8 @@ Depsgraph::Depsgraph(Scene *scene,
mode(mode),
ctime(BKE_scene_frame_get(scene)),
scene_cow(NULL),
is_active(false)
is_active(false),
effector_relations(NULL)
{
BLI_spin_init(&lock);
id_hash = BLI_ghash_ptr_new("Depsgraph id hash");
@ -360,6 +361,8 @@ void Depsgraph::clear_id_nodes()
/* Clear containers. */
BLI_ghash_clear(id_hash, NULL, NULL);
id_nodes.clear();
/* Clear physics relation caches. */
deg_clear_physics_relations(this);
}
/* Add new relationship between two nodes. */

@ -226,6 +226,10 @@ struct Depsgraph {
/* NITE: Corresponds to G_DEBUG_DEPSGRAPH_* flags. */
int debug_flags;
string debug_name;
/* Cached list of effectors for collections and the scene created
* along with relations, for fast lookup during evaluation. */
GHash *effector_relations;
};
} // namespace DEG

@ -357,31 +357,30 @@ void DEG_add_forcefield_relations(DepsNodeHandle *handle,
const char *name)
{
Depsgraph *depsgraph = DEG_get_graph_from_handle(handle);
ListBase *effectors = pdInitEffectors(depsgraph, scene, object, NULL, effector_weights, false);
if (effectors == NULL) {
return;
}
for (EffectorCache *eff = (EffectorCache*)effectors->first; eff; eff = eff->next) {
if (eff->ob != object && eff->pd->forcefield != skip_forcefield) {
DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_TRANSFORM, name);
if (eff->psys) {
DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_EVAL_PARTICLES, name);
DEG::Depsgraph *deg_graph = (DEG::Depsgraph *)depsgraph;
ListBase *relations = deg_build_effector_relations(deg_graph, effector_weights->group);
LISTBASE_FOREACH (EffectorRelation *, relation, relations) {
if (relation->ob != object && relation->pd->forcefield != skip_forcefield) {
DEG_add_object_relation(handle, relation->ob, DEG_OB_COMP_TRANSFORM, name);
if (relation->psys) {
DEG_add_object_relation(handle, relation->ob, DEG_OB_COMP_EVAL_PARTICLES, name);
/* TODO: remove this when/if EVAL_PARTICLES is sufficient
* for up to date particles.
*/
DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_GEOMETRY, name);
DEG_add_object_relation(handle, relation->ob, DEG_OB_COMP_GEOMETRY, name);
}
if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
if (relation->pd->forcefield == PFIELD_SMOKEFLOW && relation->pd->f_source) {
DEG_add_object_relation(handle,
eff->pd->f_source,
relation->pd->f_source,
DEG_OB_COMP_TRANSFORM,
"Smoke Force Domain");
DEG_add_object_relation(handle,
eff->pd->f_source,
relation->pd->f_source,
DEG_OB_COMP_GEOMETRY,
"Smoke Force Domain");
}
if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
if (add_absorption && (relation->pd->flag & PFIELD_VISIBILITY)) {
DEG_add_collision_relations(handle,
scene,
object,
@ -393,5 +392,4 @@ void DEG_add_forcefield_relations(DepsNodeHandle *handle,
}
}
}
pdEndEffectors(&effectors);
}

@ -50,6 +50,7 @@ extern "C" {
struct DEGEditorUpdateContext;
struct Collection;
struct ListBase;
struct Main;
struct Scene;
@ -139,4 +140,9 @@ bool deg_terminal_do_color(void);
string deg_color_for_pointer(const void *pointer);
string deg_color_end(void);
/* Physics Utilities -------------------------------------------------- */
struct ListBase *deg_build_effector_relations(Depsgraph *graph, struct Collection *collection);
void deg_clear_physics_relations(Depsgraph *graph);
} // namespace DEG

@ -0,0 +1,94 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2018 Blender Foundation.
* All rights reserved.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/depsgraph/intern/depsgraph_physics.cc
* \ingroup depsgraph
*
* Physics utilities for effectors and collision.
*/
#include "MEM_guardedalloc.h"
#include "BLI_compiler_compat.h"
#include "BLI_ghash.h"
extern "C" {
#include "BKE_effect.h"
} /* extern "C" */
#include "DNA_group_types.h"
#include "DEG_depsgraph_physics.h"
#include "depsgraph.h"
#include "depsgraph_intern.h"
/************************ Public API *************************/
ListBase *DEG_get_effector_relations(const Depsgraph *graph,
Collection *collection)
{
const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
if (deg_graph->effector_relations == NULL) {
return NULL;
}
return (ListBase*)BLI_ghash_lookup(deg_graph->effector_relations, collection);
}
/*********************** Internal API ************************/
namespace DEG
{
ListBase *deg_build_effector_relations(Depsgraph *graph,
Collection *collection)
{
if (graph->effector_relations == NULL) {
graph->effector_relations = BLI_ghash_ptr_new("Depsgraph effector relations hash");
}
ListBase *relations = reinterpret_cast<ListBase*>(BLI_ghash_lookup(graph->effector_relations, collection));
if (relations == NULL) {
::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph*>(graph);
relations = BKE_effector_relations_create(depsgraph, graph->view_layer, collection);
BLI_ghash_insert(graph->effector_relations, collection, relations);
}
return relations;
}
static void free_effector_relations(void *value)
{
BKE_effector_relations_free(reinterpret_cast<ListBase*>(value));
}
void deg_clear_physics_relations(Depsgraph *graph)
{
if (graph->effector_relations) {
BLI_ghash_free(graph->effector_relations, NULL, free_effector_relations);
graph->effector_relations = NULL;
}
}
}

@ -488,7 +488,7 @@ static void cloth_calc_force(Scene *scene, ClothModifierData *clmd, float UNUSED
BPH_mass_spring_get_motion_state(data, i, x, v);
pd_point_from_loc(scene, x, v, i, &epoint);
pdDoEffectors(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
BKE_effectors_apply(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
}
for (i = 0; i < cloth->tri_num; i++) {