summaryrefslogtreecommitdiff
path: root/scene/3d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d')
-rw-r--r--scene/3d/area_3d.cpp8
-rw-r--r--scene/3d/audio_listener_3d.h6
-rw-r--r--scene/3d/audio_stream_player_3d.cpp24
-rw-r--r--scene/3d/audio_stream_player_3d.h7
-rw-r--r--scene/3d/bone_attachment_3d.cpp21
-rw-r--r--scene/3d/bone_attachment_3d.h12
-rw-r--r--scene/3d/camera_3d.cpp18
-rw-r--r--scene/3d/camera_3d.h12
-rw-r--r--scene/3d/collision_object_3d.cpp8
-rw-r--r--scene/3d/collision_object_3d.h2
-rw-r--r--scene/3d/collision_polygon_3d.h2
-rw-r--r--scene/3d/collision_shape_3d.h6
-rw-r--r--scene/3d/cpu_particles_3d.cpp11
-rw-r--r--scene/3d/cpu_particles_3d.h8
-rw-r--r--scene/3d/decal.cpp13
-rw-r--r--scene/3d/decal.h4
-rw-r--r--scene/3d/gpu_particles_3d.cpp6
-rw-r--r--scene/3d/gpu_particles_3d.h6
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp59
-rw-r--r--scene/3d/gpu_particles_collision_3d.h9
-rw-r--r--scene/3d/importer_mesh_instance_3d.h7
-rw-r--r--scene/3d/joint_3d.cpp116
-rw-r--r--scene/3d/label_3d.cpp149
-rw-r--r--scene/3d/label_3d.h46
-rw-r--r--scene/3d/light_3d.cpp17
-rw-r--r--scene/3d/light_3d.h3
-rw-r--r--scene/3d/lightmap_gi.cpp18
-rw-r--r--scene/3d/lightmap_gi.h12
-rw-r--r--scene/3d/lightmapper.h6
-rw-r--r--scene/3d/mesh_instance_3d.h6
-rw-r--r--scene/3d/multimesh_instance_3d.h2
-rw-r--r--scene/3d/navigation_agent_3d.cpp42
-rw-r--r--scene/3d/navigation_agent_3d.h15
-rw-r--r--scene/3d/navigation_obstacle_3d.h6
-rw-r--r--scene/3d/navigation_region_3d.cpp362
-rw-r--r--scene/3d/navigation_region_3d.h22
-rw-r--r--scene/3d/node_3d.cpp185
-rw-r--r--scene/3d/node_3d.h36
-rw-r--r--scene/3d/occluder_instance_3d.cpp2
-rw-r--r--scene/3d/occluder_instance_3d.h2
-rw-r--r--scene/3d/path_3d.cpp107
-rw-r--r--scene/3d/path_3d.h19
-rw-r--r--scene/3d/physics_body_3d.cpp4
-rw-r--r--scene/3d/physics_body_3d.h2
-rw-r--r--scene/3d/ray_cast_3d.h2
-rw-r--r--scene/3d/reflection_probe.h6
-rw-r--r--scene/3d/remote_transform_3d.h6
-rw-r--r--scene/3d/shape_cast_3d.cpp634
-rw-r--r--scene/3d/shape_cast_3d.h142
-rw-r--r--scene/3d/skeleton_3d.cpp38
-rw-r--r--scene/3d/skeleton_3d.h6
-rw-r--r--scene/3d/skeleton_ik_3d.h6
-rw-r--r--scene/3d/soft_dynamic_body_3d.cpp11
-rw-r--r--scene/3d/soft_dynamic_body_3d.h6
-rw-r--r--scene/3d/spring_arm_3d.h6
-rw-r--r--scene/3d/sprite_3d.cpp7
-rw-r--r--scene/3d/vehicle_body_3d.h6
-rw-r--r--scene/3d/velocity_tracker_3d.h6
-rw-r--r--scene/3d/visible_on_screen_notifier_3d.h2
-rw-r--r--scene/3d/visual_instance_3d.cpp43
-rw-r--r--scene/3d/visual_instance_3d.h12
-rw-r--r--scene/3d/voxel_gi.cpp3
-rw-r--r--scene/3d/voxel_gi.h4
-rw-r--r--scene/3d/voxelizer.h6
-rw-r--r--scene/3d/world_environment.h6
-rw-r--r--scene/3d/xr_nodes.cpp8
66 files changed, 1909 insertions, 485 deletions
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index fb0c59daa1..e9e19488e9 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -239,8 +239,8 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
E->value.rc = 0;
E->value.in_tree = node && node->is_inside_tree();
if (node) {
- node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree), make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree), make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree).bind(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree).bind(objid));
if (E->value.in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
}
@@ -426,8 +426,8 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
E->value.rc = 0;
E->value.in_tree = node && node->is_inside_tree();
if (node) {
- node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree), make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree), make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree).bind(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree).bind(objid));
if (E->value.in_tree) {
emit_signal(SceneStringNames::get_singleton()->area_entered, node);
}
diff --git a/scene/3d/audio_listener_3d.h b/scene/3d/audio_listener_3d.h
index ebc37673ed..44c49f526e 100644
--- a/scene/3d/audio_listener_3d.h
+++ b/scene/3d/audio_listener_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef LISTENER_3D_H
-#define LISTENER_3D_H
+#ifndef AUDIO_LISTENER_3D_H
+#define AUDIO_LISTENER_3D_H
#include "scene/3d/node_3d.h"
@@ -67,4 +67,4 @@ public:
~AudioListener3D();
};
-#endif
+#endif // AUDIO_LISTENER_3D_H
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 7c1fb3779f..65b00742ee 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -30,6 +30,7 @@
#include "audio_stream_player_3d.h"
+#include "core/config/project_settings.h"
#include "scene/3d/area_3d.h"
#include "scene/3d/audio_listener_3d.h"
#include "scene/3d/camera_3d.h"
@@ -280,7 +281,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
if (setplay.get() >= 0 && stream.is_valid()) {
active.set();
- Ref<AudioStreamPlayback> new_playback = stream->instance_playback();
+ Ref<AudioStreamPlayback> new_playback = stream->instantiate_playback();
ERR_FAIL_COND_MSG(new_playback.is_null(), "Failed to instantiate playback.");
HashMap<StringName, Vector<AudioFrame>> bus_map;
bus_map[_get_actual_bus()] = volume_vector;
@@ -462,9 +463,10 @@ Vector<AudioFrame> AudioStreamPlayer3D::_update_panning() {
for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
AudioServer::get_singleton()->set_playback_highshelf_params(playback, linear_attenuation, attenuation_filter_cutoff_hz);
}
- //TODO: The lower the second parameter (tightness) the more the sound will "enclose" the listener (more undirected / playing from
- // speakers not facing the source) - this could be made distance dependent.
- _calc_output_vol(local_pos.normalized(), 4.0, output_volume_vector);
+ // Bake in a constant factor here to allow the project setting defaults for 2d and 3d to be normalized to 1.0.
+ float tightness = cached_global_panning_strength * 2.0f;
+ tightness *= panning_strength;
+ _calc_output_vol(local_pos.normalized(), tightness, output_volume_vector);
for (unsigned int k = 0; k < 4; k++) {
output_volume_vector.write[k] = multiplier * output_volume_vector[k];
@@ -792,6 +794,15 @@ int AudioStreamPlayer3D::get_max_polyphony() const {
return max_polyphony;
}
+void AudioStreamPlayer3D::set_panning_strength(float p_panning_strength) {
+ ERR_FAIL_COND_MSG(p_panning_strength < 0, "Panning strength must be a positive number.");
+ panning_strength = p_panning_strength;
+}
+
+float AudioStreamPlayer3D::get_panning_strength() const {
+ return panning_strength;
+}
+
void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer3D::set_stream);
ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer3D::get_stream);
@@ -857,6 +868,9 @@ void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_max_polyphony", "max_polyphony"), &AudioStreamPlayer3D::set_max_polyphony);
ClassDB::bind_method(D_METHOD("get_max_polyphony"), &AudioStreamPlayer3D::get_max_polyphony);
+ ClassDB::bind_method(D_METHOD("set_panning_strength", "panning_strength"), &AudioStreamPlayer3D::set_panning_strength);
+ ClassDB::bind_method(D_METHOD("get_panning_strength"), &AudioStreamPlayer3D::get_panning_strength);
+
ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer3D::get_stream_playback);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
@@ -870,6 +884,7 @@ void AudioStreamPlayer3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,or_greater,suffix:m"), "set_max_distance", "get_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_polyphony", PROPERTY_HINT_NONE, ""), "set_max_polyphony", "get_max_polyphony");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "panning_strength", PROPERTY_HINT_RANGE, "0,3,0.01,or_greater"), "set_panning_strength", "get_panning_strength");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask");
ADD_GROUP("Emission Angle", "emission_angle");
@@ -898,6 +913,7 @@ AudioStreamPlayer3D::AudioStreamPlayer3D() {
velocity_tracker.instantiate();
AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer3D::_bus_layout_changed));
set_disable_scale(true);
+ cached_global_panning_strength = ProjectSettings::get_singleton()->get("audio/general/3d_panning_strength");
}
AudioStreamPlayer3D::~AudioStreamPlayer3D() {
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index bc47a8de93..647b18a4a7 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -116,6 +116,9 @@ private:
float _get_attenuation_db(float p_distance) const;
+ float panning_strength = 1.0f;
+ float cached_global_panning_strength = 1.0f;
+
protected:
void _validate_property(PropertyInfo &property) const override;
void _notification(int p_what);
@@ -182,6 +185,9 @@ public:
void set_stream_paused(bool p_pause);
bool get_stream_paused() const;
+ void set_panning_strength(float p_panning_strength);
+ float get_panning_strength() const;
+
Ref<AudioStreamPlayback> get_stream_playback();
AudioStreamPlayer3D();
@@ -190,4 +196,5 @@ public:
VARIANT_ENUM_CAST(AudioStreamPlayer3D::AttenuationModel)
VARIANT_ENUM_CAST(AudioStreamPlayer3D::DopplerTracking)
+
#endif // AUDIO_STREAM_PLAYER_3D_H
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..3224361a25 100644
--- a/scene/3d/bone_attachment_3d.h
+++ b/scene/3d/bone_attachment_3d.h
@@ -28,10 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef BONE_ATTACHMENT_H
-#define BONE_ATTACHMENT_H
+#ifndef BONE_ATTACHMENT_3D_H
+#define BONE_ATTACHMENT_3D_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;
@@ -93,4 +99,4 @@ public:
BoneAttachment3D();
};
-#endif // BONE_ATTACHMENT_H
+#endif // BONE_ATTACHMENT_3D_H
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index 10348b1eb6..f654373ee5 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -31,7 +31,7 @@
#include "camera_3d.h"
#include "collision_object_3d.h"
-#include "core/math/camera_matrix.h"
+#include "core/math/projection.h"
#include "scene/main/viewport.h"
void Camera3D::_update_audio_listener_state() {
@@ -197,7 +197,7 @@ void Camera3D::set_frustum(real_t p_size, Vector2 p_offset, real_t p_z_near, rea
update_gizmos();
}
-void Camera3D::set_projection(Camera3D::Projection p_mode) {
+void Camera3D::set_projection(ProjectionType p_mode) {
if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL || p_mode == PROJECTION_FRUSTUM) {
mode = p_mode;
_update_camera_mode();
@@ -265,7 +265,7 @@ Vector3 Camera3D::project_local_ray_normal(const Point2 &p_pos) const {
if (mode == PROJECTION_ORTHOGONAL) {
ray = Vector3(0, 0, -1);
} else {
- CameraMatrix cm;
+ Projection cm;
cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
Vector2 screen_he = cm.get_viewport_half_extents();
ray = Vector3(((cpos.x / viewport_size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (cpos.y / viewport_size.height)) * 2.0 - 1.0) * screen_he.y, -near).normalized();
@@ -314,7 +314,7 @@ Vector<Vector3> Camera3D::get_near_plane_points() const {
Size2 viewport_size = get_viewport()->get_visible_rect().size;
- CameraMatrix cm;
+ Projection cm;
if (mode == PROJECTION_ORTHOGONAL) {
cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
@@ -340,7 +340,7 @@ Point2 Camera3D::unproject_position(const Vector3 &p_pos) const {
Size2 viewport_size = get_viewport()->get_visible_rect().size;
- CameraMatrix cm;
+ Projection cm;
if (mode == PROJECTION_ORTHOGONAL) {
cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
@@ -368,7 +368,7 @@ Vector3 Camera3D::project_position(const Point2 &p_point, real_t p_z_depth) cons
}
Size2 viewport_size = get_viewport()->get_visible_rect().size;
- CameraMatrix cm;
+ Projection cm;
if (mode == PROJECTION_ORTHOGONAL) {
cm.set_orthogonal(size, viewport_size.aspect(), p_z_depth, far, keep_aspect == KEEP_WIDTH);
@@ -507,7 +507,7 @@ void Camera3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal,Frustum"), "set_projection", "get_projection");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov", PROPERTY_HINT_RANGE, "1,179,0.1,degrees"), "set_fov", "get_fov");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.001,16384,0.01,suffix:m"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.001,16384,0.001,suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_frustum_offset", "get_frustum_offset");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater,exp,suffix:m"), "set_near", "get_near");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_RANGE, "0.01,4000,0.01,or_greater,exp,suffix:m"), "set_far", "get_far");
@@ -544,7 +544,7 @@ real_t Camera3D::get_far() const {
return far;
}
-Camera3D::Projection Camera3D::get_projection() const {
+Camera3D::ProjectionType Camera3D::get_projection() const {
return mode;
}
@@ -607,7 +607,7 @@ Vector<Plane> Camera3D::get_frustum() const {
ERR_FAIL_COND_V(!is_inside_world(), Vector<Plane>());
Size2 viewport_size = get_viewport()->get_visible_rect().size;
- CameraMatrix cm;
+ Projection cm;
if (mode == PROJECTION_PERSPECTIVE) {
cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
} else {
diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h
index 9f2f8ceed1..cedd976890 100644
--- a/scene/3d/camera_3d.h
+++ b/scene/3d/camera_3d.h
@@ -40,7 +40,7 @@ class Camera3D : public Node3D {
GDCLASS(Camera3D, Node3D);
public:
- enum Projection {
+ enum ProjectionType {
PROJECTION_PERSPECTIVE,
PROJECTION_ORTHOGONAL,
PROJECTION_FRUSTUM
@@ -62,7 +62,7 @@ private:
bool current = false;
Viewport *viewport = nullptr;
- Projection mode = PROJECTION_PERSPECTIVE;
+ ProjectionType mode = PROJECTION_PERSPECTIVE;
real_t fov = 0.0;
real_t size = 1.0;
@@ -112,7 +112,7 @@ public:
void set_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far);
void set_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far);
void set_frustum(real_t p_size, Vector2 p_offset, real_t p_z_near, real_t p_z_far);
- void set_projection(Camera3D::Projection p_mode);
+ void set_projection(Camera3D::ProjectionType p_mode);
void make_current();
void clear_current(bool p_enable_next = true);
@@ -127,7 +127,7 @@ public:
real_t get_near() const;
Vector2 get_frustum_offset() const;
- Projection get_projection() const;
+ ProjectionType get_projection() const;
void set_fov(real_t p_fov);
void set_size(real_t p_size);
@@ -181,8 +181,8 @@ public:
~Camera3D();
};
-VARIANT_ENUM_CAST(Camera3D::Projection);
+VARIANT_ENUM_CAST(Camera3D::ProjectionType);
VARIANT_ENUM_CAST(Camera3D::KeepAspect);
VARIANT_ENUM_CAST(Camera3D::DopplerTracking);
-#endif
+#endif // CAMERA_3D_H
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index a36357555a..9a5d4f5480 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -319,7 +319,7 @@ bool CollisionObject3D::_are_collision_shapes_visible() {
void CollisionObject3D::_update_shape_data(uint32_t p_owner) {
if (_are_collision_shapes_visible()) {
if (debug_shapes_to_update.is_empty()) {
- callable_mp(this, &CollisionObject3D::_update_debug_shapes).call_deferred({}, 0);
+ callable_mp(this, &CollisionObject3D::_update_debug_shapes).call_deferredp({}, 0);
}
debug_shapes_to_update.insert(p_owner);
}
@@ -365,8 +365,7 @@ void CollisionObject3D::_update_debug_shapes() {
RS::get_singleton()->instance_set_scenario(s.debug_shape, get_world_3d()->get_scenario());
if (!s.shape->is_connected("changed", callable_mp(this, &CollisionObject3D::_shape_changed))) {
- s.shape->connect("changed", callable_mp(this, &CollisionObject3D::_shape_changed),
- varray(s.shape), CONNECT_DEFERRED);
+ s.shape->connect("changed", callable_mp(this, &CollisionObject3D::_shape_changed).bind(s.shape), CONNECT_DEFERRED);
}
++debug_shapes_count;
@@ -404,6 +403,9 @@ void CollisionObject3D::_on_transform_changed() {
debug_shape_old_transform = get_global_transform();
for (KeyValue<uint32_t, ShapeData> &E : shapes) {
ShapeData &shapedata = E.value;
+ if (shapedata.disabled) {
+ continue; // If disabled then there are no debug shapes to update.
+ }
const ShapeData::ShapeBase *shapes = shapedata.shapes.ptr();
for (int i = 0; i < shapedata.shapes.size(); i++) {
RS::get_singleton()->instance_set_transform(shapes[i].debug_shape, debug_shape_old_transform * shapedata.xform);
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
index 098f573551..3ec3aa0fc1 100644
--- a/scene/3d/collision_object_3d.h
+++ b/scene/3d/collision_object_3d.h
@@ -166,4 +166,4 @@ public:
VARIANT_ENUM_CAST(CollisionObject3D::DisableMode);
-#endif // COLLISION_OBJECT__H
+#endif // COLLISION_OBJECT_3D_H
diff --git a/scene/3d/collision_polygon_3d.h b/scene/3d/collision_polygon_3d.h
index a24d485af2..74e5867a2f 100644
--- a/scene/3d/collision_polygon_3d.h
+++ b/scene/3d/collision_polygon_3d.h
@@ -79,4 +79,4 @@ public:
CollisionPolygon3D();
};
-#endif // COLLISION_POLYGON_H
+#endif // COLLISION_POLYGON_3D_H
diff --git a/scene/3d/collision_shape_3d.h b/scene/3d/collision_shape_3d.h
index 5c32230942..124c0d166d 100644
--- a/scene/3d/collision_shape_3d.h
+++ b/scene/3d/collision_shape_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef COLLISION_SHAPE_H
-#define COLLISION_SHAPE_H
+#ifndef COLLISION_SHAPE_3D_H
+#define COLLISION_SHAPE_3D_H
#include "scene/3d/node_3d.h"
#include "scene/resources/shape_3d.h"
@@ -68,4 +68,4 @@ public:
~CollisionShape3D();
};
-#endif // BODY_VOLUME_H
+#endif // COLLISION_SHAPE_3D_H
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/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index 7f225ee98d..e26c301038 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef CPU_PARTICLES_H
-#define CPU_PARTICLES_H
+#ifndef CPU_PARTICLES_3D_H
+#define CPU_PARTICLES_3D_H
#include "scene/3d/visual_instance_3d.h"
@@ -138,7 +138,7 @@ private:
real_t randomness_ratio = 0.0;
double lifetime_randomness = 0.0;
double speed_scale = 1.0;
- bool local_coords = true;
+ bool local_coords = false;
int fixed_fps = 0;
bool fractional_delta = true;
@@ -317,4 +317,4 @@ VARIANT_ENUM_CAST(CPUParticles3D::Parameter)
VARIANT_ENUM_CAST(CPUParticles3D::ParticleFlags)
VARIANT_ENUM_CAST(CPUParticles3D::EmissionShape)
-#endif // CPU_PARTICLES_H
+#endif // CPU_PARTICLES_3D_H
diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp
index ab07f33ace..0112f24e0c 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);
}
@@ -215,11 +215,13 @@ void Decal::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_cull_mask"), &Decal::get_cull_mask);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,suffix:m"), "set_extents", "get_extents");
+
ADD_GROUP("Textures", "texture_");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "texture_albedo", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_ALBEDO);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "texture_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_NORMAL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "texture_orm", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_ORM);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "texture_emission", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_EMISSION);
+
ADD_GROUP("Parameters", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_emission_energy", "get_emission_energy");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
@@ -227,13 +229,16 @@ void Decal::_bind_methods() {
// A Normal Fade of 1.0 causes the decal to be invisible even if fully perpendicular to a surface.
// Due to this, limit Normal Fade to 0.999.
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "normal_fade", PROPERTY_HINT_RANGE, "0,0.999,0.001"), "set_normal_fade", "get_normal_fade");
+
ADD_GROUP("Vertical Fade", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "upper_fade", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_upper_fade", "get_upper_fade");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lower_fade", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_lower_fade", "get_lower_fade");
+
ADD_GROUP("Distance Fade", "distance_fade_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distance_fade_enabled"), "set_enable_distance_fade", "is_distance_fade_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_begin", PROPERTY_HINT_NONE, "suffix:m"), "set_distance_fade_begin", "get_distance_fade_begin");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_length", PROPERTY_HINT_NONE, "suffix:m"), "set_distance_fade_length", "get_distance_fade_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_begin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater,suffix:m"), "set_distance_fade_begin", "get_distance_fade_begin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_length", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater,suffix:m"), "set_distance_fade_length", "get_distance_fade_length");
+
ADD_GROUP("Cull Mask", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
diff --git a/scene/3d/decal.h b/scene/3d/decal.h
index d5990272c6..38da4c14e3 100644
--- a/scene/3d/decal.h
+++ b/scene/3d/decal.h
@@ -57,8 +57,8 @@ private:
real_t upper_fade = 0.3;
real_t lower_fade = 0.3;
bool distance_fade_enabled = false;
- real_t distance_fade_begin = 10.0;
- real_t distance_fade_length = 1.0;
+ real_t distance_fade_begin = 40.0;
+ real_t distance_fade_length = 10.0;
protected:
static void _bind_methods();
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index d18c452ca7..2ee126e161 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -222,7 +222,7 @@ void GPUParticles3D::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {
draw_passes.write[p_pass] = p_mesh;
if (Engine::get_singleton()->is_editor_hint() && draw_passes.write[p_pass].is_valid()) {
- draw_passes.write[p_pass]->connect("changed", callable_mp((Node *)this, &Node::update_configuration_warnings), varray(), CONNECT_DEFERRED);
+ draw_passes.write[p_pass]->connect("changed", callable_mp((Node *)this, &Node::update_configuration_warnings), CONNECT_DEFERRED);
}
RID mesh_rid;
@@ -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."));
@@ -631,7 +631,7 @@ GPUParticles3D::GPUParticles3D() {
set_randomness_ratio(0);
set_trail_length(0.3);
set_visibility_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8)));
- set_use_local_coordinates(true);
+ set_use_local_coordinates(false);
set_draw_passes(1);
set_draw_order(DRAW_ORDER_INDEX);
set_speed_scale(1);
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index adce45a0a9..0c745dd734 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef PARTICLES_H
-#define PARTICLES_H
+#ifndef GPU_PARTICLES_3D_H
+#define GPU_PARTICLES_3D_H
#include "scene/3d/visual_instance_3d.h"
#include "scene/resources/skin.h"
@@ -179,4 +179,4 @@ VARIANT_ENUM_CAST(GPUParticles3D::DrawOrder)
VARIANT_ENUM_CAST(GPUParticles3D::TransformAlign)
VARIANT_ENUM_CAST(GPUParticles3D::EmitFlags)
-#endif // PARTICLES_H
+#endif // GPU_PARTICLES_3D_H
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index da0789ccd5..1cfd889272 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -30,6 +30,7 @@
#include "gpu_particles_collision_3d.h"
+#include "core/object/worker_thread_pool.h"
#include "mesh_instance_3d.h"
#include "scene/3d/camera_3d.h"
#include "scene/main/viewport.h"
@@ -126,6 +127,10 @@ GPUParticlesCollisionBox3D::~GPUParticlesCollisionBox3D() {
void GPUParticlesCollisionSDF3D::_find_meshes(const AABB &p_aabb, Node *p_at_node, List<PlotMesh> &plot_meshes) {
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node);
if (mi && mi->is_visible_in_tree()) {
+ if ((mi->get_layer_mask() & bake_mask) == 0) {
+ return;
+ }
+
Ref<Mesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
AABB aabb = mesh->get_aabb();
@@ -339,15 +344,12 @@ void GPUParticlesCollisionSDF3D::_compute_sdf_z(uint32_t p_z, ComputeSDFParams *
}
void GPUParticlesCollisionSDF3D::_compute_sdf(ComputeSDFParams *params) {
- ThreadWorkPool work_pool;
- work_pool.init();
- work_pool.begin_work(params->size.z, this, &GPUParticlesCollisionSDF3D::_compute_sdf_z, params);
- while (!work_pool.is_done_dispatching()) {
+ WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &GPUParticlesCollisionSDF3D::_compute_sdf_z, params, params->size.z);
+ while (!WorkerThreadPool::get_singleton()->is_group_task_completed(group_task)) {
OS::get_singleton()->delay_usec(10000);
- bake_step_function(work_pool.get_work_index() * 100 / params->size.z, "Baking SDF");
+ bake_step_function(WorkerThreadPool::get_singleton()->get_group_processed_element_count(group_task) * 100 / params->size.z, "Baking SDF");
}
- work_pool.end_work();
- work_pool.finish();
+ WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
}
Vector3i GPUParticlesCollisionSDF3D::get_estimated_cell_size() const {
@@ -447,7 +449,7 @@ Ref<Image> GPUParticlesCollisionSDF3D::bake() {
//compute bvh
- ERR_FAIL_COND_V(faces.size() <= 1, Ref<Image>());
+ ERR_FAIL_COND_V_MSG(faces.size() <= 1, Ref<Image>(), "No faces detected during GPUParticlesCollisionSDF3D bake. Check whether there are visible meshes matching the bake mask within its extents.");
LocalVector<FacePos> face_pos;
@@ -501,6 +503,16 @@ Ref<Image> GPUParticlesCollisionSDF3D::bake() {
return ret;
}
+TypedArray<String> GPUParticlesCollisionSDF3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
+ if (bake_mask == 0) {
+ warnings.push_back(RTR("The Bake Mask has no bits enabled, which means baking will not produce any collision for this GPUParticlesCollisionSDF3D.\nTo resolve this, enable at least one bit in the Bake Mask property."));
+ }
+
+ return warnings;
+}
+
void GPUParticlesCollisionSDF3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesCollisionSDF3D::set_extents);
ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesCollisionSDF3D::get_extents);
@@ -514,9 +526,15 @@ void GPUParticlesCollisionSDF3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_thickness", "thickness"), &GPUParticlesCollisionSDF3D::set_thickness);
ClassDB::bind_method(D_METHOD("get_thickness"), &GPUParticlesCollisionSDF3D::get_thickness);
+ ClassDB::bind_method(D_METHOD("set_bake_mask", "mask"), &GPUParticlesCollisionSDF3D::set_bake_mask);
+ ClassDB::bind_method(D_METHOD("get_bake_mask"), &GPUParticlesCollisionSDF3D::get_bake_mask);
+ ClassDB::bind_method(D_METHOD("set_bake_mask_value", "layer_number", "value"), &GPUParticlesCollisionSDF3D::set_bake_mask_value);
+ ClassDB::bind_method(D_METHOD("get_bake_mask_value", "layer_number"), &GPUParticlesCollisionSDF3D::get_bake_mask_value);
+
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_extents", "get_extents");
ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "16,32,64,128,256,512,suffix:px"), "set_resolution", "get_resolution");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "thickness", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,suffix:m"), "set_thickness", "get_thickness");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_bake_mask", "get_bake_mask");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture");
BIND_ENUM_CONSTANT(RESOLUTION_16);
@@ -555,6 +573,31 @@ GPUParticlesCollisionSDF3D::Resolution GPUParticlesCollisionSDF3D::get_resolutio
return resolution;
}
+void GPUParticlesCollisionSDF3D::set_bake_mask(uint32_t p_mask) {
+ bake_mask = p_mask;
+ update_configuration_warnings();
+}
+
+uint32_t GPUParticlesCollisionSDF3D::get_bake_mask() const {
+ return bake_mask;
+}
+
+void GPUParticlesCollisionSDF3D::set_bake_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1 || p_layer_number > 20, vformat("The render layer number (%d) must be between 1 and 20 (inclusive).", p_layer_number));
+ uint32_t mask = get_bake_mask();
+ if (p_value) {
+ mask |= 1 << (p_layer_number - 1);
+ } else {
+ mask &= ~(1 << (p_layer_number - 1));
+ }
+ set_bake_mask(mask);
+}
+
+bool GPUParticlesCollisionSDF3D::get_bake_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1 || p_layer_number > 20, false, vformat("The render layer number (%d) must be between 1 and 20 (inclusive).", p_layer_number));
+ return bake_mask & (1 << (p_layer_number - 1));
+}
+
void GPUParticlesCollisionSDF3D::set_texture(const Ref<Texture3D> &p_texture) {
texture = p_texture;
RID tex = texture.is_valid() ? texture->get_rid() : RID();
diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h
index 4b2cb930fa..712bd015ff 100644
--- a/scene/3d/gpu_particles_collision_3d.h
+++ b/scene/3d/gpu_particles_collision_3d.h
@@ -110,6 +110,7 @@ public:
private:
Vector3 extents = Vector3(1, 1, 1);
Resolution resolution = RESOLUTION_64;
+ uint32_t bake_mask = 0xFFFFFFFF;
Ref<Texture3D> texture;
float thickness = 1.0;
@@ -161,6 +162,8 @@ protected:
static void _bind_methods();
public:
+ virtual TypedArray<String> get_configuration_warnings() const override;
+
void set_thickness(float p_thickness);
float get_thickness() const;
@@ -170,6 +173,12 @@ public:
void set_resolution(Resolution p_resolution);
Resolution get_resolution() const;
+ void set_bake_mask(uint32_t p_mask);
+ uint32_t get_bake_mask() const;
+
+ void set_bake_mask_value(int p_layer_number, bool p_enable);
+ bool get_bake_mask_value(int p_layer_number) const;
+
void set_texture(const Ref<Texture3D> &p_texture);
Ref<Texture3D> get_texture() const;
diff --git a/scene/3d/importer_mesh_instance_3d.h b/scene/3d/importer_mesh_instance_3d.h
index 3daf06771d..223b6fc80a 100644
--- a/scene/3d/importer_mesh_instance_3d.h
+++ b/scene/3d/importer_mesh_instance_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SCENE_IMPORTER_MESH_INSTANCE_3D_H
-#define SCENE_IMPORTER_MESH_INSTANCE_3D_H
+#ifndef IMPORTER_MESH_INSTANCE_3D_H
+#define IMPORTER_MESH_INSTANCE_3D_H
#include "scene/3d/node_3d.h"
#include "scene/resources/immediate_mesh.h"
@@ -61,4 +61,5 @@ public:
void set_skeleton_path(const NodePath &p_path);
NodePath get_skeleton_path() const;
};
-#endif
+
+#endif // IMPORTER_MESH_INSTANCE_3D_H
diff --git a/scene/3d/joint_3d.cpp b/scene/3d/joint_3d.cpp
index 0b824ef28b..b0509475a7 100644
--- a/scene/3d/joint_3d.cpp
+++ b/scene/3d/joint_3d.cpp
@@ -737,7 +737,8 @@ void Generic6DOFJoint3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flag_z", "flag", "value"), &Generic6DOFJoint3D::set_flag_z);
ClassDB::bind_method(D_METHOD("get_flag_z", "flag"), &Generic6DOFJoint3D::get_flag_z);
- // X
+ ADD_GROUP("Linear Limit", "linear_limit_");
+
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/upper_distance", PROPERTY_HINT_NONE, "suffix:m"), "set_param_x", "get_param_x", PARAM_LINEAR_UPPER_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/lower_distance", PROPERTY_HINT_NONE, "suffix:m"), "set_param_x", "get_param_x", PARAM_LINEAR_LOWER_LIMIT);
@@ -745,15 +746,53 @@ void Generic6DOFJoint3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_RESTITUTION);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/upper_distance", PROPERTY_HINT_NONE, "suffix:m"), "set_param_y", "get_param_y", PARAM_LINEAR_UPPER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/lower_distance", PROPERTY_HINT_NONE, "suffix:m"), "set_param_y", "get_param_y", PARAM_LINEAR_LOWER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_DAMPING);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/upper_distance", PROPERTY_HINT_NONE, "suffix:m"), "set_param_z", "get_param_z", PARAM_LINEAR_UPPER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/lower_distance", PROPERTY_HINT_NONE, "suffix:m"), "set_param_z", "get_param_z", PARAM_LINEAR_LOWER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_DAMPING);
+
+ ADD_GROUP("Linear Motor", "linear_motor_");
+
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_MOTOR);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_x/target_velocity", PROPERTY_HINT_NONE, "suffix:m/s"), "set_param_x", "get_param_x", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_x/force_limit"), "set_param_x", "get_param_x", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_y/target_velocity", PROPERTY_HINT_NONE, "suffix:m/s"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_y/force_limit"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_z/target_velocity", PROPERTY_HINT_NONE, "suffix:m/s"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_z/force_limit"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
+
+ ADD_GROUP("Linear Spring", "linear_spring_");
+
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_spring_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_SPRING);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_x/stiffness"), "set_param_x", "get_param_x", PARAM_LINEAR_SPRING_STIFFNESS);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_x/damping"), "set_param_x", "get_param_x", PARAM_LINEAR_SPRING_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_x/equilibrium_point"), "set_param_x", "get_param_x", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_spring_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_SPRING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_y/stiffness"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_STIFFNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_y/damping"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_y/equilibrium_point"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_spring_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_SPRING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_z/stiffness"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_STIFFNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_z/damping"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_z/equilibrium_point"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT);
+
+ ADD_GROUP("Angular Limit", "angular_limit_");
+
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_ANGULAR_LIMIT);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_x/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_x", "_get_angular_hi_limit_x");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_x/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_x", "_get_angular_lo_limit_x");
@@ -763,68 +802,15 @@ void Generic6DOFJoint3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/force_limit"), "set_param_x", "get_param_x", PARAM_ANGULAR_FORCE_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/erp"), "set_param_x", "get_param_x", PARAM_ANGULAR_ERP);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_motor_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_MOTOR);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_x/target_velocity"), "set_param_x", "get_param_x", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_x/force_limit"), "set_param_x", "get_param_x", PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
-
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_spring_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_ANGULAR_SPRING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_x/stiffness"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_STIFFNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_x/damping"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_x/equilibrium_point"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT);
-
- // Y
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/upper_distance", PROPERTY_HINT_NONE, "suffix:m"), "set_param_y", "get_param_y", PARAM_LINEAR_UPPER_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/lower_distance", PROPERTY_HINT_NONE, "suffix:m"), "set_param_y", "get_param_y", PARAM_LINEAR_LOWER_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_LIMIT_SOFTNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_RESTITUTION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_DAMPING);
-
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_MOTOR);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_y/target_velocity", PROPERTY_HINT_NONE, "suffix:m/s"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_y/force_limit"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
-
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_spring_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_SPRING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_y/stiffness"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_STIFFNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_y/damping"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_y/equilibrium_point"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT);
-
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_ANGULAR_LIMIT);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_y/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_y", "_get_angular_hi_limit_y");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_y/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_y", "_get_angular_lo_limit_y");
-
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_LIMIT_SOFTNESS);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_RESTITUTION);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/force_limit"), "set_param_y", "get_param_y", PARAM_ANGULAR_FORCE_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/erp"), "set_param_y", "get_param_y", PARAM_ANGULAR_ERP);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_motor_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_MOTOR);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_y/target_velocity"), "set_param_y", "get_param_y", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_y/force_limit"), "set_param_y", "get_param_y", PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
-
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_spring_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_ANGULAR_SPRING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_y/stiffness"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_STIFFNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_y/damping"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_y/equilibrium_point"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT);
-
- // Z
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/upper_distance", PROPERTY_HINT_NONE, "suffix:m"), "set_param_z", "get_param_z", PARAM_LINEAR_UPPER_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/lower_distance", PROPERTY_HINT_NONE, "suffix:m"), "set_param_z", "get_param_z", PARAM_LINEAR_LOWER_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_LIMIT_SOFTNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_RESTITUTION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_DAMPING);
-
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_MOTOR);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_z/target_velocity", PROPERTY_HINT_NONE, "suffix:m/s"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_z/force_limit"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
-
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_spring_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_SPRING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_z/stiffness"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_STIFFNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_z/damping"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_z/equilibrium_point"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT);
-
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_ANGULAR_LIMIT);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_z/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_z", "_get_angular_hi_limit_z");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_z/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_z", "_get_angular_lo_limit_z");
@@ -834,10 +820,32 @@ void Generic6DOFJoint3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/force_limit"), "set_param_z", "get_param_z", PARAM_ANGULAR_FORCE_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/erp"), "set_param_z", "get_param_z", PARAM_ANGULAR_ERP);
+ ADD_GROUP("Angular Motor", "angular_motor_");
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_motor_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_x/target_velocity"), "set_param_x", "get_param_x", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_x/force_limit"), "set_param_x", "get_param_x", PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_motor_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_y/target_velocity"), "set_param_y", "get_param_y", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_y/force_limit"), "set_param_y", "get_param_y", PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
+
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_motor_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_MOTOR);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_z/target_velocity"), "set_param_z", "get_param_z", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_z/force_limit"), "set_param_z", "get_param_z", PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
+ ADD_GROUP("Angular Spring", "angular_spring_");
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_spring_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_ANGULAR_SPRING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_x/stiffness"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_STIFFNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_x/damping"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_x/equilibrium_point"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_spring_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_ANGULAR_SPRING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_y/stiffness"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_STIFFNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_y/damping"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_y/equilibrium_point"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT);
+
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_spring_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_ANGULAR_SPRING);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_z/stiffness"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_STIFFNESS);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_z/damping"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_DAMPING);
diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp
index d95cf15bfa..712a37e745 100644
--- a/scene/3d/label_3d.cpp
+++ b/scene/3d/label_3d.cpp
@@ -53,10 +53,6 @@ void Label3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_text_direction", "direction"), &Label3D::set_text_direction);
ClassDB::bind_method(D_METHOD("get_text_direction"), &Label3D::get_text_direction);
- ClassDB::bind_method(D_METHOD("set_opentype_feature", "tag", "value"), &Label3D::set_opentype_feature);
- ClassDB::bind_method(D_METHOD("get_opentype_feature", "tag"), &Label3D::get_opentype_feature);
- ClassDB::bind_method(D_METHOD("clear_opentype_features"), &Label3D::clear_opentype_features);
-
ClassDB::bind_method(D_METHOD("set_language", "language"), &Label3D::set_language);
ClassDB::bind_method(D_METHOD("get_language"), &Label3D::get_language);
@@ -130,7 +126,7 @@ void Label3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "no_depth_test"), "set_draw_flag", "get_draw_flag", FLAG_DISABLE_DEPTH_TEST);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "fixed_size"), "set_draw_flag", "get_draw_flag", FLAG_FIXED_SIZE);
ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_cut", PROPERTY_HINT_ENUM, "Disabled,Discard,Opaque Pre-Pass"), "set_alpha_cut_mode", "get_alpha_cut_mode");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "render_priority", PROPERTY_HINT_RANGE, itos(RS::MATERIAL_RENDER_PRIORITY_MIN) + "," + itos(RS::MATERIAL_RENDER_PRIORITY_MAX) + ",1"), "set_render_priority", "get_render_priority");
ADD_PROPERTY(PropertyInfo(Variant::INT, "outline_render_priority", PROPERTY_HINT_RANGE, itos(RS::MATERIAL_RENDER_PRIORITY_MIN) + "," + itos(RS::MATERIAL_RENDER_PRIORITY_MAX) + ",1"), "set_outline_render_priority", "get_outline_render_priority");
@@ -140,7 +136,7 @@ void Label3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "outline_modulate"), "set_outline_modulate", "get_outline_modulate");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT, ""), "set_text", "get_text");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_font", "get_font");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "font_size", PROPERTY_HINT_RANGE, "1,127,1,suffix:px"), "set_font_size", "get_font_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "font_size", PROPERTY_HINT_RANGE, "1,256,1,or_greater,suffix:px"), "set_font_size", "get_font_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "outline_size", PROPERTY_HINT_RANGE, "0,127,1,suffix:px"), "set_outline_size", "get_outline_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "horizontal_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_horizontal_alignment", "get_horizontal_alignment");
ADD_PROPERTY(PropertyInfo(Variant::INT, "vertical_alignment", PROPERTY_HINT_ENUM, "Top,Center,Bottom"), "set_vertical_alignment", "get_vertical_alignment");
@@ -148,17 +144,12 @@ void Label3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "line_spacing", PROPERTY_HINT_NONE, "suffix:px"), "set_line_spacing", "get_line_spacing");
ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Off,Arbitrary,Word,Word (Smart)"), "set_autowrap_mode", "get_autowrap_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "width", PROPERTY_HINT_NONE, "suffix:px"), "set_width", "get_width");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "structured_text_bidi_override", PROPERTY_HINT_ENUM, "Default,URI,File,Email,List,None,Custom"), "set_structured_text_bidi_override", "get_structured_text_bidi_override");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "structured_text_bidi_override_options"), "set_structured_text_bidi_override_options", "get_structured_text_bidi_override_options");
- ADD_GROUP("Locale", "");
+ ADD_GROUP("BiDi", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language");
-
- BIND_ENUM_CONSTANT(AUTOWRAP_OFF);
- BIND_ENUM_CONSTANT(AUTOWRAP_ARBITRARY);
- BIND_ENUM_CONSTANT(AUTOWRAP_WORD);
- BIND_ENUM_CONSTANT(AUTOWRAP_WORD_SMART);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "structured_text_bidi_override", PROPERTY_HINT_ENUM, "Default,URI,File,Email,List,None,Custom"), "set_structured_text_bidi_override", "get_structured_text_bidi_override");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "structured_text_bidi_override_options"), "set_structured_text_bidi_override_options", "get_structured_text_bidi_override_options");
BIND_ENUM_CONSTANT(FLAG_SHADED);
BIND_ENUM_CONSTANT(FLAG_DOUBLE_SIDED);
@@ -171,56 +162,6 @@ void Label3D::_bind_methods() {
BIND_ENUM_CONSTANT(ALPHA_CUT_OPAQUE_PREPASS);
}
-bool Label3D::_set(const StringName &p_name, const Variant &p_value) {
- String str = p_name;
- if (str.begins_with("opentype_features/")) {
- String name = str.get_slicec('/', 1);
- int32_t tag = TS->name_to_tag(name);
- int value = p_value;
- if (value == -1) {
- if (opentype_features.has(tag)) {
- opentype_features.erase(tag);
- dirty_font = true;
- _queue_update();
- }
- } else {
- if (!opentype_features.has(tag) || (int)opentype_features[tag] != value) {
- opentype_features[tag] = value;
- dirty_font = true;
- _queue_update();
- }
- }
- notify_property_list_changed();
- return true;
- }
-
- return false;
-}
-
-bool Label3D::_get(const StringName &p_name, Variant &r_ret) const {
- String str = p_name;
- if (str.begins_with("opentype_features/")) {
- String name = str.get_slicec('/', 1);
- int32_t tag = TS->name_to_tag(name);
- if (opentype_features.has(tag)) {
- r_ret = opentype_features[tag];
- return true;
- } else {
- r_ret = -1;
- return true;
- }
- }
- return false;
-}
-
-void Label3D::_get_property_list(List<PropertyInfo> *p_list) const {
- for (const Variant *ftr = opentype_features.next(nullptr); ftr != nullptr; ftr = opentype_features.next(ftr)) {
- String name = TS->tag_to_name(*ftr);
- p_list->push_back(PropertyInfo(Variant::INT, "opentype_features/" + name));
- }
- p_list->push_back(PropertyInfo(Variant::NIL, "opentype_features/_new", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
-}
-
void Label3D::_validate_property(PropertyInfo &property) const {
if (property.name == "material_override" || property.name == "material_overlay") {
property.usage = PROPERTY_USAGE_NO_EDITOR;
@@ -285,7 +226,7 @@ Ref<TriangleMesh> Label3D::generate_triangle_mesh() const {
float total_h = 0.0;
float max_line_w = 0.0;
for (int i = 0; i < lines_rid.size(); i++) {
- total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM) + line_spacing;
+ total_h += TS->shaped_text_get_size(lines_rid[i]).y + line_spacing;
max_line_w = MAX(max_line_w, TS->shaped_text_get_width(lines_rid[i]));
}
@@ -375,15 +316,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
@@ -412,9 +346,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);
@@ -469,7 +403,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();
@@ -483,7 +417,10 @@ void Label3D::_shape() {
TS->shaped_text_set_direction(text_rid, text_direction);
String text = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text;
- TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, opentype_features, language);
+ TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, font->get_opentype_features(), language);
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
+ }
Array stt;
if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) {
@@ -499,7 +436,10 @@ void Label3D::_shape() {
} else if (dirty_font) {
int spans = TS->shaped_get_span_count(text_rid);
for (int i = 0; i < spans; i++) {
- TS->shaped_set_span_update_font(text_rid, i, font->get_rids(), font_size, opentype_features);
+ TS->shaped_set_span_update_font(text_rid, i, font->get_rids(), font_size, font->get_opentype_features());
+ }
+ for (int i = 0; i < TextServer::SPACING_MAX; i++) {
+ TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
}
dirty_font = false;
@@ -512,18 +452,18 @@ void Label3D::_shape() {
}
lines_rid.clear();
- uint16_t autowrap_flags = TextServer::BREAK_MANDATORY;
+ BitField<TextServer::LineBreakFlag> autowrap_flags = TextServer::BREAK_MANDATORY;
switch (autowrap_mode) {
- case AUTOWRAP_WORD_SMART:
- autowrap_flags = TextServer::BREAK_WORD_BOUND_ADAPTIVE | TextServer::BREAK_MANDATORY;
+ case TextServer::AUTOWRAP_WORD_SMART:
+ autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_ADAPTIVE | TextServer::BREAK_MANDATORY;
break;
- case AUTOWRAP_WORD:
+ case TextServer::AUTOWRAP_WORD:
autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_MANDATORY;
break;
- case AUTOWRAP_ARBITRARY:
+ case TextServer::AUTOWRAP_ARBITRARY:
autowrap_flags = TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_MANDATORY;
break;
- case AUTOWRAP_OFF:
+ case TextServer::AUTOWRAP_OFF:
break;
}
PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags);
@@ -546,7 +486,7 @@ void Label3D::_shape() {
// Generate surfaces and materials.
float total_h = 0.0;
for (int i = 0; i < lines_rid.size(); i++) {
- total_h += (TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM) + line_spacing) * pixel_size;
+ total_h += (TS->shaped_text_get_size(lines_rid[i]).y + line_spacing) * pixel_size;
}
float vbegin = 0.0;
@@ -582,7 +522,7 @@ void Label3D::_shape() {
} break;
}
offset.x += lbl_offset.x * pixel_size;
- offset.y -= (TS->shaped_text_get_ascent(lines_rid[i]) + font->get_spacing(TextServer::SPACING_TOP)) * pixel_size;
+ offset.y -= TS->shaped_text_get_ascent(lines_rid[i]) * pixel_size;
if (outline_modulate.a != 0.0 && outline_size > 0) {
// Outline surfaces.
@@ -596,10 +536,10 @@ void Label3D::_shape() {
for (int j = 0; j < gl_size; j++) {
_generate_glyph_surfaces(glyphs[j], offset, modulate, render_priority);
}
- offset.y -= (TS->shaped_text_get_descent(lines_rid[i]) + line_spacing + font->get_spacing(TextServer::SPACING_BOTTOM)) * pixel_size;
+ offset.y -= (TS->shaped_text_get_descent(lines_rid[i]) + line_spacing) * 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;
@@ -669,29 +609,6 @@ TextServer::Direction Label3D::get_text_direction() const {
return text_direction;
}
-void Label3D::clear_opentype_features() {
- opentype_features.clear();
- dirty_font = true;
- _queue_update();
-}
-
-void Label3D::set_opentype_feature(const String &p_name, int p_value) {
- int32_t tag = TS->name_to_tag(p_name);
- if (!opentype_features.has(tag) || (int)opentype_features[tag] != p_value) {
- opentype_features[tag] = p_value;
- dirty_font = true;
- _queue_update();
- }
-}
-
-int Label3D::get_opentype_feature(const String &p_name) const {
- int32_t tag = TS->name_to_tag(p_name);
- if (!opentype_features.has(tag)) {
- return -1;
- }
- return opentype_features[tag];
-}
-
void Label3D::set_language(const String &p_language) {
if (language != p_language) {
language = p_language;
@@ -793,7 +710,7 @@ Ref<Font> Label3D::_get_font_or_default() const {
theme_font.unref();
}
- if (font_override.is_valid() && font_override->get_data_count() > 0) {
+ if (font_override.is_valid()) {
return font_override;
}
@@ -885,7 +802,7 @@ Color Label3D::get_outline_modulate() const {
return outline_modulate;
}
-void Label3D::set_autowrap_mode(Label3D::AutowrapMode p_mode) {
+void Label3D::set_autowrap_mode(TextServer::AutowrapMode p_mode) {
if (autowrap_mode != p_mode) {
autowrap_mode = p_mode;
dirty_lines = true;
@@ -893,7 +810,7 @@ void Label3D::set_autowrap_mode(Label3D::AutowrapMode p_mode) {
}
}
-Label3D::AutowrapMode Label3D::get_autowrap_mode() const {
+TextServer::AutowrapMode Label3D::get_autowrap_mode() const {
return autowrap_mode;
}
@@ -1023,7 +940,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 62f4c3fe96..4498e89517 100644
--- a/scene/3d/label_3d.h
+++ b/scene/3d/label_3d.h
@@ -54,13 +54,6 @@ public:
ALPHA_CUT_OPAQUE_PREPASS
};
- enum AutowrapMode {
- AUTOWRAP_OFF,
- AUTOWRAP_ARBITRARY,
- AUTOWRAP_WORD,
- AUTOWRAP_WORD_SMART
- };
-
private:
real_t pixel_size = 0.01;
bool flags[FLAG_MAX] = {};
@@ -83,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;
@@ -91,7 +106,7 @@ private:
String xl_text;
bool uppercase = false;
- AutowrapMode autowrap_mode = AUTOWRAP_OFF;
+ TextServer::AutowrapMode autowrap_mode = TextServer::AUTOWRAP_OFF;
float width = 500.0;
int font_size = 16;
@@ -107,7 +122,6 @@ private:
float line_spacing = 0.f;
- Dictionary opentype_features;
String language;
TextServer::Direction text_direction = TextServer::DIRECTION_AUTO;
TextServer::StructuredTextParser st_parser = TextServer::STRUCTURED_TEXT_DEFAULT;
@@ -135,9 +149,6 @@ protected:
static void _bind_methods();
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
void _validate_property(PropertyInfo &property) const override;
void _im_update();
@@ -165,10 +176,6 @@ public:
void set_text_direction(TextServer::Direction p_text_direction);
TextServer::Direction get_text_direction() const;
- void set_opentype_feature(const String &p_name, int p_value);
- int get_opentype_feature(const String &p_name) const;
- void clear_opentype_features();
-
void set_language(const String &p_language);
String get_language() const;
@@ -200,8 +207,8 @@ public:
void set_outline_modulate(const Color &p_color);
Color get_outline_modulate() const;
- void set_autowrap_mode(AutowrapMode p_mode);
- AutowrapMode get_autowrap_mode() const;
+ void set_autowrap_mode(TextServer::AutowrapMode p_mode);
+ TextServer::AutowrapMode get_autowrap_mode() const;
void set_width(float p_width);
float get_width() const;
@@ -234,7 +241,6 @@ public:
~Label3D();
};
-VARIANT_ENUM_CAST(Label3D::AutowrapMode);
VARIANT_ENUM_CAST(Label3D::DrawFlags);
VARIANT_ENUM_CAST(Label3D::AlphaCutMode);
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index d80c10d63a..53c072c318 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;
@@ -219,7 +224,7 @@ bool Light3D::is_editor_only() const {
}
void Light3D::_validate_property(PropertyInfo &property) const {
- if (!shadow && (property.name == "shadow_bias" || property.name == "shadow_normal_bias" || property.name == "shadow_reverse_cull_face" || property.name == "shadow_transmittance_bias" || property.name == "shadow_fog_fade" || property.name == "shadow_blur" || property.name == "distance_fade_shadow")) {
+ if (!shadow && (property.name == "shadow_bias" || property.name == "shadow_normal_bias" || property.name == "shadow_reverse_cull_face" || property.name == "shadow_transmittance_bias" || property.name == "shadow_fog_fade" || property.name == "shadow_opacity" || property.name == "shadow_blur" || property.name == "distance_fade_shadow")) {
property.usage = PROPERTY_USAGE_NO_EDITOR;
}
@@ -281,11 +286,12 @@ void Light3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.001,or_greater"), "set_param", "get_param", PARAM_INDIRECT_ENERGY);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_projector", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_projector", "get_projector");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_size", PROPERTY_HINT_RANGE, "0,1,0.001,or_greater,suffix:m"), "set_param", "get_param", PARAM_SIZE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_angular_distance", PROPERTY_HINT_RANGE, "0,90,0.01,radians"), "set_param", "get_param", PARAM_SIZE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_angular_distance", PROPERTY_HINT_RANGE, "0,90,0.01,degrees"), "set_param", "get_param", PARAM_SIZE);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "is_negative");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_specular", PROPERTY_HINT_RANGE, "0,16,0.001,or_greater"), "set_param", "get_param", PARAM_SPECULAR);
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_bake_mode", PROPERTY_HINT_ENUM, "Disabled,Static (VoxelGI/SDFGI/LightmapGI),Dynamic (VoxelGI/SDFGI only)"), "set_bake_mode", "get_bake_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
+
ADD_GROUP("Shadow", "shadow_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_enabled"), "set_shadow", "has_shadow");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_bias", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_BIAS);
@@ -293,13 +299,18 @@ void Light3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_reverse_cull_face"), "set_shadow_reverse_cull_face", "get_shadow_reverse_cull_face");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_transmittance_bias", PROPERTY_HINT_RANGE, "-16,16,0.001"), "set_param", "get_param", PARAM_TRANSMITTANCE_BIAS);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_fog_fade", PROPERTY_HINT_RANGE, "0.001,10,0.001"), "set_param", "get_param", PARAM_SHADOW_VOLUMETRIC_FOG_FADE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_opacity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_OPACITY);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_blur", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_BLUR);
+
+ ADD_GROUP("Distance Fade", "distance_fade_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distance_fade_enabled"), "set_enable_distance_fade", "is_distance_fade_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_begin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater,suffix:m"), "set_distance_fade_begin", "get_distance_fade_begin");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_shadow", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater,suffix:m"), "set_distance_fade_shadow", "get_distance_fade_shadow");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_length", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater,suffix:m"), "set_distance_fade_length", "get_distance_fade_length");
+
ADD_GROUP("Editor", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only");
+
ADD_GROUP("", "");
BIND_ENUM_CONSTANT(PARAM_ENERGY);
@@ -318,6 +329,7 @@ void Light3D::_bind_methods() {
BIND_ENUM_CONSTANT(PARAM_SHADOW_NORMAL_BIAS);
BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS);
BIND_ENUM_CONSTANT(PARAM_SHADOW_PANCAKE_SIZE);
+ BIND_ENUM_CONSTANT(PARAM_SHADOW_OPACITY);
BIND_ENUM_CONSTANT(PARAM_SHADOW_BLUR);
BIND_ENUM_CONSTANT(PARAM_SHADOW_VOLUMETRIC_FOG_FADE);
BIND_ENUM_CONSTANT(PARAM_TRANSMITTANCE_BIAS);
@@ -365,6 +377,7 @@ Light3D::Light3D(RenderingServer::LightType p_type) {
set_param(PARAM_SHADOW_SPLIT_3_OFFSET, 0.5);
set_param(PARAM_SHADOW_FADE_START, 0.8);
set_param(PARAM_SHADOW_PANCAKE_SIZE, 20.0);
+ set_param(PARAM_SHADOW_OPACITY, 1.0);
set_param(PARAM_SHADOW_BLUR, 1.0);
set_param(PARAM_SHADOW_BIAS, 0.03);
set_param(PARAM_SHADOW_NORMAL_BIAS, 1.0);
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index 383fa644e5..ef003e133d 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -54,6 +54,7 @@ public:
PARAM_SHADOW_NORMAL_BIAS = RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS,
PARAM_SHADOW_BIAS = RS::LIGHT_PARAM_SHADOW_BIAS,
PARAM_SHADOW_PANCAKE_SIZE = RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE,
+ PARAM_SHADOW_OPACITY = RS::LIGHT_PARAM_SHADOW_OPACITY,
PARAM_SHADOW_BLUR = RS::LIGHT_PARAM_SHADOW_BLUR,
PARAM_SHADOW_VOLUMETRIC_FOG_FADE = RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE,
PARAM_TRANSMITTANCE_BIAS = RS::LIGHT_PARAM_TRANSMITTANCE_BIAS,
@@ -85,6 +86,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..6b6a2eff9e 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;
}
@@ -146,7 +146,7 @@ Array LightmapGIData::_get_light_textures_data() const {
texture_image->create(slice_width, slice_height * texture_slice_count, false, images[0]->get_format());
for (int j = 0; j < texture_slice_count; j++) {
- texture_image->blit_rect(images[i * slices_per_texture + j], Rect2(0, 0, slice_width, slice_height), Point2(0, slice_height * j));
+ texture_image->blit_rect(images[i * slices_per_texture + j], Rect2i(0, 0, slice_width, slice_height), Point2i(0, slice_height * j));
}
String texture_path = texture_count > 1 ? base_name + "_" + itos(i) + ".exr" : base_name + ".exr";
@@ -291,7 +291,7 @@ void LightmapGIData::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_probe_data", "data"), &LightmapGIData::_set_probe_data);
ClassDB::bind_method(D_METHOD("_get_probe_data"), &LightmapGIData::_get_probe_data);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK), "set_light_texture", "get_light_texture"); // property usage default but no save
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered", PROPERTY_USAGE_EDITOR), "set_light_texture", "get_light_texture"); // property usage default but no save
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "light_textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_light_textures_data", "_get_light_textures_data");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uses_spherical_harmonics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_uses_spherical_harmonics", "is_using_spherical_harmonics");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_user_data", "_get_user_data");
@@ -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++) {
@@ -1219,7 +1219,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
}
data->set_path(p_image_data_path);
- Error err = ResourceSaver::save(p_image_data_path, data);
+ Error err = ResourceSaver::save(data);
if (err != OK) {
return BAKE_ERROR_CANT_CREATE_IMAGE;
diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h
index b39cde429d..85150b833f 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;
@@ -279,4 +271,4 @@ VARIANT_ENUM_CAST(LightmapGI::GenerateProbes);
VARIANT_ENUM_CAST(LightmapGI::BakeError);
VARIANT_ENUM_CAST(LightmapGI::EnvironmentMode);
-#endif // BAKED_LIGHTMAP_H
+#endif // LIGHTMAP_GI_H
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/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h
index dc9c64fa41..48d76b9a88 100644
--- a/scene/3d/mesh_instance_3d.h
+++ b/scene/3d/mesh_instance_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef MESH_INSTANCE_H
-#define MESH_INSTANCE_H
+#ifndef MESH_INSTANCE_3D_H
+#define MESH_INSTANCE_3D_H
#include "core/templates/local_vector.h"
#include "scene/3d/visual_instance_3d.h"
@@ -98,4 +98,4 @@ public:
~MeshInstance3D();
};
-#endif
+#endif // MESH_INSTANCE_3D_H
diff --git a/scene/3d/multimesh_instance_3d.h b/scene/3d/multimesh_instance_3d.h
index 111f1e9c09..2fa8dd965f 100644
--- a/scene/3d/multimesh_instance_3d.h
+++ b/scene/3d/multimesh_instance_3d.h
@@ -53,4 +53,4 @@ public:
~MultiMeshInstance3D();
};
-#endif // MULTIMESH_INSTANCE_H
+#endif // MULTIMESH_INSTANCE_3D_H
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..e05f0287f7 100644
--- a/scene/3d/navigation_agent_3d.h
+++ b/scene/3d/navigation_agent_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef NAVIGATION_AGENT_H
-#define NAVIGATION_AGENT_H
+#ifndef NAVIGATION_AGENT_3D_H
+#define NAVIGATION_AGENT_3D_H
#include "scene/main/node.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;
@@ -166,4 +175,4 @@ private:
void _check_distance_to_target();
};
-#endif
+#endif // NAVIGATION_AGENT_3D_H
diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h
index 0ddde64c0e..0316fc37a8 100644
--- a/scene/3d/navigation_obstacle_3d.h
+++ b/scene/3d/navigation_obstacle_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef NAVIGATION_OBSTACLE_H
-#define NAVIGATION_OBSTACLE_H
+#ifndef NAVIGATION_OBSTACLE_3D_H
+#define NAVIGATION_OBSTACLE_3D_H
#include "scene/3d/node_3d.h"
@@ -73,4 +73,4 @@ private:
real_t estimate_agent_radius() const;
};
-#endif
+#endif // NAVIGATION_OBSTACLE_3D_H
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 7ef16fbc0a..4150b01651 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -49,14 +49,29 @@ void NavigationRegion3D::set_enabled(bool p_enabled) {
NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
}
- if (debug_view) {
- MeshInstance3D *dm = Object::cast_to<MeshInstance3D>(debug_view);
- if (is_enabled()) {
- dm->set_material_override(get_tree()->get_debug_navigation_material());
+#ifdef DEBUG_ENABLED
+ if (debug_instance.is_valid()) {
+ if (!is_enabled()) {
+ if (debug_mesh.is_valid()) {
+ if (debug_mesh->get_surface_count() > 0) {
+ RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_face_disabled_material()->get_rid());
+ }
+ if (debug_mesh->get_surface_count() > 1) {
+ RS::get_singleton()->instance_set_surface_override_material(debug_instance, 1, NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_edge_disabled_material()->get_rid());
+ }
+ }
} else {
- dm->set_material_override(get_tree()->get_debug_navigation_disabled_material());
+ if (debug_mesh.is_valid()) {
+ if (debug_mesh->get_surface_count() > 0) {
+ RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, RID());
+ }
+ if (debug_mesh->get_surface_count() > 1) {
+ RS::get_singleton()->instance_set_surface_override_material(debug_instance, 1, RID());
+ }
+ }
}
}
+#endif // DEBUG_ENABLED
update_gizmos();
}
@@ -73,6 +88,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);
@@ -86,7 +119,7 @@ real_t NavigationRegion3D::get_enter_cost() const {
void NavigationRegion3D::set_travel_cost(real_t p_travel_cost) {
ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
travel_cost = MAX(p_travel_cost, 0.0);
- NavigationServer3D::get_singleton()->region_set_enter_cost(region, travel_cost);
+ NavigationServer3D::get_singleton()->region_set_travel_cost(region, travel_cost);
}
real_t NavigationRegion3D::get_travel_cost() const {
@@ -106,30 +139,36 @@ void NavigationRegion3D::_notification(int p_what) {
NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
}
- if (navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) {
- MeshInstance3D *dm = memnew(MeshInstance3D);
- dm->set_mesh(navmesh->get_debug_mesh());
- if (is_enabled()) {
- dm->set_material_override(get_tree()->get_debug_navigation_material());
- } else {
- dm->set_material_override(get_tree()->get_debug_navigation_disabled_material());
- }
- add_child(dm);
- debug_view = dm;
+#ifdef DEBUG_ENABLED
+ if (NavigationServer3D::get_singleton()->get_debug_enabled()) {
+ _update_debug_mesh();
}
+#endif // DEBUG_ENABLED
+
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform());
+
+#ifdef DEBUG_ENABLED
+ if (is_inside_tree() && debug_instance.is_valid()) {
+ RS::get_singleton()->instance_set_transform(debug_instance, get_global_transform());
+ }
+#endif // DEBUG_ENABLED
+
} break;
case NOTIFICATION_EXIT_TREE: {
NavigationServer3D::get_singleton()->region_set_map(region, RID());
- if (debug_view) {
- debug_view->queue_delete();
- debug_view = nullptr;
+#ifdef DEBUG_ENABLED
+ if (debug_instance.is_valid()) {
+ RS::get_singleton()->instance_set_visible(debug_instance, false);
+ }
+ if (debug_edge_connections_instance.is_valid()) {
+ RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
}
+#endif // DEBUG_ENABLED
} break;
}
}
@@ -151,20 +190,21 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes
NavigationServer3D::get_singleton()->region_set_navmesh(region, p_navmesh);
- if (debug_view == nullptr && is_inside_tree() && navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) {
- MeshInstance3D *dm = memnew(MeshInstance3D);
- dm->set_mesh(navmesh->get_debug_mesh());
- if (is_enabled()) {
- dm->set_material_override(get_tree()->get_debug_navigation_material());
+#ifdef DEBUG_ENABLED
+ if (is_inside_tree() && NavigationServer3D::get_singleton()->get_debug_enabled()) {
+ if (navmesh.is_valid()) {
+ _update_debug_mesh();
+ _update_debug_edge_connections_mesh();
} else {
- dm->set_material_override(get_tree()->get_debug_navigation_disabled_material());
+ if (debug_instance.is_valid()) {
+ RS::get_singleton()->instance_set_visible(debug_instance, false);
+ }
+ if (debug_edge_connections_instance.is_valid()) {
+ RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
+ }
}
- add_child(dm);
- debug_view = dm;
- }
- if (debug_view && navmesh.is_valid()) {
- Object::cast_to<MeshInstance3D>(debug_view)->set_mesh(navmesh->get_debug_mesh());
}
+#endif // DEBUG_ENABLED
emit_signal(SNAME("navigation_mesh_changed"));
@@ -242,6 +282,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);
@@ -266,13 +309,31 @@ void NavigationRegion3D::_bind_methods() {
void NavigationRegion3D::_navigation_changed() {
update_gizmos();
update_configuration_warnings();
+
+#ifdef DEBUG_ENABLED
+ _update_debug_edge_connections_mesh();
+#endif // DEBUG_ENABLED
}
+#ifdef DEBUG_ENABLED
+void NavigationRegion3D::_navigation_map_changed(RID p_map) {
+ if (is_inside_tree() && p_map == get_world_3d()->get_navigation_map()) {
+ _update_debug_edge_connections_mesh();
+ }
+}
+#endif // DEBUG_ENABLED
+
NavigationRegion3D::NavigationRegion3D() {
set_notify_transform(true);
region = NavigationServer3D::get_singleton()->region_create();
NavigationServer3D::get_singleton()->region_set_enter_cost(region, get_enter_cost());
NavigationServer3D::get_singleton()->region_set_travel_cost(region, get_travel_cost());
+
+#ifdef DEBUG_ENABLED
+ NavigationServer3D::get_singleton_mut()->connect("map_changed", callable_mp(this, &NavigationRegion3D::_navigation_map_changed));
+ NavigationServer3D::get_singleton_mut()->connect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_mesh));
+ NavigationServer3D::get_singleton_mut()->connect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_edge_connections_mesh));
+#endif // DEBUG_ENABLED
}
NavigationRegion3D::~NavigationRegion3D() {
@@ -280,4 +341,245 @@ NavigationRegion3D::~NavigationRegion3D() {
navmesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
}
NavigationServer3D::get_singleton()->free(region);
+
+#ifdef DEBUG_ENABLED
+ NavigationServer3D::get_singleton_mut()->disconnect("map_changed", callable_mp(this, &NavigationRegion3D::_navigation_map_changed));
+ NavigationServer3D::get_singleton_mut()->disconnect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_mesh));
+ NavigationServer3D::get_singleton_mut()->disconnect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_edge_connections_mesh));
+ if (debug_instance.is_valid()) {
+ RenderingServer::get_singleton()->free(debug_instance);
+ }
+ if (debug_mesh.is_valid()) {
+ RenderingServer::get_singleton()->free(debug_mesh->get_rid());
+ }
+ if (debug_edge_connections_instance.is_valid()) {
+ RenderingServer::get_singleton()->free(debug_edge_connections_instance);
+ }
+ if (debug_edge_connections_mesh.is_valid()) {
+ RenderingServer::get_singleton()->free(debug_edge_connections_mesh->get_rid());
+ }
+#endif // DEBUG_ENABLED
+}
+
+#ifdef DEBUG_ENABLED
+void NavigationRegion3D::_update_debug_mesh() {
+ if (!NavigationServer3D::get_singleton()->get_debug_enabled()) {
+ if (debug_instance.is_valid()) {
+ RS::get_singleton()->instance_set_visible(debug_instance, false);
+ }
+ return;
+ }
+
+ if (!navmesh.is_valid()) {
+ if (debug_instance.is_valid()) {
+ RS::get_singleton()->instance_set_visible(debug_instance, false);
+ }
+ return;
+ }
+
+ if (!debug_instance.is_valid()) {
+ debug_instance = RenderingServer::get_singleton()->instance_create();
+ }
+
+ if (!debug_mesh.is_valid()) {
+ debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
+ }
+
+ debug_mesh->clear_surfaces();
+
+ bool enabled_geometry_face_random_color = NavigationServer3D::get_singleton()->get_debug_navigation_enable_geometry_face_random_color();
+ bool enabled_edge_lines = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_lines();
+
+ Vector<Vector3> vertices = navmesh->get_vertices();
+ if (vertices.size() == 0) {
+ return;
+ }
+
+ int polygon_count = navmesh->get_polygon_count();
+ if (polygon_count == 0) {
+ return;
+ }
+
+ Vector<Vector3> face_vertex_array;
+ face_vertex_array.resize(polygon_count * 3);
+
+ Vector<Color> face_color_array;
+ if (enabled_geometry_face_random_color) {
+ face_color_array.resize(polygon_count * 3);
+ }
+
+ Vector<Vector3> line_vertex_array;
+ if (enabled_edge_lines) {
+ line_vertex_array.resize(polygon_count * 6);
+ }
+
+ Color debug_navigation_geometry_face_color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color();
+
+ Ref<StandardMaterial3D> face_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_face_material();
+ Ref<StandardMaterial3D> line_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_edge_material();
+
+ Color polygon_color = debug_navigation_geometry_face_color;
+
+ for (int i = 0; i < polygon_count; i++) {
+ if (enabled_geometry_face_random_color) {
+ polygon_color = debug_navigation_geometry_face_color * (Color(Math::randf(), Math::randf(), Math::randf()));
+ }
+
+ Vector<int> polygon = navmesh->get_polygon(i);
+
+ face_vertex_array.push_back(vertices[polygon[0]]);
+ face_vertex_array.push_back(vertices[polygon[1]]);
+ face_vertex_array.push_back(vertices[polygon[2]]);
+ if (enabled_geometry_face_random_color) {
+ face_color_array.push_back(polygon_color);
+ face_color_array.push_back(polygon_color);
+ face_color_array.push_back(polygon_color);
+ }
+
+ if (enabled_edge_lines) {
+ line_vertex_array.push_back(vertices[polygon[0]]);
+ line_vertex_array.push_back(vertices[polygon[1]]);
+ line_vertex_array.push_back(vertices[polygon[1]]);
+ line_vertex_array.push_back(vertices[polygon[2]]);
+ line_vertex_array.push_back(vertices[polygon[2]]);
+ line_vertex_array.push_back(vertices[polygon[0]]);
+ }
+ }
+
+ Array face_mesh_array;
+ face_mesh_array.resize(Mesh::ARRAY_MAX);
+ face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array;
+ if (enabled_geometry_face_random_color) {
+ face_mesh_array[Mesh::ARRAY_COLOR] = face_color_array;
+ }
+ debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array);
+ debug_mesh->surface_set_material(0, face_material);
+
+ if (enabled_edge_lines) {
+ Array line_mesh_array;
+ line_mesh_array.resize(Mesh::ARRAY_MAX);
+ line_mesh_array[Mesh::ARRAY_VERTEX] = line_vertex_array;
+ debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, line_mesh_array);
+ debug_mesh->surface_set_material(1, line_material);
+ }
+
+ RS::get_singleton()->instance_set_base(debug_instance, debug_mesh->get_rid());
+ if (is_inside_tree()) {
+ RS::get_singleton()->instance_set_scenario(debug_instance, get_world_3d()->get_scenario());
+ RS::get_singleton()->instance_set_visible(debug_instance, is_visible_in_tree());
+ }
+ if (!is_enabled()) {
+ if (debug_mesh.is_valid()) {
+ if (debug_mesh->get_surface_count() > 0) {
+ RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_face_disabled_material()->get_rid());
+ }
+ if (debug_mesh->get_surface_count() > 1) {
+ RS::get_singleton()->instance_set_surface_override_material(debug_instance, 1, NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_edge_disabled_material()->get_rid());
+ }
+ }
+ } else {
+ if (debug_mesh.is_valid()) {
+ if (debug_mesh->get_surface_count() > 0) {
+ RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, RID());
+ }
+ if (debug_mesh->get_surface_count() > 1) {
+ RS::get_singleton()->instance_set_surface_override_material(debug_instance, 1, RID());
+ }
+ }
+ }
+}
+#endif // DEBUG_ENABLED
+
+#ifdef DEBUG_ENABLED
+void NavigationRegion3D::_update_debug_edge_connections_mesh() {
+ if (!NavigationServer3D::get_singleton()->get_debug_enabled()) {
+ if (debug_edge_connections_instance.is_valid()) {
+ RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
+ }
+ return;
+ }
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (!navmesh.is_valid()) {
+ if (debug_edge_connections_instance.is_valid()) {
+ RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
+ }
+ return;
+ }
+
+ if (!debug_edge_connections_instance.is_valid()) {
+ debug_edge_connections_instance = RenderingServer::get_singleton()->instance_create();
+ }
+
+ if (!debug_edge_connections_mesh.is_valid()) {
+ debug_edge_connections_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
+ }
+
+ debug_edge_connections_mesh->clear_surfaces();
+
+ float edge_connection_margin = NavigationServer3D::get_singleton()->map_get_edge_connection_margin(get_world_3d()->get_navigation_map());
+ float half_edge_connection_margin = edge_connection_margin * 0.5;
+ int connections_count = NavigationServer3D::get_singleton()->region_get_connections_count(region);
+
+ if (connections_count == 0) {
+ RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
+ return;
+ }
+
+ Vector<Vector3> vertex_array;
+
+ for (int i = 0; i < connections_count; i++) {
+ Vector3 connection_pathway_start = NavigationServer3D::get_singleton()->region_get_connection_pathway_start(region, i);
+ Vector3 connection_pathway_end = NavigationServer3D::get_singleton()->region_get_connection_pathway_end(region, i);
+
+ Vector3 direction_start_end = connection_pathway_start.direction_to(connection_pathway_end);
+ Vector3 direction_end_start = connection_pathway_end.direction_to(connection_pathway_start);
+
+ Vector3 start_right_dir = direction_start_end.cross(Vector3(0, 1, 0));
+ Vector3 start_left_dir = -start_right_dir;
+
+ Vector3 end_right_dir = direction_end_start.cross(Vector3(0, 1, 0));
+ Vector3 end_left_dir = -end_right_dir;
+
+ Vector3 left_start_pos = connection_pathway_start + (start_left_dir * half_edge_connection_margin);
+ Vector3 right_start_pos = connection_pathway_start + (start_right_dir * half_edge_connection_margin);
+ Vector3 left_end_pos = connection_pathway_end + (end_right_dir * half_edge_connection_margin);
+ Vector3 right_end_pos = connection_pathway_end + (end_left_dir * half_edge_connection_margin);
+
+ vertex_array.push_back(right_end_pos);
+ vertex_array.push_back(left_start_pos);
+ vertex_array.push_back(right_start_pos);
+
+ vertex_array.push_back(left_end_pos);
+ vertex_array.push_back(right_end_pos);
+ vertex_array.push_back(right_start_pos);
+ }
+
+ if (vertex_array.size() == 0) {
+ return;
+ }
+
+ Ref<StandardMaterial3D> edge_connections_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_edge_connections_material();
+
+ Array mesh_array;
+ mesh_array.resize(Mesh::ARRAY_MAX);
+ mesh_array[Mesh::ARRAY_VERTEX] = vertex_array;
+
+ debug_edge_connections_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, mesh_array);
+ debug_edge_connections_mesh->surface_set_material(0, edge_connections_material);
+
+ RS::get_singleton()->instance_set_base(debug_edge_connections_instance, debug_edge_connections_mesh->get_rid());
+ RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, is_visible_in_tree());
+ if (is_inside_tree()) {
+ RS::get_singleton()->instance_set_scenario(debug_edge_connections_instance, get_world_3d()->get_scenario());
+ }
+
+ bool enable_edge_connections = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_connections();
+ if (!enable_edge_connections) {
+ RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
+ }
}
+#endif // DEBUG_ENABLED
diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h
index 92474d1429..ba326abb46 100644
--- a/scene/3d/navigation_region_3d.h
+++ b/scene/3d/navigation_region_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef NAVIGATION_REGION_H
-#define NAVIGATION_REGION_H
+#ifndef NAVIGATION_REGION_3D_H
+#define NAVIGATION_REGION_3D_H
#include "scene/3d/node_3d.h"
#include "scene/resources/navigation_mesh.h"
@@ -44,11 +44,22 @@ class NavigationRegion3D : public Node3D {
real_t enter_cost = 0.0;
real_t travel_cost = 1.0;
- Node *debug_view = nullptr;
Thread bake_thread;
void _navigation_changed();
+#ifdef DEBUG_ENABLED
+ RID debug_instance;
+ RID debug_edge_connections_instance;
+ Ref<ArrayMesh> debug_mesh;
+ Ref<ArrayMesh> debug_edge_connections_mesh;
+
+private:
+ void _update_debug_mesh();
+ void _update_debug_edge_connections_mesh();
+ void _navigation_map_changed(RID p_map);
+#endif // DEBUG_ENABLED
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -60,6 +71,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);
@@ -82,4 +96,4 @@ public:
~NavigationRegion3D();
};
-#endif // NAVIGATION_REGION_H
+#endif // NAVIGATION_REGION_3D_H
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index 6e36815f2b..1de85d57a3 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;
@@ -665,7 +733,7 @@ void Node3D::rotate_z(real_t p_angle) {
void Node3D::translate(const Vector3 &p_offset) {
Transform3D t = get_transform();
- t.translate(p_offset);
+ t.translate_local(p_offset);
set_transform(t);
}
@@ -673,7 +741,7 @@ void Node3D::translate_object_local(const Vector3 &p_offset) {
Transform3D t = get_transform();
Transform3D s;
- s.translate(p_offset);
+ s.translate_local(p_offset);
set_transform(t * s);
}
@@ -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/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp
index 66d0a8c4e2..c1c309fdbe 100644
--- a/scene/3d/occluder_instance_3d.cpp
+++ b/scene/3d/occluder_instance_3d.cpp
@@ -670,7 +670,7 @@ OccluderInstance3D::BakeError OccluderInstance3D::bake_scene(Node *p_from_node,
occ->set_arrays(vertices, indices);
- Error err = ResourceSaver::save(p_occluder_path, occ);
+ Error err = ResourceSaver::save(occ, p_occluder_path);
if (err != OK) {
return BAKE_ERROR_CANT_SAVE;
diff --git a/scene/3d/occluder_instance_3d.h b/scene/3d/occluder_instance_3d.h
index ed6610074e..11d731b989 100644
--- a/scene/3d/occluder_instance_3d.h
+++ b/scene/3d/occluder_instance_3d.h
@@ -211,4 +211,4 @@ public:
~OccluderInstance3D();
};
-#endif
+#endif // OCCLUDER_INSTANCE_3D_H
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index 8c2b1c6889..25226ad384 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) {
@@ -157,10 +247,14 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
// for a discussion about why not Frenet frame.
t.origin = pos;
-
- if (p_update_xyz_rot && delta_offset != 0) { // Only update rotation if some parameter has changed - i.e. not on addition to scene tree.
- Vector3 t_prev = (pos - c->interpolate_baked(offset - delta_offset, cubic)).normalized();
- Vector3 t_cur = (c->interpolate_baked(offset + delta_offset, cubic) - pos).normalized();
+ if (p_update_xyz_rot && prev_offset != offset) { // Only update rotation if some parameter has changed - i.e. not on addition to scene tree.
+ real_t sample_distance = bi * 0.01;
+ Vector3 t_prev_pos_a = c->interpolate_baked(prev_offset - sample_distance, cubic);
+ Vector3 t_prev_pos_b = c->interpolate_baked(prev_offset + sample_distance, cubic);
+ Vector3 t_cur_pos_a = c->interpolate_baked(offset - sample_distance, cubic);
+ Vector3 t_cur_pos_b = c->interpolate_baked(offset + sample_distance, cubic);
+ Vector3 t_prev = (t_prev_pos_a - t_prev_pos_b).normalized();
+ Vector3 t_cur = (t_cur_pos_a - t_cur_pos_b).normalized();
Vector3 axis = t_prev.cross(t_cur);
real_t dot = t_prev.dot(t_cur);
@@ -202,7 +296,7 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
}
}
- t.translate(Vector3(h_offset, v_offset, 0));
+ t.translate_local(Vector3(h_offset, v_offset, 0));
} else {
t.origin = pos + Vector3(h_offset, v_offset, 0);
}
@@ -303,7 +397,8 @@ void PathFollow3D::_bind_methods() {
}
void PathFollow3D::set_offset(real_t p_offset) {
- delta_offset = p_offset - offset;
+ ERR_FAIL_COND(!isfinite(p_offset));
+ prev_offset = offset;
offset = p_offset;
if (path) {
diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h
index e9ab557693..b4cc6db7e3 100644
--- a/scene/3d/path_3d.h
+++ b/scene/3d/path_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef PATH_H
-#define PATH_H
+#ifndef PATH_3D_H
+#define PATH_3D_H
#include "scene/3d/node_3d.h"
#include "scene/resources/curve.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 {
@@ -65,7 +74,7 @@ public:
private:
Path3D *path = nullptr;
- real_t delta_offset = 0.0; // Change in offset since last _update_transform.
+ real_t prev_offset = 0.0; // Offset during the last _update_transform.
real_t offset = 0.0;
real_t h_offset = 0.0;
real_t v_offset = 0.0;
@@ -110,4 +119,4 @@ public:
VARIANT_ENUM_CAST(PathFollow3D::RotationMode);
-#endif // PATH_H
+#endif // PATH_3D_H
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 30f7a025fa..993608c306 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -439,8 +439,8 @@ void RigidDynamicBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p
//E->value.rc=0;
E->value.in_tree = node && node->is_inside_tree();
if (node) {
- node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody3D::_body_enter_tree), make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody3D::_body_exit_tree), make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody3D::_body_enter_tree).bind(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody3D::_body_exit_tree).bind(objid));
if (E->value.in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
}
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 22dcb218bc..e4a41be6c0 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -784,4 +784,4 @@ private:
VARIANT_ENUM_CAST(PhysicalBone3D::JointType);
VARIANT_ENUM_CAST(PhysicalBone3D::DampMode);
-#endif // PHYSICS_BODY__H
+#endif // PHYSICS_BODY_3D_H
diff --git a/scene/3d/ray_cast_3d.h b/scene/3d/ray_cast_3d.h
index c69c910efb..aa62f6927e 100644
--- a/scene/3d/ray_cast_3d.h
+++ b/scene/3d/ray_cast_3d.h
@@ -126,4 +126,4 @@ public:
RayCast3D();
};
-#endif // RAY_CAST_H
+#endif // RAY_CAST_3D_H
diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h
index 424976d895..a161717ece 100644
--- a/scene/3d/reflection_probe.h
+++ b/scene/3d/reflection_probe.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef REFLECTIONPROBE_H
-#define REFLECTIONPROBE_H
+#ifndef REFLECTION_PROBE_H
+#define REFLECTION_PROBE_H
#include "scene/3d/visual_instance_3d.h"
@@ -121,4 +121,4 @@ public:
VARIANT_ENUM_CAST(ReflectionProbe::AmbientMode);
VARIANT_ENUM_CAST(ReflectionProbe::UpdateMode);
-#endif // REFLECTIONPROBE_H
+#endif // REFLECTION_PROBE_H
diff --git a/scene/3d/remote_transform_3d.h b/scene/3d/remote_transform_3d.h
index 03bb253578..ab134c1261 100644
--- a/scene/3d/remote_transform_3d.h
+++ b/scene/3d/remote_transform_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef REMOTETRANSFORM_H
-#define REMOTETRANSFORM_H
+#ifndef REMOTE_TRANSFORM_3D_H
+#define REMOTE_TRANSFORM_3D_H
#include "scene/3d/node_3d.h"
@@ -75,4 +75,4 @@ public:
RemoteTransform3D();
};
-#endif // REMOTETRANSFORM_H
+#endif // REMOTE_TRANSFORM_3D_H
diff --git a/scene/3d/shape_cast_3d.cpp b/scene/3d/shape_cast_3d.cpp
new file mode 100644
index 0000000000..d324e09df5
--- /dev/null
+++ b/scene/3d/shape_cast_3d.cpp
@@ -0,0 +1,634 @@
+/*************************************************************************/
+/* shape_cast_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "shape_cast_3d.h"
+
+#include "collision_object_3d.h"
+#include "mesh_instance_3d.h"
+#include "scene/resources/concave_polygon_shape_3d.h"
+
+void ShapeCast3D::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ _update_debug_shape_vertices();
+ }
+ if (enabled && !Engine::get_singleton()->is_editor_hint()) {
+ set_physics_process_internal(true);
+ } else {
+ set_physics_process_internal(false);
+ }
+
+ if (get_tree()->is_debugging_collisions_hint()) {
+ _update_debug_shape();
+ }
+
+ if (Object::cast_to<CollisionObject3D>(get_parent())) {
+ if (exclude_parent_body) {
+ exclude.insert(Object::cast_to<CollisionObject3D>(get_parent())->get_rid());
+ } else {
+ exclude.erase(Object::cast_to<CollisionObject3D>(get_parent())->get_rid());
+ }
+ }
+ } break;
+
+ case NOTIFICATION_EXIT_TREE: {
+ if (enabled) {
+ set_physics_process_internal(false);
+ }
+
+ if (debug_shape) {
+ _clear_debug_shape();
+ }
+ } break;
+
+ case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
+ if (!enabled) {
+ break;
+ }
+
+ bool prev_collision_state = collided;
+ _update_shapecast_state();
+ if (get_tree()->is_debugging_collisions_hint()) {
+ if (prev_collision_state != collided) {
+ _update_debug_shape_material(true);
+ }
+ if (collided) {
+ _update_debug_shape();
+ }
+ if (prev_collision_state == collided && !collided) {
+ _update_debug_shape();
+ }
+ }
+ } break;
+ }
+}
+
+void ShapeCast3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("resource_changed", "resource"), &ShapeCast3D::resource_changed);
+
+ ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &ShapeCast3D::set_enabled);
+ ClassDB::bind_method(D_METHOD("is_enabled"), &ShapeCast3D::is_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_shape", "shape"), &ShapeCast3D::set_shape);
+ ClassDB::bind_method(D_METHOD("get_shape"), &ShapeCast3D::get_shape);
+
+ ClassDB::bind_method(D_METHOD("set_target_position", "local_point"), &ShapeCast3D::set_target_position);
+ ClassDB::bind_method(D_METHOD("get_target_position"), &ShapeCast3D::get_target_position);
+
+ ClassDB::bind_method(D_METHOD("set_margin", "margin"), &ShapeCast3D::set_margin);
+ ClassDB::bind_method(D_METHOD("get_margin"), &ShapeCast3D::get_margin);
+
+ ClassDB::bind_method(D_METHOD("set_max_results", "max_results"), &ShapeCast3D::set_max_results);
+ ClassDB::bind_method(D_METHOD("get_max_results"), &ShapeCast3D::get_max_results);
+
+ ClassDB::bind_method(D_METHOD("is_colliding"), &ShapeCast3D::is_colliding);
+ ClassDB::bind_method(D_METHOD("get_collision_count"), &ShapeCast3D::get_collision_count);
+
+ ClassDB::bind_method(D_METHOD("force_shapecast_update"), &ShapeCast3D::force_shapecast_update);
+
+ ClassDB::bind_method(D_METHOD("get_collider", "index"), &ShapeCast3D::get_collider);
+ ClassDB::bind_method(D_METHOD("get_collider_shape", "index"), &ShapeCast3D::get_collider_shape);
+ ClassDB::bind_method(D_METHOD("get_collision_point", "index"), &ShapeCast3D::get_collision_point);
+ ClassDB::bind_method(D_METHOD("get_collision_normal", "index"), &ShapeCast3D::get_collision_normal);
+
+ ClassDB::bind_method(D_METHOD("get_closest_collision_safe_fraction"), &ShapeCast3D::get_closest_collision_safe_fraction);
+ ClassDB::bind_method(D_METHOD("get_closest_collision_unsafe_fraction"), &ShapeCast3D::get_closest_collision_unsafe_fraction);
+
+ ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &ShapeCast3D::add_exception_rid);
+ ClassDB::bind_method(D_METHOD("add_exception", "node"), &ShapeCast3D::add_exception);
+
+ ClassDB::bind_method(D_METHOD("remove_exception_rid", "rid"), &ShapeCast3D::remove_exception_rid);
+ ClassDB::bind_method(D_METHOD("remove_exception", "node"), &ShapeCast3D::remove_exception);
+
+ ClassDB::bind_method(D_METHOD("clear_exceptions"), &ShapeCast3D::clear_exceptions);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &ShapeCast3D::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &ShapeCast3D::get_collision_mask);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &ShapeCast3D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &ShapeCast3D::get_collision_mask_value);
+
+ ClassDB::bind_method(D_METHOD("set_exclude_parent_body", "mask"), &ShapeCast3D::set_exclude_parent_body);
+ ClassDB::bind_method(D_METHOD("get_exclude_parent_body"), &ShapeCast3D::get_exclude_parent_body);
+
+ ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &ShapeCast3D::set_collide_with_areas);
+ ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &ShapeCast3D::is_collide_with_areas_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &ShapeCast3D::set_collide_with_bodies);
+ ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &ShapeCast3D::is_collide_with_bodies_enabled);
+
+ ClassDB::bind_method(D_METHOD("_get_collision_result"), &ShapeCast3D::_get_collision_result);
+
+ ClassDB::bind_method(D_METHOD("set_debug_shape_custom_color", "debug_shape_custom_color"), &ShapeCast3D::set_debug_shape_custom_color);
+ ClassDB::bind_method(D_METHOD("get_debug_shape_custom_color"), &ShapeCast3D::get_debug_shape_custom_color);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape3D"), "set_shape", "get_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_position", PROPERTY_HINT_NONE, "suffix:m"), "set_target_position", "get_target_position");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,100,0.01,suffix:m"), "set_margin", "get_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_results"), "set_max_results", "get_max_results");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "collision_result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "", "_get_collision_result");
+
+ ADD_GROUP("Collide With", "collide_with");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_areas", "is_collide_with_areas_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
+
+ ADD_GROUP("Debug Shape", "debug_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_shape_custom_color"), "set_debug_shape_custom_color", "get_debug_shape_custom_color");
+}
+
+TypedArray<String> ShapeCast3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node3D::get_configuration_warnings();
+
+ if (shape.is_null()) {
+ warnings.push_back(RTR("This node cannot interact with other objects unless a Shape3D is assigned."));
+ }
+ if (shape.is_valid() && Object::cast_to<ConcavePolygonShape3D>(*shape)) {
+ warnings.push_back(RTR("ShapeCast3D does not support ConcavePolygonShape3Ds. Collisions will not be reported."));
+ }
+ return warnings;
+}
+
+void ShapeCast3D::set_enabled(bool p_enabled) {
+ enabled = p_enabled;
+ update_gizmos();
+
+ if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint()) {
+ set_physics_process_internal(p_enabled);
+ }
+ if (!p_enabled) {
+ collided = false;
+ }
+
+ if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
+ if (p_enabled) {
+ _update_debug_shape();
+ } else {
+ _clear_debug_shape();
+ }
+ }
+}
+
+bool ShapeCast3D::is_enabled() const {
+ return enabled;
+}
+
+void ShapeCast3D::set_target_position(const Vector3 &p_point) {
+ target_position = p_point;
+ if (is_inside_tree()) {
+ _update_debug_shape();
+ }
+ update_gizmos();
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+ if (is_inside_tree()) {
+ _update_debug_shape_vertices();
+ }
+ } else if (debug_shape) {
+ _update_debug_shape();
+ }
+}
+
+Vector3 ShapeCast3D::get_target_position() const {
+ return target_position;
+}
+
+void ShapeCast3D::set_margin(real_t p_margin) {
+ margin = p_margin;
+}
+
+real_t ShapeCast3D::get_margin() const {
+ return margin;
+}
+
+void ShapeCast3D::set_max_results(int p_max_results) {
+ max_results = p_max_results;
+}
+
+int ShapeCast3D::get_max_results() const {
+ return max_results;
+}
+
+void ShapeCast3D::set_collision_mask(uint32_t p_mask) {
+ collision_mask = p_mask;
+}
+
+uint32_t ShapeCast3D::get_collision_mask() const {
+ return collision_mask;
+}
+
+void ShapeCast3D::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
+ uint32_t mask = get_collision_mask();
+ if (p_value) {
+ mask |= 1 << (p_layer_number - 1);
+ } else {
+ mask &= ~(1 << (p_layer_number - 1));
+ }
+ set_collision_mask(mask);
+}
+
+bool ShapeCast3D::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
+}
+
+int ShapeCast3D::get_collision_count() const {
+ return result.size();
+}
+
+bool ShapeCast3D::is_colliding() const {
+ return collided;
+}
+
+Object *ShapeCast3D::get_collider(int p_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_idx, result.size(), nullptr, "No collider found.");
+
+ if (result[p_idx].collider_id.is_null()) {
+ return nullptr;
+ }
+ return ObjectDB::get_instance(result[p_idx].collider_id);
+}
+
+int ShapeCast3D::get_collider_shape(int p_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_idx, result.size(), -1, "No collider shape found.");
+ return result[p_idx].shape;
+}
+
+Vector3 ShapeCast3D::get_collision_point(int p_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_idx, result.size(), Vector3(), "No collision point found.");
+ return result[p_idx].point;
+}
+
+Vector3 ShapeCast3D::get_collision_normal(int p_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_idx, result.size(), Vector3(), "No collision normal found.");
+ return result[p_idx].normal;
+}
+
+real_t ShapeCast3D::get_closest_collision_safe_fraction() const {
+ return collision_safe_fraction;
+}
+
+real_t ShapeCast3D::get_closest_collision_unsafe_fraction() const {
+ return collision_unsafe_fraction;
+}
+
+void ShapeCast3D::resource_changed(Ref<Resource> p_res) {
+ if (is_inside_tree()) {
+ _update_debug_shape();
+ }
+ update_gizmos();
+}
+
+void ShapeCast3D::set_shape(const Ref<Shape3D> &p_shape) {
+ if (p_shape == shape) {
+ return;
+ }
+ if (!shape.is_null()) {
+ shape->unregister_owner(this);
+ }
+ shape = p_shape;
+ if (!shape.is_null()) {
+ shape->register_owner(this);
+ }
+ if (p_shape.is_valid()) {
+ shape_rid = shape->get_rid();
+ }
+
+ if (is_inside_tree()) {
+ _update_debug_shape();
+ }
+
+ update_gizmos();
+ update_configuration_warnings();
+}
+
+Ref<Shape3D> ShapeCast3D::get_shape() const {
+ return shape;
+}
+
+void ShapeCast3D::set_exclude_parent_body(bool p_exclude_parent_body) {
+ if (exclude_parent_body == p_exclude_parent_body) {
+ return;
+ }
+ exclude_parent_body = p_exclude_parent_body;
+
+ if (!is_inside_tree()) {
+ return;
+ }
+ if (Object::cast_to<CollisionObject3D>(get_parent())) {
+ if (exclude_parent_body) {
+ exclude.insert(Object::cast_to<CollisionObject3D>(get_parent())->get_rid());
+ } else {
+ exclude.erase(Object::cast_to<CollisionObject3D>(get_parent())->get_rid());
+ }
+ }
+}
+
+bool ShapeCast3D::get_exclude_parent_body() const {
+ return exclude_parent_body;
+}
+
+void ShapeCast3D::_update_shapecast_state() {
+ result.clear();
+
+ ERR_FAIL_COND_MSG(shape.is_null(), "Null reference to shape. ShapeCast3D requires a Shape3D to sweep for collisions.");
+
+ Ref<World3D> w3d = get_world_3d();
+ ERR_FAIL_COND(w3d.is_null());
+
+ PhysicsDirectSpaceState3D *dss = PhysicsServer3D::get_singleton()->space_get_direct_state(w3d->get_space());
+ ERR_FAIL_COND(!dss);
+
+ Transform3D gt = get_global_transform();
+
+ PhysicsDirectSpaceState3D::ShapeParameters params;
+ params.shape_rid = shape_rid;
+ params.transform = gt;
+ params.motion = gt.basis.xform(target_position);
+ params.margin = margin;
+ params.exclude = exclude;
+ params.collision_mask = collision_mask;
+ params.collide_with_bodies = collide_with_bodies;
+ params.collide_with_areas = collide_with_areas;
+
+ collision_safe_fraction = 0.0;
+ collision_unsafe_fraction = 0.0;
+
+ if (target_position != Vector3()) {
+ dss->cast_motion(params, collision_safe_fraction, collision_unsafe_fraction);
+ if (collision_unsafe_fraction < 1.0) {
+ // Move shape transform to the point of impact,
+ // so we can collect contact info at that point.
+ gt.set_origin(gt.get_origin() + params.motion * (collision_unsafe_fraction + CMP_EPSILON));
+ params.transform = gt;
+ }
+ }
+ // Regardless of whether the shape is stuck or it's moved along
+ // the motion vector, we'll only consider static collisions from now on.
+ params.motion = Vector3();
+
+ bool intersected = true;
+ while (intersected && result.size() < max_results) {
+ PhysicsDirectSpaceState3D::ShapeRestInfo info;
+ intersected = dss->rest_info(params, &info);
+ if (intersected) {
+ result.push_back(info);
+ params.exclude.insert(info.rid);
+ }
+ }
+ collided = !result.is_empty();
+}
+
+void ShapeCast3D::force_shapecast_update() {
+ _update_shapecast_state();
+}
+
+void ShapeCast3D::add_exception_rid(const RID &p_rid) {
+ exclude.insert(p_rid);
+}
+
+void ShapeCast3D::add_exception(const Object *p_object) {
+ ERR_FAIL_NULL(p_object);
+ const CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_object);
+ if (!co) {
+ return;
+ }
+ add_exception_rid(co->get_rid());
+}
+
+void ShapeCast3D::remove_exception_rid(const RID &p_rid) {
+ exclude.erase(p_rid);
+}
+
+void ShapeCast3D::remove_exception(const Object *p_object) {
+ ERR_FAIL_NULL(p_object);
+ const CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_object);
+ if (!co) {
+ return;
+ }
+ remove_exception_rid(co->get_rid());
+}
+
+void ShapeCast3D::clear_exceptions() {
+ exclude.clear();
+}
+
+void ShapeCast3D::set_collide_with_areas(bool p_clip) {
+ collide_with_areas = p_clip;
+}
+
+bool ShapeCast3D::is_collide_with_areas_enabled() const {
+ return collide_with_areas;
+}
+
+void ShapeCast3D::set_collide_with_bodies(bool p_clip) {
+ collide_with_bodies = p_clip;
+}
+
+bool ShapeCast3D::is_collide_with_bodies_enabled() const {
+ return collide_with_bodies;
+}
+
+Array ShapeCast3D::_get_collision_result() const {
+ Array ret;
+
+ for (int i = 0; i < result.size(); ++i) {
+ const PhysicsDirectSpaceState3D::ShapeRestInfo &sri = result[i];
+
+ Dictionary col;
+ col["point"] = sri.point;
+ col["normal"] = sri.normal;
+ col["rid"] = sri.rid;
+ col["collider"] = ObjectDB::get_instance(sri.collider_id);
+ col["collider_id"] = sri.collider_id;
+ col["shape"] = sri.shape;
+ col["linear_velocity"] = sri.linear_velocity;
+
+ ret.push_back(col);
+ }
+ return ret;
+}
+
+void ShapeCast3D::_update_debug_shape_vertices() {
+ debug_shape_vertices.clear();
+ debug_line_vertices.clear();
+
+ if (!shape.is_null()) {
+ debug_shape_vertices.append_array(shape->get_debug_mesh_lines());
+ for (int i = 0; i < debug_shape_vertices.size(); i++) {
+ debug_shape_vertices.set(i, debug_shape_vertices[i] + Vector3(target_position * get_closest_collision_safe_fraction()));
+ }
+ }
+
+ if (target_position == Vector3()) {
+ return;
+ }
+
+ debug_line_vertices.push_back(Vector3());
+ debug_line_vertices.push_back(target_position);
+}
+
+const Vector<Vector3> &ShapeCast3D::get_debug_shape_vertices() const {
+ return debug_shape_vertices;
+}
+
+const Vector<Vector3> &ShapeCast3D::get_debug_line_vertices() const {
+ return debug_line_vertices;
+}
+
+void ShapeCast3D::set_debug_shape_custom_color(const Color &p_color) {
+ debug_shape_custom_color = p_color;
+ if (debug_material.is_valid()) {
+ _update_debug_shape_material();
+ }
+}
+
+Ref<StandardMaterial3D> ShapeCast3D::get_debug_material() {
+ _update_debug_shape_material();
+ return debug_material;
+}
+
+const Color &ShapeCast3D::get_debug_shape_custom_color() const {
+ return debug_shape_custom_color;
+}
+
+void ShapeCast3D::_create_debug_shape() {
+ _update_debug_shape_material();
+
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+
+ MeshInstance3D *mi = memnew(MeshInstance3D);
+ mi->set_mesh(mesh);
+
+ add_child(mi);
+ debug_shape = mi;
+}
+
+void ShapeCast3D::_update_debug_shape_material(bool p_check_collision) {
+ if (!debug_material.is_valid()) {
+ Ref<StandardMaterial3D> material = memnew(StandardMaterial3D);
+ debug_material = material;
+
+ material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ // Use double-sided rendering so that the RayCast can be seen if the camera is inside.
+ material->set_cull_mode(BaseMaterial3D::CULL_DISABLED);
+ material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA);
+ }
+
+ Color color = debug_shape_custom_color;
+ if (color == Color(0.0, 0.0, 0.0)) {
+ // Use the default debug shape color defined in the Project Settings.
+ color = get_tree()->get_debug_collisions_color();
+ }
+
+ if (p_check_collision && collided) {
+ if ((color.get_h() < 0.055 || color.get_h() > 0.945) && color.get_s() > 0.5 && color.get_v() > 0.5) {
+ // If base color is already quite reddish, highlight collision with green color
+ color = Color(0.0, 1.0, 0.0, color.a);
+ } else {
+ // Else, highlight collision with red color
+ color = Color(1.0, 0, 0, color.a);
+ }
+ }
+
+ Ref<StandardMaterial3D> material = static_cast<Ref<StandardMaterial3D>>(debug_material);
+ material->set_albedo(color);
+}
+
+void ShapeCast3D::_update_debug_shape() {
+ if (!enabled) {
+ return;
+ }
+
+ if (!debug_shape) {
+ _create_debug_shape();
+ }
+
+ _update_debug_shape_vertices();
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+ return;
+ }
+
+ MeshInstance3D *mi = static_cast<MeshInstance3D *>(debug_shape);
+ Ref<ArrayMesh> mesh = mi->get_mesh();
+ if (!mesh.is_valid()) {
+ return;
+ }
+
+ mesh->clear_surfaces();
+
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+
+ uint32_t flags = 0;
+ int surface_count = 0;
+
+ if (!debug_shape_vertices.is_empty()) {
+ a[Mesh::ARRAY_VERTEX] = debug_shape_vertices;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a, Array(), Dictionary(), flags);
+ mesh->surface_set_material(surface_count, debug_material);
+ ++surface_count;
+ }
+
+ if (!debug_line_vertices.is_empty()) {
+ a[Mesh::ARRAY_VERTEX] = debug_line_vertices;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a, Array(), Dictionary(), flags);
+ mesh->surface_set_material(surface_count, debug_material);
+ ++surface_count;
+ }
+}
+
+void ShapeCast3D::_clear_debug_shape() {
+ if (!debug_shape) {
+ return;
+ }
+
+ MeshInstance3D *mi = static_cast<MeshInstance3D *>(debug_shape);
+ if (mi->is_inside_tree()) {
+ mi->queue_delete();
+ } else {
+ memdelete(mi);
+ }
+
+ debug_shape = nullptr;
+}
+
+ShapeCast3D::~ShapeCast3D() {
+ if (!shape.is_null()) {
+ shape->unregister_owner(this);
+ }
+}
diff --git a/scene/3d/shape_cast_3d.h b/scene/3d/shape_cast_3d.h
new file mode 100644
index 0000000000..5bda15e4b0
--- /dev/null
+++ b/scene/3d/shape_cast_3d.h
@@ -0,0 +1,142 @@
+/*************************************************************************/
+/* shape_cast_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SHAPE_CAST_3D_H
+#define SHAPE_CAST_3D_H
+
+#include "scene/3d/node_3d.h"
+#include "scene/resources/shape_3d.h"
+
+class ShapeCast3D : public Node3D {
+ GDCLASS(ShapeCast3D, Node3D);
+
+ bool enabled = true;
+ void resource_changed(Ref<Resource> p_res);
+
+ Ref<Shape3D> shape;
+ RID shape_rid;
+ Vector3 target_position = Vector3(0, -1, 0);
+
+ HashSet<RID> exclude;
+ real_t margin = 0.0;
+ uint32_t collision_mask = 1;
+ bool exclude_parent_body = true;
+ bool collide_with_areas = false;
+ bool collide_with_bodies = true;
+
+ Node *debug_shape = nullptr;
+ Ref<Material> debug_material;
+ Color debug_shape_custom_color = Color(0.0, 0.0, 0.0);
+ Vector<Vector3> debug_shape_vertices;
+ Vector<Vector3> debug_line_vertices;
+
+ void _create_debug_shape();
+ void _update_debug_shape();
+ void _update_debug_shape_material(bool p_check_collision = false);
+ void _update_debug_shape_vertices();
+ void _clear_debug_shape();
+
+ // Result
+ int max_results = 32;
+ Vector<PhysicsDirectSpaceState3D::ShapeRestInfo> result;
+ bool collided = false;
+ real_t collision_safe_fraction = 1.0;
+ real_t collision_unsafe_fraction = 1.0;
+
+ Array _get_collision_result() const;
+
+ ~ShapeCast3D();
+
+protected:
+ void _notification(int p_what);
+ void _update_shapecast_state();
+ static void _bind_methods();
+
+public:
+ void set_collide_with_areas(bool p_clip);
+ bool is_collide_with_areas_enabled() const;
+
+ void set_collide_with_bodies(bool p_clip);
+ bool is_collide_with_bodies_enabled() const;
+
+ void set_enabled(bool p_enabled);
+ bool is_enabled() const;
+
+ void set_shape(const Ref<Shape3D> &p_shape);
+ Ref<Shape3D> get_shape() const;
+
+ void set_target_position(const Vector3 &p_point);
+ Vector3 get_target_position() const;
+
+ void set_margin(real_t p_margin);
+ real_t get_margin() const;
+
+ void set_max_results(int p_max_results);
+ int get_max_results() const;
+
+ void set_collision_mask(uint32_t p_mask);
+ uint32_t get_collision_mask() const;
+
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
+
+ void set_exclude_parent_body(bool p_exclude_parent_body);
+ bool get_exclude_parent_body() const;
+
+ const Color &get_debug_shape_custom_color() const;
+ void set_debug_shape_custom_color(const Color &p_color);
+
+ const Vector<Vector3> &get_debug_shape_vertices() const;
+ const Vector<Vector3> &get_debug_line_vertices() const;
+
+ Ref<StandardMaterial3D> get_debug_material();
+
+ int get_collision_count() const;
+ Object *get_collider(int p_idx) const;
+ int get_collider_shape(int p_idx) const;
+ Vector3 get_collision_point(int p_idx) const;
+ Vector3 get_collision_normal(int p_idx) const;
+
+ real_t get_closest_collision_safe_fraction() const;
+ real_t get_closest_collision_unsafe_fraction() const;
+
+ void force_shapecast_update();
+ bool is_colliding() const;
+
+ void add_exception_rid(const RID &p_rid);
+ void add_exception(const Object *p_object);
+ void remove_exception_rid(const RID &p_rid);
+ void remove_exception(const Object *p_object);
+ void clear_exceptions();
+
+ virtual TypedArray<String> get_configuration_warnings() const override;
+};
+
+#endif // SHAPE_CAST_3D_H
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index ba2029788e..4c38fccc8b 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();
}
}
}
@@ -495,6 +493,19 @@ int Skeleton3D::get_bone_axis_forward_enum(int p_bone) {
return bones[p_bone].rest_bone_forward_axis;
}
+void Skeleton3D::set_motion_scale(float p_motion_scale) {
+ if (p_motion_scale <= 0) {
+ motion_scale = 1;
+ ERR_FAIL_MSG("Motion scale must be larger than 0.");
+ }
+ motion_scale = p_motion_scale;
+}
+
+float Skeleton3D::get_motion_scale() const {
+ ERR_FAIL_COND_V(motion_scale <= 0, 1);
+ return motion_scale;
+}
+
// Skeleton creation api
void Skeleton3D::add_bone(const String &p_name) {
@@ -641,6 +652,7 @@ void Skeleton3D::remove_bone_child(int p_bone, int p_child) {
}
Vector<int> Skeleton3D::get_parentless_bones() {
+ _update_process_order();
return parentless_bones;
}
@@ -767,8 +779,6 @@ void Skeleton3D::_make_dirty() {
}
void Skeleton3D::localize_rests() {
- _update_process_order();
-
Vector<int> bones_to_process = get_parentless_bones();
while (bones_to_process.size() > 0) {
int current_bone_idx = bones_to_process[0];
@@ -960,7 +970,6 @@ Ref<Skin> Skeleton3D::create_skin_from_rest_transforms() {
skin.instantiate();
skin->set_bind_count(bones.size());
- _update_process_order(); // Just in case.
// Pose changed, rebuild cache of inverses.
const Bone *bonesptr = bones.ptr();
@@ -1259,6 +1268,9 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("force_update_all_bone_transforms"), &Skeleton3D::force_update_all_bone_transforms);
ClassDB::bind_method(D_METHOD("force_update_bone_child_transform", "bone_idx"), &Skeleton3D::force_update_bone_children_transforms);
+ ClassDB::bind_method(D_METHOD("set_motion_scale", "motion_scale"), &Skeleton3D::set_motion_scale);
+ ClassDB::bind_method(D_METHOD("get_motion_scale"), &Skeleton3D::get_motion_scale);
+
// Helper functions
ClassDB::bind_method(D_METHOD("global_pose_to_world_transform", "global_pose"), &Skeleton3D::global_pose_to_world_transform);
ClassDB::bind_method(D_METHOD("world_transform_to_global_pose", "world_transform"), &Skeleton3D::world_transform_to_global_pose);
@@ -1282,15 +1294,13 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_modification_stack"), &Skeleton3D::get_modification_stack);
ClassDB::bind_method(D_METHOD("execute_modifications", "delta", "execution_mode"), &Skeleton3D::execute_modifications);
-#ifndef _3D_DISABLED
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "motion_scale", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater"), "set_motion_scale", "get_motion_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_rest_only"), "set_show_rest_only", "is_show_rest_only");
+#ifndef _3D_DISABLED
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "animate_physical_bones"), "set_animate_physical_bones", "get_animate_physical_bones");
#endif // _3D_DISABLED
-#ifdef TOOLS_ENABLED
ADD_SIGNAL(MethodInfo("pose_updated"));
-#endif // TOOLS_ENABLED
-
ADD_SIGNAL(MethodInfo("bone_pose_changed", PropertyInfo(Variant::INT, "bone_idx")));
ADD_SIGNAL(MethodInfo("bone_enabled_changed", PropertyInfo(Variant::INT, "bone_idx")));
ADD_SIGNAL(MethodInfo("show_rest_only_changed"));
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index cb4c82d232..8b69410a39 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -146,6 +146,7 @@ private:
bool rest_dirty = false;
bool show_rest_only = false;
+ float motion_scale = 1.0;
uint64_t version = 1;
@@ -211,6 +212,9 @@ public:
bool is_show_rest_only() const;
void clear_bones();
+ void set_motion_scale(float p_motion_scale);
+ float get_motion_scale() const;
+
// posing api
void set_bone_pose_position(int p_bone, const Vector3 &p_position);
@@ -288,4 +292,4 @@ public:
~Skeleton3D();
};
-#endif
+#endif // SKELETON_3D_H
diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h
index 0f656187de..6ae86a2bf6 100644
--- a/scene/3d/skeleton_ik_3d.h
+++ b/scene/3d/skeleton_ik_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SKELETON_IK_H
-#define SKELETON_IK_H
+#ifndef SKELETON_IK_3D_H
+#define SKELETON_IK_3D_H
#ifndef _3D_DISABLED
@@ -192,4 +192,4 @@ private:
#endif // _3D_DISABLED
-#endif // SKELETON_IK_H
+#endif // SKELETON_IK_3D_H
diff --git a/scene/3d/soft_dynamic_body_3d.cpp b/scene/3d/soft_dynamic_body_3d.cpp
index d68e7fd527..15f050defb 100644
--- a/scene/3d/soft_dynamic_body_3d.cpp
+++ b/scene/3d/soft_dynamic_body_3d.cpp
@@ -83,7 +83,16 @@ void SoftDynamicBodyRenderingServerHandler::set_vertex(int p_vertex_id, const vo
}
void SoftDynamicBodyRenderingServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
- memcpy(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3);
+ // Store normal vector in A2B10G10R10 format.
+ Vector3 n;
+ memcpy(&n, p_vector3, sizeof(Vector3));
+ n *= Vector3(0.5, 0.5, 0.5);
+ n += Vector3(0.5, 0.5, 0.5);
+ uint32_t value = 0;
+ value |= CLAMP(int(n.x * 1023.0), 0, 1023);
+ value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
+ value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
+ memcpy(&write_buffer[p_vertex_id * stride + offset_normal], &value, sizeof(uint32_t));
}
void SoftDynamicBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
diff --git a/scene/3d/soft_dynamic_body_3d.h b/scene/3d/soft_dynamic_body_3d.h
index e11e5c73df..04f3365f72 100644
--- a/scene/3d/soft_dynamic_body_3d.h
+++ b/scene/3d/soft_dynamic_body_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SOFT_DYNAMIC_BODY_H
-#define SOFT_DYNAMIC_BODY_H
+#ifndef SOFT_DYNAMIC_BODY_3D_H
+#define SOFT_DYNAMIC_BODY_3D_H
#include "scene/3d/mesh_instance_3d.h"
#include "servers/physics_server_3d.h"
@@ -199,4 +199,4 @@ private:
VARIANT_ENUM_CAST(SoftDynamicBody3D::DisableMode);
-#endif // SOFT_DYNAMIC_BODY_H
+#endif // SOFT_DYNAMIC_BODY_3D_H
diff --git a/scene/3d/spring_arm_3d.h b/scene/3d/spring_arm_3d.h
index 0b5307acf7..1a6f03abe4 100644
--- a/scene/3d/spring_arm_3d.h
+++ b/scene/3d/spring_arm_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SPRING_ARM_H
-#define SPRING_ARM_H
+#ifndef SPRING_ARM_3D_H
+#define SPRING_ARM_3D_H
#include "scene/3d/node_3d.h"
@@ -68,4 +68,4 @@ private:
void process_spring();
};
-#endif
+#endif // SPRING_ARM_3D_H
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 55b55d924c..ef2b9e1ce5 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -377,7 +377,7 @@ SpriteBase3D::SpriteBase3D() {
RS::get_singleton()->material_set_param(material, "uv1_scale", Vector3(1, 1, 1));
RS::get_singleton()->material_set_param(material, "uv2_offset", Vector3(0, 0, 0));
RS::get_singleton()->material_set_param(material, "uv2_scale", Vector3(1, 1, 1));
- RS::get_singleton()->material_set_param(material, "alpha_scissor_threshold", 0.98);
+ RS::get_singleton()->material_set_param(material, "alpha_scissor_threshold", 0.5);
mesh = RenderingServer::get_singleton()->mesh_create();
@@ -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/vehicle_body_3d.h b/scene/3d/vehicle_body_3d.h
index 0ef8bd7482..2f3a37af2a 100644
--- a/scene/3d/vehicle_body_3d.h
+++ b/scene/3d/vehicle_body_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef VEHICLE_BODY_H
-#define VEHICLE_BODY_H
+#ifndef VEHICLE_BODY_3D_H
+#define VEHICLE_BODY_3D_H
#include "scene/3d/physics_body_3d.h"
@@ -210,4 +210,4 @@ public:
VehicleBody3D();
};
-#endif // VEHICLE_BODY_H
+#endif // VEHICLE_BODY_3D_H
diff --git a/scene/3d/velocity_tracker_3d.h b/scene/3d/velocity_tracker_3d.h
index 7fdcacc9c1..6b27cdffc2 100644
--- a/scene/3d/velocity_tracker_3d.h
+++ b/scene/3d/velocity_tracker_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SPATIAL_VELOCITY_TRACKER_H
-#define SPATIAL_VELOCITY_TRACKER_H
+#ifndef VELOCITY_TRACKER_3D_H
+#define VELOCITY_TRACKER_3D_H
#include "scene/3d/node_3d.h"
@@ -58,4 +58,4 @@ public:
VelocityTracker3D();
};
-#endif // SPATIAL_VELOCITY_TRACKER_H
+#endif // VELOCITY_TRACKER_3D_H
diff --git a/scene/3d/visible_on_screen_notifier_3d.h b/scene/3d/visible_on_screen_notifier_3d.h
index fe17f1e444..60461569f4 100644
--- a/scene/3d/visible_on_screen_notifier_3d.h
+++ b/scene/3d/visible_on_screen_notifier_3d.h
@@ -96,4 +96,4 @@ public:
VARIANT_ENUM_CAST(VisibleOnScreenEnabler3D::EnableMode);
-#endif // VISIBILITY_NOTIFIER_H
+#endif // VISIBLE_ON_SCREEN_NOTIFIER_3D_H
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index 6df50bc491..5af06cff29 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -227,8 +227,8 @@ const StringName *GeometryInstance3D::_instance_uniform_get_remap(const StringNa
StringName *r = instance_uniform_property_remap.getptr(p_name);
if (!r) {
String s = p_name;
- if (s.begins_with("shader_params/")) {
- StringName name = s.replace("shader_params/", "");
+ if (s.begins_with("shader_uniforms/")) {
+ StringName name = s.replace("shader_uniforms/", "");
instance_uniform_property_remap[p_name] = name;
return instance_uniform_property_remap.getptr(p_name);
}
@@ -242,7 +242,7 @@ const StringName *GeometryInstance3D::_instance_uniform_get_remap(const StringNa
bool GeometryInstance3D::_set(const StringName &p_name, const Variant &p_value) {
const StringName *r = _instance_uniform_get_remap(p_name);
if (r) {
- set_shader_instance_uniform(*r, p_value);
+ set_instance_shader_uniform(*r, p_value);
return true;
}
#ifndef DISABLE_DEPRECATED
@@ -262,7 +262,7 @@ bool GeometryInstance3D::_set(const StringName &p_name, const Variant &p_value)
bool GeometryInstance3D::_get(const StringName &p_name, Variant &r_ret) const {
const StringName *r = _instance_uniform_get_remap(p_name);
if (r) {
- r_ret = get_shader_instance_uniform(*r);
+ r_ret = get_instance_shader_uniform(*r);
return true;
}
@@ -271,10 +271,10 @@ bool GeometryInstance3D::_get(const StringName &p_name, Variant &r_ret) const {
void GeometryInstance3D::_get_property_list(List<PropertyInfo> *p_list) const {
List<PropertyInfo> pinfo;
- RS::get_singleton()->instance_geometry_get_shader_parameter_list(get_instance(), &pinfo);
+ RS::get_singleton()->instance_geometry_get_shader_uniform_list(get_instance(), &pinfo);
for (PropertyInfo &pi : pinfo) {
bool has_def_value = false;
- Variant def_value = RS::get_singleton()->instance_geometry_get_shader_parameter_default_value(get_instance(), pi.name);
+ Variant def_value = RS::get_singleton()->instance_geometry_get_shader_uniform_default_value(get_instance(), pi.name);
if (def_value.get_type() != Variant::NIL) {
has_def_value = true;
}
@@ -284,7 +284,7 @@ void GeometryInstance3D::_get_property_list(List<PropertyInfo> *p_list) const {
pi.usage = PROPERTY_USAGE_EDITOR | (has_def_value ? PROPERTY_USAGE_CHECKABLE : PROPERTY_USAGE_NONE); //do not save if not changed
}
- pi.name = "shader_params/" + pi.name;
+ pi.name = "shader_uniforms/" + pi.name;
p_list->push_back(pi);
}
}
@@ -319,24 +319,24 @@ float GeometryInstance3D::get_lod_bias() const {
return lod_bias;
}
-void GeometryInstance3D::set_shader_instance_uniform(const StringName &p_uniform, const Variant &p_value) {
+void GeometryInstance3D::set_instance_shader_uniform(const StringName &p_uniform, const Variant &p_value) {
if (p_value.get_type() == Variant::NIL) {
- Variant def_value = RS::get_singleton()->instance_geometry_get_shader_parameter_default_value(get_instance(), p_uniform);
- RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_uniform, def_value);
+ Variant def_value = RS::get_singleton()->instance_geometry_get_shader_uniform_default_value(get_instance(), p_uniform);
+ RS::get_singleton()->instance_geometry_set_shader_uniform(get_instance(), p_uniform, def_value);
instance_uniforms.erase(p_value);
} else {
instance_uniforms[p_uniform] = p_value;
if (p_value.get_type() == Variant::OBJECT) {
RID tex_id = p_value;
- RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_uniform, tex_id);
+ RS::get_singleton()->instance_geometry_set_shader_uniform(get_instance(), p_uniform, tex_id);
} else {
- RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_uniform, p_value);
+ RS::get_singleton()->instance_geometry_set_shader_uniform(get_instance(), p_uniform, p_value);
}
}
}
-Variant GeometryInstance3D::get_shader_instance_uniform(const StringName &p_uniform) const {
- return RS::get_singleton()->instance_geometry_get_shader_parameter(get_instance(), p_uniform);
+Variant GeometryInstance3D::get_instance_shader_uniform(const StringName &p_uniform) const {
+ return RS::get_singleton()->instance_geometry_get_shader_uniform(get_instance(), p_uniform);
}
void GeometryInstance3D::set_custom_aabb(AABB aabb) {
@@ -434,8 +434,8 @@ void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_visibility_range_fade_mode", "mode"), &GeometryInstance3D::set_visibility_range_fade_mode);
ClassDB::bind_method(D_METHOD("get_visibility_range_fade_mode"), &GeometryInstance3D::get_visibility_range_fade_mode);
- ClassDB::bind_method(D_METHOD("set_shader_instance_uniform", "uniform", "value"), &GeometryInstance3D::set_shader_instance_uniform);
- ClassDB::bind_method(D_METHOD("get_shader_instance_uniform", "uniform"), &GeometryInstance3D::get_shader_instance_uniform);
+ ClassDB::bind_method(D_METHOD("set_instance_shader_uniform", "uniform", "value"), &GeometryInstance3D::set_instance_shader_uniform);
+ ClassDB::bind_method(D_METHOD("get_instance_shader_uniform", "uniform"), &GeometryInstance3D::get_instance_shader_uniform);
ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance3D::set_extra_cull_margin);
ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance3D::get_extra_cull_margin);
@@ -461,17 +461,17 @@ void GeometryInstance3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01,suffix:m"), "set_extra_cull_margin", "get_extra_cull_margin");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_bias", PROPERTY_HINT_RANGE, "0.001,128,0.001"), "set_lod_bias", "get_lod_bias");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_occlusion_culling"), "set_ignore_occlusion_culling", "is_ignoring_occlusion_culling");
+
ADD_GROUP("Global Illumination", "gi_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_mode", PROPERTY_HINT_ENUM, "Disabled,Static (VoxelGI/SDFGI/LightmapGI),Dynamic (VoxelGI only)"), "set_gi_mode", "get_gi_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_lightmap_scale", PROPERTY_HINT_ENUM, String::utf8("1×,2×,4×,8×")), "set_lightmap_scale", "get_lightmap_scale");
ADD_GROUP("Visibility Range", "visibility_range_");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_begin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,suffix:m"), "set_visibility_range_begin", "get_visibility_range_begin");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_begin_margin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,suffix:m"), "set_visibility_range_begin_margin", "get_visibility_range_begin_margin");
- 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::FLOAT, "visibility_range_begin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater,suffix:m"), "set_visibility_range_begin", "get_visibility_range_begin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_begin_margin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater,suffix:m"), "set_visibility_range_begin_margin", "get_visibility_range_begin_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_end", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater,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,or_greater,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 +494,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..f7cdcbf411 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef VISUAL_INSTANCE_H
-#define VISUAL_INSTANCE_H
+#ifndef VISUAL_INSTANCE_3D_H
+#define VISUAL_INSTANCE_3D_H
#include "scene/3d/node_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;
@@ -178,8 +178,8 @@ public:
void set_lightmap_scale(LightmapScale p_scale);
LightmapScale get_lightmap_scale() const;
- void set_shader_instance_uniform(const StringName &p_uniform, const Variant &p_value);
- Variant get_shader_instance_uniform(const StringName &p_uniform) const;
+ void set_instance_shader_uniform(const StringName &p_uniform, const Variant &p_value);
+ Variant get_instance_shader_uniform(const StringName &p_uniform) const;
void set_custom_aabb(AABB aabb);
@@ -196,4 +196,4 @@ VARIANT_ENUM_CAST(GeometryInstance3D::LightmapScale);
VARIANT_ENUM_CAST(GeometryInstance3D::GIMode);
VARIANT_ENUM_CAST(GeometryInstance3D::VisibilityRangeFadeMode);
-#endif
+#endif // VISUAL_INSTANCE_3D_H
diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp
index d81b59b3fc..ae231026a7 100644
--- a/scene/3d/voxel_gi.cpp
+++ b/scene/3d/voxel_gi.cpp
@@ -272,7 +272,8 @@ VoxelGI::Subdiv VoxelGI::get_subdiv() const {
}
void VoxelGI::set_extents(const Vector3 &p_extents) {
- extents = p_extents;
+ // Prevent very small extents as these break baking if other extents are set very high.
+ extents = Vector3(MAX(1.0, p_extents.x), MAX(1.0, p_extents.y), MAX(1.0, p_extents.z));
update_gizmos();
}
diff --git a/scene/3d/voxel_gi.h b/scene/3d/voxel_gi.h
index e1a38dd7a0..6d173dea87 100644
--- a/scene/3d/voxel_gi.h
+++ b/scene/3d/voxel_gi.h
@@ -49,9 +49,9 @@ class VoxelGIData : public Resource {
float energy = 1.0;
float bias = 1.5;
float normal_bias = 0.0;
- float propagation = 0.7;
+ float propagation = 0.5;
bool interior = false;
- bool use_two_bounces = false;
+ bool use_two_bounces = true;
protected:
static void _bind_methods();
diff --git a/scene/3d/voxelizer.h b/scene/3d/voxelizer.h
index 0179795ddc..68bce768b7 100644
--- a/scene/3d/voxelizer.h
+++ b/scene/3d/voxelizer.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef VOXEL_LIGHT_BAKER_H
-#define VOXEL_LIGHT_BAKER_H
+#ifndef VOXELIZER_H
+#define VOXELIZER_H
#include "scene/resources/multimesh.h"
@@ -129,4 +129,4 @@ public:
Voxelizer();
};
-#endif // VOXEL_LIGHT_BAKER_H
+#endif // VOXELIZER_H
diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h
index 8dbb57364c..9955aa72a8 100644
--- a/scene/3d/world_environment.h
+++ b/scene/3d/world_environment.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SCENARIO_FX_H
-#define SCENARIO_FX_H
+#ifndef WORLD_ENVIRONMENT_H
+#define WORLD_ENVIRONMENT_H
#include "scene/main/node.h"
#include "scene/resources/camera_effects.h"
@@ -60,4 +60,4 @@ public:
WorldEnvironment();
};
-#endif
+#endif // WORLD_ENVIRONMENT_H
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index 1dad6078b4..40a43043c6 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -120,7 +120,7 @@ Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const {
Vector3 ray;
// Just use the first view, if multiple views are supported this function has no good result
- CameraMatrix cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
+ Projection cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
Vector2 screen_he = cm.get_viewport_half_extents();
ray = Vector3(((cpos.x / viewport_size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (cpos.y / viewport_size.height)) * 2.0 - 1.0) * screen_he.y, -get_near()).normalized();
@@ -143,7 +143,7 @@ Point2 XRCamera3D::unproject_position(const Vector3 &p_pos) const {
Size2 viewport_size = get_viewport()->get_visible_rect().size;
// Just use the first view, if multiple views are supported this function has no good result
- CameraMatrix cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
+ Projection cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
Plane p(get_camera_transform().xform_inv(p_pos), 1.0);
@@ -173,7 +173,7 @@ Vector3 XRCamera3D::project_position(const Point2 &p_point, real_t p_z_depth) co
Size2 viewport_size = get_viewport()->get_visible_rect().size;
// Just use the first view, if multiple views are supported this function has no good result
- CameraMatrix cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
+ Projection cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
Vector2 vp_he = cm.get_viewport_half_extents();
@@ -202,7 +202,7 @@ Vector<Plane> XRCamera3D::get_frustum() const {
Size2 viewport_size = get_viewport()->get_visible_rect().size;
// TODO Just use the first view for now, this is mostly for debugging so we may look into using our combined projection here.
- CameraMatrix cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
+ Projection cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
return cm.get_projection_planes(get_camera_transform());
};