Path: blob/master/scene/3d/convert_transform_modifier_3d.cpp
9896 views
/**************************************************************************/1/* convert_transform_modifier_3d.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 "convert_transform_modifier_3d.h"3132constexpr const char *HINT_POSITION = "-10,10,0.01,or_greater,or_less,suffix:m";33constexpr const char *HINT_ROTATION = "-180,180,0.01,radians_as_degrees";34constexpr const char *HINT_SCALE = "0,10,0.01,or_greater";3536bool ConvertTransformModifier3D::_set(const StringName &p_path, const Variant &p_value) {37String path = p_path;3839if (path.begins_with("settings/")) {40int which = path.get_slicec('/', 1).to_int();41String where = path.get_slicec('/', 2);42ERR_FAIL_INDEX_V(which, settings.size(), false);43String what = path.get_slicec('/', 3);4445if (where == "apply") {46if (what == "transform_mode") {47set_apply_transform_mode(which, static_cast<TransformMode>((int)p_value));48} else if (what == "axis") {49set_apply_axis(which, static_cast<Vector3::Axis>((int)p_value));50} else if (what == "range_min") {51set_apply_range_min(which, p_value);52} else if (what == "range_max") {53set_apply_range_max(which, p_value);54} else {55return false;56}57} else if (where == "reference") {58if (what == "transform_mode") {59set_reference_transform_mode(which, static_cast<TransformMode>((int)p_value));60} else if (what == "axis") {61set_reference_axis(which, static_cast<Vector3::Axis>((int)p_value));62} else if (what == "range_min") {63set_reference_range_min(which, p_value);64} else if (what == "range_max") {65set_reference_range_max(which, p_value);66} else {67return false;68}69} else if (where == "relative") {70set_relative(which, p_value);71} else if (where == "additive") {72set_additive(which, p_value);73} else {74return false;75}76}77return true;78}7980bool ConvertTransformModifier3D::_get(const StringName &p_path, Variant &r_ret) const {81String path = p_path;8283if (path.begins_with("settings/")) {84int which = path.get_slicec('/', 1).to_int();85String where = path.get_slicec('/', 2);86ERR_FAIL_INDEX_V(which, settings.size(), false);87String what = path.get_slicec('/', 3);8889if (where == "apply") {90if (what == "transform_mode") {91r_ret = (int)get_apply_transform_mode(which);92} else if (what == "axis") {93r_ret = (int)get_apply_axis(which);94} else if (what == "range_min") {95r_ret = get_apply_range_min(which);96} else if (what == "range_max") {97r_ret = get_apply_range_max(which);98} else {99return false;100}101} else if (where == "reference") {102if (what == "transform_mode") {103r_ret = (int)get_reference_transform_mode(which);104} else if (what == "axis") {105r_ret = (int)get_reference_axis(which);106} else if (what == "range_min") {107r_ret = get_reference_range_min(which);108} else if (what == "range_max") {109r_ret = get_reference_range_max(which);110} else {111return false;112}113} else if (where == "relative") {114r_ret = is_relative(which);115} else if (where == "additive") {116r_ret = is_additive(which);117} else {118return false;119}120}121return true;122}123124void ConvertTransformModifier3D::_get_property_list(List<PropertyInfo> *p_list) const {125BoneConstraint3D::get_property_list(p_list);126127for (int i = 0; i < settings.size(); i++) {128String path = "settings/" + itos(i) + "/";129130String hint_apply_range;131if (get_apply_transform_mode(i) == TRANSFORM_MODE_POSITION) {132hint_apply_range = HINT_POSITION;133} else if (get_apply_transform_mode(i) == TRANSFORM_MODE_ROTATION) {134hint_apply_range = HINT_ROTATION;135} else {136hint_apply_range = HINT_SCALE;137}138p_list->push_back(PropertyInfo(Variant::INT, path + "apply/transform_mode", PROPERTY_HINT_ENUM, "Position,Rotation,Scale"));139p_list->push_back(PropertyInfo(Variant::INT, path + "apply/axis", PROPERTY_HINT_ENUM, "X,Y,Z"));140p_list->push_back(PropertyInfo(Variant::FLOAT, path + "apply/range_min", PROPERTY_HINT_RANGE, hint_apply_range));141p_list->push_back(PropertyInfo(Variant::FLOAT, path + "apply/range_max", PROPERTY_HINT_RANGE, hint_apply_range));142143String hint_reference_range;144if (get_reference_transform_mode(i) == TRANSFORM_MODE_POSITION) {145hint_reference_range = HINT_POSITION;146} else if (get_reference_transform_mode(i) == TRANSFORM_MODE_ROTATION) {147hint_reference_range = HINT_ROTATION;148} else {149hint_reference_range = HINT_SCALE;150}151p_list->push_back(PropertyInfo(Variant::INT, path + "reference/transform_mode", PROPERTY_HINT_ENUM, "Position,Rotation,Scale"));152p_list->push_back(PropertyInfo(Variant::INT, path + "reference/axis", PROPERTY_HINT_ENUM, "X,Y,Z"));153p_list->push_back(PropertyInfo(Variant::FLOAT, path + "reference/range_min", PROPERTY_HINT_RANGE, hint_reference_range));154p_list->push_back(PropertyInfo(Variant::FLOAT, path + "reference/range_max", PROPERTY_HINT_RANGE, hint_reference_range));155156p_list->push_back(PropertyInfo(Variant::BOOL, path + "relative"));157p_list->push_back(PropertyInfo(Variant::BOOL, path + "additive"));158}159}160161void ConvertTransformModifier3D::_validate_setting(int p_index) {162settings.write[p_index] = memnew(ConvertTransform3DSetting);163}164165void ConvertTransformModifier3D::set_apply_transform_mode(int p_index, TransformMode p_transform_mode) {166ERR_FAIL_INDEX(p_index, settings.size());167ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);168setting->apply_transform_mode = p_transform_mode;169notify_property_list_changed();170}171172ConvertTransformModifier3D::TransformMode ConvertTransformModifier3D::get_apply_transform_mode(int p_index) const {173ERR_FAIL_INDEX_V(p_index, settings.size(), TRANSFORM_MODE_POSITION);174ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);175return setting->apply_transform_mode;176}177178void ConvertTransformModifier3D::set_apply_axis(int p_index, Vector3::Axis p_axis) {179ERR_FAIL_INDEX(p_index, settings.size());180ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);181setting->apply_axis = p_axis;182}183184Vector3::Axis ConvertTransformModifier3D::get_apply_axis(int p_index) const {185ERR_FAIL_INDEX_V(p_index, settings.size(), Vector3::AXIS_X);186ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);187return setting->apply_axis;188}189190void ConvertTransformModifier3D::set_apply_range_min(int p_index, float p_range_min) {191ERR_FAIL_INDEX(p_index, settings.size());192ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);193setting->apply_range_min = p_range_min;194}195196float ConvertTransformModifier3D::get_apply_range_min(int p_index) const {197ERR_FAIL_INDEX_V(p_index, settings.size(), 0);198ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);199return setting->apply_range_min;200}201202void ConvertTransformModifier3D::set_apply_range_max(int p_index, float p_range_max) {203ERR_FAIL_INDEX(p_index, settings.size());204ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);205setting->apply_range_max = p_range_max;206}207208float ConvertTransformModifier3D::get_apply_range_max(int p_index) const {209ERR_FAIL_INDEX_V(p_index, settings.size(), 0);210ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);211return setting->apply_range_max;212}213214void ConvertTransformModifier3D::set_reference_transform_mode(int p_index, TransformMode p_transform_mode) {215ERR_FAIL_INDEX(p_index, settings.size());216ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);217setting->reference_transform_mode = p_transform_mode;218notify_property_list_changed();219}220221ConvertTransformModifier3D::TransformMode ConvertTransformModifier3D::get_reference_transform_mode(int p_index) const {222ERR_FAIL_INDEX_V(p_index, settings.size(), TRANSFORM_MODE_POSITION);223ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);224return setting->reference_transform_mode;225}226227void ConvertTransformModifier3D::set_reference_axis(int p_index, Vector3::Axis p_axis) {228ERR_FAIL_INDEX(p_index, settings.size());229ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);230setting->reference_axis = p_axis;231}232233Vector3::Axis ConvertTransformModifier3D::get_reference_axis(int p_index) const {234ERR_FAIL_INDEX_V(p_index, settings.size(), Vector3::AXIS_X);235ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);236return setting->reference_axis;237}238239void ConvertTransformModifier3D::set_reference_range_min(int p_index, float p_range_min) {240ERR_FAIL_INDEX(p_index, settings.size());241ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);242setting->reference_range_min = p_range_min;243}244245float ConvertTransformModifier3D::get_reference_range_min(int p_index) const {246ERR_FAIL_INDEX_V(p_index, settings.size(), 0);247ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);248return setting->reference_range_min;249}250251void ConvertTransformModifier3D::set_reference_range_max(int p_index, float p_range_max) {252ERR_FAIL_INDEX(p_index, settings.size());253ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);254setting->reference_range_max = p_range_max;255}256257float ConvertTransformModifier3D::get_reference_range_max(int p_index) const {258ERR_FAIL_INDEX_V(p_index, settings.size(), 0);259ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);260return setting->reference_range_max;261}262263void ConvertTransformModifier3D::set_relative(int p_index, bool p_enabled) {264ERR_FAIL_INDEX(p_index, settings.size());265ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);266setting->relative = p_enabled;267}268269bool ConvertTransformModifier3D::is_relative(int p_index) const {270ERR_FAIL_INDEX_V(p_index, settings.size(), 0);271ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);272return setting->relative;273}274275void ConvertTransformModifier3D::set_additive(int p_index, bool p_enabled) {276ERR_FAIL_INDEX(p_index, settings.size());277ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);278setting->additive = p_enabled;279}280281bool ConvertTransformModifier3D::is_additive(int p_index) const {282ERR_FAIL_INDEX_V(p_index, settings.size(), 0);283ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);284return setting->additive;285}286287void ConvertTransformModifier3D::_bind_methods() {288ClassDB::bind_method(D_METHOD("set_apply_transform_mode", "index", "transform_mode"), &ConvertTransformModifier3D::set_apply_transform_mode);289ClassDB::bind_method(D_METHOD("get_apply_transform_mode", "index"), &ConvertTransformModifier3D::get_apply_transform_mode);290ClassDB::bind_method(D_METHOD("set_apply_axis", "index", "axis"), &ConvertTransformModifier3D::set_apply_axis);291ClassDB::bind_method(D_METHOD("get_apply_axis", "index"), &ConvertTransformModifier3D::get_apply_axis);292ClassDB::bind_method(D_METHOD("set_apply_range_min", "index", "range_min"), &ConvertTransformModifier3D::set_apply_range_min);293ClassDB::bind_method(D_METHOD("get_apply_range_min", "index"), &ConvertTransformModifier3D::get_apply_range_min);294ClassDB::bind_method(D_METHOD("set_apply_range_max", "index", "range_max"), &ConvertTransformModifier3D::set_apply_range_max);295ClassDB::bind_method(D_METHOD("get_apply_range_max", "index"), &ConvertTransformModifier3D::get_apply_range_max);296297ClassDB::bind_method(D_METHOD("set_reference_transform_mode", "index", "transform_mode"), &ConvertTransformModifier3D::set_reference_transform_mode);298ClassDB::bind_method(D_METHOD("get_reference_transform_mode", "index"), &ConvertTransformModifier3D::get_reference_transform_mode);299ClassDB::bind_method(D_METHOD("set_reference_axis", "index", "axis"), &ConvertTransformModifier3D::set_reference_axis);300ClassDB::bind_method(D_METHOD("get_reference_axis", "index"), &ConvertTransformModifier3D::get_reference_axis);301ClassDB::bind_method(D_METHOD("set_reference_range_min", "index", "range_min"), &ConvertTransformModifier3D::set_reference_range_min);302ClassDB::bind_method(D_METHOD("get_reference_range_min", "index"), &ConvertTransformModifier3D::get_reference_range_min);303ClassDB::bind_method(D_METHOD("set_reference_range_max", "index", "range_max"), &ConvertTransformModifier3D::set_reference_range_max);304ClassDB::bind_method(D_METHOD("get_reference_range_max", "index"), &ConvertTransformModifier3D::get_reference_range_max);305306ClassDB::bind_method(D_METHOD("set_relative", "index", "enabled"), &ConvertTransformModifier3D::set_relative);307ClassDB::bind_method(D_METHOD("is_relative", "index"), &ConvertTransformModifier3D::is_relative);308ClassDB::bind_method(D_METHOD("set_additive", "index", "enabled"), &ConvertTransformModifier3D::set_additive);309ClassDB::bind_method(D_METHOD("is_additive", "index"), &ConvertTransformModifier3D::is_additive);310311ADD_ARRAY_COUNT("Settings", "setting_count", "set_setting_count", "get_setting_count", "settings/");312313BIND_ENUM_CONSTANT(TRANSFORM_MODE_POSITION);314BIND_ENUM_CONSTANT(TRANSFORM_MODE_ROTATION);315BIND_ENUM_CONSTANT(TRANSFORM_MODE_SCALE);316}317318void ConvertTransformModifier3D::_process_constraint(int p_index, Skeleton3D *p_skeleton, int p_apply_bone, int p_reference_bone, float p_amount) {319ConvertTransform3DSetting *setting = static_cast<ConvertTransform3DSetting *>(settings[p_index]);320321Transform3D destination = p_skeleton->get_bone_pose(p_reference_bone);322if (setting->relative) {323Vector3 scl_relative = destination.basis.get_scale() / p_skeleton->get_bone_rest(p_reference_bone).basis.get_scale();324destination.basis = p_skeleton->get_bone_rest(p_reference_bone).basis.get_rotation_quaternion().inverse() * destination.basis.get_rotation_quaternion();325destination.basis.scale_local(scl_relative);326destination.origin = destination.origin - p_skeleton->get_bone_rest(p_reference_bone).origin;327}328329// Retrieve point from reference.330double point = 0.0;331int axis = (int)setting->reference_axis;332switch (setting->reference_transform_mode) {333case TRANSFORM_MODE_POSITION: {334point = destination.origin[axis];335} break;336case TRANSFORM_MODE_ROTATION: {337Quaternion tgt_rot = destination.basis.get_rotation_quaternion();338point = get_roll_angle(tgt_rot, get_vector_from_axis(setting->reference_axis));339} break;340case TRANSFORM_MODE_SCALE: {341point = destination.basis.get_scale()[axis];342} break;343}344// Convert point to apply.345destination = p_skeleton->get_bone_pose(p_apply_bone);346if (Math::is_equal_approx(setting->reference_range_min, setting->reference_range_max)) {347point = point <= (double)setting->reference_range_min ? 0 : 1;348} else {349point = Math::inverse_lerp((double)setting->reference_range_min, (double)setting->reference_range_max, point);350}351point = Math::lerp((double)setting->apply_range_min, (double)setting->apply_range_max, CLAMP(point, 0, 1));352axis = (int)setting->apply_axis;353switch (setting->apply_transform_mode) {354case TRANSFORM_MODE_POSITION: {355if (setting->additive) {356point = p_skeleton->get_bone_pose(p_apply_bone).origin[axis] + point;357} else if (setting->relative) {358point = p_skeleton->get_bone_rest(p_apply_bone).origin[axis] + point;359}360destination.origin[axis] = point;361} break;362case TRANSFORM_MODE_ROTATION: {363Vector3 rot_axis = get_vector_from_axis(setting->apply_axis);364Vector3 dest_scl = destination.basis.get_scale();365if (influence < 1.0 || p_amount < 1.0) {366point = CLAMP(point, CMP_EPSILON - Math::PI, Math::PI - CMP_EPSILON); // Hack to consistent slerp (interpolate_with) orientation since -180/180 deg rot is mixed in slerp.367}368Quaternion rot = Quaternion(rot_axis, point);369if (setting->additive) {370destination.basis = p_skeleton->get_bone_pose(p_apply_bone).basis.get_rotation_quaternion() * rot;371} else if (setting->relative) {372destination.basis = p_skeleton->get_bone_rest(p_apply_bone).basis.get_rotation_quaternion() * rot;373} else {374destination.basis = rot;375}376// Scale may not have meaning, but it might affect when it is negative.377destination.basis.scale_local(dest_scl);378} break;379case TRANSFORM_MODE_SCALE: {380Vector3 dest_scl = Vector3(1, 1, 1);381if (setting->additive) {382dest_scl = p_skeleton->get_bone_pose(p_apply_bone).basis.get_scale();383dest_scl[axis] = dest_scl[axis] * point;384} else if (setting->relative) {385dest_scl = p_skeleton->get_bone_rest(p_apply_bone).basis.get_scale();386dest_scl[axis] = dest_scl[axis] * point;387} else {388dest_scl = p_skeleton->get_bone_pose(p_apply_bone).basis.get_scale();389dest_scl[axis] = point;390}391destination.basis = destination.basis.orthonormalized().scaled_local(dest_scl);392} break;393}394// Process interpolation depends on the amount.395destination = p_skeleton->get_bone_pose(p_apply_bone).interpolate_with(destination, p_amount);396// Apply transform depends on the mode.397switch (setting->apply_transform_mode) {398case TRANSFORM_MODE_POSITION: {399p_skeleton->set_bone_pose_position(p_apply_bone, destination.origin);400} break;401case TRANSFORM_MODE_ROTATION: {402p_skeleton->set_bone_pose_rotation(p_apply_bone, destination.basis.get_rotation_quaternion());403} break;404case TRANSFORM_MODE_SCALE: {405p_skeleton->set_bone_pose_scale(p_apply_bone, destination.basis.get_scale());406} break;407}408}409410ConvertTransformModifier3D::~ConvertTransformModifier3D() {411clear_settings();412}413414415