Blender V5.0
depsgraph_physics.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2018 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
12
13#include "BLI_listbase.h"
14
15#include "BKE_collision.h"
16#include "BKE_dynamicpaint.h"
17#include "BKE_effect.h"
18#include "BKE_modifier.hh"
19#include "BKE_object.hh"
20
23#include "DNA_object_types.h"
24
28
29#include "depsgraph.hh"
30
31namespace deg = blender::deg;
32
33/*************************** Evaluation Query API *****************************/
34
36{
37 switch (modifier_type) {
44 }
45
46 BLI_assert_msg(0, "Unknown collision modifier type");
48}
49/* Get ID from an ID type object, in a safe manner. This means that object can be nullptr,
50 * in which case the function returns nullptr.
51 */
52template<class T> static ID *object_id_safe(T *object)
53{
54 if (object == nullptr) {
55 return nullptr;
56 }
57 return &object->id;
58}
59
60ListBase *DEG_get_effector_relations(const Depsgraph *graph, Collection *collection)
61{
62 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
64 if (hash == nullptr) {
65 return nullptr;
66 }
67 /* NOTE: nullptr is a valid lookup key here as it means that the relation is not bound to a
68 * specific collection. */
69 ID *collection_orig = DEG_get_original(object_id_safe(collection));
70 return hash->lookup_default(collection_orig, nullptr);
71}
72
73ListBase *DEG_get_collision_relations(const Depsgraph *graph,
74 Collection *collection,
75 uint modifier_type)
76{
77 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
78 const ePhysicsRelationType type = modifier_to_relation_type(modifier_type);
80 if (hash == nullptr) {
81 return nullptr;
82 }
83 /* NOTE: nullptr is a valid lookup key here as it means that the relation is not bound to a
84 * specific collection. */
85 ID *collection_orig = DEG_get_original(object_id_safe(collection));
86 return hash->lookup_default(collection_orig, nullptr);
87}
88
89/********************** Depsgraph Building API ************************/
90
98enum class CollisionComponentFlag : uint8_t {
99 None = 0,
101 Transform = 1 << 0,
103 Geometry = 1 << 1,
105 EvalPose = 1 << 2,
106};
108
109void DEG_add_collision_relations(DepsNodeHandle *handle,
110 Object *object,
111 Collection *collection,
112 uint modifier_type,
113 DEG_CollobjFilterFunction filter_function,
114 const char *name)
115{
116 Depsgraph *depsgraph = DEG_get_graph_from_handle(handle);
118 ListBase *relations = build_collision_relations(deg_graph, collection, modifier_type);
119
120 /* Expand tag objects, matching: #BKE_object_modifier_update_subframe behavior. */
121
122 /* NOTE: #eModifierType_Fluid should be included,
123 * leave out for the purpose of validating the fix for dynamic paint only. */
124 const bool use_recursive_parents = (modifier_type == eModifierType_DynamicPaint);
125
126 blender::Map<Object *, CollisionComponentFlag> *object_component_map = nullptr;
127 if (use_recursive_parents) {
128 object_component_map = MEM_new<blender::Map<Object *, CollisionComponentFlag>>(__func__);
129 }
130
131 LISTBASE_FOREACH (CollisionRelation *, relation, relations) {
132 Object *ob1 = relation->ob;
133 if (ob1 == object) {
134 continue;
135 }
136 if (filter_function &&
137 !filter_function(ob1, BKE_modifiers_findby_type(ob1, (ModifierType)modifier_type)))
138 {
139 continue;
140 }
141
142 if (use_recursive_parents) {
143 /* Add relations for `ob1` and other objects it references,
144 * using `object_component_map` to avoid redundant calls.
145 *
146 * When #BKE_object_modifier_update_subframe is used by a modifier,
147 * it's important the depsgraph tags objects this modifier uses.
148 *
149 * Without this, access to objects is not thread-safe, see: #142137.
150 *
151 * NOTE(@ideasman42): #BKE_object_modifier_update_subframe calls
152 * #BKE_animsys_evaluate_animdata, depending on the object type.
153 * Equivalent relations could be added here.
154 * This was not done and there are no bug reports relating to this,
155 * so leave as-is unless the current code is failing in a real world scenario. */
156
158 ob1,
159 true,
161 modifier_type,
162 [&handle, &name, &object_component_map](Object *ob, const bool update_mesh) {
163 CollisionComponentFlag &update_flag = object_component_map->lookup_or_add_default(ob);
164 {
166 if ((update_flag & test_flag) == CollisionComponentFlag::None) {
167 update_flag |= test_flag;
169 }
170 }
171 if (update_mesh) {
173 if ((update_flag & test_flag) == CollisionComponentFlag::None) {
174 update_flag |= test_flag;
176 }
177 }
178 if (ob->type == OB_ARMATURE) {
180 if ((update_flag & test_flag) == CollisionComponentFlag::None) {
181 update_flag |= test_flag;
183 }
184 }
185 });
186
187 continue;
188 }
189
192 }
193
194 if (use_recursive_parents) {
195 MEM_delete(object_component_map);
196 }
197}
198
199void DEG_add_forcefield_relations(DepsNodeHandle *handle,
200 Object *object,
201 EffectorWeights *effector_weights,
202 bool add_absorption,
203 int skip_forcefield,
204 const char *name)
205{
206 Depsgraph *depsgraph = DEG_get_graph_from_handle(handle);
208 ListBase *relations = build_effector_relations(deg_graph, effector_weights->group);
209 LISTBASE_FOREACH (EffectorRelation *, relation, relations) {
210 if (relation->ob == object) {
211 continue;
212 }
213 if (relation->pd->forcefield == skip_forcefield) {
214 continue;
215 }
216
217 /* Relation to forcefield object, optionally including geometry.
218 * Use special point cache relations for automatic cache clearing. */
220
221 if (relation->psys || ELEM(relation->pd->shape, PFIELD_SHAPE_SURFACE, PFIELD_SHAPE_POINTS) ||
222 relation->pd->forcefield == PFIELD_GUIDE)
223 {
224 /* TODO(sergey): Consider going more granular with more dedicated
225 * particle system operation. */
227 }
228
229 /* Smoke flow relations. */
230 if (relation->pd->forcefield == PFIELD_FLUIDFLOW && relation->pd->f_source != nullptr) {
232 handle, relation->pd->f_source, DEG_OB_COMP_TRANSFORM, "Fluid Force Domain");
234 handle, relation->pd->f_source, DEG_OB_COMP_GEOMETRY, "Fluid Force Domain");
235 }
236
237 /* Absorption forces need collision relation. */
238 if (add_absorption && (relation->pd->flag & PFIELD_VISIBILITY)) {
240 handle, object, nullptr, eModifierType_Collision, nullptr, "Force Absorption");
241 }
242 }
243}
244
245/******************************** Internal API ********************************/
246
247namespace blender::deg {
248
250{
252 if (hash == nullptr) {
255 }
256 /* If collection is nullptr still use it as a key.
257 * In this case the BKE_effector_relations_create() will create relates for all bases in the
258 * view layer.
259 */
260 ID *collection_id = object_id_safe(collection);
261 return hash->lookup_or_add_cb(collection_id, [&]() {
262 ::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(graph);
263 return BKE_effector_relations_create(depsgraph, graph->scene, graph->view_layer, collection);
264 });
265}
266
267ListBase *build_collision_relations(Depsgraph *graph, Collection *collection, uint modifier_type)
268{
269 const ePhysicsRelationType type = modifier_to_relation_type(modifier_type);
271 if (hash == nullptr) {
273 hash = graph->physics_relations[type];
274 }
275 /* If collection is nullptr still use it as a key.
276 * In this case the BKE_collision_relations_create() will create relates for all bases in the
277 * view layer.
278 */
279 ID *collection_id = object_id_safe(collection);
280 return hash->lookup_or_add_cb(collection_id, [&]() {
281 ::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(graph);
282 return BKE_collision_relations_create(depsgraph, collection, modifier_type);
283 });
284}
285
287{
288 for (int i = 0; i < DEG_PHYSICS_RELATIONS_NUM; i++) {
290 if (hash) {
292
293 switch (type) {
295 for (ListBase *list : hash->values()) {
297 }
298 break;
302 for (ListBase *list : hash->values()) {
304 }
305 break;
307 break;
308 }
309 delete hash;
310 graph->physics_relations[i] = nullptr;
311 }
312 }
313}
314
315} // namespace blender::deg
struct ListBase * BKE_collision_relations_create(struct Depsgraph *depsgraph, struct Collection *collection, unsigned int modifier_type)
void BKE_collision_relations_free(struct ListBase *relations)
struct ListBase * BKE_effector_relations_create(struct Depsgraph *depsgraph, const struct Scene *scene, struct ViewLayer *view_layer, struct Collection *collection)
void BKE_effector_relations_free(struct ListBase *lb)
Definition effect.cc:239
ModifierData * BKE_modifiers_findby_type(const Object *ob, ModifierType type)
General operations, lookup, etc. for blender objects.
#define OBJECT_MODIFIER_UPDATE_SUBFRAME_RECURSION_DEFAULT
void BKE_object_modifier_update_subframe_only_callback(Object *ob, bool update_mesh, int parent_recursion_limit, int modifier_type, blender::FunctionRef< void(Object *object, bool update_mesh)> update_or_tag_fn)
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define LISTBASE_FOREACH(type, var, list)
unsigned int uint
#define ENUM_OPERATORS(_type, _max)
#define ELEM(...)
void DEG_add_object_pointcache_relation(DepsNodeHandle *node_handle, Object *object, eDepsObjectComponentType component, const char *description)
@ DEG_OB_COMP_EVAL_POSE
@ DEG_OB_COMP_GEOMETRY
@ DEG_OB_COMP_TRANSFORM
Depsgraph * DEG_get_graph_from_handle(DepsNodeHandle *node_handle)
bool(*)(Object *obj, ModifierData *md) DEG_CollobjFilterFunction
@ DEG_PHYSICS_DYNAMIC_BRUSH
@ DEG_PHYSICS_SMOKE_COLLISION
@ DEG_PHYSICS_COLLISION
@ DEG_PHYSICS_RELATIONS_NUM
@ DEG_PHYSICS_EFFECTOR
T * DEG_get_original(T *id)
Object groups, one object can be in many groups at once.
@ eModifierType_Fluid
@ eModifierType_Collision
@ eModifierType_DynamicPaint
@ PFIELD_FLUIDFLOW
@ PFIELD_VISIBILITY
@ PFIELD_SHAPE_SURFACE
@ PFIELD_SHAPE_POINTS
Object is a sort of wrapper for general info.
@ OB_ARMATURE
BPy_StructRNA * depsgraph
Value & lookup_or_add_default(const Key &key)
Definition BLI_map.hh:639
CollisionComponentFlag
void DEG_add_collision_relations(DepsNodeHandle *handle, Object *object, Collection *collection, uint modifier_type, DEG_CollobjFilterFunction filter_function, const char *name)
static ePhysicsRelationType modifier_to_relation_type(uint modifier_type)
ListBase * DEG_get_collision_relations(const Depsgraph *graph, Collection *collection, uint modifier_type)
ListBase * DEG_get_effector_relations(const Depsgraph *graph, Collection *collection)
void DEG_add_forcefield_relations(DepsNodeHandle *handle, Object *object, EffectorWeights *effector_weights, bool add_absorption, int skip_forcefield, const char *name)
static ID * object_id_safe(T *object)
#define T
ListBase * build_collision_relations(Depsgraph *graph, Collection *collection, uint modifier_type)
ListBase * build_effector_relations(Depsgraph *graph, Collection *collection)
void clear_physics_relations(Depsgraph *graph)
#define hash
Definition noise_c.cc:154
const char * name
struct Collection * group
Definition DNA_ID.h:414
Map< const ID *, ListBase * > * physics_relations[DEG_PHYSICS_RELATIONS_NUM]
Definition depsgraph.hh:181
i
Definition text_draw.cc:230