summaryrefslogtreecommitdiff
path: root/scene/3d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d')
-rw-r--r--scene/3d/bone_attachment_3d.cpp21
-rw-r--r--scene/3d/bone_attachment_3d.h6
-rw-r--r--scene/3d/cpu_particles_3d.cpp11
-rw-r--r--scene/3d/decal.cpp4
-rw-r--r--scene/3d/gpu_particles_3d.cpp2
-rw-r--r--scene/3d/label_3d.cpp21
-rw-r--r--scene/3d/label_3d.h24
-rw-r--r--scene/3d/light_3d.cpp5
-rw-r--r--scene/3d/light_3d.h2
-rw-r--r--scene/3d/lightmap_gi.cpp12
-rw-r--r--scene/3d/lightmap_gi.h10
-rw-r--r--scene/3d/lightmapper.h6
-rw-r--r--scene/3d/navigation_agent_3d.cpp42
-rw-r--r--scene/3d/navigation_agent_3d.h9
-rw-r--r--scene/3d/navigation_region_3d.cpp21
-rw-r--r--scene/3d/navigation_region_3d.h3
-rw-r--r--scene/3d/node_3d.cpp181
-rw-r--r--scene/3d/node_3d.h36
-rw-r--r--scene/3d/path_3d.cpp90
-rw-r--r--scene/3d/path_3d.h11
-rw-r--r--scene/3d/skeleton_3d.cpp12
-rw-r--r--scene/3d/sprite_3d.cpp5
-rw-r--r--scene/3d/visual_instance_3d.cpp2
-rw-r--r--scene/3d/visual_instance_3d.h2
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;