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