Blender V5.0
rigidbody_object.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2013 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9
10#include <cstdlib>
11#include <cstring>
12
13#include "DNA_object_types.h"
14#include "DNA_rigidbody_types.h"
15#include "DNA_scene_types.h"
16
17#include "BLT_translation.hh"
18
19#include "BKE_context.hh"
20#include "BKE_library.hh"
21#include "BKE_report.hh"
22#include "BKE_rigidbody.h"
23
24#include "DEG_depsgraph.hh"
27
28#include "RNA_access.hh"
29#include "RNA_define.hh"
30#include "RNA_enum_types.hh"
31#include "RNA_prototypes.hh"
32
33#include "WM_api.hh"
34#include "WM_types.hh"
35
36#include "ED_object.hh"
37#include "ED_physics.hh"
38#include "ED_screen.hh"
39
40#include "physics_intern.hh"
41
42/* ********************************************** */
43/* Helper API's for RigidBody Objects Editing */
44
46{
47 if (scene == nullptr || !ID_IS_EDITABLE(scene) || ID_IS_OVERRIDE_LIBRARY(scene) ||
48 (scene->rigidbody_world != nullptr && scene->rigidbody_world->group != nullptr &&
51 {
52 return false;
53 }
54 return true;
55}
56
58{
59 Scene *scene = CTX_data_scene(C);
61 return false;
62 }
63
66 return (ob && ob->rigidbody_object);
67 }
68
69 return false;
70}
71
73{
74 Scene *scene = CTX_data_scene(C);
76 return false;
77 }
78
81 return (ob && ob->type == OB_MESH);
82 }
83
84 return false;
85}
86
87/* ----------------- */
88
89bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
90{
91 return BKE_rigidbody_add_object(bmain, scene, ob, type, reports);
92}
93
95{
96 BKE_rigidbody_remove_object(bmain, scene, ob, false);
97}
98
99/* ********************************************** */
100/* Active Object Add/Remove Operators */
101
102/* ************ Add Rigid Body ************** */
103
105{
106 Main *bmain = CTX_data_main(C);
107 Scene *scene = CTX_data_scene(C);
109 int type = RNA_enum_get(op->ptr, "type");
110 bool changed;
111
112 /* apply to active object */
113 changed = ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
114
115 if (changed) {
116 /* send updates */
119
120 /* done */
121 return OPERATOR_FINISHED;
122 }
123 return OPERATOR_CANCELLED;
124}
125
127{
128 /* identifiers */
129 ot->idname = "RIGIDBODY_OT_object_add";
130 ot->name = "Add Rigid Body";
131 ot->description = "Add active object as Rigid Body";
132
133 /* callbacks */
136
137 /* flags */
139
140 /* properties */
141 ot->prop = RNA_def_enum(ot->srna,
142 "type",
145 "Rigid Body Type",
146 "");
147}
148
149/* ************ Remove Rigid Body ************** */
150
152{
153 Main *bmain = CTX_data_main(C);
154 Scene *scene = CTX_data_scene(C);
156 bool changed = false;
157
158 /* apply to active object */
159 if (!ELEM(nullptr, ob, ob->rigidbody_object)) {
160 ED_rigidbody_object_remove(bmain, scene, ob);
161 changed = true;
162 }
163
164 if (changed) {
165 /* send updates */
168
169 /* done */
170 return OPERATOR_FINISHED;
171 }
172
173 BKE_report(op->reports, RPT_ERROR, "Object has no Rigid Body settings to remove");
174 return OPERATOR_CANCELLED;
175}
176
178{
179 /* identifiers */
180 ot->idname = "RIGIDBODY_OT_object_remove";
181 ot->name = "Remove Rigid Body";
182 ot->description = "Remove Rigid Body settings from Object";
183
184 /* callbacks */
187
188 /* flags */
190}
191
192/* ********************************************** */
193/* Selected Object Add/Remove Operators */
194
195/* ************ Add Rigid Bodies ************** */
196
198{
199 Main *bmain = CTX_data_main(C);
200 Scene *scene = CTX_data_scene(C);
201 int type = RNA_enum_get(op->ptr, "type");
202 bool changed = false;
203
204 /* create rigid body objects and add them to the world's group */
205 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
206 changed |= ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
207 }
209
210 if (changed) {
211 /* send updates */
214
215 /* done */
216 return OPERATOR_FINISHED;
217 }
218 return OPERATOR_CANCELLED;
219}
220
222{
223 /* identifiers */
224 ot->idname = "RIGIDBODY_OT_objects_add";
225 ot->name = "Add Rigid Bodies";
226 ot->description = "Add selected objects as Rigid Bodies";
227
228 /* callbacks */
231
232 /* flags */
234
235 /* properties */
236 ot->prop = RNA_def_enum(ot->srna,
237 "type",
240 "Rigid Body Type",
241 "");
242}
243
244/* ************ Remove Rigid Bodies ************** */
245
247{
248 Main *bmain = CTX_data_main(C);
249 Scene *scene = CTX_data_scene(C);
250 bool changed = false;
251
252 /* apply this to all selected objects... */
253 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
254 if (ob->rigidbody_object) {
255 ED_rigidbody_object_remove(bmain, scene, ob);
256 changed = true;
257 }
258 }
260
261 if (changed) {
262 /* send updates */
265
266 /* done */
267 return OPERATOR_FINISHED;
268 }
269 return OPERATOR_CANCELLED;
270}
271
273{
274 /* identifiers */
275 ot->idname = "RIGIDBODY_OT_objects_remove";
276 ot->name = "Remove Rigid Bodies";
277 ot->description = "Remove selected objects from Rigid Body simulation";
278
279 /* callbacks */
282
283 /* flags */
285}
286
287/* ********************************************** */
288/* Utility Operators */
289
290/* ************ Change Collision Shapes ************** */
291
293{
294 int shape = RNA_enum_get(op->ptr, "type");
295 bool changed = false;
296
297 /* apply this to all selected objects... */
298 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
299 if (ob->rigidbody_object) {
300 /* use RNA-system to change the property and perform all necessary changes */
302 &ob->id, &RNA_RigidBodyObject, ob->rigidbody_object);
303 RNA_enum_set(&ptr, "collision_shape", shape);
304
306
307 changed = true;
308 }
309 }
311
312 if (changed) {
313 /* send updates */
316
317 /* done */
318 return OPERATOR_FINISHED;
319 }
320 return OPERATOR_CANCELLED;
321}
322
324{
325 /* identifiers */
326 ot->idname = "RIGIDBODY_OT_shape_change";
327 ot->name = "Change Collision Shape";
328 ot->description = "Change collision shapes for selected Rigid Body Objects";
329
330 /* callbacks */
331 ot->invoke = WM_menu_invoke;
334
335 /* flags */
337
338 /* properties */
339 ot->prop = RNA_def_enum(ot->srna,
340 "type",
343 "Rigid Body Shape",
344 "");
345}
346
347/* ************ Calculate Mass ************** */
348
349/* Entry in material density table */
351 const char *name; /* Name of material */
352 float density; /* Density (kg/m^3) */
353};
354
355/* Preset density values for materials (kg/m^3)
356 * Selected values obtained from:
357 * 1) http://www.jaredzone.info/2010/09/densities.html
358 * 2) http://www.avlandesign.com/density_construction.htm
359 * 3) http://www.avlandesign.com/density_metal.htm
360 */
362 {N_("Air"), 1.0f}, /* not quite; adapted from 1.43 for oxygen for use as default */
363 {N_("Acrylic"), 1400.0f},
364 {N_("Asphalt (Crushed)"), 721.0f},
365 {N_("Bark"), 240.0f},
366 {N_("Beans (Cocoa)"), 593.0f},
367 {N_("Beans (Soy)"), 721.0f},
368 {N_("Brick (Pressed)"), 2400.0f},
369 {N_("Brick (Common)"), 2000.0f},
370 {N_("Brick (Soft)"), 1600.0f},
371 {N_("Brass"), 8216.0f},
372 {N_("Bronze"), 8860.0f},
373 {N_("Carbon (Solid)"), 2146.0f},
374 {N_("Cardboard"), 689.0f},
375 {N_("Cast Iron"), 7150.0f}, /* {N_("Cement"), 1442.0f}, */
376 {N_("Chalk (Solid)"), 2499.0f}, /* {N_("Coffee (Fresh/Roast)"), ~500}, */
377 {N_("Concrete"), 2320.0f},
378 {N_("Charcoal"), 208.0f},
379 {N_("Cork"), 240.0f},
380 {N_("Copper"), 8933.0f},
381 {N_("Garbage"), 481.0f},
382 {N_("Glass (Broken)"), 1940.0f},
383 {N_("Glass (Solid)"), 2190.0f},
384 {N_("Gold"), 19282.0f},
385 {N_("Granite (Broken)"), 1650.0f},
386 {N_("Granite (Solid)"), 2691.0f},
387 {N_("Gravel"), 2780.0f},
388 {N_("Ice (Crushed)"), 593.0f},
389 {N_("Ice (Solid)"), 919.0f},
390 {N_("Iron"), 7874.0f},
391 {N_("Lead"), 11342.0f},
392 {N_("Limestone (Broken)"), 1554.0f},
393 {N_("Limestone (Solid)"), 2611.0f},
394 {N_("Marble (Broken)"), 1570.0f},
395 {N_("Marble (Solid)"), 2563.0f},
396 {N_("Paper"), 1201.0f},
397 {N_("Peanuts (Shelled)"), 641.0f},
398 {N_("Peanuts (Not Shelled)"), 272.0f},
399 {N_("Plaster"), 849.0f},
400 {N_("Plastic"), 1200.0f},
401 {N_("Polystyrene"), 1050.0f},
402 {N_("Rubber"), 1522.0f},
403 {N_("Silver"), 10501.0f},
404 {N_("Steel"), 7860.0f},
405 {N_("Stone"), 2515.0f},
406 {N_("Stone (Crushed)"), 1602.0f},
407 {N_("Timber"), 610.0f},
408};
410 sizeof(rbMaterialDensityItem);
411
412/* dynamically generate list of items
413 * - Although there is a runtime cost, this has a lower maintenance cost
414 * in the long run than other two-list solutions...
415 */
417 PointerRNA * /*ptr*/,
418 PropertyRNA * /*prop*/,
419 bool *r_free)
420{
421 EnumPropertyItem item_tmp = {0};
422 EnumPropertyItem *item = nullptr;
423 int totitem = 0;
424 int i = 0;
425
426 /* add each preset to the list */
427 for (i = 0; i < NUM_RB_MATERIAL_PRESETS; i++) {
429
430 item_tmp.identifier = preset->name;
431 item_tmp.name = IFACE_(preset->name);
432 item_tmp.value = i;
433 RNA_enum_item_add(&item, &totitem, &item_tmp);
434 }
435
436 /* add special "custom" entry to the end of the list */
437 {
438 item_tmp.identifier = "Custom";
439 item_tmp.name = IFACE_("Custom");
440 item_tmp.value = -1;
441 RNA_enum_item_add(&item, &totitem, &item_tmp);
442 }
443
444 RNA_enum_item_end(&item, &totitem);
445 *r_free = true;
446
447 return item;
448}
449
450/* ------------------------------------------ */
451
453{
455 int material = RNA_enum_get(op->ptr, "material");
456 float density;
457 bool changed = false;
458
459 /* get density (kg/m^3) to apply */
460 if (material >= 0) {
461 /* get density from table, and store in props for later repeating */
462 if (material >= NUM_RB_MATERIAL_PRESETS) {
463 material = 0;
464 }
465
466 density = RB_MATERIAL_DENSITY_TABLE[material].density;
467 RNA_float_set(op->ptr, "density", density);
468 }
469 else {
470 /* custom - grab from whatever value is set */
471 density = RNA_float_get(op->ptr, "density");
472 }
473
474 /* Apply this to all selected objects (with rigid-bodies). */
475 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
476 if (ob->rigidbody_object) {
477 float volume; /* m^3 */
478 float mass; /* kg */
479
480 /* mass is calculated from the approximate volume of the object,
481 * and the density of the material we're simulating
482 */
483 Object *ob_eval = DEG_get_evaluated(depsgraph, ob);
484 BKE_rigidbody_calc_volume(ob_eval, &volume);
485 mass = volume * density;
486
487 /* use RNA-system to change the property and perform all necessary changes */
489 &ob->id, &RNA_RigidBodyObject, ob->rigidbody_object);
490 RNA_float_set(&ptr, "mass", mass);
491
493
494 changed = true;
495 }
496 }
498
499 if (changed) {
500 /* send updates */
502
503 /* done */
504 return OPERATOR_FINISHED;
505 }
506 return OPERATOR_CANCELLED;
507}
508
509static bool mass_calculate_poll_property(const bContext * /*C*/,
510 wmOperator *op,
511 const PropertyRNA *prop)
512{
513 const char *prop_id = RNA_property_identifier(prop);
514
515 /* Disable density input when not using the 'Custom' preset. */
516 if (STREQ(prop_id, "density")) {
517 int material = RNA_enum_get(op->ptr, "material");
518 if (material >= 0) {
520 }
521 else {
523 }
524 }
525
526 return true;
527}
528
530{
531 PropertyRNA *prop;
532
533 /* identifiers */
534 ot->idname = "RIGIDBODY_OT_mass_calculate";
535 ot->name = "Calculate Mass";
536 ot->description = "Automatically calculate mass values for Rigid Body Objects based on volume";
537
538 /* callbacks */
539 ot->invoke = WM_menu_invoke; /* XXX */
542 ot->poll_property = mass_calculate_poll_property;
543
544 /* flags */
546
547 /* properties */
548 ot->prop = prop = RNA_def_enum(
549 ot->srna,
550 "material",
552 0,
553 "Material Preset",
554 "Type of material that objects are made of (determines material density)");
557
558 RNA_def_float(ot->srna,
559 "density",
560 1.0,
561 FLT_MIN,
562 FLT_MAX,
563 "Density",
564 "Density value (kg/m^3), allows custom value if the 'Custom' preset is used",
565 1.0f,
566 2500.0f);
567}
568
569/* ********************************************** */
#define CTX_DATA_BEGIN(C, Type, instance, member)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
#define CTX_DATA_END
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
API for Blender-side Rigid Body stuff.
void BKE_rigidbody_remove_object(struct Main *bmain, struct Scene *scene, struct Object *ob, bool free_us)
void BKE_rigidbody_calc_volume(struct Object *ob, float *r_vol)
bool BKE_rigidbody_add_object(struct Main *bmain, struct Scene *scene, struct Object *ob, int type, struct ReportList *reports)
#define ELEM(...)
#define STREQ(a, b)
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1054
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:730
Object is a sort of wrapper for general info.
@ OB_MESH
Types and defines for representing Rigid Body entities.
@ RBO_TYPE_ACTIVE
@ RB_SHAPE_TRIMESH
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
bool ED_operator_object_active_editable(bContext *C)
@ PROP_EDITABLE
Definition RNA_types.hh:306
@ PROP_ENUM_NO_TRANSLATE
Definition RNA_types.hh:432
#define C
Definition RandGen.cpp:29
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_TRANSFORM
Definition WM_types.hh:456
#define ND_POINTCACHE
Definition WM_types.hh:466
#define ND_SPACE_VIEW3D
Definition WM_types.hh:528
#define NC_OBJECT
Definition WM_types.hh:379
#define NC_SPACE
Definition WM_types.hh:392
BPy_StructRNA * depsgraph
Object * context_active_object(const bContext *C)
void RIGIDBODY_OT_object_remove(wmOperatorType *ot)
static const int NUM_RB_MATERIAL_PRESETS
static const EnumPropertyItem * rigidbody_materials_itemf(bContext *, PointerRNA *, PropertyRNA *, bool *r_free)
void RIGIDBODY_OT_shape_change(wmOperatorType *ot)
static wmOperatorStatus rigidbody_object_remove_exec(bContext *C, wmOperator *op)
static bool operator_rigidbody_editable_poll(Scene *scene)
static bool operator_rigidbody_add_poll(bContext *C)
void RIGIDBODY_OT_object_add(wmOperatorType *ot)
void RIGIDBODY_OT_mass_calculate(wmOperatorType *ot)
static wmOperatorStatus rigidbody_objects_shape_change_exec(bContext *C, wmOperator *op)
static bool operator_rigidbody_active_poll(bContext *C)
static wmOperatorStatus rigidbody_objects_add_exec(bContext *C, wmOperator *op)
static wmOperatorStatus rigidbody_object_add_exec(bContext *C, wmOperator *op)
void RIGIDBODY_OT_objects_remove(wmOperatorType *ot)
static wmOperatorStatus rigidbody_objects_remove_exec(bContext *C, wmOperator *)
void RIGIDBODY_OT_objects_add(wmOperatorType *ot)
static rbMaterialDensityItem RB_MATERIAL_DENSITY_TABLE[]
static bool mass_calculate_poll_property(const bContext *, wmOperator *op, const PropertyRNA *prop)
static wmOperatorStatus rigidbody_objects_calc_mass_exec(bContext *C, wmOperator *op)
void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob)
bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
const char * RNA_property_identifier(const PropertyRNA *prop)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
const EnumPropertyItem rna_enum_rigidbody_object_type_items[]
const EnumPropertyItem rna_enum_rigidbody_object_shape_items[]
const EnumPropertyItem rna_enum_dummy_DEFAULT_items[]
Definition rna_rna.cc:32
#define FLT_MAX
Definition stdcycles.h:14
const char * identifier
Definition RNA_types.hh:657
const char * name
Definition RNA_types.hh:661
struct RigidBodyOb * rigidbody_object
struct Collection * group
struct RigidBodyWorld * rigidbody_world
struct ReportList * reports
struct PointerRNA * ptr
i
Definition text_draw.cc:230
#define N_(msgid)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237
wmOperatorStatus WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)