diff options
Diffstat (limited to 'scene/3d')
-rw-r--r-- | scene/3d/bone_attachment_3d.cpp | 21 | ||||
-rw-r--r-- | scene/3d/bone_attachment_3d.h | 6 | ||||
-rw-r--r-- | scene/3d/cpu_particles_3d.cpp | 11 | ||||
-rw-r--r-- | scene/3d/decal.cpp | 4 | ||||
-rw-r--r-- | scene/3d/gpu_particles_3d.cpp | 2 | ||||
-rw-r--r-- | scene/3d/label_3d.cpp | 21 | ||||
-rw-r--r-- | scene/3d/label_3d.h | 24 | ||||
-rw-r--r-- | scene/3d/light_3d.cpp | 5 | ||||
-rw-r--r-- | scene/3d/light_3d.h | 2 | ||||
-rw-r--r-- | scene/3d/lightmap_gi.cpp | 12 | ||||
-rw-r--r-- | scene/3d/lightmap_gi.h | 10 | ||||
-rw-r--r-- | scene/3d/lightmapper.h | 6 | ||||
-rw-r--r-- | scene/3d/navigation_agent_3d.cpp | 42 | ||||
-rw-r--r-- | scene/3d/navigation_agent_3d.h | 9 | ||||
-rw-r--r-- | scene/3d/navigation_region_3d.cpp | 21 | ||||
-rw-r--r-- | scene/3d/navigation_region_3d.h | 3 | ||||
-rw-r--r-- | scene/3d/node_3d.cpp | 181 | ||||
-rw-r--r-- | scene/3d/node_3d.h | 36 | ||||
-rw-r--r-- | scene/3d/path_3d.cpp | 90 | ||||
-rw-r--r-- | scene/3d/path_3d.h | 11 | ||||
-rw-r--r-- | scene/3d/skeleton_3d.cpp | 12 | ||||
-rw-r--r-- | scene/3d/sprite_3d.cpp | 5 | ||||
-rw-r--r-- | scene/3d/visual_instance_3d.cpp | 2 | ||||
-rw-r--r-- | scene/3d/visual_instance_3d.h | 2 |
24 files changed, 427 insertions, 111 deletions
diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp index d0aeffb166..fbd5b5b65b 100644 --- a/scene/3d/bone_attachment_3d.cpp +++ b/scene/3d/bone_attachment_3d.cpp @@ -376,6 +376,24 @@ void BoneAttachment3D::on_bone_pose_update(int p_bone_index) { } } } +#ifdef TOOLS_ENABLED +void BoneAttachment3D::_notify_skeleton_bones_renamed(Node *p_base_scene, Skeleton3D *p_skeleton, Ref<BoneMap> p_bone_map) { + const Skeleton3D *parent = nullptr; + if (use_external_skeleton) { + if (external_skeleton_node_cache.is_valid()) { + parent = Object::cast_to<Skeleton3D>(ObjectDB::get_instance(external_skeleton_node_cache)); + } + } else { + parent = Object::cast_to<Skeleton3D>(get_parent()); + } + if (parent && parent == p_skeleton) { + StringName bn = p_bone_map->find_profile_bone_name(bone_name); + if (bn) { + set_bone_name(bn); + } + } +} +#endif // TOOLS_ENABLED BoneAttachment3D::BoneAttachment3D() { } @@ -398,6 +416,9 @@ void BoneAttachment3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_use_external_skeleton"), &BoneAttachment3D::get_use_external_skeleton); ClassDB::bind_method(D_METHOD("set_external_skeleton", "external_skeleton"), &BoneAttachment3D::set_external_skeleton); ClassDB::bind_method(D_METHOD("get_external_skeleton"), &BoneAttachment3D::get_external_skeleton); +#ifdef TOOLS_ENABLED + ClassDB::bind_method(D_METHOD("_notify_skeleton_bones_renamed"), &BoneAttachment3D::_notify_skeleton_bones_renamed); +#endif // TOOLS_ENABLED ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bone_name"), "set_bone_name", "get_bone_name"); ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_idx"), "set_bone_idx", "get_bone_idx"); diff --git a/scene/3d/bone_attachment_3d.h b/scene/3d/bone_attachment_3d.h index 395dfde1d7..137360b141 100644 --- a/scene/3d/bone_attachment_3d.h +++ b/scene/3d/bone_attachment_3d.h @@ -32,6 +32,9 @@ #define BONE_ATTACHMENT_H #include "scene/3d/skeleton_3d.h" +#ifdef TOOLS_ENABLED +#include "scene/resources/bone_map.h" +#endif // TOOLS_ENABLED class BoneAttachment3D : public Node3D { GDCLASS(BoneAttachment3D, Node3D); @@ -68,6 +71,9 @@ protected: void _notification(int p_what); static void _bind_methods(); +#ifdef TOOLS_ENABLED + virtual void _notify_skeleton_bones_renamed(Node *p_base_scene, Skeleton3D *p_skeleton, Ref<BoneMap> p_bone_map); +#endif // TOOLS_ENABLED public: virtual TypedArray<String> get_configuration_warnings() const override; diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index 8585f3bdfc..4df0c37ad6 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -164,6 +164,8 @@ void CPUParticles3D::set_mesh(const Ref<Mesh> &p_mesh) { } else { RS::get_singleton()->multimesh_set_mesh(multimesh, RID()); } + + update_configuration_warnings(); } Ref<Mesh> CPUParticles3D::get_mesh() const { @@ -187,7 +189,7 @@ bool CPUParticles3D::get_fractional_delta() const { } TypedArray<String> CPUParticles3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); + TypedArray<String> warnings = GeometryInstance3D::get_configuration_warnings(); bool mesh_found = false; bool anim_material_found = false; @@ -266,6 +268,8 @@ void CPUParticles3D::set_param_min(Parameter p_param, real_t p_value) { if (parameters_min[p_param] > parameters_max[p_param]) { set_param_max(p_param, p_value); } + + update_configuration_warnings(); } real_t CPUParticles3D::get_param_min(Parameter p_param) const { @@ -276,10 +280,13 @@ real_t CPUParticles3D::get_param_min(Parameter p_param) const { void CPUParticles3D::set_param_max(Parameter p_param, real_t p_value) { ERR_FAIL_INDEX(p_param, PARAM_MAX); + parameters_max[p_param] = p_value; if (parameters_min[p_param] > parameters_max[p_param]) { set_param_min(p_param, p_value); } + + update_configuration_warnings(); } real_t CPUParticles3D::get_param_max(Parameter p_param) const { @@ -340,6 +347,8 @@ void CPUParticles3D::set_param_curve(Parameter p_param, const Ref<Curve> &p_curv default: { } } + + update_configuration_warnings(); } Ref<Curve> CPUParticles3D::get_param_curve(Parameter p_param) const { diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp index ab07f33ace..01cab493ec 100644 --- a/scene/3d/decal.cpp +++ b/scene/3d/decal.cpp @@ -72,7 +72,7 @@ real_t Decal::get_albedo_mix() const { } void Decal::set_upper_fade(real_t p_fade) { - upper_fade = p_fade; + upper_fade = MAX(p_fade, 0.0); RS::get_singleton()->decal_set_fade(decal, upper_fade, lower_fade); } @@ -81,7 +81,7 @@ real_t Decal::get_upper_fade() const { } void Decal::set_lower_fade(real_t p_fade) { - lower_fade = p_fade; + lower_fade = MAX(p_fade, 0.0); RS::get_singleton()->decal_set_fade(decal, upper_fade, lower_fade); } diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index d18c452ca7..b352114c7f 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -270,7 +270,7 @@ bool GPUParticles3D::get_interpolate() const { } TypedArray<String> GPUParticles3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); + TypedArray<String> warnings = GeometryInstance3D::get_configuration_warnings(); if (RenderingServer::get_singleton()->is_low_end()) { warnings.push_back(RTR("GPU-based particles are not supported by the OpenGL video driver.\nUse the CPUParticles3D node instead. You can use the \"Convert to CPUParticles3D\" option for this purpose.")); diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp index 6ed4ce8c5b..1ae59451a1 100644 --- a/scene/3d/label_3d.cpp +++ b/scene/3d/label_3d.cpp @@ -370,15 +370,8 @@ void Label3D::_generate_glyph_surfaces(const Glyph &p_glyph, Vector2 &r_offset, bool msdf = TS->font_is_multichannel_signed_distance_field(p_glyph.font_rid); - uint64_t mat_hash; - if (tex != RID()) { - mat_hash = hash_one_uint64(tex.get_id()); - } else { - mat_hash = hash_one_uint64(0); - } - mat_hash = hash_djb2_one_64(p_priority | (p_outline_size << 31), mat_hash); - - if (!surfaces.has(mat_hash)) { + SurfaceKey key = SurfaceKey(tex.get_id(), p_priority, p_outline_size); + if (!surfaces.has(key)) { SurfaceData surf; surf.material = RenderingServer::get_singleton()->material_create(); // Set defaults for material, names need to match up those in StandardMaterial3D @@ -407,9 +400,9 @@ void Label3D::_generate_glyph_surfaces(const Glyph &p_glyph, Vector2 &r_offset, surf.z_shift = p_priority * pixel_size; } - surfaces[mat_hash] = surf; + surfaces[key] = surf; } - SurfaceData &s = surfaces[mat_hash]; + SurfaceData &s = surfaces[key]; s.mesh_vertices.resize((s.offset + 1) * 4); s.mesh_normals.resize((s.offset + 1) * 4); @@ -464,7 +457,7 @@ void Label3D::_shape() { aabb = AABB(); // Clear materials. - for (const KeyValue<uint64_t, SurfaceData> &E : surfaces) { + for (const KeyValue<SurfaceKey, SurfaceData> &E : surfaces) { RenderingServer::get_singleton()->free(E.value.material); } surfaces.clear(); @@ -594,7 +587,7 @@ void Label3D::_shape() { offset.y -= (TS->shaped_text_get_descent(lines_rid[i]) + line_spacing + font->get_spacing(TextServer::SPACING_BOTTOM)) * pixel_size; } - for (const KeyValue<uint64_t, SurfaceData> &E : surfaces) { + for (const KeyValue<SurfaceKey, SurfaceData> &E : surfaces) { Array mesh_array; mesh_array.resize(RS::ARRAY_MAX); mesh_array[RS::ARRAY_VERTEX] = E.value.mesh_vertices; @@ -1018,7 +1011,7 @@ Label3D::~Label3D() { TS->free_rid(text_rid); RenderingServer::get_singleton()->free(mesh); - for (KeyValue<uint64_t, SurfaceData> E : surfaces) { + for (KeyValue<SurfaceKey, SurfaceData> E : surfaces) { RenderingServer::get_singleton()->free(E.value.material); } surfaces.clear(); diff --git a/scene/3d/label_3d.h b/scene/3d/label_3d.h index 7766bca068..7ac38a9f3c 100644 --- a/scene/3d/label_3d.h +++ b/scene/3d/label_3d.h @@ -76,7 +76,29 @@ private: RID material; }; - HashMap<uint64_t, SurfaceData> surfaces; + struct SurfaceKey { + uint64_t texture_id; + int32_t priority; + int32_t outline_size; + + bool operator==(const SurfaceKey &p_b) const { + return (texture_id == p_b.texture_id) && (priority == p_b.priority) && (outline_size == p_b.outline_size); + } + + SurfaceKey(uint64_t p_texture_id, int p_priority, int p_outline_size) { + texture_id = p_texture_id; + priority = p_priority; + outline_size = p_outline_size; + } + }; + + struct SurfaceKeyHasher { + _FORCE_INLINE_ static uint32_t hash(const SurfaceKey &p_a) { + return hash_murmur3_buffer(&p_a, sizeof(SurfaceKey)); + } + }; + + HashMap<SurfaceKey, SurfaceData, SurfaceKeyHasher> surfaces; HorizontalAlignment horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER; VerticalAlignment vertical_alignment = VERTICAL_ALIGNMENT_CENTER; diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index 28614d7cae..6c999d85e2 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -176,6 +176,11 @@ Ref<Texture2D> Light3D::get_projector() const { return projector; } +void Light3D::owner_changed_notify() { + // For cases where owner changes _after_ entering tree (as example, editor editing). + _update_visibility(); +} + void Light3D::_update_visibility() { if (!is_inside_tree()) { return; diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index 383fa644e5..6ff332df5a 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -85,6 +85,8 @@ private: // bind helpers + virtual void owner_changed_notify() override; + protected: RID light; diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 9d1d8721e6..abe942b97a 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -116,7 +116,7 @@ void LightmapGIData::_set_light_textures_data(const Array &p_data) { Array LightmapGIData::_get_light_textures_data() const { Array ret; - if (light_texture.is_null()) { + if (light_texture.is_null() || light_texture->get_layers() == 0) { return ret; } @@ -665,7 +665,7 @@ void LightmapGI::_plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cel } } -void LightmapGI::_gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool, Vector3iHash> &positions_used, const AABB &p_bounds) { +void LightmapGI::_gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool> &positions_used, const AABB &p_bounds) { for (int i = 0; i < 8; i++) { Vector3i pos = p_cell->offset; if (i & 1) { @@ -934,7 +934,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa } LocalVector<Vector3> new_probe_positions; - HashMap<Vector3i, bool, Vector3iHash> positions_used; + HashMap<Vector3i, bool> positions_used; for (uint32_t i = 0; i < 8; i++) { //insert bounding endpoints Vector3i pos; if (i & 1) { @@ -979,13 +979,13 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa Color linear_color = light->get_color().srgb_to_linear(); if (Object::cast_to<DirectionalLight3D>(light)) { DirectionalLight3D *l = Object::cast_to<DirectionalLight3D>(light); - lightmapper->add_directional_light(light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_SIZE)); + lightmapper->add_directional_light(light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); } else if (Object::cast_to<OmniLight3D>(light)) { OmniLight3D *l = Object::cast_to<OmniLight3D>(light); - lightmapper->add_omni_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SIZE)); + lightmapper->add_omni_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); } else if (Object::cast_to<SpotLight3D>(light)) { SpotLight3D *l = Object::cast_to<SpotLight3D>(light); - lightmapper->add_spot_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SPOT_ANGLE), l->get_param(Light3D::PARAM_SPOT_ATTENUATION), l->get_param(Light3D::PARAM_SIZE)); + lightmapper->add_spot_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SPOT_ANGLE), l->get_param(Light3D::PARAM_SPOT_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); } } for (int i = 0; i < probes_found.size(); i++) { diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h index b39cde429d..f7a23c776a 100644 --- a/scene/3d/lightmap_gi.h +++ b/scene/3d/lightmap_gi.h @@ -212,16 +212,8 @@ private: } }; - struct Vector3iHash { - _FORCE_INLINE_ static uint32_t hash(const Vector3i &p_vtx) { - uint32_t h = hash_djb2_one_32(p_vtx.x); - h = hash_djb2_one_32(p_vtx.y, h); - return hash_djb2_one_32(p_vtx.z, h); - } - }; - void _plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cell_size, const Vector3 *p_triangle); - void _gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool, Vector3iHash> &positions_used, const AABB &p_bounds); + void _gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool> &positions_used, const AABB &p_bounds); protected: void _validate_property(PropertyInfo &property) const override; diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h index 4e6f76e360..9b973fd6bc 100644 --- a/scene/3d/lightmapper.h +++ b/scene/3d/lightmapper.h @@ -176,9 +176,9 @@ public: }; virtual void add_mesh(const MeshData &p_mesh) = 0; - virtual void add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance) = 0; - virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size) = 0; - virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size) = 0; + virtual void add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance, float p_shadow_blur) = 0; + virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) = 0; + virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) = 0; virtual void add_probe(const Vector3 &p_position) = 0; virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_step_userdata = nullptr) = 0; diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index 09d75dd284..3752713d6a 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -38,6 +38,9 @@ void NavigationAgent3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_avoidance_enabled", "enabled"), &NavigationAgent3D::set_avoidance_enabled); ClassDB::bind_method(D_METHOD("get_avoidance_enabled"), &NavigationAgent3D::get_avoidance_enabled); + ClassDB::bind_method(D_METHOD("set_path_desired_distance", "desired_distance"), &NavigationAgent3D::set_path_desired_distance); + ClassDB::bind_method(D_METHOD("get_path_desired_distance"), &NavigationAgent3D::get_path_desired_distance); + ClassDB::bind_method(D_METHOD("set_target_desired_distance", "desired_distance"), &NavigationAgent3D::set_target_desired_distance); ClassDB::bind_method(D_METHOD("get_target_desired_distance"), &NavigationAgent3D::get_target_desired_distance); @@ -68,6 +71,9 @@ void NavigationAgent3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationAgent3D::set_navigation_layers); ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationAgent3D::get_navigation_layers); + ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationAgent3D::set_navigation_layer_value); + ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationAgent3D::get_navigation_layer_value); + ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationAgent3D::set_navigation_map); ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationAgent3D::get_navigation_map); @@ -85,17 +91,21 @@ void NavigationAgent3D::_bind_methods() { ClassDB::bind_method(D_METHOD("_avoidance_done", "new_velocity"), &NavigationAgent3D::_avoidance_done); + ADD_GROUP("Pathfinding", ""); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_path_desired_distance", "get_path_desired_distance"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_target_desired_distance", "get_target_desired_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_radius", "get_radius"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_height_offset", PROPERTY_HINT_RANGE, "-100.0,100,0.01,suffix:m"), "set_agent_height_offset", "get_agent_height_offset"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "0.01,100,0.1,suffix:m"), "set_path_max_distance", "get_path_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); + + ADD_GROUP("Avoidance", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_radius", "get_radius"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_dist", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:m"), "set_neighbor_dist", "get_neighbor_dist"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_neighbors", PROPERTY_HINT_RANGE, "1,10000,1"), "set_max_neighbors", "get_max_neighbors"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon", PROPERTY_HINT_RANGE, "0.01,100,0.01,suffix:s"), "set_time_horizon", "get_time_horizon"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:m/s"), "set_max_speed", "get_max_speed"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "0.01,100,0.1,suffix:m"), "set_path_max_distance", "get_path_max_distance"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_y"), "set_ignore_y", "get_ignore_y"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); ADD_SIGNAL(MethodInfo("path_changed")); ADD_SIGNAL(MethodInfo("target_reached")); @@ -226,6 +236,24 @@ uint32_t NavigationAgent3D::get_navigation_layers() const { return navigation_layers; } +void NavigationAgent3D::set_navigation_layer_value(int p_layer_number, bool p_value) { + ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive."); + ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive."); + uint32_t _navigation_layers = get_navigation_layers(); + if (p_value) { + _navigation_layers |= 1 << (p_layer_number - 1); + } else { + _navigation_layers &= ~(1 << (p_layer_number - 1)); + } + set_navigation_layers(_navigation_layers); +} + +bool NavigationAgent3D::get_navigation_layer_value(int p_layer_number) const { + ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive."); + ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive."); + return get_navigation_layers() & (1 << (p_layer_number - 1)); +} + void NavigationAgent3D::set_navigation_map(RID p_navigation_map) { map_override = p_navigation_map; NavigationServer3D::get_singleton()->agent_set_map(agent, map_override); @@ -241,6 +269,10 @@ RID NavigationAgent3D::get_navigation_map() const { return RID(); } +void NavigationAgent3D::set_path_desired_distance(real_t p_dd) { + path_desired_distance = p_dd; +} + void NavigationAgent3D::set_target_desired_distance(real_t p_dd) { target_desired_distance = p_dd; } @@ -416,7 +448,7 @@ void NavigationAgent3D::update_navigation() { // Check if we can advance the navigation path if (navigation_finished == false) { // Advances to the next far away location. - while (o.distance_to(navigation_path[nav_path_index] - Vector3(0, navigation_height_offset, 0)) < target_desired_distance) { + while (o.distance_to(navigation_path[nav_path_index] - Vector3(0, navigation_height_offset, 0)) < path_desired_distance) { nav_path_index += 1; if (nav_path_index == navigation_path.size()) { _check_distance_to_target(); diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h index d0eaead3f1..0a00d769c3 100644 --- a/scene/3d/navigation_agent_3d.h +++ b/scene/3d/navigation_agent_3d.h @@ -47,6 +47,7 @@ class NavigationAgent3D : public Node { bool avoidance_enabled = false; uint32_t navigation_layers = 1; + real_t path_desired_distance = 1.0; real_t target_desired_distance = 1.0; real_t radius = 0.0; real_t navigation_height_offset = 0.0; @@ -90,9 +91,17 @@ public: void set_navigation_layers(uint32_t p_navigation_layers); uint32_t get_navigation_layers() const; + void set_navigation_layer_value(int p_layer_number, bool p_value); + bool get_navigation_layer_value(int p_layer_number) const; + void set_navigation_map(RID p_navigation_map); RID get_navigation_map() const; + void set_path_desired_distance(real_t p_dd); + real_t get_path_desired_distance() const { + return path_desired_distance; + } + void set_target_desired_distance(real_t p_dd); real_t get_target_desired_distance() const { return target_desired_distance; diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 7ef16fbc0a..2a8149c6f6 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -73,6 +73,24 @@ uint32_t NavigationRegion3D::get_navigation_layers() const { return NavigationServer3D::get_singleton()->region_get_navigation_layers(region); } +void NavigationRegion3D::set_navigation_layer_value(int p_layer_number, bool p_value) { + ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive."); + ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive."); + uint32_t _navigation_layers = get_navigation_layers(); + if (p_value) { + _navigation_layers |= 1 << (p_layer_number - 1); + } else { + _navigation_layers &= ~(1 << (p_layer_number - 1)); + } + set_navigation_layers(_navigation_layers); +} + +bool NavigationRegion3D::get_navigation_layer_value(int p_layer_number) const { + ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive."); + ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive."); + return get_navigation_layers() & (1 << (p_layer_number - 1)); +} + void NavigationRegion3D::set_enter_cost(real_t p_enter_cost) { ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive."); enter_cost = MAX(p_enter_cost, 0.0); @@ -242,6 +260,9 @@ void NavigationRegion3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationRegion3D::set_navigation_layers); ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationRegion3D::get_navigation_layers); + ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationRegion3D::set_navigation_layer_value); + ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationRegion3D::get_navigation_layer_value); + ClassDB::bind_method(D_METHOD("get_region_rid"), &NavigationRegion3D::get_region_rid); ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationRegion3D::set_enter_cost); diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h index 92474d1429..aaaf5dd3b8 100644 --- a/scene/3d/navigation_region_3d.h +++ b/scene/3d/navigation_region_3d.h @@ -60,6 +60,9 @@ public: void set_navigation_layers(uint32_t p_navigation_layers); uint32_t get_navigation_layers() const; + void set_navigation_layer_value(int p_layer_number, bool p_value); + bool get_navigation_layer_value(int p_layer_number) const; + RID get_region_rid() const; void set_enter_cost(real_t p_enter_cost); diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index 6e36815f2b..04b1081516 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_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_LOCAL; + 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); @@ -212,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); @@ -227,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) { @@ -240,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(); } @@ -249,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(); } @@ -264,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; @@ -314,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(); @@ -333,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); @@ -372,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); @@ -390,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; @@ -865,14 +933,14 @@ Variant Node3D::property_get_revert(const String &p_name) { } 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_ret = Quaternion(Transform3D(variant).get_basis().get_rotation_quaternion()); } else { return 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_ret = Transform3D(variant).get_basis().get_euler_normalized(data.euler_rotation_order); } else { return Vector3(); } @@ -904,8 +972,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); @@ -980,7 +1054,7 @@ void Node3D::_bind_methods() { ADD_GROUP("Transform", ""); 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_lesser,noslider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_lesser,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_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::BASIS, "basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_basis", "get_basis"); @@ -988,6 +1062,9 @@ void Node3D::_bind_methods() { 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"); diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h index 6d857a83ea..b1e129798d 100644 --- a/scene/3d/node_3d.h +++ b/scene/3d/node_3d.h @@ -52,6 +52,9 @@ class Node3D : public Node { GDCLASS(Node3D, Node); public: + // Edit mode for the rotation. + // THIS MODE ONLY AFFECTS HOW DATA IS EDITED AND SAVED + // IT DOES _NOT_ AFFECT THE TRANSFORM LOGIC (see comment in TransformDirty). enum RotationEditMode { ROTATION_EDIT_MODE_EULER, ROTATION_EDIT_MODE_QUATERNION, @@ -68,11 +71,27 @@ public: }; private: + // For the sake of ease of use, Node3D can operate with Transforms (Basis+Origin), Quaterinon/Scale and Euler Rotation/Scale. + // Transform and Quaterinon are stored in data.local_transform Basis (so quaternion is not really stored, but converted back/forth from 3x3 matrix on demand). + // Euler needs to be kept separate because converting to Basis and back may result in a different vector (which is troublesome for users + // editing in the inspector, not only because of the numerical precision loss but because they expect these rotations to be consistent, or support + // "redundant" rotations for animation interpolation, like going from 0 to 720 degrees). + // + // As such, the system works in a way where if the local transform is set (via transform/basis/quaternion), the EULER rotation and scale becomes dirty. + // It will remain dirty until reading back is attempted (for performance reasons). Likewise, if the Euler rotation scale are set, the local transform + // will become dirty (and again, will not become valid again until read). + // + // All this is transparent from outside the Node3D API, which allows everything to works by calling these functions in exchange. + // + // Additionally, setting either transform, quaternion, Euler rotation or scale makes the global transform dirty, which will be updated when read again. + // + // NOTE: Again, RotationEditMode is _independent_ of this mechanism, it is only meant to expose the right set of properties for editing (editor) and saving + // (to scene, in order to keep the same values and avoid data loss on conversions). It has zero influence in the logic described above. enum TransformDirty { DIRTY_NONE = 0, - DIRTY_VECTORS = 1, - DIRTY_LOCAL = 2, - DIRTY_GLOBAL = 4 + DIRTY_EULER_ROTATION_AND_SCALE = 1, + DIRTY_LOCAL_TRANSFORM = 2, + DIRTY_GLOBAL_TRANSFORM = 4 }; mutable SelfList<Node> xform_change; @@ -80,8 +99,8 @@ private: struct Data { mutable Transform3D global_transform; mutable Transform3D local_transform; - mutable Basis::EulerOrder rotation_order = Basis::EULER_ORDER_YXZ; - mutable Vector3 rotation; + mutable Basis::EulerOrder euler_rotation_order = Basis::EULER_ORDER_YXZ; + mutable Vector3 euler_rotation; mutable Vector3 scale = Vector3(1, 1, 1); mutable RotationEditMode rotation_edit_mode = ROTATION_EDIT_MODE_EULER; @@ -131,6 +150,7 @@ protected: _FORCE_INLINE_ void set_ignore_transform_notification(bool p_ignore) { data.ignore_notification = p_ignore; } _FORCE_INLINE_ void _update_local_transform() const; + _FORCE_INLINE_ void _update_rotation_and_scale() const; void _notification(int p_what); static void _bind_methods(); @@ -162,12 +182,18 @@ public: void set_rotation(const Vector3 &p_euler_rad); void set_scale(const Vector3 &p_scale); + void set_global_position(const Vector3 &p_position); + void set_global_rotation(const Vector3 &p_euler_rad); + Vector3 get_position() const; RotationOrder get_rotation_order() const; Vector3 get_rotation() const; Vector3 get_scale() const; + Vector3 get_global_position() const; + Vector3 get_global_rotation() const; + void set_transform(const Transform3D &p_transform); void set_basis(const Basis &p_basis); void set_quaternion(const Quaternion &p_quaternion); diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index e13cf6f9c8..f53e783fbd 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -30,6 +30,92 @@ #include "path_3d.h" +Path3D::Path3D() { + SceneTree *st = SceneTree::get_singleton(); + if (st && st->is_debugging_paths_hint()) { + debug_instance = RS::get_singleton()->instance_create(); + set_notify_transform(true); + _update_debug_mesh(); + } +} + +Path3D::~Path3D() { + if (debug_instance.is_valid()) { + RS::get_singleton()->free(debug_instance); + } + if (debug_mesh.is_valid()) { + RS::get_singleton()->free(debug_mesh->get_rid()); + } +} + +void Path3D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + SceneTree *st = SceneTree::get_singleton(); + if (st && st->is_debugging_paths_hint()) { + _update_debug_mesh(); + } + } break; + + case NOTIFICATION_EXIT_TREE: { + SceneTree *st = SceneTree::get_singleton(); + if (st && st->is_debugging_paths_hint()) { + RS::get_singleton()->instance_set_visible(debug_instance, false); + } + } break; + + case NOTIFICATION_TRANSFORM_CHANGED: { + if (is_inside_tree() && debug_instance.is_valid()) { + RS::get_singleton()->instance_set_transform(debug_instance, get_global_transform()); + } + } break; + } +} + +void Path3D::_update_debug_mesh() { + SceneTree *st = SceneTree::get_singleton(); + if (!(st && st->is_debugging_paths_hint())) { + return; + } + + if (!debug_mesh.is_valid()) { + debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); + } + + if (!(curve.is_valid())) { + RS::get_singleton()->instance_set_visible(debug_instance, false); + return; + } + if (curve->get_point_count() < 2) { + RS::get_singleton()->instance_set_visible(debug_instance, false); + return; + } + + Vector<Vector3> vertex_array; + + for (int i = 1; i < curve->get_point_count(); i++) { + Vector3 line_end = curve->get_point_position(i); + Vector3 line_start = curve->get_point_position(i - 1); + vertex_array.push_back(line_start); + vertex_array.push_back(line_end); + } + + Array mesh_array; + mesh_array.resize(Mesh::ARRAY_MAX); + mesh_array[Mesh::ARRAY_VERTEX] = vertex_array; + + debug_mesh->clear_surfaces(); + debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, mesh_array); + + RS::get_singleton()->instance_set_base(debug_instance, debug_mesh->get_rid()); + RS::get_singleton()->mesh_surface_set_material(debug_mesh->get_rid(), 0, st->get_debug_paths_material()->get_rid()); + if (is_inside_tree()) { + RS::get_singleton()->instance_set_scenario(debug_instance, get_world_3d()->get_scenario()); + RS::get_singleton()->instance_set_transform(debug_instance, get_global_transform()); + RS::get_singleton()->instance_set_visible(debug_instance, is_visible_in_tree()); + } +} + void Path3D::_curve_changed() { if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) { update_gizmos(); @@ -48,6 +134,10 @@ void Path3D::_curve_changed() { } } } + SceneTree *st = SceneTree::get_singleton(); + if (st && st->is_debugging_paths_hint()) { + _update_debug_mesh(); + } } void Path3D::set_curve(const Ref<Curve3D> &p_curve) { diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h index cb67a044d1..7c7284534e 100644 --- a/scene/3d/path_3d.h +++ b/scene/3d/path_3d.h @@ -41,14 +41,23 @@ class Path3D : public Node3D { void _curve_changed(); + RID debug_instance; + Ref<ArrayMesh> debug_mesh; + +private: + void _update_debug_mesh(); + protected: + void _notification(int p_what); + static void _bind_methods(); public: void set_curve(const Ref<Curve3D> &p_curve); Ref<Curve3D> get_curve() const; - Path3D() {} + Path3D(); + ~Path3D(); }; class PathFollow3D : public Node3D { diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index ba2029788e..fbd5f31dd5 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -326,13 +326,11 @@ void Skeleton3D::_notification(int p_what) { case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { // This is active only if the skeleton animates the physical bones // and the state of the bone is not active. - if (Engine::get_singleton()->is_editor_hint()) { - if (animate_physical_bones) { - for (int i = 0; i < bones.size(); i += 1) { - if (bones[i].physical_bone) { - if (bones[i].physical_bone->is_simulating_physics() == false) { - bones[i].physical_bone->reset_to_rest_position(); - } + if (animate_physical_bones) { + for (int i = 0; i < bones.size(); i += 1) { + if (bones[i].physical_bone) { + if (bones[i].physical_bone->is_simulating_physics() == false) { + bones[i].physical_bone->reset_to_rest_position(); } } } diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 55b55d924c..cb6354f7a8 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -1034,8 +1034,11 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &property) const { if (property.name == "frame") { property.hint = PROPERTY_HINT_RANGE; - if (frames->has_animation(animation) && frames->get_frame_count(animation) > 1) { + if (frames->has_animation(animation) && frames->get_frame_count(animation) > 0) { property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1"; + } else { + // Avoid an error, `hint_string` is required for `PROPERTY_HINT_RANGE`. + property.hint_string = "0,0,1"; } property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; } diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index 6df50bc491..69917f6992 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -471,7 +471,6 @@ void GeometryInstance3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_end", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,suffix:m"), "set_visibility_range_end", "get_visibility_range_end"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_end_margin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,suffix:m"), "set_visibility_range_end_margin", "get_visibility_range_end_margin"); ADD_PROPERTY(PropertyInfo(Variant::INT, "visibility_range_fade_mode", PROPERTY_HINT_ENUM, "Disabled,Self,Dependencies"), "set_visibility_range_fade_mode", "get_visibility_range_fade_mode"); - //ADD_SIGNAL( MethodInfo("visibility_changed")); BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_OFF); BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_ON); @@ -494,7 +493,6 @@ void GeometryInstance3D::_bind_methods() { } GeometryInstance3D::GeometryInstance3D() { - //RS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0); } GeometryInstance3D::~GeometryInstance3D() { diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index e5f98bd65e..9e0d9b9a2a 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -126,7 +126,7 @@ private: float extra_cull_margin = 0.0; LightmapScale lightmap_scale = LIGHTMAP_SCALE_1X; - GIMode gi_mode = GI_MODE_DISABLED; + GIMode gi_mode = GI_MODE_STATIC; bool ignore_occlusion_culling = false; const StringName *_instance_uniform_get_remap(const StringName p_name) const; |