Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/gltf/extensions/physics/gltf_physics_body.cpp
10279 views
1
/**************************************************************************/
2
/* gltf_physics_body.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "gltf_physics_body.h"
32
33
#include "scene/3d/physics/animatable_body_3d.h"
34
#include "scene/3d/physics/area_3d.h"
35
#include "scene/3d/physics/character_body_3d.h"
36
#include "scene/3d/physics/static_body_3d.h"
37
#include "scene/3d/physics/vehicle_body_3d.h"
38
39
void GLTFPhysicsBody::_bind_methods() {
40
ClassDB::bind_static_method("GLTFPhysicsBody", D_METHOD("from_node", "body_node"), &GLTFPhysicsBody::from_node);
41
ClassDB::bind_method(D_METHOD("to_node"), &GLTFPhysicsBody::to_node);
42
43
ClassDB::bind_static_method("GLTFPhysicsBody", D_METHOD("from_dictionary", "dictionary"), &GLTFPhysicsBody::from_dictionary);
44
ClassDB::bind_method(D_METHOD("to_dictionary"), &GLTFPhysicsBody::to_dictionary);
45
46
ClassDB::bind_method(D_METHOD("get_body_type"), &GLTFPhysicsBody::get_body_type);
47
ClassDB::bind_method(D_METHOD("set_body_type", "body_type"), &GLTFPhysicsBody::set_body_type);
48
ClassDB::bind_method(D_METHOD("get_mass"), &GLTFPhysicsBody::get_mass);
49
ClassDB::bind_method(D_METHOD("set_mass", "mass"), &GLTFPhysicsBody::set_mass);
50
ClassDB::bind_method(D_METHOD("get_linear_velocity"), &GLTFPhysicsBody::get_linear_velocity);
51
ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &GLTFPhysicsBody::set_linear_velocity);
52
ClassDB::bind_method(D_METHOD("get_angular_velocity"), &GLTFPhysicsBody::get_angular_velocity);
53
ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &GLTFPhysicsBody::set_angular_velocity);
54
ClassDB::bind_method(D_METHOD("get_center_of_mass"), &GLTFPhysicsBody::get_center_of_mass);
55
ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &GLTFPhysicsBody::set_center_of_mass);
56
ClassDB::bind_method(D_METHOD("get_inertia_diagonal"), &GLTFPhysicsBody::get_inertia_diagonal);
57
ClassDB::bind_method(D_METHOD("set_inertia_diagonal", "inertia_diagonal"), &GLTFPhysicsBody::set_inertia_diagonal);
58
ClassDB::bind_method(D_METHOD("get_inertia_orientation"), &GLTFPhysicsBody::get_inertia_orientation);
59
ClassDB::bind_method(D_METHOD("set_inertia_orientation", "inertia_orientation"), &GLTFPhysicsBody::set_inertia_orientation);
60
#ifndef DISABLE_DEPRECATED
61
ClassDB::bind_method(D_METHOD("get_inertia_tensor"), &GLTFPhysicsBody::get_inertia_tensor);
62
ClassDB::bind_method(D_METHOD("set_inertia_tensor", "inertia_tensor"), &GLTFPhysicsBody::set_inertia_tensor);
63
#endif // DISABLE_DEPRECATED
64
65
ADD_PROPERTY(PropertyInfo(Variant::STRING, "body_type"), "set_body_type", "get_body_type");
66
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass"), "set_mass", "get_mass");
67
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
68
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity"), "set_angular_velocity", "get_angular_velocity");
69
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass"), "set_center_of_mass", "get_center_of_mass");
70
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "inertia_diagonal"), "set_inertia_diagonal", "get_inertia_diagonal");
71
ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "inertia_orientation"), "set_inertia_orientation", "get_inertia_orientation");
72
#ifndef DISABLE_DEPRECATED
73
ADD_PROPERTY(PropertyInfo(Variant::BASIS, "inertia_tensor"), "set_inertia_tensor", "get_inertia_tensor");
74
#endif // DISABLE_DEPRECATED
75
}
76
77
String GLTFPhysicsBody::get_body_type() const {
78
switch (body_type) {
79
case PhysicsBodyType::STATIC:
80
return "static";
81
case PhysicsBodyType::ANIMATABLE:
82
return "animatable";
83
case PhysicsBodyType::CHARACTER:
84
return "character";
85
case PhysicsBodyType::RIGID:
86
return "rigid";
87
case PhysicsBodyType::VEHICLE:
88
return "vehicle";
89
case PhysicsBodyType::TRIGGER:
90
return "trigger";
91
}
92
// Unreachable, the switch cases handle all values the enum can take.
93
// Omitting this works on Clang but not GCC or MSVC. If reached, it's UB.
94
return "rigid";
95
}
96
97
void GLTFPhysicsBody::set_body_type(String p_body_type) {
98
if (p_body_type == "static") {
99
body_type = PhysicsBodyType::STATIC;
100
} else if (p_body_type == "animatable") {
101
body_type = PhysicsBodyType::ANIMATABLE;
102
} else if (p_body_type == "character") {
103
body_type = PhysicsBodyType::CHARACTER;
104
} else if (p_body_type == "rigid") {
105
body_type = PhysicsBodyType::RIGID;
106
} else if (p_body_type == "vehicle") {
107
body_type = PhysicsBodyType::VEHICLE;
108
} else if (p_body_type == "trigger") {
109
body_type = PhysicsBodyType::TRIGGER;
110
} else {
111
ERR_PRINT("Error setting glTF physics body type: The body type must be one of \"static\", \"animatable\", \"character\", \"rigid\", \"vehicle\", or \"trigger\".");
112
}
113
}
114
115
GLTFPhysicsBody::PhysicsBodyType GLTFPhysicsBody::get_physics_body_type() const {
116
return body_type;
117
}
118
119
void GLTFPhysicsBody::set_physics_body_type(PhysicsBodyType p_body_type) {
120
body_type = p_body_type;
121
}
122
123
real_t GLTFPhysicsBody::get_mass() const {
124
return mass;
125
}
126
127
void GLTFPhysicsBody::set_mass(real_t p_mass) {
128
mass = p_mass;
129
}
130
131
Vector3 GLTFPhysicsBody::get_linear_velocity() const {
132
return linear_velocity;
133
}
134
135
void GLTFPhysicsBody::set_linear_velocity(Vector3 p_linear_velocity) {
136
linear_velocity = p_linear_velocity;
137
}
138
139
Vector3 GLTFPhysicsBody::get_angular_velocity() const {
140
return angular_velocity;
141
}
142
143
void GLTFPhysicsBody::set_angular_velocity(Vector3 p_angular_velocity) {
144
angular_velocity = p_angular_velocity;
145
}
146
147
Vector3 GLTFPhysicsBody::get_center_of_mass() const {
148
return center_of_mass;
149
}
150
151
void GLTFPhysicsBody::set_center_of_mass(const Vector3 &p_center_of_mass) {
152
center_of_mass = p_center_of_mass;
153
}
154
155
Vector3 GLTFPhysicsBody::get_inertia_diagonal() const {
156
return inertia_diagonal;
157
}
158
159
void GLTFPhysicsBody::set_inertia_diagonal(const Vector3 &p_inertia_diagonal) {
160
inertia_diagonal = p_inertia_diagonal;
161
}
162
163
Quaternion GLTFPhysicsBody::get_inertia_orientation() const {
164
return inertia_orientation;
165
}
166
167
void GLTFPhysicsBody::set_inertia_orientation(const Quaternion &p_inertia_orientation) {
168
inertia_orientation = p_inertia_orientation;
169
}
170
171
#ifndef DISABLE_DEPRECATED
172
Basis GLTFPhysicsBody::get_inertia_tensor() const {
173
return Basis::from_scale(inertia_diagonal);
174
}
175
176
void GLTFPhysicsBody::set_inertia_tensor(Basis p_inertia_tensor) {
177
inertia_diagonal = p_inertia_tensor.get_main_diagonal();
178
}
179
#endif // DISABLE_DEPRECATED
180
181
Ref<GLTFPhysicsBody> GLTFPhysicsBody::from_node(const CollisionObject3D *p_body_node) {
182
Ref<GLTFPhysicsBody> physics_body;
183
physics_body.instantiate();
184
ERR_FAIL_NULL_V_MSG(p_body_node, physics_body, "Tried to create a GLTFPhysicsBody from a CollisionObject3D node, but the given node was null.");
185
if (cast_to<CharacterBody3D>(p_body_node)) {
186
physics_body->body_type = PhysicsBodyType::CHARACTER;
187
} else if (cast_to<AnimatableBody3D>(p_body_node)) {
188
physics_body->body_type = PhysicsBodyType::ANIMATABLE;
189
} else if (cast_to<RigidBody3D>(p_body_node)) {
190
const RigidBody3D *body = cast_to<const RigidBody3D>(p_body_node);
191
physics_body->mass = body->get_mass();
192
physics_body->linear_velocity = body->get_linear_velocity();
193
physics_body->angular_velocity = body->get_angular_velocity();
194
physics_body->center_of_mass = body->get_center_of_mass();
195
physics_body->inertia_diagonal = body->get_inertia();
196
if (cast_to<VehicleBody3D>(p_body_node)) {
197
physics_body->body_type = PhysicsBodyType::VEHICLE;
198
} else {
199
physics_body->body_type = PhysicsBodyType::RIGID;
200
}
201
} else if (cast_to<StaticBody3D>(p_body_node)) {
202
physics_body->body_type = PhysicsBodyType::STATIC;
203
} else if (cast_to<Area3D>(p_body_node)) {
204
physics_body->body_type = PhysicsBodyType::TRIGGER;
205
}
206
return physics_body;
207
}
208
209
CollisionObject3D *GLTFPhysicsBody::to_node() const {
210
switch (body_type) {
211
case PhysicsBodyType::CHARACTER: {
212
CharacterBody3D *body = memnew(CharacterBody3D);
213
return body;
214
}
215
case PhysicsBodyType::ANIMATABLE: {
216
AnimatableBody3D *body = memnew(AnimatableBody3D);
217
return body;
218
}
219
case PhysicsBodyType::VEHICLE: {
220
VehicleBody3D *body = memnew(VehicleBody3D);
221
body->set_mass(mass);
222
body->set_linear_velocity(linear_velocity);
223
body->set_angular_velocity(angular_velocity);
224
body->set_inertia(inertia_diagonal);
225
body->set_center_of_mass_mode(RigidBody3D::CENTER_OF_MASS_MODE_CUSTOM);
226
body->set_center_of_mass(center_of_mass);
227
return body;
228
}
229
case PhysicsBodyType::RIGID: {
230
RigidBody3D *body = memnew(RigidBody3D);
231
body->set_mass(mass);
232
body->set_linear_velocity(linear_velocity);
233
body->set_angular_velocity(angular_velocity);
234
body->set_inertia(inertia_diagonal);
235
body->set_center_of_mass_mode(RigidBody3D::CENTER_OF_MASS_MODE_CUSTOM);
236
body->set_center_of_mass(center_of_mass);
237
return body;
238
}
239
case PhysicsBodyType::STATIC: {
240
StaticBody3D *body = memnew(StaticBody3D);
241
return body;
242
}
243
case PhysicsBodyType::TRIGGER: {
244
Area3D *body = memnew(Area3D);
245
return body;
246
}
247
}
248
// Unreachable, the switch cases handle all values the enum can take.
249
// Omitting this works on Clang but not GCC or MSVC. If reached, it's UB.
250
return nullptr;
251
}
252
253
Ref<GLTFPhysicsBody> GLTFPhysicsBody::from_dictionary(const Dictionary p_dictionary) {
254
Ref<GLTFPhysicsBody> physics_body;
255
physics_body.instantiate();
256
Dictionary motion;
257
if (p_dictionary.has("motion")) {
258
motion = p_dictionary["motion"];
259
#ifndef DISABLE_DEPRECATED
260
} else {
261
motion = p_dictionary;
262
#endif // DISABLE_DEPRECATED
263
}
264
if (motion.has("type")) {
265
// Read the body type. This representation sits between glTF's and Godot's physics nodes.
266
// While we may only read "static", "kinematic", or "dynamic" from a valid glTF file, we
267
// want to allow another extension to override this to another Godot node type mid-import.
268
// For example, a vehicle extension may want to override the body type to "vehicle"
269
// so Godot generates a VehicleBody3D node. Therefore we distinguish by importing
270
// "dynamic" as "rigid", and "kinematic" as "animatable", in the GLTFPhysicsBody code.
271
String body_type_string = motion["type"];
272
if (body_type_string == "static") {
273
physics_body->body_type = PhysicsBodyType::STATIC;
274
} else if (body_type_string == "kinematic") {
275
physics_body->body_type = PhysicsBodyType::ANIMATABLE;
276
} else if (body_type_string == "dynamic") {
277
physics_body->body_type = PhysicsBodyType::RIGID;
278
#ifndef DISABLE_DEPRECATED
279
} else if (body_type_string == "character") {
280
physics_body->body_type = PhysicsBodyType::CHARACTER;
281
} else if (body_type_string == "rigid") {
282
physics_body->body_type = PhysicsBodyType::RIGID;
283
} else if (body_type_string == "vehicle") {
284
physics_body->body_type = PhysicsBodyType::VEHICLE;
285
} else if (body_type_string == "trigger") {
286
physics_body->body_type = PhysicsBodyType::TRIGGER;
287
#endif // DISABLE_DEPRECATED
288
} else {
289
ERR_PRINT("Error parsing glTF physics body: The body type in the glTF file \"" + body_type_string + "\" was not recognized.");
290
}
291
}
292
if (motion.has("mass")) {
293
physics_body->mass = motion["mass"];
294
}
295
if (motion.has("linearVelocity")) {
296
const Array &arr = motion["linearVelocity"];
297
if (arr.size() == 3) {
298
physics_body->set_linear_velocity(Vector3(arr[0], arr[1], arr[2]));
299
} else {
300
ERR_PRINT("Error parsing glTF physics body: The linear velocity vector must have exactly 3 numbers.");
301
}
302
}
303
if (motion.has("angularVelocity")) {
304
const Array &arr = motion["angularVelocity"];
305
if (arr.size() == 3) {
306
physics_body->set_angular_velocity(Vector3(arr[0], arr[1], arr[2]));
307
} else {
308
ERR_PRINT("Error parsing glTF physics body: The angular velocity vector must have exactly 3 numbers.");
309
}
310
}
311
if (motion.has("centerOfMass")) {
312
const Array &arr = motion["centerOfMass"];
313
if (arr.size() == 3) {
314
physics_body->set_center_of_mass(Vector3(arr[0], arr[1], arr[2]));
315
} else {
316
ERR_PRINT("Error parsing glTF physics body: The center of mass vector must have exactly 3 numbers.");
317
}
318
}
319
if (motion.has("inertiaDiagonal")) {
320
const Array &arr = motion["inertiaDiagonal"];
321
if (arr.size() == 3) {
322
physics_body->set_inertia_diagonal(Vector3(arr[0], arr[1], arr[2]));
323
} else {
324
ERR_PRINT("Error parsing glTF physics body: The inertia diagonal vector must have exactly 3 numbers.");
325
}
326
}
327
if (motion.has("inertiaOrientation")) {
328
const Array &arr = motion["inertiaOrientation"];
329
if (arr.size() == 4) {
330
physics_body->set_inertia_orientation(Quaternion(arr[0], arr[1], arr[2], arr[3]));
331
} else {
332
ERR_PRINT("Error parsing glTF physics body: The inertia orientation quaternion must have exactly 4 numbers.");
333
}
334
}
335
return physics_body;
336
}
337
338
Dictionary GLTFPhysicsBody::to_dictionary() const {
339
Dictionary ret;
340
if (body_type == PhysicsBodyType::TRIGGER) {
341
// The equivalent of a Godot Area3D node in glTF is a node that
342
// defines that it is a trigger, but does not have a shape.
343
Dictionary trigger;
344
ret["trigger"] = trigger;
345
return ret;
346
}
347
// All non-trigger body types are defined using the motion property.
348
Dictionary motion;
349
// When stored in memory, the body type can correspond to a Godot
350
// node type. However, when exporting to glTF, we need to squash
351
// this down to one of "static", "kinematic", or "dynamic".
352
if (body_type == PhysicsBodyType::STATIC) {
353
motion["type"] = "static";
354
} else if (body_type == PhysicsBodyType::ANIMATABLE || body_type == PhysicsBodyType::CHARACTER) {
355
motion["type"] = "kinematic";
356
} else {
357
motion["type"] = "dynamic";
358
}
359
if (mass != 1.0) {
360
motion["mass"] = mass;
361
}
362
if (linear_velocity != Vector3()) {
363
Array velocity_array;
364
velocity_array.resize(3);
365
velocity_array[0] = linear_velocity.x;
366
velocity_array[1] = linear_velocity.y;
367
velocity_array[2] = linear_velocity.z;
368
motion["linearVelocity"] = velocity_array;
369
}
370
if (angular_velocity != Vector3()) {
371
Array velocity_array;
372
velocity_array.resize(3);
373
velocity_array[0] = angular_velocity.x;
374
velocity_array[1] = angular_velocity.y;
375
velocity_array[2] = angular_velocity.z;
376
motion["angularVelocity"] = velocity_array;
377
}
378
if (center_of_mass != Vector3()) {
379
Array center_of_mass_array;
380
center_of_mass_array.resize(3);
381
center_of_mass_array[0] = center_of_mass.x;
382
center_of_mass_array[1] = center_of_mass.y;
383
center_of_mass_array[2] = center_of_mass.z;
384
motion["centerOfMass"] = center_of_mass_array;
385
}
386
if (inertia_diagonal != Vector3()) {
387
Array inertia_array;
388
inertia_array.resize(3);
389
inertia_array[0] = inertia_diagonal[0];
390
inertia_array[1] = inertia_diagonal[1];
391
inertia_array[2] = inertia_diagonal[2];
392
motion["inertiaDiagonal"] = inertia_array;
393
}
394
if (inertia_orientation != Quaternion()) {
395
Array inertia_array;
396
inertia_array.resize(4);
397
inertia_array[0] = inertia_orientation[0];
398
inertia_array[1] = inertia_orientation[1];
399
inertia_array[2] = inertia_orientation[2];
400
inertia_array[3] = inertia_orientation[3];
401
motion["inertiaDiagonal"] = inertia_array;
402
}
403
ret["motion"] = motion;
404
return ret;
405
}
406
407