diff options
Diffstat (limited to 'scene/3d/node_3d.cpp')
-rw-r--r-- | scene/3d/node_3d.cpp | 270 |
1 files changed, 168 insertions, 102 deletions
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index 62cc7c143b..59ec036558 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -85,12 +85,20 @@ void Node3D::_notify_dirty() { } void Node3D::_update_local_transform() const { - if (this->get_rotation_edit_mode() != ROTATION_EDIT_MODE_BASIS) { - data.local_transform = data.local_transform.orthogonalized(); - } - data.local_transform.basis.set_euler_scale(data.rotation, data.scale); + // This function is called when the local transform (data.local_transform) is dirty and the right value is contained in the Euler rotation and scale. + + data.local_transform.basis.set_euler_scale(data.euler_rotation, data.scale, data.euler_rotation_order); - data.dirty &= ~DIRTY_LOCAL; + data.dirty &= ~DIRTY_LOCAL_TRANSFORM; +} + +void Node3D::_update_rotation_and_scale() const { + // This function is called when the Euler rotation (data.euler_rotation) is dirty and the right value is contained in the local transform + + data.scale = data.local_transform.basis.get_scale(); + data.euler_rotation = data.local_transform.basis.get_euler_normalized(data.euler_rotation_order); + + data.dirty &= ~DIRTY_EULER_ROTATION_AND_SCALE; } void Node3D::_propagate_transform_changed(Node3D *p_origin) { @@ -113,7 +121,7 @@ void Node3D::_propagate_transform_changed(Node3D *p_origin) { #endif get_tree()->xform_change_list.add(&xform_change); } - data.dirty |= DIRTY_GLOBAL; + data.dirty |= DIRTY_GLOBAL_TRANSFORM; data.children_lock--; } @@ -137,12 +145,12 @@ void Node3D::_notification(int p_what) { if (data.top_level && !Engine::get_singleton()->is_editor_hint()) { if (data.parent) { data.local_transform = data.parent->get_global_transform() * get_transform(); - data.dirty = DIRTY_VECTORS; //global is always dirty upon entering a scene + data.dirty = DIRTY_EULER_ROTATION_AND_SCALE; // As local transform was updated, rot/scale should be dirty. } data.top_level_active = true; } - data.dirty |= DIRTY_GLOBAL; //global is always dirty upon entering a scene + data.dirty |= DIRTY_GLOBAL_TRANSFORM; // Global is always dirty upon entering a scene. _notify_dirty(); notification(NOTIFICATION_ENTER_WORLD); @@ -180,16 +188,7 @@ void Node3D::_notification(int p_what) { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) { - get_tree()->call_group_flags(0, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this); - if (!data.gizmos_disabled) { - for (int i = 0; i < data.gizmos.size(); i++) { - data.gizmos.write[i]->create(); - if (is_visible_in_tree()) { - data.gizmos.write[i]->redraw(); - } - data.gizmos.write[i]->transform(); - } - } + get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this); } #endif } break; @@ -221,12 +220,49 @@ void Node3D::set_basis(const Basis &p_basis) { set_transform(Transform3D(p_basis, data.local_transform.origin)); } void Node3D::set_quaternion(const Quaternion &p_quaternion) { - set_transform(Transform3D(Basis(p_quaternion), data.local_transform.origin)); + if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) { + // We need the scale part, so if these are dirty, update it + data.scale = data.local_transform.basis.get_scale(); + data.dirty &= ~DIRTY_EULER_ROTATION_AND_SCALE; + } + data.local_transform.basis = Basis(p_quaternion, data.scale); + // Rotscale should not be marked dirty because that would cause precision loss issues with the scale. Instead reconstruct rotation now. + data.euler_rotation = data.local_transform.basis.get_euler_normalized(data.euler_rotation_order); + + data.dirty = DIRTY_NONE; + + _propagate_transform_changed(this); + if (data.notify_local_transform) { + notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); + } +} + +Vector3 Node3D::get_global_position() const { + return get_global_transform().get_origin(); +} + +void Node3D::set_global_position(const Vector3 &p_position) { + Transform3D transform = get_global_transform(); + transform.set_origin(p_position); + set_global_transform(transform); +} + +Vector3 Node3D::get_global_rotation() const { + return get_global_transform().get_basis().get_euler(); +} + +void Node3D::set_global_rotation(const Vector3 &p_euler_rad) { + Transform3D transform = get_global_transform(); + Basis new_basis = transform.get_basis(); + new_basis.set_euler(p_euler_rad); + transform.set_basis(new_basis); + set_global_transform(transform); } void Node3D::set_transform(const Transform3D &p_transform) { data.local_transform = p_transform; - data.dirty |= DIRTY_VECTORS; + data.dirty = DIRTY_EULER_ROTATION_AND_SCALE; // Make rot/scale dirty. + _propagate_transform_changed(this); if (data.notify_local_transform) { notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); @@ -236,8 +272,13 @@ void Node3D::set_transform(const Transform3D &p_transform) { Basis Node3D::get_basis() const { return get_transform().basis; } + Quaternion Node3D::get_quaternion() const { - return Quaternion(get_transform().basis); + if (data.dirty & DIRTY_LOCAL_TRANSFORM) { + _update_local_transform(); + } + + return data.local_transform.basis.get_rotation_quaternion(); } void Node3D::set_global_transform(const Transform3D &p_transform) { @@ -249,7 +290,7 @@ void Node3D::set_global_transform(const Transform3D &p_transform) { } Transform3D Node3D::get_transform() const { - if (data.dirty & DIRTY_LOCAL) { + if (data.dirty & DIRTY_LOCAL_TRANSFORM) { _update_local_transform(); } @@ -258,8 +299,8 @@ Transform3D Node3D::get_transform() const { Transform3D Node3D::get_global_transform() const { ERR_FAIL_COND_V(!is_inside_tree(), Transform3D()); - if (data.dirty & DIRTY_GLOBAL) { - if (data.dirty & DIRTY_LOCAL) { + if (data.dirty & DIRTY_GLOBAL_TRANSFORM) { + if (data.dirty & DIRTY_LOCAL_TRANSFORM) { _update_local_transform(); } @@ -273,7 +314,7 @@ Transform3D Node3D::get_global_transform() const { data.global_transform.basis.orthonormalize(); } - data.dirty &= ~DIRTY_GLOBAL; + data.dirty &= ~DIRTY_GLOBAL_TRANSFORM; } return data.global_transform; @@ -323,13 +364,27 @@ void Node3D::set_rotation_edit_mode(RotationEditMode p_mode) { if (data.rotation_edit_mode == p_mode) { return; } + + bool transform_changed = false; + if (data.rotation_edit_mode == ROTATION_EDIT_MODE_BASIS && !(data.dirty & DIRTY_LOCAL_TRANSFORM)) { + data.local_transform.orthogonalize(); + transform_changed = true; + } + data.rotation_edit_mode = p_mode; - // Shearing is not allowed except in ROTATION_EDIT_MODE_BASIS. - data.dirty |= DIRTY_LOCAL; - _propagate_transform_changed(this); - if (data.notify_local_transform) { - notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); + if (p_mode == ROTATION_EDIT_MODE_EULER && (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE)) { + // If going to Euler mode, ensure that vectors are _not_ dirty, else the retrieved value may be wrong. + // Otherwise keep what is there, so switching back and forth between modes does not break the vectors. + + _update_rotation_and_scale(); + } + + if (transform_changed) { + _propagate_transform_changed(this); + if (data.notify_local_transform) { + notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); + } } notify_property_list_changed(); @@ -342,38 +397,47 @@ Node3D::RotationEditMode Node3D::get_rotation_edit_mode() const { void Node3D::set_rotation_order(RotationOrder p_order) { Basis::EulerOrder order = Basis::EulerOrder(p_order); - if (data.rotation_order == order) { + if (data.euler_rotation_order == order) { return; } ERR_FAIL_INDEX(int32_t(order), 6); + bool transform_changed = false; - if (data.dirty & DIRTY_VECTORS) { - data.rotation = data.local_transform.basis.get_euler_normalized(order); - data.scale = data.local_transform.basis.get_scale(); - data.dirty &= ~DIRTY_VECTORS; + if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) { + _update_rotation_and_scale(); + } else if (data.dirty & DIRTY_LOCAL_TRANSFORM) { + data.euler_rotation = Basis::from_euler(data.euler_rotation, data.euler_rotation_order).get_euler_normalized(order); + transform_changed = true; } else { - data.rotation = Basis::from_euler(data.rotation, data.rotation_order).get_euler_normalized(order); + data.dirty |= DIRTY_LOCAL_TRANSFORM; + transform_changed = true; } - data.rotation_order = order; - //changing rotation order should not affect transform + data.euler_rotation_order = order; - notify_property_list_changed(); //will change rotation + if (transform_changed) { + _propagate_transform_changed(this); + if (data.notify_local_transform) { + notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); + } + } + notify_property_list_changed(); // Will change the rotation property. } Node3D::RotationOrder Node3D::get_rotation_order() const { - return RotationOrder(data.rotation_order); + return RotationOrder(data.euler_rotation_order); } void Node3D::set_rotation(const Vector3 &p_euler_rad) { - if (data.dirty & DIRTY_VECTORS) { + if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) { + // Update scale only if rotation and scale are dirty, as rotation will be overridden. data.scale = data.local_transform.basis.get_scale(); - data.dirty &= ~DIRTY_VECTORS; + data.dirty &= ~DIRTY_EULER_ROTATION_AND_SCALE; } - data.rotation = p_euler_rad; - data.dirty |= DIRTY_LOCAL; + data.euler_rotation = p_euler_rad; + data.dirty = DIRTY_LOCAL_TRANSFORM; _propagate_transform_changed(this); if (data.notify_local_transform) { notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); @@ -381,13 +445,14 @@ void Node3D::set_rotation(const Vector3 &p_euler_rad) { } void Node3D::set_scale(const Vector3 &p_scale) { - if (data.dirty & DIRTY_VECTORS) { - data.rotation = data.local_transform.basis.get_euler_normalized(data.rotation_order); - data.dirty &= ~DIRTY_VECTORS; + if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) { + // Update rotation only if rotation and scale are dirty, as scale will be overridden. + data.euler_rotation = data.local_transform.basis.get_euler_normalized(data.euler_rotation_order); + data.dirty &= ~DIRTY_EULER_ROTATION_AND_SCALE; } data.scale = p_scale; - data.dirty |= DIRTY_LOCAL; + data.dirty = DIRTY_LOCAL_TRANSFORM; _propagate_transform_changed(this); if (data.notify_local_transform) { notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); @@ -399,22 +464,16 @@ Vector3 Node3D::get_position() const { } Vector3 Node3D::get_rotation() const { - if (data.dirty & DIRTY_VECTORS) { - data.scale = data.local_transform.basis.get_scale(); - data.rotation = data.local_transform.basis.get_euler_normalized(data.rotation_order); - - data.dirty &= ~DIRTY_VECTORS; + if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) { + _update_rotation_and_scale(); } - return data.rotation; + return data.euler_rotation; } Vector3 Node3D::get_scale() const { - if (data.dirty & DIRTY_VECTORS) { - data.scale = data.local_transform.basis.get_scale(); - data.rotation = data.local_transform.basis.get_euler_normalized(data.rotation_order); - - data.dirty &= ~DIRTY_VECTORS; + if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) { + _update_rotation_and_scale(); } return data.scale; @@ -427,6 +486,7 @@ void Node3D::update_gizmos() { } if (data.gizmos.is_empty()) { + get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this); return; } if (data.gizmos_dirty) { @@ -444,7 +504,7 @@ void Node3D::set_subgizmo_selection(Ref<Node3DGizmo> p_gizmo, int p_id, Transfor } if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) { - get_tree()->call_group_flags(0, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_set_subgizmo_selection, this, p_gizmo, p_id, p_transform); + get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_set_subgizmo_selection, this, p_gizmo, p_id, p_transform); } #endif } @@ -460,7 +520,7 @@ void Node3D::clear_subgizmo_selection() { } if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) { - get_tree()->call_group_flags(0, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_clear_subgizmo_selection, this); + get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_clear_subgizmo_selection, this); } #endif } @@ -501,8 +561,8 @@ void Node3D::clear_gizmos() { #endif } -Array Node3D::get_gizmos_bind() const { - Array ret; +TypedArray<Node3DGizmo> Node3D::get_gizmos_bind() const { + TypedArray<Node3DGizmo> ret; #ifdef TOOLS_ENABLED for (int i = 0; i < data.gizmos.size(); i++) { @@ -673,7 +733,7 @@ void Node3D::rotate_z(real_t p_angle) { void Node3D::translate(const Vector3 &p_offset) { Transform3D t = get_transform(); - t.translate(p_offset); + t.translate_local(p_offset); set_transform(t); } @@ -681,7 +741,7 @@ void Node3D::translate_object_local(const Vector3 &p_offset) { Transform3D t = get_transform(); Transform3D s; - s.translate(p_offset); + s.translate_local(p_offset); set_transform(t * s); } @@ -732,8 +792,8 @@ void Node3D::look_at(const Vector3 &p_target, const Vector3 &p_up) { void Node3D::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) { ERR_FAIL_COND_MSG(p_pos.is_equal_approx(p_target), "Node origin and target are in the same position, look_at() failed."); - ERR_FAIL_COND_MSG(p_up.is_equal_approx(Vector3()), "The up vector can't be zero, look_at() failed."); - ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos).is_equal_approx(Vector3()), "Up vector and direction between node origin and target are aligned, look_at() failed."); + ERR_FAIL_COND_MSG(p_up.is_zero_approx(), "The up vector can't be zero, look_at() failed."); + ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos).is_zero_approx(), "Up vector and direction between node origin and target are aligned, look_at() failed."); Transform3D lookat = Transform3D(Basis::looking_at(p_target - p_pos, p_up), p_pos); Vector3 original_scale = get_scale(); @@ -819,25 +879,25 @@ NodePath Node3D::get_visibility_parent() const { return visibility_parent_path; } -void Node3D::_validate_property(PropertyInfo &property) const { - if (data.rotation_edit_mode != ROTATION_EDIT_MODE_BASIS && property.name == "basis") { - property.usage = 0; +void Node3D::_validate_property(PropertyInfo &p_property) const { + if (data.rotation_edit_mode != ROTATION_EDIT_MODE_BASIS && p_property.name == "basis") { + p_property.usage = 0; } - if (data.rotation_edit_mode == ROTATION_EDIT_MODE_BASIS && property.name == "scale") { - property.usage = 0; + if (data.rotation_edit_mode == ROTATION_EDIT_MODE_BASIS && p_property.name == "scale") { + p_property.usage = 0; } - if (data.rotation_edit_mode != ROTATION_EDIT_MODE_QUATERNION && property.name == "quaternion") { - property.usage = 0; + if (data.rotation_edit_mode != ROTATION_EDIT_MODE_QUATERNION && p_property.name == "quaternion") { + p_property.usage = 0; } - if (data.rotation_edit_mode != ROTATION_EDIT_MODE_EULER && property.name == "rotation") { - property.usage = 0; + if (data.rotation_edit_mode != ROTATION_EDIT_MODE_EULER && p_property.name == "rotation") { + p_property.usage = 0; } - if (data.rotation_edit_mode != ROTATION_EDIT_MODE_EULER && property.name == "rotation_order") { - property.usage = 0; + if (data.rotation_edit_mode != ROTATION_EDIT_MODE_EULER && p_property.name == "rotation_order") { + p_property.usage = 0; } } -bool Node3D::property_can_revert(const String &p_name) { +bool Node3D::_property_can_revert(const StringName &p_name) const { if (p_name == "basis") { return true; } else if (p_name == "scale") { @@ -852,47 +912,48 @@ bool Node3D::property_can_revert(const String &p_name) { return false; } -Variant Node3D::property_get_revert(const String &p_name) { - Variant r_ret; +bool Node3D::_property_get_revert(const StringName &p_name, Variant &r_property) const { bool valid = false; if (p_name == "basis") { Variant variant = PropertyUtils::get_property_default_value(this, "transform", &valid); if (valid && variant.get_type() == Variant::Type::TRANSFORM3D) { - r_ret = Transform3D(variant).get_basis(); + r_property = Transform3D(variant).get_basis(); } else { - r_ret = Basis(); + r_property = Basis(); } } else if (p_name == "scale") { Variant variant = PropertyUtils::get_property_default_value(this, "transform", &valid); if (valid && variant.get_type() == Variant::Type::TRANSFORM3D) { - r_ret = Transform3D(variant).get_basis().get_scale(); + r_property = Transform3D(variant).get_basis().get_scale(); } else { - return Vector3(1.0, 1.0, 1.0); + r_property = Vector3(1.0, 1.0, 1.0); } } else if (p_name == "quaternion") { Variant variant = PropertyUtils::get_property_default_value(this, "transform", &valid); if (valid && variant.get_type() == Variant::Type::TRANSFORM3D) { - r_ret = Quaternion(Transform3D(variant).get_basis()); + r_property = Quaternion(Transform3D(variant).get_basis().get_rotation_quaternion()); } else { - return Quaternion(); + r_property = Quaternion(); } } else if (p_name == "rotation") { Variant variant = PropertyUtils::get_property_default_value(this, "transform", &valid); if (valid && variant.get_type() == Variant::Type::TRANSFORM3D) { - r_ret = Transform3D(variant).get_basis().get_euler_normalized(data.rotation_order); + r_property = Transform3D(variant).get_basis().get_euler_normalized(data.euler_rotation_order); } else { - return Vector3(); + r_property = Vector3(); } } else if (p_name == "position") { Variant variant = PropertyUtils::get_property_default_value(this, "transform", &valid); if (valid) { - r_ret = Transform3D(variant).get_origin(); + r_property = Transform3D(variant).get_origin(); } else { - return Vector3(); + r_property = Vector3(); } + } else { + return false; } - return r_ret; + return true; } void Node3D::_bind_methods() { @@ -912,8 +973,14 @@ void Node3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_quaternion"), &Node3D::get_quaternion); ClassDB::bind_method(D_METHOD("set_basis", "basis"), &Node3D::set_basis); ClassDB::bind_method(D_METHOD("get_basis"), &Node3D::get_basis); + ClassDB::bind_method(D_METHOD("set_global_transform", "global"), &Node3D::set_global_transform); ClassDB::bind_method(D_METHOD("get_global_transform"), &Node3D::get_global_transform); + ClassDB::bind_method(D_METHOD("set_global_position", "position"), &Node3D::set_global_position); + ClassDB::bind_method(D_METHOD("get_global_position"), &Node3D::get_global_position); + ClassDB::bind_method(D_METHOD("set_global_rotation", "radians"), &Node3D::set_global_rotation); + ClassDB::bind_method(D_METHOD("get_global_rotation"), &Node3D::get_global_rotation); + ClassDB::bind_method(D_METHOD("get_parent_node_3d"), &Node3D::get_parent_node_3d); ClassDB::bind_method(D_METHOD("set_ignore_transform_notification", "enabled"), &Node3D::set_ignore_transform_notification); ClassDB::bind_method(D_METHOD("set_as_top_level", "enable"), &Node3D::set_as_top_level); @@ -966,9 +1033,6 @@ void Node3D::_bind_methods() { ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Node3D::to_local); ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Node3D::to_global); - ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &Node3D::property_can_revert); - ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &Node3D::property_get_revert); - BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED); BIND_CONSTANT(NOTIFICATION_ENTER_WORLD); BIND_CONSTANT(NOTIFICATION_EXIT_WORLD); @@ -985,18 +1049,20 @@ void Node3D::_bind_methods() { BIND_ENUM_CONSTANT(ROTATION_ORDER_ZXY); BIND_ENUM_CONSTANT(ROTATION_ORDER_ZYX); - //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM3D,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), "set_global_transform", "get_global_transform") ; ADD_GROUP("Transform", ""); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_transform", "get_transform"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_lesser,noslider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation"); - ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "quaternion", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_quaternion", "get_quaternion"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NO_EDITOR), "set_transform", "get_transform"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_less,no_slider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "quaternion", PROPERTY_HINT_HIDE_QUATERNION_EDIT, "", PROPERTY_USAGE_EDITOR), "set_quaternion", "get_quaternion"); ADD_PROPERTY(PropertyInfo(Variant::BASIS, "basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_basis", "get_basis"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_LINK, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_edit_mode", PROPERTY_HINT_ENUM, "Euler,Quaternion,Basis"), "set_rotation_edit_mode", "get_rotation_edit_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_order", PROPERTY_HINT_ENUM, "XYZ,XZY,YXZ,YZX,ZXY,ZYX"), "set_rotation_order", "get_rotation_order"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level"); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_position", "get_global_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_rotation", "get_global_rotation"); ADD_GROUP("Visibility", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "visibility_parent", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GeometryInstance3D"), "set_visibility_parent", "get_visibility_parent"); |