summaryrefslogtreecommitdiff
path: root/scene/3d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d')
-rw-r--r--scene/3d/area.cpp2
-rw-r--r--scene/3d/arvr_nodes.cpp20
-rw-r--r--scene/3d/audio_stream_player_3d.cpp52
-rw-r--r--scene/3d/audio_stream_player_3d.h5
-rw-r--r--scene/3d/camera.cpp13
-rw-r--r--scene/3d/camera.h6
-rw-r--r--scene/3d/collision_polygon.cpp5
-rw-r--r--scene/3d/collision_polygon.h2
-rw-r--r--scene/3d/interpolated_camera.cpp8
-rw-r--r--scene/3d/light.cpp12
-rw-r--r--scene/3d/mesh_instance.cpp2
-rw-r--r--scene/3d/navigation.cpp1
-rw-r--r--scene/3d/particles.cpp61
-rw-r--r--scene/3d/path.cpp223
-rw-r--r--scene/3d/path.h43
-rw-r--r--scene/3d/physics_body.cpp1119
-rw-r--r--scene/3d/physics_body.h266
-rw-r--r--scene/3d/physics_joint.cpp29
-rw-r--r--scene/3d/physics_joint.h3
-rw-r--r--scene/3d/ray_cast.cpp10
-rw-r--r--scene/3d/reflection_probe.cpp6
-rw-r--r--scene/3d/remote_transform.cpp2
-rw-r--r--scene/3d/scenario_fx.cpp11
-rw-r--r--scene/3d/skeleton.cpp185
-rw-r--r--scene/3d/skeleton.h46
-rw-r--r--scene/3d/spatial.cpp31
-rw-r--r--scene/3d/spatial.h7
-rw-r--r--scene/3d/sprite_3d.cpp86
-rw-r--r--scene/3d/sprite_3d.h4
-rw-r--r--scene/3d/vehicle_body.cpp22
-rw-r--r--scene/3d/vehicle_body.h2
-rw-r--r--scene/3d/voxel_light_baker.cpp9
32 files changed, 2166 insertions, 127 deletions
diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp
index 21f471039f..6ea980ec97 100644
--- a/scene/3d/area.cpp
+++ b/scene/3d/area.cpp
@@ -711,7 +711,7 @@ void Area::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001"), "set_gravity_distance_scale", "get_gravity_distance_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_vec"), "set_gravity_vector", "get_gravity_vector");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_gravity", "get_gravity");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_damp", PROPERTY_HINT_RANGE, "0,1024,0.001"), "set_linear_damp", "get_linear_damp");
diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp
index 001c58ea76..4bff26a200 100644
--- a/scene/3d/arvr_nodes.cpp
+++ b/scene/3d/arvr_nodes.cpp
@@ -73,7 +73,10 @@ Vector3 ARVRCamera::project_local_ray_normal(const Point2 &p_pos) const {
ERR_FAIL_NULL_V(arvr_server, Vector3());
Ref<ARVRInterface> arvr_interface = arvr_server->get_primary_interface();
- ERR_FAIL_COND_V(arvr_interface.is_null(), Vector3());
+ if (arvr_interface.is_null()) {
+ // we might be in the editor or have VR turned off, just call superclass
+ return Camera::project_local_ray_normal(p_pos);
+ }
if (!is_inside_tree()) {
ERR_EXPLAIN("Camera is not inside scene.");
@@ -98,7 +101,10 @@ Point2 ARVRCamera::unproject_position(const Vector3 &p_pos) const {
ERR_FAIL_NULL_V(arvr_server, Vector2());
Ref<ARVRInterface> arvr_interface = arvr_server->get_primary_interface();
- ERR_FAIL_COND_V(arvr_interface.is_null(), Vector2());
+ if (arvr_interface.is_null()) {
+ // we might be in the editor or have VR turned off, just call superclass
+ return Camera::unproject_position(p_pos);
+ }
if (!is_inside_tree()) {
ERR_EXPLAIN("Camera is not inside scene.");
@@ -127,7 +133,10 @@ Vector3 ARVRCamera::project_position(const Point2 &p_point) const {
ERR_FAIL_NULL_V(arvr_server, Vector3());
Ref<ARVRInterface> arvr_interface = arvr_server->get_primary_interface();
- ERR_FAIL_COND_V(arvr_interface.is_null(), Vector3());
+ if (arvr_interface.is_null()) {
+ // we might be in the editor or have VR turned off, just call superclass
+ return Camera::project_position(p_point);
+ }
if (!is_inside_tree()) {
ERR_EXPLAIN("Camera is not inside scene.");
@@ -157,7 +166,10 @@ Vector<Plane> ARVRCamera::get_frustum() const {
ERR_FAIL_NULL_V(arvr_server, Vector<Plane>());
Ref<ARVRInterface> arvr_interface = arvr_server->get_primary_interface();
- ERR_FAIL_COND_V(arvr_interface.is_null(), Vector<Plane>());
+ if (arvr_interface.is_null()) {
+ // we might be in the editor or have VR turned off, just call superclass
+ return Camera::get_frustum();
+ }
ERR_FAIL_COND_V(!is_inside_world(), Vector<Plane>());
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index c2a50ec7bb..f1da375451 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -35,11 +35,8 @@
#include "scene/main/viewport.h"
void AudioStreamPlayer3D::_mix_audio() {
- if (!stream_playback.is_valid()) {
- return;
- }
-
- if (!active) {
+ if (!stream_playback.is_valid() || !active ||
+ (stream_paused && stream_paused_fade <= 0.f)) {
return;
}
@@ -54,8 +51,9 @@ void AudioStreamPlayer3D::_mix_audio() {
AudioFrame *buffer = mix_buffer.ptrw();
int buffer_size = mix_buffer.size();
- //mix
- if (output_count > 0 || out_of_range_mode == OUT_OF_RANGE_MIX) {
+ // Mix if we're not paused or we're fading out
+ if ((output_count > 0 || out_of_range_mode == OUT_OF_RANGE_MIX) &&
+ (!stream_paused || stream_paused_fade > 0.f)) {
float output_pitch_scale = 0.0;
if (output_count) {
@@ -108,6 +106,13 @@ void AudioStreamPlayer3D::_mix_audio() {
AudioFrame vol_inc = (current.vol[k] - prev_outputs[i].vol[k]) / float(buffer_size);
AudioFrame vol = current.vol[k];
+ if (stream_paused) {
+ vol = vol * stream_paused_fade;
+ if (stream_paused_fade > 0.f) {
+ stream_paused_fade -= 0.1f;
+ }
+ }
+
AudioFrame *target = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, k);
current.filter.set_mode(AudioFilterSW::HIGHSHELF);
@@ -237,6 +242,18 @@ void AudioStreamPlayer3D::_notification(int p_what) {
AudioServer::get_singleton()->remove_callback(_mix_audios, this);
}
+
+ if (p_what == NOTIFICATION_PAUSED) {
+ if (!can_process()) {
+ // Node can't process so we start fading out to silence
+ set_stream_paused(true);
+ }
+ }
+
+ if (p_what == NOTIFICATION_UNPAUSED) {
+ set_stream_paused(false);
+ }
+
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
@@ -825,6 +842,19 @@ AudioStreamPlayer3D::DopplerTracking AudioStreamPlayer3D::get_doppler_tracking()
return doppler_tracking;
}
+void AudioStreamPlayer3D::set_stream_paused(bool p_pause) {
+
+ if (p_pause != stream_paused) {
+ stream_paused = p_pause;
+ stream_paused_fade = stream_paused ? 1.f : 0.f;
+ }
+}
+
+bool AudioStreamPlayer3D::get_stream_paused() const {
+
+ return stream_paused;
+}
+
void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer3D::set_stream);
@@ -888,6 +918,9 @@ void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &AudioStreamPlayer3D::set_doppler_tracking);
ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &AudioStreamPlayer3D::get_doppler_tracking);
+ ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer3D::set_stream_paused);
+ ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer3D::get_stream_paused);
+
ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer3D::_bus_layout_changed);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
@@ -898,7 +931,8 @@ void AudioStreamPlayer3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,32,0.01"), "set_pitch_scale", "get_pitch_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_RANGE, "0,65536,1"), "set_max_distance", "get_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,4096,1,or_greater"), "set_max_distance", "get_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "out_of_range_mode", PROPERTY_HINT_ENUM, "Mix,Pause"), "set_out_of_range_mode", "get_out_of_range_mode");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "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");
@@ -949,6 +983,8 @@ AudioStreamPlayer3D::AudioStreamPlayer3D() {
attenuation_filter_db = -24;
out_of_range_mode = OUT_OF_RANGE_MIX;
doppler_tracking = DOPPLER_TRACKING_DISABLED;
+ stream_paused = false;
+ stream_paused_fade = 0.f;
velocity_tracker.instance();
AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed");
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index 1fcb83cf21..cab1ff121a 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -107,7 +107,9 @@ private:
float unit_size;
float max_db;
float pitch_scale;
+ float stream_paused_fade;
bool autoplay;
+ bool stream_paused;
StringName bus;
void _mix_audio();
@@ -199,6 +201,9 @@ public:
void set_doppler_tracking(DopplerTracking p_tracking);
DopplerTracking get_doppler_tracking() const;
+ void set_stream_paused(bool p_pause);
+ bool get_stream_paused() const;
+
AudioStreamPlayer3D();
~AudioStreamPlayer3D();
};
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
index 6998b34cfd..e11e8abe5b 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -201,7 +201,7 @@ void Camera::make_current() {
//get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,camera_group,"_camera_make_current",this);
}
-void Camera::clear_current() {
+void Camera::clear_current(bool p_enable_next) {
current = false;
if (!is_inside_tree())
@@ -209,7 +209,10 @@ void Camera::clear_current() {
if (get_viewport()->get_camera() == this) {
get_viewport()->_camera_set(NULL);
- get_viewport()->_camera_make_next_current(this);
+
+ if (p_enable_next) {
+ get_viewport()->_camera_make_next_current(this);
+ }
}
}
@@ -439,7 +442,7 @@ void Camera::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_perspective", "fov", "z_near", "z_far"), &Camera::set_perspective);
ClassDB::bind_method(D_METHOD("set_orthogonal", "size", "z_near", "z_far"), &Camera::set_orthogonal);
ClassDB::bind_method(D_METHOD("make_current"), &Camera::make_current);
- ClassDB::bind_method(D_METHOD("clear_current"), &Camera::clear_current);
+ ClassDB::bind_method(D_METHOD("clear_current", "enable_next"), &Camera::clear_current, DEFVAL(true));
ClassDB::bind_method(D_METHOD("set_current"), &Camera::set_current);
ClassDB::bind_method(D_METHOD("is_current"), &Camera::is_current);
ClassDB::bind_method(D_METHOD("get_camera_transform"), &Camera::get_camera_transform);
@@ -477,8 +480,8 @@ void Camera::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "near"), "set_znear", "get_znear");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "far"), "set_zfar", "get_zfar");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "near", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_znear", "get_znear");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "far", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_zfar", "get_zfar");
BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE);
BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL);
diff --git a/scene/3d/camera.h b/scene/3d/camera.h
index e2679870de..1b506e0c4f 100644
--- a/scene/3d/camera.h
+++ b/scene/3d/camera.h
@@ -113,7 +113,7 @@ public:
void set_projection(Camera::Projection p_mode);
void make_current();
- void clear_current();
+ void clear_current(bool p_enable_next = true);
void set_current(bool p_current);
bool is_current() const;
@@ -132,9 +132,9 @@ public:
virtual Transform get_camera_transform() const;
- Vector3 project_ray_normal(const Point2 &p_pos) const;
+ virtual Vector3 project_ray_normal(const Point2 &p_pos) const;
virtual Vector3 project_ray_origin(const Point2 &p_pos) const;
- Vector3 project_local_ray_normal(const Point2 &p_pos) const;
+ virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const;
virtual Point2 unproject_position(const Vector3 &p_pos) const;
bool is_position_behind(const Vector3 &p_pos) const;
virtual Vector3 project_position(const Point2 &p_point) const;
diff --git a/scene/3d/collision_polygon.cpp b/scene/3d/collision_polygon.cpp
index 3a77360bc2..379dd21c39 100644
--- a/scene/3d/collision_polygon.cpp
+++ b/scene/3d/collision_polygon.cpp
@@ -173,6 +173,9 @@ String CollisionPolygon::get_configuration_warning() const {
return String();
}
+bool CollisionPolygon::_is_editable_3d_polygon() const {
+ return true;
+}
void CollisionPolygon::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CollisionPolygon::set_depth);
@@ -184,6 +187,8 @@ void CollisionPolygon::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionPolygon::set_disabled);
ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon::is_disabled);
+ ClassDB::bind_method(D_METHOD("_is_editable_3d_polygon"), &CollisionPolygon::_is_editable_3d_polygon);
+
ADD_PROPERTY(PropertyInfo(Variant::REAL, "depth"), "set_depth", "get_depth");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
diff --git a/scene/3d/collision_polygon.h b/scene/3d/collision_polygon.h
index 971c67f1ad..f1f137c9c5 100644
--- a/scene/3d/collision_polygon.h
+++ b/scene/3d/collision_polygon.h
@@ -53,6 +53,8 @@ protected:
void _update_in_shape_owner(bool p_xform_only = false);
+ bool _is_editable_3d_polygon() const;
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/3d/interpolated_camera.cpp b/scene/3d/interpolated_camera.cpp
index 9865fe156a..ffa283f634 100644
--- a/scene/3d/interpolated_camera.cpp
+++ b/scene/3d/interpolated_camera.cpp
@@ -38,10 +38,10 @@ void InterpolatedCamera::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
if (Engine::get_singleton()->is_editor_hint() && enabled)
- set_physics_process(false);
+ set_process_internal(false);
} break;
- case NOTIFICATION_PROCESS: {
+ case NOTIFICATION_INTERNAL_PROCESS: {
if (!enabled)
break;
@@ -111,9 +111,9 @@ void InterpolatedCamera::set_interpolation_enabled(bool p_enable) {
if (p_enable) {
if (is_inside_tree() && Engine::get_singleton()->is_editor_hint())
return;
- set_process(true);
+ set_process_internal(true);
} else
- set_process(false);
+ set_process_internal(false);
}
bool InterpolatedCamera::is_interpolation_enabled() const {
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index 240bd631a1..7c42638107 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -375,7 +375,7 @@ void DirectionalLight::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_normal_bias", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_bias_split_scale", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_BIAS_SPLIT_SCALE);
ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_depth_range", PROPERTY_HINT_ENUM, "Stable,Optimized"), "set_shadow_depth_range", "get_shadow_depth_range");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_max_distance", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_max_distance", PROPERTY_HINT_EXP_RANGE, "0,8192,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE);
BIND_ENUM_CONSTANT(SHADOW_ORTHOGONAL);
BIND_ENUM_CONSTANT(SHADOW_PARALLEL_2_SPLITS);
@@ -428,8 +428,8 @@ void OmniLight::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_shadow_detail"), &OmniLight::get_shadow_detail);
ADD_GROUP("Omni", "omni_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_range", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_RANGE);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_attenuation", PROPERTY_HINT_EXP_EASING), "set_param", "get_param", PARAM_ATTENUATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION);
ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_mode", PROPERTY_HINT_ENUM, "Dual Paraboloid,Cube"), "set_shadow_mode", "get_shadow_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_detail", PROPERTY_HINT_ENUM, "Vertical,Horizontal"), "set_shadow_detail", "get_shadow_detail");
@@ -450,8 +450,8 @@ OmniLight::OmniLight() :
void SpotLight::_bind_methods() {
ADD_GROUP("Spot", "spot_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_range", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_RANGE);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_attenuation", PROPERTY_HINT_EXP_EASING), "set_param", "get_param", PARAM_ATTENUATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_param", "get_param", PARAM_SPOT_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle_attenuation", PROPERTY_HINT_EXP_EASING), "set_param", "get_param", PARAM_SPOT_ATTENUATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_SPOT_ATTENUATION);
}
diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp
index 80bae911d4..e836a6154a 100644
--- a/scene/3d/mesh_instance.cpp
+++ b/scene/3d/mesh_instance.cpp
@@ -371,7 +371,7 @@ void MeshInstance::_bind_methods() {
ClassDB::set_method_flags("MeshInstance", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton"), "set_skeleton_path", "get_skeleton_path");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path");
}
MeshInstance::MeshInstance() {
diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp
index e7ab6cde8a..77bf703706 100644
--- a/scene/3d/navigation.cpp
+++ b/scene/3d/navigation.cpp
@@ -35,6 +35,7 @@ void Navigation::_navmesh_link(int p_id) {
ERR_FAIL_COND(!navmesh_map.has(p_id));
NavMesh &nm = navmesh_map[p_id];
ERR_FAIL_COND(nm.linked);
+ ERR_FAIL_COND(nm.navmesh.is_null());
PoolVector<Vector3> vertices = nm.navmesh->get_vertices();
int len = vertices.size();
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index 8617bbc2f6..2b3a62fcdc 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -324,11 +324,11 @@ void Particles::_bind_methods() {
ClassDB::bind_method(D_METHOD("capture_aabb"), &Particles::capture_aabb);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
ADD_GROUP("Time", "");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
@@ -849,9 +849,9 @@ void ParticlesMaterial::_update_shader() {
code += " vec4(1.250, -1.050, -0.203, 0.0),\n";
code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_s;\n";
if (color_ramp.is_valid()) {
- code += " COLOR = textureLod(color_ramp,vec2(CUSTOM.y,0.0),0.0) * hue_rot_mat;\n";
+ code += " COLOR = hue_rot_mat * textureLod(color_ramp,vec2(CUSTOM.y,0.0),0.0);\n";
} else {
- code += " COLOR = color_value * hue_rot_mat;\n";
+ code += " COLOR = hue_rot_mat * color_value;\n";
}
if (emission_color_texture.is_valid() && emission_shape >= EMISSION_SHAPE_POINTS) {
code += " COLOR*= texelFetch(emission_texture_color,emission_tex_ofs,0);\n";
@@ -1028,8 +1028,6 @@ void ParticlesMaterial::set_param(Parameter p_param, float p_value) {
case PARAM_ANIM_OFFSET: {
VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset, p_value);
} break;
- case PARAM_MAX: {
- };
}
}
float ParticlesMaterial::get_param(Parameter p_param) const {
@@ -1082,8 +1080,6 @@ void ParticlesMaterial::set_param_randomness(Parameter p_param, float p_value) {
case PARAM_ANIM_OFFSET: {
VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_random, p_value);
} break;
- case PARAM_MAX: {
- };
}
}
float ParticlesMaterial::get_param_randomness(Parameter p_param) const {
@@ -1160,8 +1156,6 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture>
case PARAM_ANIM_OFFSET: {
VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, p_texture);
} break;
- case PARAM_MAX: {
- };
}
_queue_shader_change();
@@ -1233,28 +1227,19 @@ void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) {
void ParticlesMaterial::set_emission_point_texture(const Ref<Texture> &p_points) {
emission_point_texture = p_points;
- RID texture;
- if (p_points.is_valid())
- texture = p_points->get_rid();
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, texture);
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, p_points);
}
void ParticlesMaterial::set_emission_normal_texture(const Ref<Texture> &p_normals) {
emission_normal_texture = p_normals;
- RID texture;
- if (p_normals.is_valid())
- texture = p_normals->get_rid();
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, texture);
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, p_normals);
}
void ParticlesMaterial::set_emission_color_texture(const Ref<Texture> &p_colors) {
emission_color_texture = p_colors;
- RID texture;
- if (p_colors.is_valid())
- texture = p_colors->get_rid();
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, texture);
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, p_colors);
_queue_shader_change();
}
@@ -1316,10 +1301,7 @@ void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail
curve->ensure_default_setup();
}
- RID texture;
- if (p_trail_size_modifier.is_valid())
- texture = p_trail_size_modifier->get_rid();
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, texture);
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, curve);
_queue_shader_change();
}
@@ -1331,10 +1313,7 @@ Ref<CurveTexture> ParticlesMaterial::get_trail_size_modifier() const {
void ParticlesMaterial::set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier) {
trail_color_modifier = p_trail_color_modifier;
- RID texture;
- if (p_trail_color_modifier.is_valid())
- texture = p_trail_color_modifier->get_rid();
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, texture);
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, p_trail_color_modifier);
_queue_shader_change();
}
@@ -1465,7 +1444,7 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_color_modifier", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_trail_color_modifier", "get_trail_color_modifier");
ADD_GROUP("Emission Shape", "emission_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01,or_greater"), "set_emission_sphere_radius", "get_emission_sphere_radius");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_point_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_point_texture", "get_emission_point_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_normal_texture", "get_emission_normal_texture");
@@ -1481,38 +1460,38 @@ void ParticlesMaterial::_bind_methods() {
ADD_GROUP("Gravity", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity");
ADD_GROUP("Initial Velocity", "initial_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-360,360,0.01"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGULAR_VELOCITY);
ADD_GROUP("Orbit Velocity", "orbit_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01"), "set_param", "get_param", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ORBIT_VELOCITY);
ADD_GROUP("Linear Accel", "linear_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_LINEAR_ACCEL);
ADD_GROUP("Radial Accel", "radial_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_RADIAL_ACCEL);
ADD_GROUP("Tangential Accel", "tangential_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TANGENTIAL_ACCEL);
ADD_GROUP("Damping", "");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param", "get_param", PARAM_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param", "get_param", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_DAMPING);
ADD_GROUP("Angle", "");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1"), "set_param", "get_param", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGLE);
ADD_GROUP("Scale", "");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_param", "get_param", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_SCALE);
ADD_GROUP("Color", "");
@@ -1524,7 +1503,7 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_HUE_VARIATION);
ADD_GROUP("Animation", "anim_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_param", "get_param", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_param", "get_param", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp
index 7ac7f74bb0..9acaa15641 100644
--- a/scene/3d/path.cpp
+++ b/scene/3d/path.cpp
@@ -40,6 +40,9 @@ void Path::_curve_changed() {
if (is_inside_tree() && Engine::get_singleton()->is_editor_hint())
update_gizmo();
+ if (is_inside_tree()) {
+ emit_signal("curve_changed");
+ }
}
void Path::set_curve(const Ref<Curve3D> &p_curve) {
@@ -68,6 +71,8 @@ void Path::_bind_methods() {
ClassDB::bind_method(D_METHOD("_curve_changed"), &Path::_curve_changed);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve3D"), "set_curve", "get_curve");
+
+ ADD_SIGNAL(MethodInfo("curve_changed"));
}
Path::Path() {
@@ -225,7 +230,7 @@ void PathFollow::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow::set_loop);
ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow::has_loop);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01"), "set_offset", "get_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_EXP_RANGE, "0,10000,0.01,or_greater"), "set_offset", "get_offset");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset");
@@ -324,3 +329,219 @@ PathFollow::PathFollow() {
cubic = true;
loop = true;
}
+
+//////////////
+
+void OrientedPathFollow::_update_transform() {
+
+ if (!path)
+ return;
+
+ Ref<Curve3D> c = path->get_curve();
+ if (!c.is_valid())
+ return;
+
+ int count = c->get_point_count();
+ if (count < 2)
+ return;
+
+ if (delta_offset == 0) {
+ return;
+ }
+
+ float offset = get_offset();
+ float bl = c->get_baked_length();
+ float bi = c->get_bake_interval();
+ float o = offset;
+ float o_next = offset + bi;
+
+ if (has_loop()) {
+ o = Math::fposmod(o, bl);
+ o_next = Math::fposmod(o_next, bl);
+ } else if (o_next >= bl) {
+ o = bl - bi;
+ o_next = bl;
+ }
+
+ bool cubic = get_cubic_interpolation();
+ Vector3 pos = c->interpolate_baked(o, cubic);
+ Vector3 forward = c->interpolate_baked(o_next, cubic) - pos;
+
+ if (forward.length_squared() < CMP_EPSILON2)
+ forward = Vector3(0, 0, 1);
+ else
+ forward.normalize();
+
+ Vector3 up = c->interpolate_baked_up_vector(o, true);
+
+ if (o_next < o) {
+ Vector3 up1 = c->interpolate_baked_up_vector(o_next, true);
+ Vector3 axis = up.cross(up1);
+
+ if (axis.length_squared() < CMP_EPSILON2)
+ axis = forward;
+ else
+ axis.normalize();
+
+ up.rotate(axis, up.angle_to(up1) * 0.5f);
+ }
+
+ Transform t = get_transform();
+ Vector3 scale = t.basis.get_scale();
+
+ Vector3 sideways = up.cross(forward).normalized();
+ up = forward.cross(sideways).normalized();
+
+ t.basis.set(sideways, up, forward);
+ t.basis.scale_local(scale);
+
+ t.origin = pos + sideways * get_h_offset() + up * get_v_offset();
+
+ set_transform(t);
+}
+
+void OrientedPathFollow::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_ENTER_TREE: {
+
+ Node *parent = get_parent();
+ if (parent) {
+ path = Object::cast_to<Path>(parent);
+ if (path) {
+ _update_transform();
+ }
+ }
+
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+
+ path = NULL;
+ } break;
+ }
+}
+
+void OrientedPathFollow::set_cubic_interpolation(bool p_enable) {
+
+ cubic = p_enable;
+}
+
+bool OrientedPathFollow::get_cubic_interpolation() const {
+
+ return cubic;
+}
+
+void OrientedPathFollow::_validate_property(PropertyInfo &property) const {
+
+ if (property.name == "offset") {
+
+ float max = 10000;
+ if (path && path->get_curve().is_valid())
+ max = path->get_curve()->get_baked_length();
+
+ property.hint_string = "0," + rtos(max) + ",0.01";
+ }
+}
+
+void OrientedPathFollow::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_offset", "offset"), &OrientedPathFollow::set_offset);
+ ClassDB::bind_method(D_METHOD("get_offset"), &OrientedPathFollow::get_offset);
+
+ ClassDB::bind_method(D_METHOD("set_h_offset", "h_offset"), &OrientedPathFollow::set_h_offset);
+ ClassDB::bind_method(D_METHOD("get_h_offset"), &OrientedPathFollow::get_h_offset);
+
+ ClassDB::bind_method(D_METHOD("set_v_offset", "v_offset"), &OrientedPathFollow::set_v_offset);
+ ClassDB::bind_method(D_METHOD("get_v_offset"), &OrientedPathFollow::get_v_offset);
+
+ ClassDB::bind_method(D_METHOD("set_unit_offset", "unit_offset"), &OrientedPathFollow::set_unit_offset);
+ ClassDB::bind_method(D_METHOD("get_unit_offset"), &OrientedPathFollow::get_unit_offset);
+
+ ClassDB::bind_method(D_METHOD("set_cubic_interpolation", "enable"), &OrientedPathFollow::set_cubic_interpolation);
+ ClassDB::bind_method(D_METHOD("get_cubic_interpolation"), &OrientedPathFollow::get_cubic_interpolation);
+
+ ClassDB::bind_method(D_METHOD("set_loop", "loop"), &OrientedPathFollow::set_loop);
+ ClassDB::bind_method(D_METHOD("has_loop"), &OrientedPathFollow::has_loop);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01"), "set_offset", "get_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cubic_interp"), "set_cubic_interpolation", "get_cubic_interpolation");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
+}
+
+void OrientedPathFollow::set_offset(float p_offset) {
+ delta_offset = p_offset - offset;
+ offset = p_offset;
+
+ if (path)
+ _update_transform();
+ _change_notify("offset");
+ _change_notify("unit_offset");
+}
+
+void OrientedPathFollow::set_h_offset(float p_h_offset) {
+
+ h_offset = p_h_offset;
+ if (path)
+ _update_transform();
+}
+
+float OrientedPathFollow::get_h_offset() const {
+
+ return h_offset;
+}
+
+void OrientedPathFollow::set_v_offset(float p_v_offset) {
+
+ v_offset = p_v_offset;
+ if (path)
+ _update_transform();
+}
+
+float OrientedPathFollow::get_v_offset() const {
+
+ return v_offset;
+}
+
+float OrientedPathFollow::get_offset() const {
+
+ return offset;
+}
+
+void OrientedPathFollow::set_unit_offset(float p_unit_offset) {
+
+ if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length())
+ set_offset(p_unit_offset * path->get_curve()->get_baked_length());
+}
+
+float OrientedPathFollow::get_unit_offset() const {
+
+ if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length())
+ return get_offset() / path->get_curve()->get_baked_length();
+ else
+ return 0;
+}
+
+void OrientedPathFollow::set_loop(bool p_loop) {
+
+ loop = p_loop;
+}
+
+bool OrientedPathFollow::has_loop() const {
+
+ return loop;
+}
+
+OrientedPathFollow::OrientedPathFollow() {
+
+ offset = 0;
+ delta_offset = 0;
+ h_offset = 0;
+ v_offset = 0;
+ path = NULL;
+ cubic = true;
+ loop = true;
+}
diff --git a/scene/3d/path.h b/scene/3d/path.h
index 2ed686ac3c..f73bf17dfe 100644
--- a/scene/3d/path.h
+++ b/scene/3d/path.h
@@ -111,4 +111,47 @@ public:
VARIANT_ENUM_CAST(PathFollow::RotationMode);
+class OrientedPathFollow : public Spatial {
+
+ GDCLASS(OrientedPathFollow, Spatial);
+
+private:
+ Path *path;
+ real_t delta_offset; // change in offset since last _update_transform
+ real_t offset;
+ real_t h_offset;
+ real_t v_offset;
+ bool cubic;
+ bool loop;
+
+ void _update_transform();
+
+protected:
+ virtual void _validate_property(PropertyInfo &property) const;
+
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_offset(float p_offset);
+ float get_offset() const;
+
+ void set_h_offset(float p_h_offset);
+ float get_h_offset() const;
+
+ void set_v_offset(float p_v_offset);
+ float get_v_offset() const;
+
+ void set_unit_offset(float p_unit_offset);
+ float get_unit_offset() const;
+
+ void set_loop(bool p_loop);
+ bool has_loop() const;
+
+ void set_cubic_interpolation(bool p_enable);
+ bool get_cubic_interpolation() const;
+
+ OrientedPathFollow();
+};
+
#endif // PATH_H
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index ff4a807de0..e851c8d643 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -34,6 +34,10 @@
#include "method_bind_ext.gen.inc"
#include "scene/scene_string_names.h"
+#ifdef TOOLS_ENABLED
+#include "editor/plugins/spatial_editor_plugin.h"
+#endif
+
void PhysicsBody::_notification(int p_what) {
/*
@@ -781,7 +785,7 @@ String RigidBody::get_configuration_warning() const {
String warning = CollisionObject::get_configuration_warning();
- if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(0).length() - 1.0) > 0.05)) {
+ if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) {
if (warning != String()) {
warning += "\n";
}
@@ -975,7 +979,7 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_in
return colliding;
}
-Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, bool p_infinite_inertia, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle) {
+Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) {
Vector3 lv = p_linear_velocity;
@@ -1124,7 +1128,7 @@ Ref<KinematicCollision> KinematicBody::_get_slide_collision(int p_bounce) {
void KinematicBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia"), &KinematicBody::_move, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "infinite_inertia", "slope_stop_min_velocity", "max_slides", "floor_max_angle"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(true), DEFVAL(0.05), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)));
+ ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "slope_stop_min_velocity", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(0.05), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true));
ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody::test_move);
@@ -1266,3 +1270,1112 @@ KinematicCollision::KinematicCollision() {
collision.local_shape = 0;
owner = NULL;
}
+
+///////////////////////////////////////
+
+bool PhysicalBone::JointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ return false;
+}
+
+bool PhysicalBone::JointData::_get(const StringName &p_name, Variant &r_ret) const {
+ return false;
+}
+
+void PhysicalBone::JointData::_get_property_list(List<PropertyInfo> *p_list) const {
+}
+
+bool PhysicalBone::PinJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ if (JointData::_set(p_name, p_value, j)) {
+ return true;
+ }
+
+ if ("joint_constraints/bias" == p_name) {
+ bias = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->pin_joint_set_param(j, PhysicsServer::PIN_JOINT_BIAS, bias);
+
+ } else if ("joint_constraints/damping" == p_name) {
+ damping = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->pin_joint_set_param(j, PhysicsServer::PIN_JOINT_DAMPING, damping);
+
+ } else if ("joint_constraints/impulse_clamp" == p_name) {
+ impulse_clamp = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->pin_joint_set_param(j, PhysicsServer::PIN_JOINT_IMPULSE_CLAMP, impulse_clamp);
+
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool PhysicalBone::PinJointData::_get(const StringName &p_name, Variant &r_ret) const {
+ if (JointData::_get(p_name, r_ret)) {
+ return true;
+ }
+
+ if ("joint_constraints/bias" == p_name) {
+ r_ret = bias;
+ } else if ("joint_constraints/damping" == p_name) {
+ r_ret = damping;
+ } else if ("joint_constraints/impulse_clamp" == p_name) {
+ r_ret = impulse_clamp;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void PhysicalBone::PinJointData::_get_property_list(List<PropertyInfo> *p_list) const {
+ JointData::_get_property_list(p_list);
+
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/damping", PROPERTY_HINT_RANGE, "0.01,8.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/impulse_clamp", PROPERTY_HINT_RANGE, "0.0,64.0,0.01"));
+}
+
+bool PhysicalBone::ConeJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ if (JointData::_set(p_name, p_value, j)) {
+ return true;
+ }
+
+ if ("joint_constraints/swing_span" == p_name) {
+ swing_span = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN, swing_span);
+
+ } else if ("joint_constraints/twist_span" == p_name) {
+ twist_span = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN, twist_span);
+
+ } else if ("joint_constraints/bias" == p_name) {
+ bias = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_BIAS, bias);
+
+ } else if ("joint_constraints/softness" == p_name) {
+ softness = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_SOFTNESS, softness);
+
+ } else if ("joint_constraints/relaxation" == p_name) {
+ relaxation = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_RELAXATION, relaxation);
+
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool PhysicalBone::ConeJointData::_get(const StringName &p_name, Variant &r_ret) const {
+ if (JointData::_get(p_name, r_ret)) {
+ return true;
+ }
+
+ if ("joint_constraints/swing_span" == p_name) {
+ r_ret = Math::rad2deg(swing_span);
+ } else if ("joint_constraints/twist_span" == p_name) {
+ r_ret = Math::rad2deg(twist_span);
+ } else if ("joint_constraints/bias" == p_name) {
+ r_ret = bias;
+ } else if ("joint_constraints/softness" == p_name) {
+ r_ret = softness;
+ } else if ("joint_constraints/relaxation" == p_name) {
+ r_ret = relaxation;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void PhysicalBone::ConeJointData::_get_property_list(List<PropertyInfo> *p_list) const {
+ JointData::_get_property_list(p_list);
+
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/swing_span", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1,or_lesser,or_greater"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/relaxation", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+}
+
+bool PhysicalBone::HingeJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ if (JointData::_set(p_name, p_value, j)) {
+ return true;
+ }
+
+ if ("joint_constraints/angular_limit_enabled" == p_name) {
+ angular_limit_enabled = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->hinge_joint_set_flag(j, PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT, angular_limit_enabled);
+
+ } else if ("joint_constraints/angular_limit_upper" == p_name) {
+ angular_limit_upper = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_UPPER, angular_limit_upper);
+
+ } else if ("joint_constraints/angular_limit_lower" == p_name) {
+ angular_limit_lower = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_LOWER, angular_limit_lower);
+
+ } else if ("joint_constraints/angular_limit_bias" == p_name) {
+ angular_limit_bias = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_BIAS, angular_limit_bias);
+
+ } else if ("joint_constraints/angular_limit_softness" == p_name) {
+ angular_limit_softness = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS, angular_limit_softness);
+
+ } else if ("joint_constraints/angular_limit_relaxation" == p_name) {
+ angular_limit_relaxation = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION, angular_limit_relaxation);
+
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool PhysicalBone::HingeJointData::_get(const StringName &p_name, Variant &r_ret) const {
+ if (JointData::_get(p_name, r_ret)) {
+ return true;
+ }
+
+ if ("joint_constraints/angular_limit_enabled" == p_name) {
+ r_ret = angular_limit_enabled;
+ } else if ("joint_constraints/angular_limit_upper" == p_name) {
+ r_ret = Math::rad2deg(angular_limit_upper);
+ } else if ("joint_constraints/angular_limit_lower" == p_name) {
+ r_ret = Math::rad2deg(angular_limit_lower);
+ } else if ("joint_constraints/angular_limit_bias" == p_name) {
+ r_ret = angular_limit_bias;
+ } else if ("joint_constraints/angular_limit_softness" == p_name) {
+ r_ret = angular_limit_softness;
+ } else if ("joint_constraints/angular_limit_relaxation" == p_name) {
+ r_ret = angular_limit_relaxation;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void PhysicalBone::HingeJointData::_get_property_list(List<PropertyInfo> *p_list) const {
+ JointData::_get_property_list(p_list);
+
+ p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/angular_limit_enabled"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+}
+
+bool PhysicalBone::SliderJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ if (JointData::_set(p_name, p_value, j)) {
+ return true;
+ }
+
+ if ("joint_constraints/linear_limit_upper" == p_name) {
+ linear_limit_upper = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER, linear_limit_upper);
+
+ } else if ("joint_constraints/linear_limit_lower" == p_name) {
+ linear_limit_lower = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER, linear_limit_lower);
+
+ } else if ("joint_constraints/linear_limit_softness" == p_name) {
+ linear_limit_softness = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, linear_limit_softness);
+
+ } else if ("joint_constraints/linear_limit_restitution" == p_name) {
+ linear_limit_restitution = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, linear_limit_restitution);
+
+ } else if ("joint_constraints/linear_limit_damping" == p_name) {
+ linear_limit_damping = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, linear_limit_restitution);
+
+ } else if ("joint_constraints/angular_limit_upper" == p_name) {
+ angular_limit_upper = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, angular_limit_upper);
+
+ } else if ("joint_constraints/angular_limit_lower" == p_name) {
+ angular_limit_lower = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, angular_limit_lower);
+
+ } else if ("joint_constraints/angular_limit_softness" == p_name) {
+ angular_limit_softness = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, angular_limit_softness);
+
+ } else if ("joint_constraints/angular_limit_restitution" == p_name) {
+ angular_limit_restitution = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, angular_limit_softness);
+
+ } else if ("joint_constraints/angular_limit_damping" == p_name) {
+ angular_limit_damping = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, angular_limit_damping);
+
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool PhysicalBone::SliderJointData::_get(const StringName &p_name, Variant &r_ret) const {
+ if (JointData::_get(p_name, r_ret)) {
+ return true;
+ }
+
+ if ("joint_constraints/linear_limit_upper" == p_name) {
+ r_ret = linear_limit_upper;
+ } else if ("joint_constraints/linear_limit_lower" == p_name) {
+ r_ret = linear_limit_lower;
+ } else if ("joint_constraints/linear_limit_softness" == p_name) {
+ r_ret = linear_limit_softness;
+ } else if ("joint_constraints/linear_limit_restitution" == p_name) {
+ r_ret = linear_limit_restitution;
+ } else if ("joint_constraints/linear_limit_damping" == p_name) {
+ r_ret = linear_limit_damping;
+ } else if ("joint_constraints/angular_limit_upper" == p_name) {
+ r_ret = Math::rad2deg(angular_limit_upper);
+ } else if ("joint_constraints/angular_limit_lower" == p_name) {
+ r_ret = Math::rad2deg(angular_limit_lower);
+ } else if ("joint_constraints/angular_limit_softness" == p_name) {
+ r_ret = angular_limit_softness;
+ } else if ("joint_constraints/angular_limit_restitution" == p_name) {
+ r_ret = angular_limit_restitution;
+ } else if ("joint_constraints/angular_limit_damping" == p_name) {
+ r_ret = angular_limit_damping;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void PhysicalBone::SliderJointData::_get_property_list(List<PropertyInfo> *p_list) const {
+ JointData::_get_property_list(p_list);
+
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_upper"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_lower"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"));
+
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"));
+}
+
+bool PhysicalBone::SixDOFJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ if (JointData::_set(p_name, p_value, j)) {
+ return true;
+ }
+
+ String path = p_name;
+
+ Vector3::Axis axis;
+ {
+ const String axis_s = path.get_slicec('/', 1);
+ if ("x" == axis_s) {
+ axis = Vector3::AXIS_X;
+ } else if ("y" == axis_s) {
+ axis = Vector3::AXIS_Y;
+ } else if ("z" == axis_s) {
+ axis = Vector3::AXIS_Z;
+ } else {
+ return false;
+ }
+ }
+
+ String var_name = path.get_slicec('/', 2);
+
+ if ("linear_limit_enabled" == var_name) {
+ axis_data[axis].linear_limit_enabled = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, axis_data[axis].linear_limit_enabled);
+
+ } else if ("linear_limit_upper" == var_name) {
+ axis_data[axis].linear_limit_upper = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT, axis_data[axis].linear_limit_upper);
+
+ } else if ("linear_limit_lower" == var_name) {
+ axis_data[axis].linear_limit_lower = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT, axis_data[axis].linear_limit_lower);
+
+ } else if ("linear_limit_softness" == var_name) {
+ axis_data[axis].linear_limit_softness = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, axis_data[axis].linear_limit_softness);
+
+ } else if ("linear_restitution" == var_name) {
+ axis_data[axis].linear_restitution = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION, axis_data[axis].linear_restitution);
+
+ } else if ("linear_damping" == var_name) {
+ axis_data[axis].linear_damping = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING, axis_data[axis].linear_damping);
+
+ } else if ("angular_limit_enabled" == var_name) {
+ axis_data[axis].angular_limit_enabled = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, axis_data[axis].angular_limit_enabled);
+
+ } else if ("angular_limit_upper" == var_name) {
+ axis_data[axis].angular_limit_upper = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, axis_data[axis].angular_limit_upper);
+
+ } else if ("angular_limit_lower" == var_name) {
+ axis_data[axis].angular_limit_lower = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, axis_data[axis].angular_limit_lower);
+
+ } else if ("angular_limit_softness" == var_name) {
+ axis_data[axis].angular_limit_softness = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, axis_data[axis].angular_limit_softness);
+
+ } else if ("angular_restitution" == var_name) {
+ axis_data[axis].angular_restitution = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION, axis_data[axis].angular_restitution);
+
+ } else if ("angular_damping" == var_name) {
+ axis_data[axis].angular_damping = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING, axis_data[axis].angular_damping);
+
+ } else if ("erp" == var_name) {
+ axis_data[axis].erp = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_ERP, axis_data[axis].erp);
+
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool PhysicalBone::SixDOFJointData::_get(const StringName &p_name, Variant &r_ret) const {
+ if (JointData::_get(p_name, r_ret)) {
+ return true;
+ }
+
+ String path = p_name;
+
+ int axis;
+ {
+ const String axis_s = path.get_slicec('/', 1);
+ if ("x" == axis_s) {
+ axis = 0;
+ } else if ("y" == axis_s) {
+ axis = 1;
+ } else if ("z" == axis_s) {
+ axis = 2;
+ } else {
+ return false;
+ }
+ }
+
+ String var_name = path.get_slicec('/', 2);
+
+ if ("linear_limit_enabled" == var_name) {
+ r_ret = axis_data[axis].linear_limit_enabled;
+ } else if ("linear_limit_upper" == var_name) {
+ r_ret = axis_data[axis].linear_limit_upper;
+ } else if ("linear_limit_lower" == var_name) {
+ r_ret = axis_data[axis].linear_limit_lower;
+ } else if ("linear_limit_softness" == var_name) {
+ r_ret = axis_data[axis].linear_limit_softness;
+ } else if ("linear_restitution" == var_name) {
+ r_ret = axis_data[axis].linear_restitution;
+ } else if ("linear_damping" == var_name) {
+ r_ret = axis_data[axis].linear_damping;
+ } else if ("angular_limit_enabled" == var_name) {
+ r_ret = axis_data[axis].angular_limit_enabled;
+ } else if ("angular_limit_upper" == var_name) {
+ r_ret = Math::rad2deg(axis_data[axis].angular_limit_upper);
+ } else if ("angular_limit_lower" == var_name) {
+ r_ret = Math::rad2deg(axis_data[axis].angular_limit_lower);
+ } else if ("angular_limit_softness" == var_name) {
+ r_ret = axis_data[axis].angular_limit_softness;
+ } else if ("angular_restitution" == var_name) {
+ r_ret = axis_data[axis].angular_restitution;
+ } else if ("angular_damping" == var_name) {
+ r_ret = axis_data[axis].angular_damping;
+ } else if ("erp" == var_name) {
+ r_ret = axis_data[axis].erp;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void PhysicalBone::SixDOFJointData::_get_property_list(List<PropertyInfo> *p_list) const {
+ const StringName axis_names[] = { "x", "y", "z" };
+ for (int i = 0; i < 3; ++i) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/linear_limit_enabled"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_limit_upper"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_limit_lower"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/angular_limit_enabled"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/erp"));
+ }
+}
+
+bool PhysicalBone::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "bone_name") {
+ set_bone_name(p_value);
+ return true;
+ }
+
+ if (joint_data) {
+ if (joint_data->_set(p_name, p_value)) {
+#ifdef TOOLS_ENABLED
+ if (get_gizmo().is_valid())
+ get_gizmo()->redraw();
+#endif
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool PhysicalBone::_get(const StringName &p_name, Variant &r_ret) const {
+ if (p_name == "bone_name") {
+ r_ret = get_bone_name();
+ return true;
+ }
+
+ if (joint_data) {
+ return joint_data->_get(p_name, r_ret);
+ }
+
+ return false;
+}
+
+void PhysicalBone::_get_property_list(List<PropertyInfo> *p_list) const {
+
+ Skeleton *parent = find_skeleton_parent(get_parent());
+
+ if (parent) {
+
+ String names;
+ for (int i = 0; i < parent->get_bone_count(); i++) {
+ if (i > 0)
+ names += ",";
+ names += parent->get_bone_name(i);
+ }
+
+ p_list->push_back(PropertyInfo(Variant::STRING, "bone_name", PROPERTY_HINT_ENUM, names));
+ } else {
+
+ p_list->push_back(PropertyInfo(Variant::STRING, "bone_name"));
+ }
+
+ if (joint_data) {
+ joint_data->_get_property_list(p_list);
+ }
+}
+
+void PhysicalBone::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ parent_skeleton = find_skeleton_parent(get_parent());
+ update_bone_id();
+ reset_to_rest_position();
+ _reset_physics_simulation_state();
+ break;
+ case NOTIFICATION_EXIT_TREE:
+ if (parent_skeleton) {
+ if (-1 != bone_id) {
+ parent_skeleton->unbind_physical_bone_from_bone(bone_id);
+ }
+ }
+ parent_skeleton = NULL;
+ update_bone_id();
+ break;
+ case NOTIFICATION_TRANSFORM_CHANGED:
+ if (Engine::get_singleton()->is_editor_hint()) {
+
+ update_offset();
+ }
+ break;
+ }
+}
+
+void PhysicalBone::_direct_state_changed(Object *p_state) {
+
+ if (!simulate_physics) {
+ return;
+ }
+
+ /// Update bone transform
+
+ PhysicsDirectBodyState *state;
+
+#ifdef DEBUG_ENABLED
+ state = Object::cast_to<PhysicsDirectBodyState>(p_state);
+#else
+ state = (PhysicsDirectBodyState *)p_state; //trust it
+#endif
+
+ Transform global_transform(state->get_transform());
+
+ set_ignore_transform_notification(true);
+ set_global_transform(global_transform);
+ set_ignore_transform_notification(false);
+
+ // Update skeleton
+ if (parent_skeleton) {
+ if (-1 != bone_id) {
+ parent_skeleton->set_bone_global_pose(bone_id, parent_skeleton->get_global_transform().affine_inverse() * (global_transform * body_offset_inverse));
+ }
+ }
+}
+
+void PhysicalBone::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_direct_state_changed"), &PhysicalBone::_direct_state_changed);
+
+ ClassDB::bind_method(D_METHOD("set_joint_type", "joint_type"), &PhysicalBone::set_joint_type);
+ ClassDB::bind_method(D_METHOD("get_joint_type"), &PhysicalBone::get_joint_type);
+
+ ClassDB::bind_method(D_METHOD("set_joint_offset", "offset"), &PhysicalBone::set_joint_offset);
+ ClassDB::bind_method(D_METHOD("get_joint_offset"), &PhysicalBone::get_joint_offset);
+
+ ClassDB::bind_method(D_METHOD("set_body_offset", "offset"), &PhysicalBone::set_body_offset);
+ ClassDB::bind_method(D_METHOD("get_body_offset"), &PhysicalBone::get_body_offset);
+
+ ClassDB::bind_method(D_METHOD("is_static_body"), &PhysicalBone::is_static_body);
+
+ ClassDB::bind_method(D_METHOD("get_simulate_physics"), &PhysicalBone::get_simulate_physics);
+
+ ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone::is_simulating_physics);
+
+ ClassDB::bind_method(D_METHOD("set_mass", "mass"), &PhysicalBone::set_mass);
+ ClassDB::bind_method(D_METHOD("get_mass"), &PhysicalBone::get_mass);
+
+ ClassDB::bind_method(D_METHOD("set_weight", "weight"), &PhysicalBone::set_weight);
+ ClassDB::bind_method(D_METHOD("get_weight"), &PhysicalBone::get_weight);
+
+ ClassDB::bind_method(D_METHOD("set_friction", "friction"), &PhysicalBone::set_friction);
+ ClassDB::bind_method(D_METHOD("get_friction"), &PhysicalBone::get_friction);
+
+ ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &PhysicalBone::set_bounce);
+ ClassDB::bind_method(D_METHOD("get_bounce"), &PhysicalBone::get_bounce);
+
+ ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &PhysicalBone::set_gravity_scale);
+ ClassDB::bind_method(D_METHOD("get_gravity_scale"), &PhysicalBone::get_gravity_scale);
+
+ ADD_GROUP("Joint", "joint_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "joint_offset"), "set_joint_offset", "get_joint_offset");
+
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "body_offset"), "set_body_offset", "get_body_offset");
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_weight", "get_weight");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-10,10,0.01"), "set_gravity_scale", "get_gravity_scale");
+
+ BIND_ENUM_CONSTANT(JOINT_TYPE_NONE);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_PIN);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_CONE);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_HINGE);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_SLIDER);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_6DOF);
+}
+
+Skeleton *PhysicalBone::find_skeleton_parent(Node *p_parent) {
+ if (!p_parent) {
+ return NULL;
+ }
+ Skeleton *s = Object::cast_to<Skeleton>(p_parent);
+ return s ? s : find_skeleton_parent(p_parent->get_parent());
+}
+
+void PhysicalBone::_fix_joint_offset() {
+ // Clamp joint origin to bone origin
+ if (parent_skeleton) {
+ joint_offset.origin = body_offset.affine_inverse().origin;
+ }
+}
+
+void PhysicalBone::_reload_joint() {
+
+ if (joint.is_valid()) {
+ PhysicsServer::get_singleton()->free(joint);
+ joint = RID();
+ }
+
+ if (!parent_skeleton) {
+ return;
+ }
+
+ PhysicalBone *body_a = parent_skeleton->get_physical_bone_parent(bone_id);
+ if (!body_a) {
+ return;
+ }
+
+ Transform joint_transf = get_global_transform() * joint_offset;
+ Transform local_a = body_a->get_global_transform().affine_inverse() * joint_transf;
+ local_a.orthonormalize();
+
+ switch (get_joint_type()) {
+ case JOINT_TYPE_PIN: {
+
+ joint = PhysicsServer::get_singleton()->joint_create_pin(body_a->get_rid(), local_a.origin, get_rid(), joint_offset.origin);
+ const PinJointData *pjd(static_cast<const PinJointData *>(joint_data));
+ PhysicsServer::get_singleton()->pin_joint_set_param(joint, PhysicsServer::PIN_JOINT_BIAS, pjd->bias);
+ PhysicsServer::get_singleton()->pin_joint_set_param(joint, PhysicsServer::PIN_JOINT_DAMPING, pjd->damping);
+ PhysicsServer::get_singleton()->pin_joint_set_param(joint, PhysicsServer::PIN_JOINT_IMPULSE_CLAMP, pjd->impulse_clamp);
+
+ } break;
+ case JOINT_TYPE_CONE: {
+
+ joint = PhysicsServer::get_singleton()->joint_create_cone_twist(body_a->get_rid(), local_a, get_rid(), joint_offset);
+ const ConeJointData *cjd(static_cast<const ConeJointData *>(joint_data));
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN, cjd->swing_span);
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN, cjd->twist_span);
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_BIAS, cjd->bias);
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_SOFTNESS, cjd->softness);
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_RELAXATION, cjd->relaxation);
+
+ } break;
+ case JOINT_TYPE_HINGE: {
+
+ joint = PhysicsServer::get_singleton()->joint_create_hinge(body_a->get_rid(), local_a, get_rid(), joint_offset);
+ const HingeJointData *hjd(static_cast<const HingeJointData *>(joint_data));
+ PhysicsServer::get_singleton()->hinge_joint_set_flag(joint, PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT, hjd->angular_limit_enabled);
+ PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_UPPER, hjd->angular_limit_upper);
+ PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_LOWER, hjd->angular_limit_lower);
+ PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_BIAS, hjd->angular_limit_bias);
+ PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS, hjd->angular_limit_softness);
+ PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION, hjd->angular_limit_relaxation);
+
+ } break;
+ case JOINT_TYPE_SLIDER: {
+
+ joint = PhysicsServer::get_singleton()->joint_create_slider(body_a->get_rid(), local_a, get_rid(), joint_offset);
+ const SliderJointData *sjd(static_cast<const SliderJointData *>(joint_data));
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER, sjd->linear_limit_upper);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER, sjd->linear_limit_lower);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, sjd->linear_limit_softness);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, sjd->linear_limit_restitution);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, sjd->linear_limit_restitution);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, sjd->angular_limit_upper);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, sjd->angular_limit_lower);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, sjd->angular_limit_softness);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, sjd->angular_limit_softness);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, sjd->angular_limit_damping);
+
+ } break;
+ case JOINT_TYPE_6DOF: {
+
+ joint = PhysicsServer::get_singleton()->joint_create_generic_6dof(body_a->get_rid(), local_a, get_rid(), joint_offset);
+ const SixDOFJointData *g6dofjd(static_cast<const SixDOFJointData *>(joint_data));
+ for (int axis = 0; axis < 3; ++axis) {
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, g6dofjd->axis_data[axis].linear_limit_enabled);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT, g6dofjd->axis_data[axis].linear_limit_upper);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT, g6dofjd->axis_data[axis].linear_limit_lower);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, g6dofjd->axis_data[axis].linear_limit_softness);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION, g6dofjd->axis_data[axis].linear_restitution);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING, g6dofjd->axis_data[axis].linear_damping);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, g6dofjd->axis_data[axis].angular_limit_enabled);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, g6dofjd->axis_data[axis].angular_limit_upper);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, g6dofjd->axis_data[axis].angular_limit_lower);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, g6dofjd->axis_data[axis].angular_limit_softness);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION, g6dofjd->axis_data[axis].angular_restitution);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING, g6dofjd->axis_data[axis].angular_damping);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_ERP, g6dofjd->axis_data[axis].erp);
+ }
+
+ } break;
+ }
+}
+
+void PhysicalBone::_on_bone_parent_changed() {
+ _reload_joint();
+}
+
+void PhysicalBone::_set_gizmo_move_joint(bool p_move_joint) {
+#ifdef TOOLS_ENABLED
+ gizmo_move_joint = p_move_joint;
+ SpatialEditor::get_singleton()->update_transform_gizmo();
+#endif
+}
+
+#ifdef TOOLS_ENABLED
+Transform PhysicalBone::get_global_gizmo_transform() const {
+ return gizmo_move_joint ? get_global_transform() * joint_offset : get_global_transform();
+}
+
+Transform PhysicalBone::get_local_gizmo_transform() const {
+ return gizmo_move_joint ? get_transform() * joint_offset : get_transform();
+}
+#endif
+
+const PhysicalBone::JointData *PhysicalBone::get_joint_data() const {
+ return joint_data;
+}
+
+Skeleton *PhysicalBone::find_skeleton_parent() {
+ return find_skeleton_parent(this);
+}
+
+void PhysicalBone::set_joint_type(JointType p_joint_type) {
+
+ if (p_joint_type == get_joint_type())
+ return;
+
+ memdelete(joint_data);
+ joint_data = NULL;
+ switch (p_joint_type) {
+ case JOINT_TYPE_PIN:
+ joint_data = memnew(PinJointData);
+ break;
+ case JOINT_TYPE_CONE:
+ joint_data = memnew(ConeJointData);
+ break;
+ case JOINT_TYPE_HINGE:
+ joint_data = memnew(HingeJointData);
+ break;
+ case JOINT_TYPE_SLIDER:
+ joint_data = memnew(SliderJointData);
+ break;
+ case JOINT_TYPE_6DOF:
+ joint_data = memnew(SixDOFJointData);
+ break;
+ }
+
+ _reload_joint();
+
+#ifdef TOOLS_ENABLED
+ _change_notify();
+ if (get_gizmo().is_valid())
+ get_gizmo()->redraw();
+#endif
+}
+
+PhysicalBone::JointType PhysicalBone::get_joint_type() const {
+ return joint_data ? joint_data->get_joint_type() : JOINT_TYPE_NONE;
+}
+
+void PhysicalBone::set_joint_offset(const Transform &p_offset) {
+ joint_offset = p_offset;
+
+ _fix_joint_offset();
+
+ set_ignore_transform_notification(true);
+ reset_to_rest_position();
+ set_ignore_transform_notification(false);
+
+#ifdef TOOLS_ENABLED
+ if (get_gizmo().is_valid())
+ get_gizmo()->redraw();
+#endif
+}
+
+const Transform &PhysicalBone::get_body_offset() const {
+ return body_offset;
+}
+
+void PhysicalBone::set_body_offset(const Transform &p_offset) {
+ body_offset = p_offset;
+ body_offset_inverse = body_offset.affine_inverse();
+
+ _fix_joint_offset();
+
+ set_ignore_transform_notification(true);
+ reset_to_rest_position();
+ set_ignore_transform_notification(false);
+
+#ifdef TOOLS_ENABLED
+ if (get_gizmo().is_valid())
+ get_gizmo()->redraw();
+#endif
+}
+
+const Transform &PhysicalBone::get_joint_offset() const {
+ return joint_offset;
+}
+
+void PhysicalBone::set_static_body(bool p_static) {
+
+ static_body = p_static;
+
+ set_as_toplevel(!static_body);
+
+ _reset_physics_simulation_state();
+}
+
+bool PhysicalBone::is_static_body() {
+ return static_body;
+}
+
+void PhysicalBone::set_simulate_physics(bool p_simulate) {
+ if (simulate_physics == p_simulate) {
+ return;
+ }
+
+ simulate_physics = p_simulate;
+ _reset_physics_simulation_state();
+}
+
+bool PhysicalBone::get_simulate_physics() {
+ return simulate_physics;
+}
+
+bool PhysicalBone::is_simulating_physics() {
+ return _internal_simulate_physics && !_internal_static_body;
+}
+
+void PhysicalBone::set_bone_name(const String &p_name) {
+
+ bone_name = p_name;
+ bone_id = -1;
+
+ update_bone_id();
+ reset_to_rest_position();
+}
+
+const String &PhysicalBone::get_bone_name() const {
+
+ return bone_name;
+}
+
+void PhysicalBone::set_mass(real_t p_mass) {
+
+ ERR_FAIL_COND(p_mass <= 0);
+ mass = p_mass;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_MASS, mass);
+}
+
+real_t PhysicalBone::get_mass() const {
+
+ return mass;
+}
+
+void PhysicalBone::set_weight(real_t p_weight) {
+
+ set_mass(p_weight / real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8)));
+}
+
+real_t PhysicalBone::get_weight() const {
+
+ return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8));
+}
+
+void PhysicalBone::set_friction(real_t p_friction) {
+
+ ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
+
+ friction = p_friction;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, friction);
+}
+
+real_t PhysicalBone::get_friction() const {
+
+ return friction;
+}
+
+void PhysicalBone::set_bounce(real_t p_bounce) {
+
+ ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
+
+ bounce = p_bounce;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, bounce);
+}
+real_t PhysicalBone::get_bounce() const {
+
+ return bounce;
+}
+
+void PhysicalBone::set_gravity_scale(real_t p_gravity_scale) {
+
+ gravity_scale = p_gravity_scale;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_GRAVITY_SCALE, gravity_scale);
+}
+
+real_t PhysicalBone::get_gravity_scale() const {
+
+ return gravity_scale;
+}
+
+PhysicalBone::PhysicalBone() :
+ PhysicsBody(PhysicsServer::BODY_MODE_STATIC),
+#ifdef TOOLS_ENABLED
+ gizmo_move_joint(false),
+#endif
+ joint_data(NULL),
+ static_body(false),
+ simulate_physics(false),
+ _internal_static_body(false),
+ _internal_simulate_physics(false),
+ bone_id(-1),
+ parent_skeleton(NULL),
+ bone_name(""),
+ bounce(0),
+ mass(1),
+ friction(1),
+ gravity_scale(1) {
+
+ set_static_body(static_body);
+ _reset_physics_simulation_state();
+}
+
+PhysicalBone::~PhysicalBone() {
+ memdelete(joint_data);
+}
+
+void PhysicalBone::update_bone_id() {
+ if (!parent_skeleton) {
+ return;
+ }
+
+ const int new_bone_id = parent_skeleton->find_bone(bone_name);
+
+ if (new_bone_id != bone_id) {
+ if (-1 != bone_id) {
+ // Assert the unbind from old node
+ parent_skeleton->unbind_physical_bone_from_bone(bone_id);
+ parent_skeleton->unbind_child_node_from_bone(bone_id, this);
+ }
+
+ bone_id = new_bone_id;
+
+ parent_skeleton->bind_physical_bone_to_bone(bone_id, this);
+
+ _fix_joint_offset();
+ _internal_static_body = !static_body; // Force staticness reset
+ _reset_staticness_state();
+ }
+}
+
+void PhysicalBone::update_offset() {
+#ifdef TOOLS_ENABLED
+ if (parent_skeleton) {
+
+ Transform bone_transform(parent_skeleton->get_global_transform());
+ if (-1 != bone_id)
+ bone_transform *= parent_skeleton->get_bone_global_pose(bone_id);
+
+ if (gizmo_move_joint) {
+ bone_transform *= body_offset;
+ set_joint_offset(bone_transform.affine_inverse() * get_global_transform());
+ } else {
+ set_body_offset(bone_transform.affine_inverse() * get_global_transform());
+ }
+ }
+#endif
+}
+
+void PhysicalBone::reset_to_rest_position() {
+ if (parent_skeleton) {
+ if (-1 == bone_id) {
+ set_global_transform(parent_skeleton->get_global_transform() * body_offset);
+ } else {
+ set_global_transform(parent_skeleton->get_global_transform() * parent_skeleton->get_bone_global_pose(bone_id) * body_offset);
+ }
+ }
+}
+
+void PhysicalBone::_reset_physics_simulation_state() {
+ if (simulate_physics && !static_body) {
+ _start_physics_simulation();
+ } else {
+ _stop_physics_simulation();
+ }
+
+ _reset_staticness_state();
+}
+
+void PhysicalBone::_reset_staticness_state() {
+
+ if (parent_skeleton && -1 != bone_id) {
+ if (static_body && simulate_physics) { // With this check I'm sure the position of this body is updated only when it's necessary
+
+ if (_internal_static_body) {
+ return;
+ }
+
+ parent_skeleton->bind_child_node_to_bone(bone_id, this);
+ _internal_static_body = true;
+ } else {
+
+ if (!_internal_static_body) {
+ return;
+ }
+
+ parent_skeleton->unbind_child_node_from_bone(bone_id, this);
+ _internal_static_body = false;
+ }
+ }
+}
+
+void PhysicalBone::_start_physics_simulation() {
+ if (_internal_simulate_physics || !parent_skeleton) {
+ return;
+ }
+ reset_to_rest_position();
+ PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_RIGID);
+ PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
+ PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
+ PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ parent_skeleton->set_bone_ignore_animation(bone_id, true);
+ _internal_simulate_physics = true;
+}
+
+void PhysicalBone::_stop_physics_simulation() {
+ if (!_internal_simulate_physics || !parent_skeleton) {
+ return;
+ }
+ PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_STATIC);
+ PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), 0);
+ PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), 0);
+ PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), NULL, "");
+ parent_skeleton->set_bone_ignore_animation(bone_id, false);
+ _internal_simulate_physics = false;
+}
diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h
index ffdc9ab309..0190dcbfc3 100644
--- a/scene/3d/physics_body.h
+++ b/scene/3d/physics_body.h
@@ -33,6 +33,7 @@
#include "scene/3d/collision_object.h"
#include "servers/physics_server.h"
+#include "skeleton.h"
#include "vset.h"
class PhysicsBody : public CollisionObject {
@@ -302,7 +303,7 @@ public:
void set_safe_margin(float p_margin);
float get_safe_margin() const;
- Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction = Vector3(0, 0, 0), bool p_infinite_inertia = true, float p_slope_stop_min_velocity = 0.05, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45));
+ Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction = Vector3(0, 0, 0), float p_slope_stop_min_velocity = 0.05, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true);
bool is_on_floor() const;
bool is_on_wall() const;
bool is_on_ceiling() const;
@@ -342,4 +343,267 @@ public:
KinematicCollision();
};
+class PhysicalBone : public PhysicsBody {
+
+ GDCLASS(PhysicalBone, PhysicsBody);
+
+public:
+ enum JointType {
+ JOINT_TYPE_NONE,
+ JOINT_TYPE_PIN,
+ JOINT_TYPE_CONE,
+ JOINT_TYPE_HINGE,
+ JOINT_TYPE_SLIDER,
+ JOINT_TYPE_6DOF
+ };
+
+ struct JointData {
+ virtual JointType get_joint_type() { return JOINT_TYPE_NONE; }
+
+ /// "j" is used to set the parameter inside the PhysicsServer
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+ };
+
+ struct PinJointData : public JointData {
+ virtual JointType get_joint_type() { return JOINT_TYPE_PIN; }
+
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ real_t bias;
+ real_t damping;
+ real_t impulse_clamp;
+
+ PinJointData() :
+ bias(0.3),
+ damping(1.),
+ impulse_clamp(0) {}
+ };
+
+ struct ConeJointData : public JointData {
+ virtual JointType get_joint_type() { return JOINT_TYPE_CONE; }
+
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ real_t swing_span;
+ real_t twist_span;
+ real_t bias;
+ real_t softness;
+ real_t relaxation;
+
+ ConeJointData() :
+ swing_span(Math_PI * 0.25),
+ twist_span(Math_PI),
+ bias(0.3),
+ softness(0.8),
+ relaxation(1.) {}
+ };
+
+ struct HingeJointData : public JointData {
+ virtual JointType get_joint_type() { return JOINT_TYPE_HINGE; }
+
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ bool angular_limit_enabled;
+ real_t angular_limit_upper;
+ real_t angular_limit_lower;
+ real_t angular_limit_bias;
+ real_t angular_limit_softness;
+ real_t angular_limit_relaxation;
+
+ HingeJointData() :
+ angular_limit_enabled(false),
+ angular_limit_upper(Math_PI * 0.5),
+ angular_limit_lower(-Math_PI * 0.5),
+ angular_limit_bias(0.3),
+ angular_limit_softness(0.9),
+ angular_limit_relaxation(1.) {}
+ };
+
+ struct SliderJointData : public JointData {
+ virtual JointType get_joint_type() { return JOINT_TYPE_SLIDER; }
+
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ real_t linear_limit_upper;
+ real_t linear_limit_lower;
+ real_t linear_limit_softness;
+ real_t linear_limit_restitution;
+ real_t linear_limit_damping;
+ real_t angular_limit_upper;
+ real_t angular_limit_lower;
+ real_t angular_limit_softness;
+ real_t angular_limit_restitution;
+ real_t angular_limit_damping;
+
+ SliderJointData() :
+ linear_limit_upper(1.),
+ linear_limit_lower(-1.),
+ linear_limit_softness(1.),
+ linear_limit_restitution(0.7),
+ linear_limit_damping(1.),
+ angular_limit_upper(0),
+ angular_limit_lower(0),
+ angular_limit_softness(1.),
+ angular_limit_restitution(0.7),
+ angular_limit_damping(1.) {}
+ };
+
+ struct SixDOFJointData : public JointData {
+ struct SixDOFAxisData {
+ bool linear_limit_enabled;
+ real_t linear_limit_upper;
+ real_t linear_limit_lower;
+ real_t linear_limit_softness;
+ real_t linear_restitution;
+ real_t linear_damping;
+ bool angular_limit_enabled;
+ real_t angular_limit_upper;
+ real_t angular_limit_lower;
+ real_t angular_limit_softness;
+ real_t angular_restitution;
+ real_t angular_damping;
+ real_t erp;
+
+ SixDOFAxisData() :
+ linear_limit_enabled(true),
+ linear_limit_upper(0),
+ linear_limit_lower(0),
+ linear_limit_softness(0.7),
+ linear_restitution(0.5),
+ linear_damping(1.),
+ angular_limit_enabled(true),
+ angular_limit_upper(0),
+ angular_limit_lower(0),
+ angular_limit_softness(0.5),
+ angular_restitution(0),
+ angular_damping(1.),
+ erp(0.5) {}
+ };
+
+ virtual JointType get_joint_type() { return JOINT_TYPE_6DOF; }
+
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ SixDOFAxisData axis_data[3];
+
+ SixDOFJointData() {}
+ };
+
+private:
+#ifdef TOOLS_ENABLED
+ // if false gizmo move body
+ bool gizmo_move_joint;
+#endif
+
+ JointData *joint_data;
+ Transform joint_offset;
+ RID joint;
+
+ Skeleton *parent_skeleton;
+ Transform body_offset;
+ Transform body_offset_inverse;
+ bool static_body;
+ bool _internal_static_body;
+ bool simulate_physics;
+ bool _internal_simulate_physics;
+ int bone_id;
+
+ String bone_name;
+ real_t bounce;
+ real_t mass;
+ real_t friction;
+ real_t gravity_scale;
+
+protected:
+ 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 _notification(int p_what);
+ void _direct_state_changed(Object *p_state);
+
+ static void _bind_methods();
+
+private:
+ static Skeleton *find_skeleton_parent(Node *p_parent);
+ void _fix_joint_offset();
+ void _reload_joint();
+
+public:
+ void _on_bone_parent_changed();
+ void _set_gizmo_move_joint(bool p_move_joint);
+
+public:
+#ifdef TOOLS_ENABLED
+ virtual Transform get_global_gizmo_transform() const;
+ virtual Transform get_local_gizmo_transform() const;
+#endif
+
+ const JointData *get_joint_data() const;
+ Skeleton *find_skeleton_parent();
+
+ int get_bone_id() const { return bone_id; }
+
+ void set_joint_type(JointType p_joint_type);
+ JointType get_joint_type() const;
+
+ void set_joint_offset(const Transform &p_offset);
+ const Transform &get_joint_offset() const;
+
+ void set_body_offset(const Transform &p_offset);
+ const Transform &get_body_offset() const;
+
+ void set_static_body(bool p_static);
+ bool is_static_body();
+
+ void set_simulate_physics(bool p_simulate);
+ bool get_simulate_physics();
+ bool is_simulating_physics();
+
+ void set_bone_name(const String &p_name);
+ const String &get_bone_name() const;
+
+ void set_mass(real_t p_mass);
+ real_t get_mass() const;
+
+ void set_weight(real_t p_weight);
+ real_t get_weight() const;
+
+ void set_friction(real_t p_friction);
+ real_t get_friction() const;
+
+ void set_bounce(real_t p_bounce);
+ real_t get_bounce() const;
+
+ void set_gravity_scale(real_t p_gravity_scale);
+ real_t get_gravity_scale() const;
+
+ PhysicalBone();
+ ~PhysicalBone();
+
+private:
+ void update_bone_id();
+ void update_offset();
+ void reset_to_rest_position();
+
+ void _reset_physics_simulation_state();
+ void _reset_staticness_state();
+
+ void _start_physics_simulation();
+ void _stop_physics_simulation();
+};
+
+VARIANT_ENUM_CAST(PhysicalBone::JointType);
+
#endif // PHYSICS_BODY__H
diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp
index 2e9f1a241a..7988c43eab 100644
--- a/scene/3d/physics_joint.cpp
+++ b/scene/3d/physics_joint.cpp
@@ -154,8 +154,8 @@ void Joint::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint::set_exclude_nodes_from_collision);
ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint::get_exclude_nodes_from_collision);
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_a"), "set_node_a", "get_node_a");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_b"), "set_node_b", "get_node_b");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject"), "set_node_a", "get_node_a");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject"), "set_node_b", "get_node_b");
ADD_PROPERTY(PropertyInfo(Variant::INT, "solver/priority", PROPERTY_HINT_RANGE, "1,8,1"), "set_solver_priority", "get_solver_priority");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision/exclude_nodes"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision");
@@ -260,7 +260,7 @@ void HingeJoint::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_lower_limit", "lower_limit"), &HingeJoint::_set_lower_limit);
ClassDB::bind_method(D_METHOD("_get_lower_limit"), &HingeJoint::_get_lower_limit);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "params/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_BIAS);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "params/bias", PROPERTY_HINT_RANGE, "0.00,0.99,0.01"), "set_param", "get_param", PARAM_BIAS);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit/enable"), "set_flag", "get_flag", FLAG_USE_LIMIT);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit/upper", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_upper_limit", "_get_upper_limit");
@@ -270,7 +270,7 @@ void HingeJoint::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit/relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_RELAXATION);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "motor/enable"), "set_flag", "get_flag", FLAG_ENABLE_MOTOR);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "motor/target_velocity", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "motor/target_velocity", PROPERTY_HINT_RANGE, "-200,200,0.01,or_greater,or_lesser"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "motor/max_impulse", PROPERTY_HINT_RANGE, "0.01,1024,0.01"), "set_param", "get_param", PARAM_MOTOR_MAX_IMPULSE);
BIND_ENUM_CONSTANT(PARAM_BIAS);
@@ -716,6 +716,9 @@ void Generic6DOFJoint::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_x/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_LIMIT_SOFTNESS);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "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::REAL, "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_motor_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_x/target_velocity"), "set_param_x", "get_param_x", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_x/force_limit"), "set_param_x", "get_param_x", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_ANGULAR_LIMIT);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "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::REAL, "angular_limit_x/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_x", "_get_angular_lo_limit_x");
@@ -734,6 +737,9 @@ void Generic6DOFJoint::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "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::REAL, "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::REAL, "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::REAL, "linear_motor_y/target_velocity"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_y/force_limit"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_ANGULAR_LIMIT);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "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::REAL, "angular_limit_y/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_y", "_get_angular_lo_limit_y");
@@ -752,6 +758,9 @@ void Generic6DOFJoint::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "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::REAL, "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::REAL, "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::REAL, "linear_motor_z/target_velocity"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_z/force_limit"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_ANGULAR_LIMIT);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "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::REAL, "angular_limit_z/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_z", "_get_angular_lo_limit_z");
@@ -769,6 +778,8 @@ void Generic6DOFJoint::_bind_methods() {
BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_SOFTNESS);
BIND_ENUM_CONSTANT(PARAM_LINEAR_RESTITUTION);
BIND_ENUM_CONSTANT(PARAM_LINEAR_DAMPING);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTOR_FORCE_LIMIT);
BIND_ENUM_CONSTANT(PARAM_ANGULAR_LOWER_LIMIT);
BIND_ENUM_CONSTANT(PARAM_ANGULAR_UPPER_LIMIT);
BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_SOFTNESS);
@@ -783,6 +794,7 @@ void Generic6DOFJoint::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_ENABLE_LINEAR_LIMIT);
BIND_ENUM_CONSTANT(FLAG_ENABLE_ANGULAR_LIMIT);
BIND_ENUM_CONSTANT(FLAG_ENABLE_MOTOR);
+ BIND_ENUM_CONSTANT(FLAG_ENABLE_LINEAR_MOTOR);
BIND_ENUM_CONSTANT(FLAG_MAX);
}
@@ -912,6 +924,8 @@ Generic6DOFJoint::Generic6DOFJoint() {
set_param_x(PARAM_LINEAR_LIMIT_SOFTNESS, 0.7);
set_param_x(PARAM_LINEAR_RESTITUTION, 0.5);
set_param_x(PARAM_LINEAR_DAMPING, 1.0);
+ set_param_x(PARAM_LINEAR_MOTOR_TARGET_VELOCITY, 0);
+ set_param_x(PARAM_LINEAR_MOTOR_FORCE_LIMIT, 0);
set_param_x(PARAM_ANGULAR_LOWER_LIMIT, 0);
set_param_x(PARAM_ANGULAR_UPPER_LIMIT, 0);
set_param_x(PARAM_ANGULAR_LIMIT_SOFTNESS, 0.5f);
@@ -925,12 +939,15 @@ Generic6DOFJoint::Generic6DOFJoint() {
set_flag_x(FLAG_ENABLE_ANGULAR_LIMIT, true);
set_flag_x(FLAG_ENABLE_LINEAR_LIMIT, true);
set_flag_x(FLAG_ENABLE_MOTOR, false);
+ set_flag_x(FLAG_ENABLE_LINEAR_MOTOR, false);
set_param_y(PARAM_LINEAR_LOWER_LIMIT, 0);
set_param_y(PARAM_LINEAR_UPPER_LIMIT, 0);
set_param_y(PARAM_LINEAR_LIMIT_SOFTNESS, 0.7);
set_param_y(PARAM_LINEAR_RESTITUTION, 0.5);
set_param_y(PARAM_LINEAR_DAMPING, 1.0);
+ set_param_y(PARAM_LINEAR_MOTOR_TARGET_VELOCITY, 0);
+ set_param_y(PARAM_LINEAR_MOTOR_FORCE_LIMIT, 0);
set_param_y(PARAM_ANGULAR_LOWER_LIMIT, 0);
set_param_y(PARAM_ANGULAR_UPPER_LIMIT, 0);
set_param_y(PARAM_ANGULAR_LIMIT_SOFTNESS, 0.5f);
@@ -944,12 +961,15 @@ Generic6DOFJoint::Generic6DOFJoint() {
set_flag_y(FLAG_ENABLE_ANGULAR_LIMIT, true);
set_flag_y(FLAG_ENABLE_LINEAR_LIMIT, true);
set_flag_y(FLAG_ENABLE_MOTOR, false);
+ set_flag_y(FLAG_ENABLE_LINEAR_MOTOR, false);
set_param_z(PARAM_LINEAR_LOWER_LIMIT, 0);
set_param_z(PARAM_LINEAR_UPPER_LIMIT, 0);
set_param_z(PARAM_LINEAR_LIMIT_SOFTNESS, 0.7);
set_param_z(PARAM_LINEAR_RESTITUTION, 0.5);
set_param_z(PARAM_LINEAR_DAMPING, 1.0);
+ set_param_z(PARAM_LINEAR_MOTOR_TARGET_VELOCITY, 0);
+ set_param_z(PARAM_LINEAR_MOTOR_FORCE_LIMIT, 0);
set_param_z(PARAM_ANGULAR_LOWER_LIMIT, 0);
set_param_z(PARAM_ANGULAR_UPPER_LIMIT, 0);
set_param_z(PARAM_ANGULAR_LIMIT_SOFTNESS, 0.5f);
@@ -963,4 +983,5 @@ Generic6DOFJoint::Generic6DOFJoint() {
set_flag_z(FLAG_ENABLE_ANGULAR_LIMIT, true);
set_flag_z(FLAG_ENABLE_LINEAR_LIMIT, true);
set_flag_z(FLAG_ENABLE_MOTOR, false);
+ set_flag_z(FLAG_ENABLE_LINEAR_MOTOR, false);
}
diff --git a/scene/3d/physics_joint.h b/scene/3d/physics_joint.h
index 000109ac55..37870d6f30 100644
--- a/scene/3d/physics_joint.h
+++ b/scene/3d/physics_joint.h
@@ -249,6 +249,8 @@ public:
PARAM_LINEAR_LIMIT_SOFTNESS = PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS,
PARAM_LINEAR_RESTITUTION = PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION,
PARAM_LINEAR_DAMPING = PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING,
+ PARAM_LINEAR_MOTOR_TARGET_VELOCITY = PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY,
+ PARAM_LINEAR_MOTOR_FORCE_LIMIT = PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT,
PARAM_ANGULAR_LOWER_LIMIT = PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT,
PARAM_ANGULAR_UPPER_LIMIT = PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT,
PARAM_ANGULAR_LIMIT_SOFTNESS = PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS,
@@ -265,6 +267,7 @@ public:
FLAG_ENABLE_LINEAR_LIMIT = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT,
FLAG_ENABLE_ANGULAR_LIMIT = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT,
FLAG_ENABLE_MOTOR = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR,
+ FLAG_ENABLE_LINEAR_MOTOR = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR,
FLAG_MAX = PhysicsServer::G6DOF_JOINT_FLAG_MAX
};
diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp
index dd5ae8a999..7f83e2c3ea 100644
--- a/scene/3d/ray_cast.cpp
+++ b/scene/3d/ray_cast.cpp
@@ -103,7 +103,7 @@ void RayCast::set_enabled(bool p_enabled) {
enabled = p_enabled;
if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint())
- set_physics_process(p_enabled);
+ set_physics_process_internal(p_enabled);
if (!p_enabled)
collided = false;
@@ -150,12 +150,12 @@ void RayCast::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
if (enabled && !Engine::get_singleton()->is_editor_hint()) {
- set_physics_process(true);
+ set_physics_process_internal(true);
if (get_tree()->is_debugging_collisions_hint())
_update_debug_shape();
} else
- set_physics_process(false);
+ set_physics_process_internal(false);
if (Object::cast_to<CollisionObject>(get_parent())) {
if (exclude_parent_body)
@@ -168,14 +168,14 @@ void RayCast::_notification(int p_what) {
case NOTIFICATION_EXIT_TREE: {
if (enabled) {
- set_physics_process(false);
+ set_physics_process_internal(false);
}
if (debug_shape)
_clear_debug_shape();
} break;
- case NOTIFICATION_PHYSICS_PROCESS: {
+ case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (!enabled)
break;
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index 2178da02b5..4d50945062 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -240,9 +240,9 @@ void ReflectionProbe::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Once,Always"), "set_update_mode", "get_update_mode");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "intensity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_intensity", "get_intensity");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_RANGE, "0,16384,0.1"), "set_max_distance", "get_max_distance");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "extents"), "set_extents", "get_extents");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "origin_offset"), "set_origin_offset", "get_origin_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,16384,0.1,or_greater"), "set_max_distance", "get_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "origin_offset"), "set_origin_offset", "get_origin_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "box_projection"), "set_enable_box_projection", "is_box_projection_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_shadows"), "set_enable_shadows", "are_shadows_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
diff --git a/scene/3d/remote_transform.cpp b/scene/3d/remote_transform.cpp
index afb85f7314..2156e24cd0 100644
--- a/scene/3d/remote_transform.cpp
+++ b/scene/3d/remote_transform.cpp
@@ -194,7 +194,7 @@ void RemoteTransform::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_update_scale", "update_remote_scale"), &RemoteTransform::set_update_scale);
ClassDB::bind_method(D_METHOD("get_update_scale"), &RemoteTransform::get_update_scale);
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path"), "set_remote_node", "get_remote_node");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Spatial"), "set_remote_node", "get_remote_node");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_global_coordinates"), "set_use_global_coordinates", "get_use_global_coordinates");
ADD_GROUP("Update", "update_");
diff --git a/scene/3d/scenario_fx.cpp b/scene/3d/scenario_fx.cpp
index 02768ac91f..26cbfc0b11 100644
--- a/scene/3d/scenario_fx.cpp
+++ b/scene/3d/scenario_fx.cpp
@@ -79,7 +79,11 @@ Ref<Environment> WorldEnvironment::get_environment() const {
String WorldEnvironment::get_configuration_warning() const {
- if (/*!is_visible_in_tree() ||*/ !is_inside_tree() || !environment.is_valid())
+ if (!environment.is_valid()) {
+ return TTR("WorldEnvironment needs an Environment resource.");
+ }
+
+ if (/*!is_visible_in_tree() ||*/ !is_inside_tree())
return String();
List<Node *> nodes;
@@ -89,6 +93,11 @@ String WorldEnvironment::get_configuration_warning() const {
return TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes).");
}
+ // Commenting this warning for now, I think it makes no sense. If anyone can figure out what its supposed to do, feedback welcome. Else it should be deprecated.
+ //if (environment.is_valid() && get_viewport() && !get_viewport()->get_camera() && environment->get_background() != Environment::BG_CANVAS) {
+ // return TTR("This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set this environment's Background Mode to Canvas (for 2D scenes).");
+ //}
+
return String();
}
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index d3a13c741e..8d91b6f09f 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -33,6 +33,7 @@
#include "message_queue.h"
#include "core/project_settings.h"
+#include "scene/3d/physics_body.h"
#include "scene/resources/surface_tool.h"
bool Skeleton::_set(const StringName &p_path, const Variant &p_value) {
@@ -329,7 +330,7 @@ void Skeleton::add_bone(const String &p_name) {
_make_dirty();
update_gizmo();
}
-int Skeleton::find_bone(String p_name) const {
+int Skeleton::find_bone(const String &p_name) const {
for (int i = 0; i < bones.size(); i++) {
@@ -346,6 +347,19 @@ String Skeleton::get_bone_name(int p_bone) const {
return bones[p_bone].name;
}
+bool Skeleton::is_bone_parent_of(int p_bone, int p_parent_bone_id) const {
+
+ int parent_of_bone = get_bone_parent(p_bone);
+
+ if (-1 == parent_of_bone)
+ return false;
+
+ if (parent_of_bone == p_parent_bone_id)
+ return true;
+
+ return is_bone_parent_of(parent_of_bone, p_parent_bone_id);
+}
+
int Skeleton::get_bone_count() const {
return bones.size();
@@ -377,6 +391,17 @@ void Skeleton::unparent_bone_and_rest(int p_bone) {
_make_dirty();
}
+void Skeleton::set_bone_ignore_animation(int p_bone, bool p_ignore) {
+ ERR_FAIL_INDEX(p_bone, bones.size());
+ bones[p_bone].ignore_animation = p_ignore;
+}
+
+bool Skeleton::is_bone_ignore_animation(int p_bone) const {
+
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), false);
+ return bones[p_bone].ignore_animation;
+}
+
void Skeleton::set_bone_disable_rest(int p_bone, bool p_disable) {
ERR_FAIL_INDEX(p_bone, bones.size());
@@ -522,6 +547,154 @@ void Skeleton::localize_rests() {
}
}
+#ifndef _3D_DISABLED
+
+void Skeleton::bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone) {
+ ERR_FAIL_INDEX(p_bone, bones.size());
+ ERR_FAIL_COND(bones[p_bone].physical_bone);
+ ERR_FAIL_COND(!p_physical_bone);
+ bones[p_bone].physical_bone = p_physical_bone;
+
+ _rebuild_physical_bones_cache();
+}
+
+void Skeleton::unbind_physical_bone_from_bone(int p_bone) {
+ ERR_FAIL_INDEX(p_bone, bones.size());
+ bones[p_bone].physical_bone = NULL;
+
+ _rebuild_physical_bones_cache();
+}
+
+PhysicalBone *Skeleton::get_physical_bone(int p_bone) {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), NULL);
+
+ return bones[p_bone].physical_bone;
+}
+
+PhysicalBone *Skeleton::get_physical_bone_parent(int p_bone) {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), NULL);
+
+ if (bones[p_bone].cache_parent_physical_bone) {
+ return bones[p_bone].cache_parent_physical_bone;
+ }
+
+ return _get_physical_bone_parent(p_bone);
+}
+
+PhysicalBone *Skeleton::_get_physical_bone_parent(int p_bone) {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), NULL);
+
+ const int parent_bone = bones[p_bone].parent;
+ if (0 > parent_bone) {
+ return NULL;
+ }
+
+ PhysicalBone *pb = bones[parent_bone].physical_bone;
+ if (pb) {
+ return pb;
+ } else {
+ return get_physical_bone_parent(parent_bone);
+ }
+}
+
+void Skeleton::_rebuild_physical_bones_cache() {
+ const int b_size = bones.size();
+ for (int i = 0; i < b_size; ++i) {
+ bones[i].cache_parent_physical_bone = _get_physical_bone_parent(i);
+ if (bones[i].physical_bone)
+ bones[i].physical_bone->_on_bone_parent_changed();
+ }
+}
+
+void _pb_stop_simulation(Node *p_node) {
+
+ for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
+ _pb_stop_simulation(p_node->get_child(i));
+ }
+
+ PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
+ if (pb) {
+ pb->set_simulate_physics(false);
+ pb->set_static_body(false);
+ }
+}
+
+void Skeleton::physical_bones_stop_simulation() {
+ _pb_stop_simulation(this);
+}
+
+void _pb_start_simulation(const Skeleton *p_skeleton, Node *p_node, const Vector<int> &p_sim_bones) {
+
+ for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
+ _pb_start_simulation(p_skeleton, p_node->get_child(i), p_sim_bones);
+ }
+
+ PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
+ if (pb) {
+ bool sim = false;
+ for (int i = p_sim_bones.size() - 1; 0 <= i; --i) {
+ if (p_sim_bones[i] == pb->get_bone_id() || p_skeleton->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) {
+ sim = true;
+ break;
+ }
+ }
+
+ pb->set_simulate_physics(true);
+ if (sim) {
+ pb->set_static_body(false);
+ } else {
+ pb->set_static_body(true);
+ }
+ }
+}
+
+void Skeleton::physical_bones_start_simulation_on(const Array &p_bones) {
+
+ Vector<int> sim_bones;
+ if (p_bones.size() <= 0) {
+ sim_bones.push_back(0); // if no bones is specified, activate ragdoll on full body
+ } else {
+ sim_bones.resize(p_bones.size());
+ int c = 0;
+ for (int i = sim_bones.size() - 1; 0 <= i; --i) {
+ if (Variant::STRING == p_bones.get(i).get_type()) {
+ int bone_id = find_bone(p_bones.get(i));
+ if (bone_id != -1)
+ sim_bones[c++] = bone_id;
+ }
+ }
+ sim_bones.resize(c);
+ }
+
+ _pb_start_simulation(this, this, sim_bones);
+}
+
+void _physical_bones_add_remove_collision_exception(bool p_add, Node *p_node, RID p_exception) {
+
+ for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
+ _physical_bones_add_remove_collision_exception(p_add, p_node->get_child(i), p_exception);
+ }
+
+ CollisionObject *co = Object::cast_to<CollisionObject>(p_node);
+ if (co) {
+ if (p_add) {
+ PhysicsServer::get_singleton()->body_add_collision_exception(co->get_rid(), p_exception);
+ } else {
+ PhysicsServer::get_singleton()->body_remove_collision_exception(co->get_rid(), p_exception);
+ }
+ }
+}
+
+void Skeleton::physical_bones_add_collision_exception(RID p_exception) {
+ _physical_bones_add_remove_collision_exception(true, this, p_exception);
+}
+
+void Skeleton::physical_bones_remove_collision_exception(RID p_exception) {
+ _physical_bones_add_remove_collision_exception(false, this, p_exception);
+}
+
+#endif // _3D_DISABLED
+
void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton::add_bone);
@@ -558,6 +731,15 @@ void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_transform", "bone_idx"), &Skeleton::get_bone_transform);
+#ifndef _3D_DISABLED
+
+ ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation);
+ ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &Skeleton::physical_bones_start_simulation_on, DEFVAL(Array()));
+ ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton::physical_bones_add_collision_exception);
+ ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton::physical_bones_remove_collision_exception);
+
+#endif // _3D_DISABLED
+
BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
}
@@ -570,6 +752,5 @@ Skeleton::Skeleton() {
}
Skeleton::~Skeleton() {
-
VisualServer::get_singleton()->free(skeleton);
}
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index d693670055..9672acb57a 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -37,6 +37,11 @@
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
+
+#ifndef _3D_DISABLED
+class PhysicalBone;
+#endif // _3D_DISABLED
+
class Skeleton : public Spatial {
GDCLASS(Skeleton, Spatial);
@@ -48,6 +53,8 @@ class Skeleton : public Spatial {
bool enabled;
int parent;
+ bool ignore_animation;
+
bool disable_rest;
Transform rest;
Transform rest_global_inverse;
@@ -60,13 +67,23 @@ class Skeleton : public Spatial {
Transform transform_final;
+#ifndef _3D_DISABLED
+ PhysicalBone *physical_bone;
+ PhysicalBone *cache_parent_physical_bone;
+#endif // _3D_DISABLED
+
List<uint32_t> nodes_bound;
Bone() {
parent = -1;
enabled = true;
+ ignore_animation = false;
custom_pose_enable = false;
disable_rest = false;
+#ifndef _3D_DISABLED
+ physical_bone = NULL;
+ cache_parent_physical_bone = NULL;
+#endif // _3D_DISABLED
}
};
@@ -110,14 +127,19 @@ public:
// skeleton creation api
void add_bone(const String &p_name);
- int find_bone(String p_name) const;
+ int find_bone(const String &p_name) const;
String get_bone_name(int p_bone) const;
+ bool is_bone_parent_of(int p_bone_id, int p_parent_bone_id) const;
+
void set_bone_parent(int p_bone, int p_parent);
int get_bone_parent(int p_bone) const;
void unparent_bone_and_rest(int p_bone);
+ void set_bone_ignore_animation(int p_bone, bool p_ignore);
+ bool is_bone_ignore_animation(int p_bone) const;
+
void set_bone_disable_rest(int p_bone, bool p_disable);
bool is_bone_rest_disabled(int p_bone) const;
@@ -149,6 +171,28 @@ public:
void localize_rests(); // used for loaders and tools
+#ifndef _3D_DISABLED
+ // Physical bone API
+
+ void bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone);
+ void unbind_physical_bone_from_bone(int p_bone);
+
+ PhysicalBone *get_physical_bone(int p_bone);
+ PhysicalBone *get_physical_bone_parent(int p_bone);
+
+private:
+ /// This is a slow API os it's cached
+ PhysicalBone *_get_physical_bone_parent(int p_bone);
+ void _rebuild_physical_bones_cache();
+
+public:
+ void physical_bones_stop_simulation();
+ void physical_bones_start_simulation_on(const Array &p_bones);
+ void physical_bones_add_collision_exception(RID p_exception);
+ void physical_bones_remove_collision_exception(RID p_exception);
+#endif // _3D_DISABLED
+
+public:
Skeleton();
~Skeleton();
};
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index 721641e09b..748aa8aad4 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -85,9 +85,7 @@ void Spatial::_notify_dirty() {
}
void Spatial::_update_local_transform() const {
- data.local_transform.basis = Basis();
- data.local_transform.basis.scale(data.scale);
- data.local_transform.basis.rotate(data.rotation);
+ data.local_transform.basis.set_euler_scale(data.rotation, data.scale);
data.dirty &= ~DIRTY_LOCAL;
}
@@ -188,7 +186,9 @@ void Spatial::_notification(int p_what) {
if (data.gizmo.is_valid()) {
data.gizmo->create();
if (data.gizmo->can_draw()) {
- data.gizmo->redraw();
+ if (is_visible_in_tree()) {
+ data.gizmo->redraw();
+ }
}
data.gizmo->transform();
}
@@ -286,6 +286,16 @@ Transform Spatial::get_global_transform() const {
return data.global_transform;
}
+#ifdef TOOLS_ENABLED
+Transform Spatial::get_global_gizmo_transform() const {
+ return get_global_transform();
+}
+
+Transform Spatial::get_local_gizmo_transform() const {
+ return get_transform();
+}
+#endif
+
Spatial *Spatial::get_parent_spatial() const {
return data.parent;
@@ -409,7 +419,9 @@ void Spatial::set_gizmo(const Ref<SpatialGizmo> &p_gizmo) {
data.gizmo->create();
if (data.gizmo->can_draw()) {
- data.gizmo->redraw();
+ if (is_visible_in_tree()) {
+ data.gizmo->redraw();
+ }
}
data.gizmo->transform();
}
@@ -428,10 +440,9 @@ Ref<SpatialGizmo> Spatial::get_gizmo() const {
#endif
}
-#ifdef TOOLS_ENABLED
-
void Spatial::_update_gizmo() {
+#ifdef TOOLS_ENABLED
if (!is_inside_world())
return;
data.gizmo_dirty = false;
@@ -443,8 +454,10 @@ void Spatial::_update_gizmo() {
data.gizmo->clear();
}
}
+#endif
}
+#ifdef TOOLS_ENABLED
void Spatial::set_disable_gizmo(bool p_enabled) {
data.gizmo_disabled = p_enabled;
@@ -724,9 +737,7 @@ void Spatial::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &Spatial::is_set_as_toplevel);
ClassDB::bind_method(D_METHOD("get_world"), &Spatial::get_world);
-#ifdef TOOLS_ENABLED
ClassDB::bind_method(D_METHOD("_update_gizmo"), &Spatial::_update_gizmo);
-#endif
ClassDB::bind_method(D_METHOD("update_gizmo"), &Spatial::update_gizmo);
ClassDB::bind_method(D_METHOD("set_gizmo", "gizmo"), &Spatial::set_gizmo);
@@ -788,9 +799,7 @@ void Spatial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
ADD_GROUP("Visibility", "");
ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
-#ifdef TOOLS_ENABLED
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "SpatialGizmo", 0), "set_gizmo", "get_gizmo");
-#endif
ADD_SIGNAL(MethodInfo("visibility_changed"));
}
diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h
index 518bba9a51..a43bed3e4a 100644
--- a/scene/3d/spatial.h
+++ b/scene/3d/spatial.h
@@ -100,10 +100,8 @@ class Spatial : public Node {
#endif
} data;
-#ifdef TOOLS_ENABLED
void _update_gizmo();
-#endif
void _notify_dirty();
void _propagate_transform_changed(Spatial *p_origin);
@@ -147,6 +145,11 @@ public:
Transform get_transform() const;
Transform get_global_transform() const;
+#ifdef TOOLS_ENABLED
+ virtual Transform get_global_gizmo_transform() const;
+ virtual Transform get_local_gizmo_transform() const;
+#endif
+
void set_as_toplevel(bool p_enabled);
bool is_set_as_toplevel() const;
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 232855c978..036a748c83 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -185,6 +185,9 @@ void SpriteBase3D::_queue_update() {
if (pending_update)
return;
+ triangle_mesh.unref();
+ update_gizmo();
+
pending_update = true;
call_deferred(SceneStringNames::get_singleton()->_im_update);
}
@@ -198,6 +201,66 @@ PoolVector<Face3> SpriteBase3D::get_faces(uint32_t p_usage_flags) const {
return PoolVector<Face3>();
}
+Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const {
+ if (triangle_mesh.is_valid())
+ return triangle_mesh;
+
+ PoolVector<Vector3> faces;
+ faces.resize(6);
+ PoolVector<Vector3>::Write facesw = faces.write();
+
+ Rect2 final_rect = get_item_rect();
+
+ if (final_rect.size.x == 0 || final_rect.size.y == 0)
+ return Ref<TriangleMesh>();
+
+ float pixel_size = get_pixel_size();
+
+ Vector2 vertices[4] = {
+
+ (final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
+ (final_rect.position + final_rect.size) * pixel_size,
+ (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
+ final_rect.position * pixel_size,
+
+ };
+
+ int x_axis = ((axis + 1) % 3);
+ int y_axis = ((axis + 2) % 3);
+
+ if (axis != Vector3::AXIS_Z) {
+ SWAP(x_axis, y_axis);
+
+ for (int i = 0; i < 4; i++) {
+ if (axis == Vector3::AXIS_Y) {
+ vertices[i].y = -vertices[i].y;
+ } else if (axis == Vector3::AXIS_X) {
+ vertices[i].x = -vertices[i].x;
+ }
+ }
+ }
+
+ static const int indices[6] = {
+ 0, 1, 2,
+ 0, 2, 3
+ };
+
+ for (int j = 0; j < 6; j++) {
+ int i = indices[j];
+ Vector3 vtx;
+ vtx[x_axis] = vertices[i][0];
+ vtx[y_axis] = vertices[i][1];
+ facesw[j] = vtx;
+ }
+
+ facesw = PoolVector<Vector3>::Write();
+
+ triangle_mesh = Ref<TriangleMesh>(memnew(TriangleMesh));
+ triangle_mesh->create(faces);
+
+ return triangle_mesh;
+}
+
void SpriteBase3D::set_draw_flag(DrawFlags p_flag, bool p_enable) {
ERR_FAIL_INDEX(p_flag, FLAG_MAX);
@@ -255,6 +318,7 @@ void SpriteBase3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_alpha_cut_mode"), &SpriteBase3D::get_alpha_cut_mode);
ClassDB::bind_method(D_METHOD("get_item_rect"), &SpriteBase3D::get_item_rect);
+ ClassDB::bind_method(D_METHOD("generate_triangle_mesh"), &SpriteBase3D::generate_triangle_mesh);
ClassDB::bind_method(D_METHOD("_queue_update"), &SpriteBase3D::_queue_update);
ClassDB::bind_method(D_METHOD("_im_update"), &SpriteBase3D::_im_update);
@@ -366,6 +430,16 @@ void Sprite3D::_draw() {
final_rect.position * pixel_size,
};
+
+ Vector2 src_tsize = Vector2(texture->get_width(), texture->get_height());
+
+ // Properly setup UVs for impostor textures (AtlasTexture).
+ Ref<AtlasTexture> atlas_tex = texture;
+ if (atlas_tex != NULL) {
+ src_tsize[0] = atlas_tex->get_atlas()->get_width();
+ src_tsize[1] = atlas_tex->get_atlas()->get_height();
+ }
+
Vector2 uvs[4] = {
final_src_rect.position / tsize,
(final_src_rect.position + Vector2(final_src_rect.size.x, 0)) / tsize,
@@ -656,6 +730,16 @@ void AnimatedSprite3D::_draw() {
final_rect.position * pixel_size,
};
+
+ Vector2 src_tsize = Vector2(texture->get_width(), texture->get_height());
+
+ // Properly setup UVs for impostor textures (AtlasTexture).
+ Ref<AtlasTexture> atlas_tex = texture;
+ if (atlas_tex != NULL) {
+ src_tsize[0] = atlas_tex->get_atlas()->get_width();
+ src_tsize[1] = atlas_tex->get_atlas()->get_height();
+ }
+
Vector2 uvs[4] = {
final_src_rect.position / tsize,
(final_src_rect.position + Vector2(final_src_rect.size.x, 0)) / tsize,
@@ -881,7 +965,7 @@ Rect2 AnimatedSprite3D::get_item_rect() const {
return Rect2(0, 0, 1, 1);
Size2i s = t->get_size();
- Point2 ofs = offset;
+ Point2 ofs = get_offset();
if (centered)
ofs -= s / 2;
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index 23e1d96b4b..a4705a8970 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -38,6 +38,8 @@ class SpriteBase3D : public GeometryInstance {
GDCLASS(SpriteBase3D, GeometryInstance);
+ mutable Ref<TriangleMesh> triangle_mesh; //cached
+
public:
enum DrawFlags {
FLAG_TRANSPARENT,
@@ -133,6 +135,7 @@ public:
virtual AABB get_aabb() const;
virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
+ Ref<TriangleMesh> generate_triangle_mesh() const;
SpriteBase3D();
~SpriteBase3D();
@@ -192,7 +195,6 @@ class AnimatedSprite3D : public SpriteBase3D {
int frame;
bool centered;
- Point2 offset;
float timeout;
diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp
index ed3bde9504..385956dc16 100644
--- a/scene/3d/vehicle_body.cpp
+++ b/scene/3d/vehicle_body.cpp
@@ -524,7 +524,7 @@ void VehicleBody::_update_suspension(PhysicsDirectBodyState *s) {
//bilateral constraint between two dynamic objects
void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1,
- PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse) {
+ PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, real_t p_rollInfluence) {
real_t normalLenSqr = normal.length_squared();
//ERR_FAIL_COND( normalLenSqr < real_t(1.1));
@@ -582,8 +582,15 @@ void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vec
rel_vel = normal.dot(vel);
- //TODO: move this into proper structure
- real_t contactDamping = real_t(0.4);
+ // !BAS! We had this set to 0.4, in bullet its 0.2
+ real_t contactDamping = real_t(0.2);
+
+ if (p_rollInfluence > 0.0) {
+ // !BAS! But seeing we apply this frame by frame, makes more sense to me to make this time based
+ // keeping in mind our anti roll factor if it is set
+ contactDamping = s->get_step() / p_rollInfluence;
+ }
+
#define ONLY_USE_LINEAR_MASS
#ifdef ONLY_USE_LINEAR_MASS
real_t massTerm = real_t(1.) / ((1.0 / mass) + b2invmass);
@@ -668,13 +675,8 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
m_forwardImpulse.resize(numWheel);
m_sideImpulse.resize(numWheel);
- int numWheelsOnGround = 0;
-
//collapse all those loops into one!
for (int i = 0; i < wheels.size(); i++) {
- VehicleWheel &wheelInfo = *wheels[i];
- if (wheelInfo.m_raycastInfo.m_isInContact)
- numWheelsOnGround++;
m_sideImpulse[i] = real_t(0.);
m_forwardImpulse[i] = real_t(0.);
}
@@ -704,7 +706,7 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
_resolve_single_bilateral(s, wheelInfo.m_raycastInfo.m_contactPointWS,
wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS,
- m_axle[i], m_sideImpulse[i]);
+ m_axle[i], m_sideImpulse[i], wheelInfo.m_rollInfluence);
m_sideImpulse[i] *= sideFrictionStiffness2;
}
@@ -925,7 +927,7 @@ void VehicleBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_steering"), &VehicleBody::get_steering);
ADD_GROUP("Motion", "");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01"), "set_engine_force", "get_engine_force");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering");
}
diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h
index 7810a42e8a..1ac3693cc4 100644
--- a/scene/3d/vehicle_body.h
+++ b/scene/3d/vehicle_body.h
@@ -168,7 +168,7 @@ class VehicleBody : public RigidBody {
btVehicleWheelContactPoint(PhysicsDirectBodyState *s, PhysicsBody *body1, const Vector3 &frictionPosWorld, const Vector3 &frictionDirectionWorld, real_t maxImpulse);
};
- void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1, PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse);
+ void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1, PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, real_t p_rollInfluence);
real_t _calc_rolling_friction(btVehicleWheelContactPoint &contactPoint);
void _update_friction(PhysicsDirectBodyState *s);
diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp
index d389b69ef3..670df5cc7f 100644
--- a/scene/3d/voxel_light_baker.cpp
+++ b/scene/3d/voxel_light_baker.cpp
@@ -2316,13 +2316,10 @@ Ref<MultiMesh> VoxelLightBaker::create_debug_multimesh(DebugMode p_mode) {
PoolVector<Vector3> vertices;
PoolVector<Color> colors;
-
- int vtx_idx = 0;
#define ADD_VTX(m_idx) \
; \
vertices.push_back(face_points[m_idx]); \
- colors.push_back(Color(1, 1, 1, 1)); \
- vtx_idx++;
+ colors.push_back(Color(1, 1, 1, 1));
for (int i = 0; i < 6; i++) {
@@ -2338,9 +2335,9 @@ Ref<MultiMesh> VoxelLightBaker::create_debug_multimesh(DebugMode p_mode) {
for (int k = 0; k < 3; k++) {
if (i < 3)
- face_points[j][(i + k) % 3] = v[k] * (i >= 3 ? -1 : 1);
+ face_points[j][(i + k) % 3] = v[k];
else
- face_points[3 - j][(i + k) % 3] = v[k] * (i >= 3 ? -1 : 1);
+ face_points[3 - j][(i + k) % 3] = -v[k];
}
}