summaryrefslogtreecommitdiff
path: root/scene/3d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d')
-rw-r--r--scene/3d/SCsub5
-rw-r--r--scene/3d/area_3d.cpp98
-rw-r--r--scene/3d/area_3d.h14
-rw-r--r--scene/3d/audio_listener_3d.cpp (renamed from scene/3d/listener_3d.cpp)69
-rw-r--r--scene/3d/audio_listener_3d.h (renamed from scene/3d/listener_3d.h)14
-rw-r--r--scene/3d/audio_stream_player_3d.cpp727
-rw-r--r--scene/3d/audio_stream_player_3d.h66
-rw-r--r--scene/3d/bone_attachment_3d.cpp320
-rw-r--r--scene/3d/bone_attachment_3d.h39
-rw-r--r--scene/3d/camera_3d.cpp308
-rw-r--r--scene/3d/camera_3d.h119
-rw-r--r--scene/3d/collision_object_3d.cpp89
-rw-r--r--scene/3d/collision_object_3d.h14
-rw-r--r--scene/3d/collision_polygon_3d.cpp3
-rw-r--r--scene/3d/collision_shape_3d.cpp18
-rw-r--r--scene/3d/collision_shape_3d.h1
-rw-r--r--scene/3d/cpu_particles_3d.cpp413
-rw-r--r--scene/3d/cpu_particles_3d.h121
-rw-r--r--scene/3d/decal.cpp28
-rw-r--r--scene/3d/decal.h44
-rw-r--r--scene/3d/gpu_particles_3d.cpp38
-rw-r--r--scene/3d/gpu_particles_3d.h44
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp27
-rw-r--r--scene/3d/gpu_particles_collision_3d.h32
-rw-r--r--scene/3d/importer_mesh_instance_3d.cpp85
-rw-r--r--scene/3d/importer_mesh_instance_3d.h64
-rw-r--r--scene/3d/joint_3d.cpp (renamed from scene/3d/physics_joint_3d.cpp)8
-rw-r--r--scene/3d/joint_3d.h (renamed from scene/3d/physics_joint_3d.h)8
-rw-r--r--scene/3d/light_3d.cpp24
-rw-r--r--scene/3d/light_3d.h10
-rw-r--r--scene/3d/lightmap_gi.cpp11
-rw-r--r--scene/3d/lightmap_gi.h3
-rw-r--r--scene/3d/lightmapper.h5
-rw-r--r--scene/3d/mesh_instance_3d.cpp11
-rw-r--r--scene/3d/mesh_instance_3d.h6
-rw-r--r--scene/3d/navigation_agent_3d.cpp1
-rw-r--r--scene/3d/navigation_agent_3d.h1
-rw-r--r--scene/3d/navigation_obstacle_3d.h1
-rw-r--r--scene/3d/navigation_region_3d.cpp1
-rw-r--r--scene/3d/navigation_region_3d.h1
-rw-r--r--scene/3d/node_3d.cpp30
-rw-r--r--scene/3d/node_3d.h13
-rw-r--r--scene/3d/occluder_instance_3d.cpp24
-rw-r--r--scene/3d/occluder_instance_3d.h5
-rw-r--r--scene/3d/path_3d.cpp37
-rw-r--r--scene/3d/path_3d.h16
-rw-r--r--scene/3d/physics_body_3d.cpp1751
-rw-r--r--scene/3d/physics_body_3d.h304
-rw-r--r--scene/3d/position_3d.cpp1
-rw-r--r--scene/3d/proximity_group_3d.h2
-rw-r--r--scene/3d/ray_cast_3d.cpp22
-rw-r--r--scene/3d/ray_cast_3d.h4
-rw-r--r--scene/3d/reflection_probe.h3
-rw-r--r--scene/3d/skeleton_3d.cpp713
-rw-r--r--scene/3d/skeleton_3d.h106
-rw-r--r--scene/3d/skeleton_ik_3d.cpp20
-rw-r--r--scene/3d/skeleton_ik_3d.h5
-rw-r--r--scene/3d/soft_dynamic_body_3d.cpp (renamed from scene/3d/soft_body_3d.cpp)289
-rw-r--r--scene/3d/soft_dynamic_body_3d.h (renamed from scene/3d/soft_body_3d.h)40
-rw-r--r--scene/3d/spring_arm_3d.cpp37
-rw-r--r--scene/3d/sprite_3d.cpp30
-rw-r--r--scene/3d/sprite_3d.h10
-rw-r--r--scene/3d/vehicle_body_3d.cpp39
-rw-r--r--scene/3d/vehicle_body_3d.h7
-rw-r--r--scene/3d/velocity_tracker_3d.cpp13
-rw-r--r--scene/3d/visible_on_screen_notifier_3d.cpp4
-rw-r--r--scene/3d/visual_instance_3d.cpp28
-rw-r--r--scene/3d/visual_instance_3d.h7
-rw-r--r--scene/3d/voxel_gi.cpp3
-rw-r--r--scene/3d/voxel_gi.h1
-rw-r--r--scene/3d/voxelizer.cpp55
-rw-r--r--scene/3d/voxelizer.h2
-rw-r--r--scene/3d/world_environment.cpp1
-rw-r--r--scene/3d/world_environment.h2
-rw-r--r--scene/3d/xr_nodes.cpp9
-rw-r--r--scene/3d/xr_nodes.h8
76 files changed, 3859 insertions, 2673 deletions
diff --git a/scene/3d/SCsub b/scene/3d/SCsub
index 40bdaee47d..fc61250247 100644
--- a/scene/3d/SCsub
+++ b/scene/3d/SCsub
@@ -2,7 +2,4 @@
Import("env")
-if env["disable_3d"]:
- env.add_source_files(env.scene_sources, "node_3d.cpp")
-else:
- env.add_source_files(env.scene_sources, "*.cpp")
+env.add_source_files(env.scene_sources, "*.cpp")
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index cd64a813dd..7e4c40ca0e 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -32,7 +32,6 @@
#include "scene/scene_string_names.h"
#include "servers/audio_server.h"
-#include "servers/physics_server_3d.h"
void Area3D::set_space_override_mode(SpaceOverride p_mode) {
space_override = p_mode;
@@ -106,6 +105,61 @@ real_t Area3D::get_priority() const {
return priority;
}
+void Area3D::set_wind_force_magnitude(real_t p_wind_force_magnitude) {
+ wind_force_magnitude = p_wind_force_magnitude;
+ if (is_inside_tree()) {
+ _initialize_wind();
+ }
+}
+
+real_t Area3D::get_wind_force_magnitude() const {
+ return wind_force_magnitude;
+}
+
+void Area3D::set_wind_attenuation_factor(real_t p_wind_force_attenuation_factor) {
+ wind_attenuation_factor = p_wind_force_attenuation_factor;
+ if (is_inside_tree()) {
+ _initialize_wind();
+ }
+}
+
+real_t Area3D::get_wind_attenuation_factor() const {
+ return wind_attenuation_factor;
+}
+
+void Area3D::set_wind_source_path(const NodePath &p_wind_source_path) {
+ wind_source_path = p_wind_source_path;
+ if (is_inside_tree()) {
+ _initialize_wind();
+ }
+}
+
+const NodePath &Area3D::get_wind_source_path() const {
+ return wind_source_path;
+}
+
+void Area3D::_initialize_wind() {
+ real_t temp_magnitude = 0.0;
+ Vector3 wind_direction(0., 0., 0.);
+ Vector3 wind_source(0., 0., 0.);
+
+ // Overwrite with area-specified info if available
+ if (!wind_source_path.is_empty()) {
+ Node3D *p_wind_source = Object::cast_to<Node3D>(get_node(wind_source_path));
+ ERR_FAIL_NULL(p_wind_source);
+ Transform3D global_transform = p_wind_source->get_transform();
+ wind_direction = -global_transform.basis.get_axis(Vector3::AXIS_Z).normalized();
+ wind_source = global_transform.origin;
+ temp_magnitude = wind_force_magnitude;
+ }
+
+ // Set force, source and direction in the physics server.
+ PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_WIND_ATTENUATION_FACTOR, wind_attenuation_factor);
+ PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_WIND_SOURCE, wind_source);
+ PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_WIND_DIRECTION, wind_direction);
+ PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_WIND_FORCE_MAGNITUDE, temp_magnitude);
+}
+
void Area3D::_body_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
@@ -208,8 +262,8 @@ void Area3D::_clear_monitoring() {
body_map.clear();
//disconnect all monitored stuff
- for (Map<ObjectID, BodyState>::Element *E = bmcopy.front(); E; E = E->next()) {
- Object *obj = ObjectDB::get_instance(E->key());
+ for (const KeyValue<ObjectID, BodyState> &E : bmcopy) {
+ Object *obj = ObjectDB::get_instance(E.key);
Node *node = Object::cast_to<Node>(obj);
if (!node) { //node may have been deleted in previous frame or at other legitimate point
@@ -220,12 +274,12 @@ void Area3D::_clear_monitoring() {
node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree));
node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree));
- if (!E->get().in_tree) {
+ if (!E.value.in_tree) {
continue;
}
- for (int i = 0; i < E->get().shapes.size(); i++) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
+ for (int i = 0; i < E.value.shapes.size(); i++) {
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E.value.rid, node, E.value.shapes[i].body_shape, E.value.shapes[i].area_shape);
}
emit_signal(SceneStringNames::get_singleton()->body_exited, node);
@@ -237,8 +291,8 @@ void Area3D::_clear_monitoring() {
area_map.clear();
//disconnect all monitored stuff
- for (Map<ObjectID, AreaState>::Element *E = bmcopy.front(); E; E = E->next()) {
- Object *obj = ObjectDB::get_instance(E->key());
+ for (const KeyValue<ObjectID, AreaState> &E : bmcopy) {
+ Object *obj = ObjectDB::get_instance(E.key);
Node *node = Object::cast_to<Node>(obj);
if (!node) { //node may have been deleted in previous frame or at other legitimate point
@@ -249,12 +303,12 @@ void Area3D::_clear_monitoring() {
node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree));
node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree));
- if (!E->get().in_tree) {
+ if (!E.value.in_tree) {
continue;
}
- for (int i = 0; i < E->get().shapes.size(); i++) {
- emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E->get().rid, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
+ for (int i = 0; i < E.value.shapes.size(); i++) {
+ emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E.value.rid, node, E.value.shapes[i].area_shape, E.value.shapes[i].self_shape);
}
emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
@@ -265,6 +319,8 @@ void Area3D::_clear_monitoring() {
void Area3D::_notification(int p_what) {
if (p_what == NOTIFICATION_EXIT_TREE) {
_clear_monitoring();
+ } else if (p_what == NOTIFICATION_ENTER_TREE) {
+ _initialize_wind();
}
}
@@ -390,8 +446,8 @@ TypedArray<Node3D> Area3D::get_overlapping_bodies() const {
Array ret;
ret.resize(body_map.size());
int idx = 0;
- for (const Map<ObjectID, BodyState>::Element *E = body_map.front(); E; E = E->next()) {
- Object *obj = ObjectDB::get_instance(E->key());
+ for (const KeyValue<ObjectID, BodyState> &E : body_map) {
+ Object *obj = ObjectDB::get_instance(E.key);
if (!obj) {
ret.resize(ret.size() - 1); //ops
} else {
@@ -423,8 +479,8 @@ TypedArray<Area3D> Area3D::get_overlapping_areas() const {
Array ret;
ret.resize(area_map.size());
int idx = 0;
- for (const Map<ObjectID, AreaState>::Element *E = area_map.front(); E; E = E->next()) {
- Object *obj = ObjectDB::get_instance(E->key());
+ for (const KeyValue<ObjectID, AreaState> &E : area_map) {
+ Object *obj = ObjectDB::get_instance(E.key);
if (!obj) {
ret.resize(ret.size() - 1); //ops
} else {
@@ -551,6 +607,15 @@ void Area3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_priority", "priority"), &Area3D::set_priority);
ClassDB::bind_method(D_METHOD("get_priority"), &Area3D::get_priority);
+ ClassDB::bind_method(D_METHOD("set_wind_force_magnitude", "wind_force_magnitude"), &Area3D::set_wind_force_magnitude);
+ ClassDB::bind_method(D_METHOD("get_wind_force_magnitude"), &Area3D::get_wind_force_magnitude);
+
+ ClassDB::bind_method(D_METHOD("set_wind_attenuation_factor", "wind_attenuation_factor"), &Area3D::set_wind_attenuation_factor);
+ ClassDB::bind_method(D_METHOD("get_wind_attenuation_factor"), &Area3D::get_wind_attenuation_factor);
+
+ ClassDB::bind_method(D_METHOD("set_wind_source_path", "wind_source_path"), &Area3D::set_wind_source_path);
+ ClassDB::bind_method(D_METHOD("get_wind_source_path"), &Area3D::get_wind_source_path);
+
ClassDB::bind_method(D_METHOD("set_monitorable", "enable"), &Area3D::set_monitorable);
ClassDB::bind_method(D_METHOD("is_monitorable"), &Area3D::is_monitorable);
@@ -606,6 +671,9 @@ void Area3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, "-32,32,0.001,or_lesser,or_greater"), "set_gravity", "get_gravity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wind_force_magnitude", PROPERTY_HINT_RANGE, "0,10,0.001,or_greater"), "set_wind_force_magnitude", "get_wind_force_magnitude");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wind_attenuation_factor", PROPERTY_HINT_RANGE, "0.0,3.0,0.001,or_greater"), "set_wind_attenuation_factor", "get_wind_attenuation_factor");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "wind_source_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_wind_source_path", "get_wind_source_path");
ADD_GROUP("Audio Bus", "audio_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_bus_override"), "set_audio_bus_override", "is_overriding_audio_bus");
diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h
index 5b8d612717..847d1c5966 100644
--- a/scene/3d/area_3d.h
+++ b/scene/3d/area_3d.h
@@ -55,6 +55,9 @@ private:
real_t angular_damp = 0.1;
real_t linear_damp = 0.1;
int priority = 0;
+ real_t wind_force_magnitude = 0.0;
+ real_t wind_attenuation_factor = 0.0;
+ NodePath wind_source_path;
bool monitoring = false;
bool monitorable = false;
bool locked = false;
@@ -134,6 +137,8 @@ private:
void _validate_property(PropertyInfo &property) const override;
+ void _initialize_wind();
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -163,6 +168,15 @@ public:
void set_priority(real_t p_priority);
real_t get_priority() const;
+ void set_wind_force_magnitude(real_t p_wind_force_magnitude);
+ real_t get_wind_force_magnitude() const;
+
+ void set_wind_attenuation_factor(real_t p_wind_attenuation_factor);
+ real_t get_wind_attenuation_factor() const;
+
+ void set_wind_source_path(const NodePath &p_wind_source_path);
+ const NodePath &get_wind_source_path() const;
+
void set_monitoring(bool p_enable);
bool is_monitoring() const;
diff --git a/scene/3d/listener_3d.cpp b/scene/3d/audio_listener_3d.cpp
index 636be083ab..b2319e40d7 100644
--- a/scene/3d/listener_3d.cpp
+++ b/scene/3d/audio_listener_3d.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* listener_3d.cpp */
+/* audio_listener_3d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,18 +28,18 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "listener_3d.h"
+#include "audio_listener_3d.h"
-#include "scene/resources/mesh.h"
+#include "scene/main/viewport.h"
-void Listener3D::_update_audio_listener_state() {
+void AudioListener3D::_update_audio_listener_state() {
}
-void Listener3D::_request_listener_update() {
+void AudioListener3D::_request_listener_update() {
_update_listener();
}
-bool Listener3D::_set(const StringName &p_name, const Variant &p_value) {
+bool AudioListener3D::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == "current") {
if (p_value.operator bool()) {
make_current();
@@ -53,7 +53,7 @@ bool Listener3D::_set(const StringName &p_name, const Variant &p_value) {
return true;
}
-bool Listener3D::_get(const StringName &p_name, Variant &r_ret) const {
+bool AudioListener3D::_get(const StringName &p_name, Variant &r_ret) const {
if (p_name == "current") {
if (is_inside_tree() && get_tree()->is_node_being_edited(this)) {
r_ret = current;
@@ -67,20 +67,20 @@ bool Listener3D::_get(const StringName &p_name, Variant &r_ret) const {
return true;
}
-void Listener3D::_get_property_list(List<PropertyInfo> *p_list) const {
+void AudioListener3D::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, "current"));
}
-void Listener3D::_update_listener() {
+void AudioListener3D::_update_listener() {
if (is_inside_tree() && is_current()) {
- get_viewport()->_listener_transform_changed_notify();
+ get_viewport()->_listener_transform_3d_changed_notify();
}
}
-void Listener3D::_notification(int p_what) {
+void AudioListener3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_WORLD: {
- bool first_listener = get_viewport()->_listener_add(this);
+ bool first_listener = get_viewport()->_audio_listener_3d_add(this);
if (!get_tree()->is_node_being_edited(this) && (current || first_listener)) {
make_current();
}
@@ -99,41 +99,41 @@ void Listener3D::_notification(int p_what) {
}
}
- get_viewport()->_listener_remove(this);
+ get_viewport()->_audio_listener_3d_remove(this);
} break;
}
}
-Transform3D Listener3D::get_listener_transform() const {
+Transform3D AudioListener3D::get_listener_transform() const {
return get_global_transform().orthonormalized();
}
-void Listener3D::make_current() {
+void AudioListener3D::make_current() {
current = true;
if (!is_inside_tree()) {
return;
}
- get_viewport()->_listener_set(this);
+ get_viewport()->_audio_listener_3d_set(this);
}
-void Listener3D::clear_current() {
+void AudioListener3D::clear_current() {
current = false;
if (!is_inside_tree()) {
return;
}
- if (get_viewport()->get_listener() == this) {
- get_viewport()->_listener_set(nullptr);
- get_viewport()->_listener_make_next_current(this);
+ if (get_viewport()->get_audio_listener_3d() == this) {
+ get_viewport()->_audio_listener_3d_set(nullptr);
+ get_viewport()->_audio_listener_3d_make_next_current(this);
}
}
-bool Listener3D::is_current() const {
+bool AudioListener3D::is_current() const {
if (is_inside_tree() && !get_tree()->is_node_being_edited(this)) {
- return get_viewport()->get_listener() == this;
+ return get_viewport()->get_audio_listener_3d() == this;
} else {
return current;
}
@@ -141,27 +141,16 @@ bool Listener3D::is_current() const {
return false;
}
-bool Listener3D::_can_gizmo_scale() const {
- return false;
-}
-
-RES Listener3D::_get_gizmo_geometry() const {
- Ref<ArrayMesh> mesh = memnew(ArrayMesh);
-
- return mesh;
-}
-
-void Listener3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("make_current"), &Listener3D::make_current);
- ClassDB::bind_method(D_METHOD("clear_current"), &Listener3D::clear_current);
- ClassDB::bind_method(D_METHOD("is_current"), &Listener3D::is_current);
- ClassDB::bind_method(D_METHOD("get_listener_transform"), &Listener3D::get_listener_transform);
+void AudioListener3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("make_current"), &AudioListener3D::make_current);
+ ClassDB::bind_method(D_METHOD("clear_current"), &AudioListener3D::clear_current);
+ ClassDB::bind_method(D_METHOD("is_current"), &AudioListener3D::is_current);
+ ClassDB::bind_method(D_METHOD("get_listener_transform"), &AudioListener3D::get_listener_transform);
}
-Listener3D::Listener3D() {
+AudioListener3D::AudioListener3D() {
set_notify_transform(true);
- //active=false;
}
-Listener3D::~Listener3D() {
+AudioListener3D::~AudioListener3D() {
}
diff --git a/scene/3d/listener_3d.h b/scene/3d/audio_listener_3d.h
index bcc66f167c..492cacb0e9 100644
--- a/scene/3d/listener_3d.h
+++ b/scene/3d/audio_listener_3d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* listener_3d.h */
+/* audio_listener_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -32,10 +32,9 @@
#define LISTENER_3D_H
#include "scene/3d/node_3d.h"
-#include "scene/main/window.h"
-class Listener3D : public Node3D {
- GDCLASS(Listener3D, Node3D);
+class AudioListener3D : public Node3D {
+ GDCLASS(AudioListener3D, Node3D);
private:
bool force_change = false;
@@ -43,9 +42,6 @@ private:
RID scenario_id;
- virtual bool _can_gizmo_scale() const;
- virtual RES _get_gizmo_geometry() const;
-
friend class Viewport;
void _update_audio_listener_state();
@@ -70,8 +66,8 @@ public:
void set_visible_layers(uint32_t p_layers);
uint32_t get_visible_layers() const;
- Listener3D();
- ~Listener3D();
+ AudioListener3D();
+ ~AudioListener3D();
};
#endif
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index bb8f9f8ccb..a54b10ba70 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -30,11 +30,10 @@
#include "audio_stream_player_3d.h"
-#include "core/config/engine.h"
#include "scene/3d/area_3d.h"
+#include "scene/3d/audio_listener_3d.h"
#include "scene/3d/camera_3d.h"
-#include "scene/3d/listener_3d.h"
-#include "scene/main/window.h"
+#include "scene/main/viewport.h"
// Based on "A Novel Multichannel Panning Method for Standard and Arbitrary Loudspeaker Configurations" by Ramy Sadek and Chris Kyriakakis (2004)
// Speaker-Placement Correction Amplitude Panning (SPCAP)
@@ -96,7 +95,7 @@ static const Vector3 speaker_directions[7] = {
Vector3(1.0, 0.0, 0.0).normalized(), // side-right
};
-void AudioStreamPlayer3D::_calc_output_vol(const Vector3 &source_dir, real_t tightness, AudioStreamPlayer3D::Output &output) {
+void AudioStreamPlayer3D::_calc_output_vol(const Vector3 &source_dir, real_t tightness, Vector<AudioFrame> &output) {
unsigned int speaker_count = 0; // only main speakers (no LFE)
switch (AudioServer::get_singleton()->get_speaker_mode()) {
case AudioServer::SPEAKER_MODE_STEREO:
@@ -119,182 +118,94 @@ void AudioStreamPlayer3D::_calc_output_vol(const Vector3 &source_dir, real_t tig
switch (AudioServer::get_singleton()->get_speaker_mode()) {
case AudioServer::SPEAKER_SURROUND_71:
- output.vol[3].l = volumes[5]; // side-left
- output.vol[3].r = volumes[6]; // side-right
+ output.write[3].l = volumes[5]; // side-left
+ output.write[3].r = volumes[6]; // side-right
[[fallthrough]];
case AudioServer::SPEAKER_SURROUND_51:
- output.vol[2].l = volumes[3]; // rear-left
- output.vol[2].r = volumes[4]; // rear-right
+ output.write[2].l = volumes[3]; // rear-left
+ output.write[2].r = volumes[4]; // rear-right
[[fallthrough]];
case AudioServer::SPEAKER_SURROUND_31:
- output.vol[1].r = 1.0; // LFE - always full power
- output.vol[1].l = volumes[2]; // center
+ output.write[1].r = 1.0; // LFE - always full power
+ output.write[1].l = volumes[2]; // center
[[fallthrough]];
case AudioServer::SPEAKER_MODE_STEREO:
- output.vol[0].r = volumes[1]; // front-right
- output.vol[0].l = volumes[0]; // front-left
+ output.write[0].r = volumes[1]; // front-right
+ output.write[0].l = volumes[0]; // front-left
break;
}
}
-void AudioStreamPlayer3D::_mix_audio() {
- if (!stream_playback.is_valid() || !active.is_set() ||
- (stream_paused && !stream_paused_fade_out)) {
- return;
- }
-
- bool started = false;
- if (setseek.get() >= 0.0) {
- stream_playback->start(setseek.get());
- setseek.set(-1.0); //reset seek
- started = true;
- }
+void AudioStreamPlayer3D::_calc_reverb_vol(Area3D *area, Vector3 listener_area_pos, Vector<AudioFrame> direct_path_vol, Vector<AudioFrame> &reverb_vol) {
+ reverb_vol.resize(4);
+ reverb_vol.write[0] = AudioFrame(0, 0);
+ reverb_vol.write[1] = AudioFrame(0, 0);
+ reverb_vol.write[2] = AudioFrame(0, 0);
+ reverb_vol.write[3] = AudioFrame(0, 0);
- //get data
- AudioFrame *buffer = mix_buffer.ptrw();
- int buffer_size = mix_buffer.size();
+ float uniformity = area->get_reverb_uniformity();
+ float area_send = area->get_reverb_amount();
- if (stream_paused_fade_out) {
- // Short fadeout ramp
- buffer_size = MIN(buffer_size, 128);
- }
-
- // Mix if we're not paused or we're fading out
- if ((output_count.get() > 0 || out_of_range_mode == OUT_OF_RANGE_MIX)) {
- float output_pitch_scale = 0.0;
- if (output_count.get()) {
- //used for doppler, not realistic but good enough
- for (int i = 0; i < output_count.get(); i++) {
- output_pitch_scale += outputs[i].pitch_scale;
- }
- output_pitch_scale /= float(output_count.get());
- } else {
- output_pitch_scale = 1.0;
- }
+ if (uniformity > 0.0) {
+ float distance = listener_area_pos.length();
+ float attenuation = Math::db2linear(_get_attenuation_db(distance));
- stream_playback->mix(buffer, pitch_scale * output_pitch_scale, buffer_size);
- }
+ // Determine the fraction of sound that would come from each speaker if they were all driven uniformly.
+ float center_val[3] = { 0.5f, 0.25f, 0.16666f };
+ int channel_count = AudioServer::get_singleton()->get_channel_count();
+ AudioFrame center_frame(center_val[channel_count - 1], center_val[channel_count - 1]);
- //write all outputs
- for (int i = 0; i < output_count.get(); i++) {
- Output current = outputs[i];
+ if (attenuation < 1.0) {
+ //pan the uniform sound
+ Vector3 rev_pos = listener_area_pos;
+ rev_pos.y = 0;
+ rev_pos.normalize();
- //see if current output exists, to keep volume ramp
- bool found = false;
- for (int j = i; j < prev_output_count; j++) {
- if (prev_outputs[j].viewport == current.viewport) {
- if (j != i) {
- SWAP(prev_outputs[j], prev_outputs[i]);
- }
- found = true;
- break;
+ if (channel_count >= 1) {
+ // Stereo pair
+ float c = rev_pos.x * 0.5 + 0.5;
+ reverb_vol.write[0].l = 1.0 - c;
+ reverb_vol.write[0].r = c;
}
- }
- bool interpolate_filter = !started;
+ if (channel_count >= 3) {
+ // Center pair + Side pair
+ float xl = Vector3(-1, 0, -1).normalized().dot(rev_pos) * 0.5 + 0.5;
+ float xr = Vector3(1, 0, -1).normalized().dot(rev_pos) * 0.5 + 0.5;
- if (!found) {
- //create new if was not used before
- if (prev_output_count < MAX_OUTPUTS) {
- prev_outputs[prev_output_count] = prev_outputs[i]; //may be owned by another viewport
- prev_output_count++;
+ reverb_vol.write[1].l = xl;
+ reverb_vol.write[1].r = xr;
+ reverb_vol.write[2].l = 1.0 - xr;
+ reverb_vol.write[2].r = 1.0 - xl;
}
- prev_outputs[i] = current;
- interpolate_filter = false;
- }
-
- //mix!
-
- int buffers = AudioServer::get_singleton()->get_channel_count();
-
- for (int k = 0; k < buffers; k++) {
- AudioFrame target_volume = stream_paused_fade_out ? AudioFrame(0.f, 0.f) : current.vol[k];
- AudioFrame vol_prev = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : prev_outputs[i].vol[k];
- AudioFrame vol_inc = (target_volume - vol_prev) / float(buffer_size);
- AudioFrame vol = vol_prev;
- if (!AudioServer::get_singleton()->thread_has_channel_mix_buffer(current.bus_index, k)) {
- continue; //may have been deleted, will be updated on process
+ if (channel_count >= 4) {
+ // Rear pair
+ // FIXME: Not sure what math should be done here
+ float c = rev_pos.x * 0.5 + 0.5;
+ reverb_vol.write[3].l = 1.0 - c;
+ reverb_vol.write[3].r = c;
}
- AudioFrame *target = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, k);
- current.filter.set_mode(AudioFilterSW::HIGHSHELF);
- current.filter.set_sampling_rate(AudioServer::get_singleton()->get_mix_rate());
- current.filter.set_cutoff(attenuation_filter_cutoff_hz);
- current.filter.set_resonance(1);
- current.filter.set_stages(1);
- current.filter.set_gain(current.filter_gain);
-
- if (interpolate_filter) {
- current.filter_process[k * 2 + 0] = prev_outputs[i].filter_process[k * 2 + 0];
- current.filter_process[k * 2 + 1] = prev_outputs[i].filter_process[k * 2 + 1];
-
- current.filter_process[k * 2 + 0].set_filter(&current.filter, false);
- current.filter_process[k * 2 + 1].set_filter(&current.filter, false);
-
- current.filter_process[k * 2 + 0].update_coeffs(buffer_size);
- current.filter_process[k * 2 + 1].update_coeffs(buffer_size);
- for (int j = 0; j < buffer_size; j++) {
- AudioFrame f = buffer[j] * vol;
- current.filter_process[k * 2 + 0].process_one_interp(f.l);
- current.filter_process[k * 2 + 1].process_one_interp(f.r);
-
- target[j] += f;
- vol += vol_inc;
- }
- } else {
- current.filter_process[k * 2 + 0].set_filter(&current.filter);
- current.filter_process[k * 2 + 1].set_filter(&current.filter);
-
- current.filter_process[k * 2 + 0].update_coeffs();
- current.filter_process[k * 2 + 1].update_coeffs();
- for (int j = 0; j < buffer_size; j++) {
- AudioFrame f = buffer[j] * vol;
- current.filter_process[k * 2 + 0].process_one(f.l);
- current.filter_process[k * 2 + 1].process_one(f.r);
-
- target[j] += f;
- vol += vol_inc;
- }
+ for (int i = 0; i < channel_count; i++) {
+ reverb_vol.write[i] = reverb_vol[i].lerp(center_frame, attenuation);
}
-
- if (current.reverb_bus_index >= 0) {
- if (!AudioServer::get_singleton()->thread_has_channel_mix_buffer(current.reverb_bus_index, k)) {
- continue; //may have been deleted, will be updated on process
- }
-
- AudioFrame *rtarget = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.reverb_bus_index, k);
-
- if (current.reverb_bus_index == prev_outputs[i].reverb_bus_index) {
- AudioFrame rvol_inc = (current.reverb_vol[k] - prev_outputs[i].reverb_vol[k]) / float(buffer_size);
- AudioFrame rvol = prev_outputs[i].reverb_vol[k];
-
- for (int j = 0; j < buffer_size; j++) {
- rtarget[j] += buffer[j] * rvol;
- rvol += rvol_inc;
- }
- } else {
- AudioFrame rvol = current.reverb_vol[k];
- for (int j = 0; j < buffer_size; j++) {
- rtarget[j] += buffer[j] * rvol;
- }
- }
+ } else {
+ for (int i = 0; i < channel_count; i++) {
+ reverb_vol.write[i] = center_frame;
}
}
- prev_outputs[i] = current;
- }
-
- prev_output_count = output_count.get();
+ for (int i = 0; i < channel_count; i++) {
+ reverb_vol.write[i] = direct_path_vol[i].lerp(reverb_vol[i] * attenuation, uniformity);
+ reverb_vol.write[i] *= area_send;
+ }
- //stream is no longer active, disable this.
- if (!stream_playback->is_playing()) {
- active.clear();
+ } else {
+ for (int i = 0; i < 4; i++) {
+ reverb_vol.write[i] = direct_path_vol[i] * area_send;
+ }
}
-
- output_ready.clear();
- stream_paused_fade_in = false;
- stream_paused_fade_out = false;
}
float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const {
@@ -330,14 +241,15 @@ float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const {
void AudioStreamPlayer3D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
velocity_tracker->reset(get_global_transform().origin);
- AudioServer::get_singleton()->add_callback(_mix_audios, this);
+ AudioServer::get_singleton()->add_listener_changed_callback(_listener_changed_cb, this);
if (autoplay && !Engine::get_singleton()->is_editor_hint()) {
play();
}
}
if (p_what == NOTIFICATION_EXIT_TREE) {
- AudioServer::get_singleton()->remove_callback(_mix_audios, this);
+ stop();
+ AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this);
}
if (p_what == NOTIFICATION_PAUSED) {
@@ -359,281 +271,240 @@ void AudioStreamPlayer3D::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
//update anything related to position first, if possible of course
+ Vector<AudioFrame> volume_vector;
+ if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count())) {
+ volume_vector = _update_panning();
+ }
- if (!output_ready.is_set()) {
- Vector3 linear_velocity;
+ if (setplay.get() >= 0 && stream.is_valid()) {
+ active.set();
+ Ref<AudioStreamPlayback> new_playback = stream->instance_playback();
+ ERR_FAIL_COND_MSG(new_playback.is_null(), "Failed to instantiate playback.");
+ Map<StringName, Vector<AudioFrame>> bus_map;
+ bus_map[_get_actual_bus()] = volume_vector;
+ AudioServer::get_singleton()->start_playback_stream(new_playback, bus_map, setplay.get(), linear_attenuation, attenuation_filter_cutoff_hz, actual_pitch_scale);
+ stream_playbacks.push_back(new_playback);
+ setplay.set(-1);
+ }
- //compute linear velocity for doppler
- if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
- linear_velocity = velocity_tracker->get_tracked_linear_velocity();
+ if (!stream_playbacks.is_empty() && active.is_set()) {
+ // Stop playing if no longer active.
+ Vector<Ref<AudioStreamPlayback>> playbacks_to_remove;
+ for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
+ if (playback.is_valid() && !AudioServer::get_singleton()->is_playback_active(playback) && !AudioServer::get_singleton()->is_playback_paused(playback)) {
+ emit_signal(SNAME("finished"));
+ playbacks_to_remove.push_back(playback);
+ }
}
+ // Now go through and remove playbacks that have finished. Removing elements from a Vector in a range based for is asking for trouble.
+ for (Ref<AudioStreamPlayback> &playback : playbacks_to_remove) {
+ stream_playbacks.erase(playback);
+ }
+ if (!playbacks_to_remove.is_empty() && stream_playbacks.is_empty()) {
+ // This node is no longer actively playing audio.
+ active.clear();
+ set_physics_process_internal(false);
+ }
+ }
- Ref<World3D> world_3d = get_world_3d();
- ERR_FAIL_COND(world_3d.is_null());
-
- int new_output_count = 0;
-
- Vector3 global_pos = get_global_transform().origin;
+ while (stream_playbacks.size() > max_polyphony) {
+ AudioServer::get_singleton()->stop_playback_stream(stream_playbacks[0]);
+ stream_playbacks.remove(0);
+ }
+ }
+}
- int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
+Area3D *AudioStreamPlayer3D::_get_overriding_area() {
+ //check if any area is diverting sound into a bus
+ Ref<World3D> world_3d = get_world_3d();
+ ERR_FAIL_COND_V(world_3d.is_null(), nullptr);
- //check if any area is diverting sound into a bus
+ Vector3 global_pos = get_global_transform().origin;
- PhysicsDirectSpaceState3D *space_state = PhysicsServer3D::get_singleton()->space_get_direct_state(world_3d->get_space());
+ PhysicsDirectSpaceState3D *space_state = PhysicsServer3D::get_singleton()->space_get_direct_state(world_3d->get_space());
- PhysicsDirectSpaceState3D::ShapeResult sr[MAX_INTERSECT_AREAS];
+ PhysicsDirectSpaceState3D::ShapeResult sr[MAX_INTERSECT_AREAS];
- int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, false, true);
- Area3D *area = nullptr;
+ int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, false, true);
- for (int i = 0; i < areas; i++) {
- if (!sr[i].collider) {
- continue;
- }
+ for (int i = 0; i < areas; i++) {
+ if (!sr[i].collider) {
+ continue;
+ }
- Area3D *tarea = Object::cast_to<Area3D>(sr[i].collider);
- if (!tarea) {
- continue;
- }
+ Area3D *tarea = Object::cast_to<Area3D>(sr[i].collider);
+ if (!tarea) {
+ continue;
+ }
- if (!tarea->is_overriding_audio_bus() && !tarea->is_using_reverb_bus()) {
- continue;
- }
+ if (!tarea->is_overriding_audio_bus() && !tarea->is_using_reverb_bus()) {
+ continue;
+ }
- area = tarea;
- break;
- }
+ return tarea;
+ }
+ return nullptr;
+}
- for (const Set<Camera3D *>::Element *E = world_3d->get_cameras().front(); E; E = E->next()) {
- Camera3D *camera = E->get();
- Viewport *vp = camera->get_viewport();
- if (!vp->is_audio_listener()) {
- continue;
- }
+StringName AudioStreamPlayer3D::_get_actual_bus() {
+ Area3D *overriding_area = _get_overriding_area();
+ if (overriding_area && overriding_area->is_overriding_audio_bus() && !overriding_area->is_using_reverb_bus()) {
+ return overriding_area->get_audio_bus_name();
+ }
+ return bus;
+}
- bool listener_is_camera = true;
- Node3D *listener_node = camera;
+Vector<AudioFrame> AudioStreamPlayer3D::_update_panning() {
+ Vector<AudioFrame> output_volume_vector;
+ output_volume_vector.resize(4);
+ for (AudioFrame &frame : output_volume_vector) {
+ frame = AudioFrame(0, 0);
+ }
- Listener3D *listener = vp->get_listener();
- if (listener) {
- listener_node = listener;
- listener_is_camera = false;
- }
+ if (!active.is_set() || stream.is_null()) {
+ return output_volume_vector;
+ }
- Vector3 local_pos = listener_node->get_global_transform().orthonormalized().affine_inverse().xform(global_pos);
+ Vector3 linear_velocity;
- float dist = local_pos.length();
+ //compute linear velocity for doppler
+ if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
+ linear_velocity = velocity_tracker->get_tracked_linear_velocity();
+ }
- Vector3 area_sound_pos;
- Vector3 listener_area_pos;
+ Vector3 global_pos = get_global_transform().origin;
- if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) {
- area_sound_pos = space_state->get_closest_point_to_object_volume(area->get_rid(), listener_node->get_global_transform().origin);
- listener_area_pos = listener_node->get_global_transform().affine_inverse().xform(area_sound_pos);
- }
+ Ref<World3D> world_3d = get_world_3d();
+ ERR_FAIL_COND_V(world_3d.is_null(), output_volume_vector);
- if (max_distance > 0) {
- float total_max = max_distance;
+ Set<Camera3D *> cameras = world_3d->get_cameras();
+ cameras.insert(get_viewport()->get_camera_3d());
- if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) {
- total_max = MAX(total_max, listener_area_pos.length());
- }
- if (total_max > max_distance) {
- continue; //can't hear this sound in this listener
- }
- }
+ PhysicsDirectSpaceState3D *space_state = PhysicsServer3D::get_singleton()->space_get_direct_state(world_3d->get_space());
- float multiplier = Math::db2linear(_get_attenuation_db(dist));
- if (max_distance > 0) {
- multiplier *= MAX(0, 1.0 - (dist / max_distance));
- }
+ for (Camera3D *camera : cameras) {
+ Viewport *vp = camera->get_viewport();
+ if (!vp->is_audio_listener_3d()) {
+ continue;
+ }
- Output output;
- output.bus_index = bus_index;
- output.reverb_bus_index = -1; //no reverb by default
- output.viewport = vp;
+ bool listener_is_camera = true;
+ Node3D *listener_node = camera;
- float db_att = (1.0 - MIN(1.0, multiplier)) * attenuation_filter_db;
+ AudioListener3D *listener = vp->get_audio_listener_3d();
+ if (listener) {
+ listener_node = listener;
+ listener_is_camera = false;
+ }
- if (emission_angle_enabled) {
- Vector3 listenertopos = global_pos - listener_node->get_global_transform().origin;
- float c = listenertopos.normalized().dot(get_global_transform().basis.get_axis(2).normalized()); //it's z negative
- float angle = Math::rad2deg(Math::acos(c));
- if (angle > emission_angle) {
- db_att -= -emission_angle_filter_attenuation_db;
- }
- }
+ Vector3 local_pos = listener_node->get_global_transform().orthonormalized().affine_inverse().xform(global_pos);
- output.filter_gain = Math::db2linear(db_att);
+ float dist = local_pos.length();
- //TODO: The lower the second parameter (tightness) the more the sound will "enclose" the listener (more undirected / playing from
- // speakers not facing the source) - this could be made distance dependent.
- _calc_output_vol(local_pos.normalized(), 4.0, output);
+ Vector3 area_sound_pos;
+ Vector3 listener_area_pos;
- unsigned int cc = AudioServer::get_singleton()->get_channel_count();
- for (unsigned int k = 0; k < cc; k++) {
- output.vol[k] *= multiplier;
- }
+ Area3D *area = _get_overriding_area();
- bool filled_reverb = false;
- int vol_index_max = AudioServer::get_singleton()->get_speaker_mode() + 1;
-
- if (area) {
- if (area->is_overriding_audio_bus()) {
- //override audio bus
- StringName bus_name = area->get_audio_bus_name();
- output.bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus_name);
- }
-
- if (area->is_using_reverb_bus()) {
- filled_reverb = true;
- StringName bus_name = area->get_reverb_bus();
- output.reverb_bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus_name);
-
- float uniformity = area->get_reverb_uniformity();
- float area_send = area->get_reverb_amount();
-
- if (uniformity > 0.0) {
- float distance = listener_area_pos.length();
- float attenuation = Math::db2linear(_get_attenuation_db(distance));
-
- //float dist_att_db = -20 * Math::log(dist + 0.00001); //logarithmic attenuation, like in real life
-
- float center_val[3] = { 0.5f, 0.25f, 0.16666f };
- AudioFrame center_frame(center_val[vol_index_max - 1], center_val[vol_index_max - 1]);
-
- if (attenuation < 1.0) {
- //pan the uniform sound
- Vector3 rev_pos = listener_area_pos;
- rev_pos.y = 0;
- rev_pos.normalize();
-
- if (cc >= 1) {
- // Stereo pair
- float c = rev_pos.x * 0.5 + 0.5;
- output.reverb_vol[0].l = 1.0 - c;
- output.reverb_vol[0].r = c;
- }
-
- if (cc >= 3) {
- // Center pair + Side pair
- float xl = Vector3(-1, 0, -1).normalized().dot(rev_pos) * 0.5 + 0.5;
- float xr = Vector3(1, 0, -1).normalized().dot(rev_pos) * 0.5 + 0.5;
-
- output.reverb_vol[1].l = xl;
- output.reverb_vol[1].r = xr;
- output.reverb_vol[2].l = 1.0 - xr;
- output.reverb_vol[2].r = 1.0 - xl;
- }
-
- if (cc >= 4) {
- // Rear pair
- // FIXME: Not sure what math should be done here
- float c = rev_pos.x * 0.5 + 0.5;
- output.reverb_vol[3].l = 1.0 - c;
- output.reverb_vol[3].r = c;
- }
-
- for (int i = 0; i < vol_index_max; i++) {
- output.reverb_vol[i] = output.reverb_vol[i].lerp(center_frame, attenuation);
- }
- } else {
- for (int i = 0; i < vol_index_max; i++) {
- output.reverb_vol[i] = center_frame;
- }
- }
-
- for (int i = 0; i < vol_index_max; i++) {
- output.reverb_vol[i] = output.vol[i].lerp(output.reverb_vol[i] * attenuation, uniformity);
- output.reverb_vol[i] *= area_send;
- }
-
- } else {
- for (int i = 0; i < vol_index_max; i++) {
- output.reverb_vol[i] = output.vol[i] * area_send;
- }
- }
- }
- }
+ if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) {
+ area_sound_pos = space_state->get_closest_point_to_object_volume(area->get_rid(), listener_node->get_global_transform().origin);
+ listener_area_pos = listener_node->get_global_transform().affine_inverse().xform(area_sound_pos);
+ }
- if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
- Vector3 listener_velocity;
+ if (max_distance > 0) {
+ float total_max = max_distance;
- if (listener_is_camera) {
- listener_velocity = camera->get_doppler_tracked_velocity();
- }
+ if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) {
+ total_max = MAX(total_max, listener_area_pos.length());
+ }
+ if (total_max > max_distance) {
+ continue; //can't hear this sound in this listener
+ }
+ }
- Vector3 local_velocity = listener_node->get_global_transform().orthonormalized().basis.xform_inv(linear_velocity - listener_velocity);
+ float multiplier = Math::db2linear(_get_attenuation_db(dist));
+ if (max_distance > 0) {
+ multiplier *= MAX(0, 1.0 - (dist / max_distance));
+ }
- if (local_velocity == Vector3()) {
- output.pitch_scale = 1.0;
- } else {
- float approaching = local_pos.normalized().dot(local_velocity.normalized());
- float velocity = local_velocity.length();
- float speed_of_sound = 343.0;
+ float db_att = (1.0 - MIN(1.0, multiplier)) * attenuation_filter_db;
- output.pitch_scale = speed_of_sound / (speed_of_sound + velocity * approaching);
- output.pitch_scale = CLAMP(output.pitch_scale, (1 / 8.0), 8.0); //avoid crazy stuff
- }
+ if (emission_angle_enabled) {
+ Vector3 listenertopos = global_pos - listener_node->get_global_transform().origin;
+ float c = listenertopos.normalized().dot(get_global_transform().basis.get_axis(2).normalized()); //it's z negative
+ float angle = Math::rad2deg(Math::acos(c));
+ if (angle > emission_angle) {
+ db_att -= -emission_angle_filter_attenuation_db;
+ }
+ }
- } else {
- output.pitch_scale = 1.0;
- }
+ linear_attenuation = Math::db2linear(db_att);
+ for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
+ AudioServer::get_singleton()->set_playback_highshelf_params(playback, linear_attenuation, attenuation_filter_cutoff_hz);
+ }
+ //TODO: The lower the second parameter (tightness) the more the sound will "enclose" the listener (more undirected / playing from
+ // speakers not facing the source) - this could be made distance dependent.
+ _calc_output_vol(local_pos.normalized(), 4.0, output_volume_vector);
- if (!filled_reverb) {
- for (int i = 0; i < vol_index_max; i++) {
- output.reverb_vol[i] = AudioFrame(0, 0);
- }
- }
+ for (unsigned int k = 0; k < 4; k++) {
+ output_volume_vector.write[k] = multiplier * output_volume_vector[k];
+ }
- outputs[new_output_count] = output;
- new_output_count++;
- if (new_output_count == MAX_OUTPUTS) {
- break;
- }
+ Map<StringName, Vector<AudioFrame>> bus_volumes;
+ if (area) {
+ if (area->is_overriding_audio_bus()) {
+ //override audio bus
+ bus_volumes[area->get_audio_bus_name()] = output_volume_vector;
}
- output_count.set(new_output_count);
- output_ready.set();
- }
-
- //start playing if requested
- if (setplay.get() >= 0.0) {
- setseek.set(setplay.get());
- active.set();
- setplay.set(-1);
+ if (area->is_using_reverb_bus()) {
+ StringName reverb_bus_name = area->get_reverb_bus();
+ Vector<AudioFrame> reverb_vol;
+ _calc_reverb_vol(area, listener_area_pos, output_volume_vector, reverb_vol);
+ bus_volumes[reverb_bus_name] = reverb_vol;
+ }
+ } else {
+ bus_volumes[bus] = output_volume_vector;
}
- //stop playing if no longer active
- if (!active.is_set()) {
- set_physics_process_internal(false);
- emit_signal(SNAME("finished"));
+ for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
+ AudioServer::get_singleton()->set_playback_bus_volumes_linear(playback, bus_volumes);
}
- }
-}
-void AudioStreamPlayer3D::set_stream(Ref<AudioStream> p_stream) {
- AudioServer::get_singleton()->lock();
+ if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
+ Vector3 listener_velocity;
- mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size());
+ if (listener_is_camera) {
+ listener_velocity = camera->get_doppler_tracked_velocity();
+ }
- if (stream_playback.is_valid()) {
- stream_playback.unref();
- stream.unref();
- active.clear();
- setseek.set(-1);
- }
+ Vector3 local_velocity = listener_node->get_global_transform().orthonormalized().basis.xform_inv(linear_velocity - listener_velocity);
- if (p_stream.is_valid()) {
- stream = p_stream;
- stream_playback = p_stream->instance_playback();
- }
+ if (local_velocity != Vector3()) {
+ float approaching = local_pos.normalized().dot(local_velocity.normalized());
+ float velocity = local_velocity.length();
+ float speed_of_sound = 343.0;
- AudioServer::get_singleton()->unlock();
+ float doppler_pitch_scale = pitch_scale * speed_of_sound / (speed_of_sound + velocity * approaching);
+ doppler_pitch_scale = CLAMP(doppler_pitch_scale, (1 / 8.0), 8.0); //avoid crazy stuff
- if (p_stream.is_valid() && stream_playback.is_null()) {
- stream.unref();
+ actual_pitch_scale = doppler_pitch_scale;
+ } else {
+ actual_pitch_scale = pitch_scale;
+ }
+ } else {
+ actual_pitch_scale = pitch_scale;
+ }
+ for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
+ AudioServer::get_singleton()->set_playback_pitch_scale(playback, actual_pitch_scale);
+ }
}
+ return output_volume_vector;
+}
+
+void AudioStreamPlayer3D::set_stream(Ref<AudioStream> p_stream) {
+ stop();
+ stream = p_stream;
}
Ref<AudioStream> AudioStreamPlayer3D::get_stream() const {
@@ -674,49 +545,47 @@ float AudioStreamPlayer3D::get_pitch_scale() const {
}
void AudioStreamPlayer3D::play(float p_from_pos) {
- if (!is_playing()) {
- // Reset the prev_output_count if the stream is stopped
- prev_output_count = 0;
+ if (stream.is_null()) {
+ return;
}
-
- if (stream_playback.is_valid()) {
- setplay.set(p_from_pos);
- output_ready.clear();
- set_physics_process_internal(true);
+ ERR_FAIL_COND_MSG(!is_inside_tree(), "Playback can only happen when a node is inside the scene tree");
+ if (stream->is_monophonic() && is_playing()) {
+ stop();
}
+ setplay.set(p_from_pos);
+ active.set();
+ set_physics_process_internal(true);
}
void AudioStreamPlayer3D::seek(float p_seconds) {
- if (stream_playback.is_valid()) {
- setseek.set(p_seconds);
- }
+ stop();
+ play(p_seconds);
}
void AudioStreamPlayer3D::stop() {
- if (stream_playback.is_valid()) {
- active.clear();
- set_physics_process_internal(false);
- setplay.set(-1);
+ setplay.set(-1);
+ for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
+ AudioServer::get_singleton()->stop_playback_stream(playback);
}
+ stream_playbacks.clear();
+ active.clear();
+ set_physics_process_internal(false);
}
bool AudioStreamPlayer3D::is_playing() const {
- if (stream_playback.is_valid()) {
- return active.is_set() || setplay.get() >= 0;
+ for (const Ref<AudioStreamPlayback> &playback : stream_playbacks) {
+ if (AudioServer::get_singleton()->is_playback_active(playback)) {
+ return true;
+ }
}
-
return false;
}
float AudioStreamPlayer3D::get_playback_position() {
- if (stream_playback.is_valid()) {
- float ss = setseek.get();
- if (ss >= 0.0) {
- return ss;
- }
- return stream_playback->get_playback_position();
+ // Return the playback position of the most recently started playback stream.
+ if (!stream_playbacks.is_empty()) {
+ return AudioServer::get_singleton()->get_playback_position(stream_playbacks[stream_playbacks.size() - 1]);
}
-
return 0;
}
@@ -733,7 +602,7 @@ StringName AudioStreamPlayer3D::get_bus() const {
return bus;
}
}
- return "Master";
+ return SNAME("Master");
}
void AudioStreamPlayer3D::set_autoplay(bool p_enable) {
@@ -844,15 +713,6 @@ AudioStreamPlayer3D::AttenuationModel AudioStreamPlayer3D::get_attenuation_model
return attenuation_model;
}
-void AudioStreamPlayer3D::set_out_of_range_mode(OutOfRangeMode p_mode) {
- ERR_FAIL_INDEX((int)p_mode, 2);
- out_of_range_mode = p_mode;
-}
-
-AudioStreamPlayer3D::OutOfRangeMode AudioStreamPlayer3D::get_out_of_range_mode() const {
- return out_of_range_mode;
-}
-
void AudioStreamPlayer3D::set_doppler_tracking(DopplerTracking p_tracking) {
if (doppler_tracking == p_tracking) {
return;
@@ -876,19 +736,35 @@ AudioStreamPlayer3D::DopplerTracking AudioStreamPlayer3D::get_doppler_tracking()
}
void AudioStreamPlayer3D::set_stream_paused(bool p_pause) {
- if (p_pause != stream_paused) {
- stream_paused = p_pause;
- stream_paused_fade_in = !stream_paused;
- stream_paused_fade_out = stream_paused;
+ // TODO this does not have perfect recall, fix that maybe? If there are zero playbacks registered with the AudioServer, this bool isn't persisted.
+ for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
+ AudioServer::get_singleton()->set_playback_paused(playback, p_pause);
}
}
bool AudioStreamPlayer3D::get_stream_paused() const {
- return stream_paused;
+ // There's currently no way to pause some playback streams but not others. Check the first and don't bother looking at the rest.
+ if (!stream_playbacks.is_empty()) {
+ return AudioServer::get_singleton()->is_playback_paused(stream_playbacks[0]);
+ }
+ return false;
}
Ref<AudioStreamPlayback> AudioStreamPlayer3D::get_stream_playback() {
- return stream_playback;
+ if (!stream_playbacks.is_empty()) {
+ return stream_playbacks[stream_playbacks.size() - 1];
+ }
+ return nullptr;
+}
+
+void AudioStreamPlayer3D::set_max_polyphony(int p_max_polyphony) {
+ if (p_max_polyphony > 0) {
+ max_polyphony = p_max_polyphony;
+ }
+}
+
+int AudioStreamPlayer3D::get_max_polyphony() const {
+ return max_polyphony;
}
void AudioStreamPlayer3D::_bind_methods() {
@@ -947,15 +823,15 @@ void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_attenuation_model", "model"), &AudioStreamPlayer3D::set_attenuation_model);
ClassDB::bind_method(D_METHOD("get_attenuation_model"), &AudioStreamPlayer3D::get_attenuation_model);
- ClassDB::bind_method(D_METHOD("set_out_of_range_mode", "mode"), &AudioStreamPlayer3D::set_out_of_range_mode);
- ClassDB::bind_method(D_METHOD("get_out_of_range_mode"), &AudioStreamPlayer3D::get_out_of_range_mode);
-
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("set_max_polyphony", "max_polyphony"), &AudioStreamPlayer3D::set_max_polyphony);
+ ClassDB::bind_method(D_METHOD("get_max_polyphony"), &AudioStreamPlayer3D::get_max_polyphony);
+
ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer3D::get_stream_playback);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
@@ -968,7 +844,7 @@ void AudioStreamPlayer3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,4096,1,or_greater,exp"), "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::INT, "max_polyphony", PROPERTY_HINT_NONE, ""), "set_max_polyphony", "get_max_polyphony");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask");
ADD_GROUP("Emission Angle", "emission_angle");
@@ -986,9 +862,6 @@ void AudioStreamPlayer3D::_bind_methods() {
BIND_ENUM_CONSTANT(ATTENUATION_LOGARITHMIC);
BIND_ENUM_CONSTANT(ATTENUATION_DISABLED);
- BIND_ENUM_CONSTANT(OUT_OF_RANGE_MIX);
- BIND_ENUM_CONSTANT(OUT_OF_RANGE_PAUSE);
-
BIND_ENUM_CONSTANT(DOPPLER_TRACKING_DISABLED);
BIND_ENUM_CONSTANT(DOPPLER_TRACKING_IDLE_STEP);
BIND_ENUM_CONSTANT(DOPPLER_TRACKING_PHYSICS_STEP);
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index 8aec493602..697bbe2381 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -31,7 +31,8 @@
#ifndef AUDIO_STREAM_PLAYER_3D_H
#define AUDIO_STREAM_PLAYER_3D_H
-#include "core/templates/safe_refcount.h"
+#include "core/os/mutex.h"
+#include "scene/3d/area_3d.h"
#include "scene/3d/node_3d.h"
#include "scene/3d/velocity_tracker_3d.h"
#include "servers/audio/audio_filter_sw.h"
@@ -50,11 +51,6 @@ public:
ATTENUATION_DISABLED,
};
- enum OutOfRangeMode {
- OUT_OF_RANGE_MIX,
- OUT_OF_RANGE_PAUSE,
- };
-
enum DopplerTracking {
DOPPLER_TRACKING_DISABLED,
DOPPLER_TRACKING_IDLE_STEP,
@@ -68,32 +64,10 @@ private:
};
- struct Output {
- AudioFilterSW filter;
- AudioFilterSW::Processor filter_process[8];
- AudioFrame vol[4];
- float filter_gain = 0.0;
- float pitch_scale = 0.0;
- int bus_index = -1;
- int reverb_bus_index = -1;
- AudioFrame reverb_vol[4];
- Viewport *viewport = nullptr; //pointer only used for reference to previous mix
- };
-
- Output outputs[MAX_OUTPUTS];
- SafeNumeric<int> output_count;
- SafeFlag output_ready;
-
- //these are used by audio thread to have a reference of previous volumes (for ramping volume and avoiding clicks)
- Output prev_outputs[MAX_OUTPUTS];
- int prev_output_count = 0;
-
- Ref<AudioStreamPlayback> stream_playback;
+ Vector<Ref<AudioStreamPlayback>> stream_playbacks;
Ref<AudioStream> stream;
- Vector<AudioFrame> mix_buffer;
- SafeNumeric<float> setseek{ -1.0 };
- SafeFlag active;
+ SafeFlag active{ false };
SafeNumeric<float> setplay{ -1.0 };
AttenuationModel attenuation_model = ATTENUATION_INVERSE_DISTANCE;
@@ -101,18 +75,25 @@ private:
float unit_size = 10.0;
float max_db = 3.0;
float pitch_scale = 1.0;
+ // Internally used to take doppler tracking into account.
+ float actual_pitch_scale = 1.0;
bool autoplay = false;
- bool stream_paused = false;
- bool stream_paused_fade_in = false;
- bool stream_paused_fade_out = false;
- StringName bus;
+ StringName bus = SNAME("Master");
+ int max_polyphony = 1;
+
+ uint64_t last_mix_count = -1;
- static void _calc_output_vol(const Vector3 &source_dir, real_t tightness, Output &output);
- void _mix_audio();
- static void _mix_audios(void *self) { reinterpret_cast<AudioStreamPlayer3D *>(self)->_mix_audio(); }
+ static void _calc_output_vol(const Vector3 &source_dir, real_t tightness, Vector<AudioFrame> &output);
+
+ void _calc_reverb_vol(Area3D *area, Vector3 listener_area_pos, Vector<AudioFrame> direct_path_vol, Vector<AudioFrame> &reverb_vol);
+
+ static void _listener_changed_cb(void *self) { reinterpret_cast<AudioStreamPlayer3D *>(self)->_update_panning(); }
void _set_playing(bool p_enable);
bool _is_active() const;
+ StringName _get_actual_bus();
+ Area3D *_get_overriding_area();
+ Vector<AudioFrame> _update_panning();
void _bus_layout_changed();
@@ -124,14 +105,14 @@ private:
float attenuation_filter_cutoff_hz = 5000.0;
float attenuation_filter_db = -24.0;
+ float linear_attenuation = 0;
+
float max_distance = 0.0;
Ref<VelocityTracker3D> velocity_tracker;
DopplerTracking doppler_tracking = DOPPLER_TRACKING_DISABLED;
- OutOfRangeMode out_of_range_mode = OUT_OF_RANGE_MIX;
-
float _get_attenuation_db(float p_distance) const;
protected:
@@ -164,6 +145,9 @@ public:
void set_bus(const StringName &p_bus);
StringName get_bus() const;
+ void set_max_polyphony(int p_max_polyphony);
+ int get_max_polyphony() const;
+
void set_autoplay(bool p_enable);
bool is_autoplay_enabled();
@@ -191,9 +175,6 @@ public:
void set_attenuation_model(AttenuationModel p_model);
AttenuationModel get_attenuation_model() const;
- void set_out_of_range_mode(OutOfRangeMode p_mode);
- OutOfRangeMode get_out_of_range_mode() const;
-
void set_doppler_tracking(DopplerTracking p_tracking);
DopplerTracking get_doppler_tracking() const;
@@ -207,6 +188,5 @@ public:
};
VARIANT_ENUM_CAST(AudioStreamPlayer3D::AttenuationModel)
-VARIANT_ENUM_CAST(AudioStreamPlayer3D::OutOfRangeMode)
VARIANT_ENUM_CAST(AudioStreamPlayer3D::DopplerTracking)
#endif // AUDIO_STREAM_PLAYER_3D_H
diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp
index 5315e685a0..afd11482e3 100644
--- a/scene/3d/bone_attachment_3d.cpp
+++ b/scene/3d/bone_attachment_3d.cpp
@@ -32,7 +32,15 @@
void BoneAttachment3D::_validate_property(PropertyInfo &property) const {
if (property.name == "bone_name") {
- Skeleton3D *parent = Object::cast_to<Skeleton3D>(get_parent());
+ // Because it is a constant function, we cannot use the _get_skeleton_3d function.
+ const Skeleton3D *parent = nullptr;
+ if (use_external_skeleton) {
+ if (external_skeleton_node_cache.is_valid()) {
+ parent = Object::cast_to<Skeleton3D>(ObjectDB::get_instance(external_skeleton_node_cache));
+ }
+ } else {
+ parent = Object::cast_to<Skeleton3D>(get_parent());
+ }
if (parent) {
String names;
@@ -52,55 +60,321 @@ void BoneAttachment3D::_validate_property(PropertyInfo &property) const {
}
}
+bool BoneAttachment3D::_set(const StringName &p_path, const Variant &p_value) {
+ if (p_path == SNAME("override_pose")) {
+ set_override_pose(p_value);
+ } else if (p_path == SNAME("override_mode")) {
+ set_override_mode(p_value);
+ } else if (p_path == SNAME("use_external_skeleton")) {
+ set_use_external_skeleton(p_value);
+ } else if (p_path == SNAME("external_skeleton")) {
+ set_external_skeleton(p_value);
+ }
+
+ return true;
+}
+
+bool BoneAttachment3D::_get(const StringName &p_path, Variant &r_ret) const {
+ if (p_path == SNAME("override_pose")) {
+ r_ret = get_override_pose();
+ } else if (p_path == SNAME("override_mode")) {
+ r_ret = get_override_mode();
+ } else if (p_path == SNAME("use_external_skeleton")) {
+ r_ret = get_use_external_skeleton();
+ } else if (p_path == SNAME("external_skeleton")) {
+ r_ret = get_external_skeleton();
+ }
+
+ return true;
+}
+
+void BoneAttachment3D::_get_property_list(List<PropertyInfo> *p_list) const {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "override_pose", PROPERTY_HINT_NONE, ""));
+ if (override_pose) {
+ p_list->push_back(PropertyInfo(Variant::INT, "override_mode", PROPERTY_HINT_ENUM, "Global Pose Override, Local Pose Override, Custom Pose"));
+ }
+
+ p_list->push_back(PropertyInfo(Variant::BOOL, "use_external_skeleton", PROPERTY_HINT_NONE, ""));
+ if (use_external_skeleton) {
+ p_list->push_back(PropertyInfo(Variant::NODE_PATH, "external_skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton3D"));
+ }
+}
+
+TypedArray<String> BoneAttachment3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node3D::get_configuration_warnings();
+
+ if (use_external_skeleton) {
+ if (external_skeleton_node_cache.is_null()) {
+ warnings.append(TTR("External Skeleton3D node not set! Please set a path to an external Skeleton3D node."));
+ }
+ } else {
+ Skeleton3D *parent = Object::cast_to<Skeleton3D>(get_parent());
+ if (!parent) {
+ warnings.append(TTR("Parent node is not a Skeleton3D node! Please use an external Skeleton3D if you intend to use the BoneAttachment3D without it being a child of a Skeleton3D node."));
+ }
+ }
+
+ if (bone_idx == -1) {
+ warnings.append(TTR("BoneAttachment3D node is not bound to any bones! Please select a bone to attach this node."));
+ }
+
+ return warnings;
+}
+
+void BoneAttachment3D::_update_external_skeleton_cache() {
+ external_skeleton_node_cache = ObjectID();
+ if (has_node(external_skeleton_node)) {
+ Node *node = get_node(external_skeleton_node);
+ ERR_FAIL_COND_MSG(!node, "Cannot update external skeleton cache: Node cannot be found!");
+
+ // Make sure it's a skeleton3D
+ Skeleton3D *sk = Object::cast_to<Skeleton3D>(node);
+ ERR_FAIL_COND_MSG(!sk, "Cannot update external skeleton cache: Skeleton3D Nodepath does not point to a Skeleton3D node!");
+
+ external_skeleton_node_cache = node->get_instance_id();
+ } else {
+ if (external_skeleton_node.is_empty()) {
+ BoneAttachment3D *parent_attachment = Object::cast_to<BoneAttachment3D>(get_parent());
+ if (parent_attachment) {
+ parent_attachment->_update_external_skeleton_cache();
+ if (parent_attachment->has_node(parent_attachment->external_skeleton_node)) {
+ Node *node = parent_attachment->get_node(parent_attachment->external_skeleton_node);
+ ERR_FAIL_COND_MSG(!node, "Cannot update external skeleton cache: Parent's Skeleton3D node cannot be found!");
+
+ // Make sure it's a skeleton3D
+ Skeleton3D *sk = Object::cast_to<Skeleton3D>(node);
+ ERR_FAIL_COND_MSG(!sk, "Cannot update external skeleton cache: Parent Skeleton3D Nodepath does not point to a Skeleton3D node!");
+
+ external_skeleton_node_cache = node->get_instance_id();
+ external_skeleton_node = get_path_to(node);
+ }
+ }
+ }
+ }
+}
+
void BoneAttachment3D::_check_bind() {
- Skeleton3D *sk = Object::cast_to<Skeleton3D>(get_parent());
- if (sk) {
- int idx = sk->find_bone(bone_name);
- if (idx != -1) {
- sk->bind_child_node_to_bone(idx, this);
- set_transform(sk->get_bone_global_pose(idx));
+ Skeleton3D *sk = _get_skeleton3d();
+
+ if (sk && !bound) {
+ if (bone_idx <= -1) {
+ bone_idx = sk->find_bone(bone_name);
+ }
+ if (bone_idx != -1) {
+ sk->call_deferred(SNAME("connect"), "bone_pose_changed", callable_mp(this, &BoneAttachment3D::on_bone_pose_update));
bound = true;
+ call_deferred(SNAME("on_bone_pose_update"), bone_idx);
+ }
+ }
+}
+
+Skeleton3D *BoneAttachment3D::_get_skeleton3d() {
+ if (use_external_skeleton) {
+ if (external_skeleton_node_cache.is_valid()) {
+ return Object::cast_to<Skeleton3D>(ObjectDB::get_instance(external_skeleton_node_cache));
+ } else {
+ _update_external_skeleton_cache();
+ if (external_skeleton_node_cache.is_valid()) {
+ return Object::cast_to<Skeleton3D>(ObjectDB::get_instance(external_skeleton_node_cache));
+ }
}
+ } else {
+ return Object::cast_to<Skeleton3D>(get_parent());
}
+ return nullptr;
}
void BoneAttachment3D::_check_unbind() {
if (bound) {
- Skeleton3D *sk = Object::cast_to<Skeleton3D>(get_parent());
+ Skeleton3D *sk = _get_skeleton3d();
+
if (sk) {
- int idx = sk->find_bone(bone_name);
- if (idx != -1) {
- sk->unbind_child_node_from_bone(idx, this);
- }
+ sk->disconnect(SNAME("bone_pose_changed"), callable_mp(this, &BoneAttachment3D::on_bone_pose_update));
}
bound = false;
}
}
+void BoneAttachment3D::_transform_changed() {
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (override_pose) {
+ Skeleton3D *sk = _get_skeleton3d();
+
+ ERR_FAIL_COND_MSG(!sk, "Cannot override pose: Skeleton not found!");
+ ERR_FAIL_INDEX_MSG(bone_idx, sk->get_bone_count(), "Cannot override pose: Bone index is out of range!");
+
+ Transform3D our_trans = get_transform();
+ if (use_external_skeleton) {
+ our_trans = sk->world_transform_to_global_pose(get_global_transform());
+ }
+
+ if (override_mode == OVERRIDE_MODES::MODE_GLOBAL_POSE) {
+ sk->set_bone_global_pose_override(bone_idx, our_trans, 1.0, true);
+ } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) {
+ sk->set_bone_local_pose_override(bone_idx, sk->global_pose_to_local_pose(bone_idx, our_trans), 1.0, true);
+ } else if (override_mode == OVERRIDE_MODES::MODE_CUSTOM_POSE) {
+ sk->set_bone_custom_pose(bone_idx, sk->global_pose_to_local_pose(bone_idx, our_trans));
+ }
+ }
+}
+
void BoneAttachment3D::set_bone_name(const String &p_name) {
+ bone_name = p_name;
+ Skeleton3D *sk = _get_skeleton3d();
+ if (sk) {
+ set_bone_idx(sk->find_bone(bone_name));
+ }
+}
+
+String BoneAttachment3D::get_bone_name() const {
+ return bone_name;
+}
+
+void BoneAttachment3D::set_bone_idx(const int &p_idx) {
if (is_inside_tree()) {
_check_unbind();
}
- bone_name = p_name;
+ bone_idx = p_idx;
+
+ Skeleton3D *sk = _get_skeleton3d();
+ if (sk) {
+ if (bone_idx <= -1 || bone_idx >= sk->get_bone_count()) {
+ WARN_PRINT("Bone index out of range! Cannot connect BoneAttachment to node!");
+ bone_idx = -1;
+ } else {
+ bone_name = sk->get_bone_name(bone_idx);
+ }
+ }
if (is_inside_tree()) {
_check_bind();
}
+
+ notify_property_list_changed();
}
-String BoneAttachment3D::get_bone_name() const {
- return bone_name;
+int BoneAttachment3D::get_bone_idx() const {
+ return bone_idx;
+}
+
+void BoneAttachment3D::set_override_pose(bool p_override) {
+ override_pose = p_override;
+ set_notify_local_transform(override_pose);
+ set_process_internal(override_pose);
+
+ if (!override_pose) {
+ Skeleton3D *sk = _get_skeleton3d();
+ if (sk) {
+ if (override_mode == OVERRIDE_MODES::MODE_GLOBAL_POSE) {
+ sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false);
+ } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) {
+ sk->set_bone_local_pose_override(bone_idx, Transform3D(), 0.0, false);
+ } else if (override_mode == OVERRIDE_MODES::MODE_CUSTOM_POSE) {
+ sk->set_bone_custom_pose(bone_idx, Transform3D());
+ }
+ }
+ _transform_changed();
+ }
+ notify_property_list_changed();
+}
+
+bool BoneAttachment3D::get_override_pose() const {
+ return override_pose;
+}
+
+void BoneAttachment3D::set_override_mode(int p_mode) {
+ if (override_pose) {
+ Skeleton3D *sk = _get_skeleton3d();
+ if (sk) {
+ if (override_mode == OVERRIDE_MODES::MODE_GLOBAL_POSE) {
+ sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false);
+ } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) {
+ sk->set_bone_local_pose_override(bone_idx, Transform3D(), 0.0, false);
+ } else if (override_mode == OVERRIDE_MODES::MODE_CUSTOM_POSE) {
+ sk->set_bone_custom_pose(bone_idx, Transform3D());
+ }
+ }
+ override_mode = p_mode;
+ _transform_changed();
+ return;
+ }
+ override_mode = p_mode;
+}
+
+int BoneAttachment3D::get_override_mode() const {
+ return override_mode;
+}
+
+void BoneAttachment3D::set_use_external_skeleton(bool p_use_external) {
+ use_external_skeleton = p_use_external;
+
+ if (use_external_skeleton) {
+ _check_unbind();
+ _update_external_skeleton_cache();
+ _check_bind();
+ _transform_changed();
+ }
+
+ notify_property_list_changed();
+}
+
+bool BoneAttachment3D::get_use_external_skeleton() const {
+ return use_external_skeleton;
+}
+
+void BoneAttachment3D::set_external_skeleton(NodePath p_path) {
+ external_skeleton_node = p_path;
+ _update_external_skeleton_cache();
+ notify_property_list_changed();
+}
+
+NodePath BoneAttachment3D::get_external_skeleton() const {
+ return external_skeleton_node;
}
void BoneAttachment3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
+ if (use_external_skeleton) {
+ _update_external_skeleton_cache();
+ }
_check_bind();
} break;
case NOTIFICATION_EXIT_TREE: {
_check_unbind();
} break;
+ case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
+ _transform_changed();
+ } break;
+ case NOTIFICATION_INTERNAL_PROCESS: {
+ if (_override_dirty) {
+ _override_dirty = false;
+ }
+ }
+ }
+}
+
+void BoneAttachment3D::on_bone_pose_update(int p_bone_index) {
+ if (bone_idx == p_bone_index) {
+ Skeleton3D *sk = _get_skeleton3d();
+ if (sk) {
+ if (!override_pose) {
+ if (use_external_skeleton) {
+ set_global_transform(sk->global_pose_to_world_transform(sk->get_bone_global_pose(bone_idx)));
+ } else {
+ set_transform(sk->get_bone_global_pose(bone_idx));
+ }
+ } else {
+ if (!_override_dirty) {
+ _transform_changed();
+ _override_dirty = true;
+ }
+ }
+ }
}
}
@@ -111,5 +385,21 @@ void BoneAttachment3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bone_name", "bone_name"), &BoneAttachment3D::set_bone_name);
ClassDB::bind_method(D_METHOD("get_bone_name"), &BoneAttachment3D::get_bone_name);
+ ClassDB::bind_method(D_METHOD("set_bone_idx", "bone_idx"), &BoneAttachment3D::set_bone_idx);
+ ClassDB::bind_method(D_METHOD("get_bone_idx"), &BoneAttachment3D::get_bone_idx);
+
+ ClassDB::bind_method(D_METHOD("on_bone_pose_update", "bone_index"), &BoneAttachment3D::on_bone_pose_update);
+
+ ClassDB::bind_method(D_METHOD("set_override_pose", "override_pose"), &BoneAttachment3D::set_override_pose);
+ ClassDB::bind_method(D_METHOD("get_override_pose"), &BoneAttachment3D::get_override_pose);
+ ClassDB::bind_method(D_METHOD("set_override_mode", "override_mode"), &BoneAttachment3D::set_override_mode);
+ ClassDB::bind_method(D_METHOD("get_override_mode"), &BoneAttachment3D::get_override_mode);
+
+ ClassDB::bind_method(D_METHOD("set_use_external_skeleton", "use_external_skeleton"), &BoneAttachment3D::set_use_external_skeleton);
+ ClassDB::bind_method(D_METHOD("get_use_external_skeleton"), &BoneAttachment3D::get_use_external_skeleton);
+ ClassDB::bind_method(D_METHOD("set_external_skeleton", "external_skeleton"), &BoneAttachment3D::set_external_skeleton);
+ ClassDB::bind_method(D_METHOD("get_external_skeleton"), &BoneAttachment3D::get_external_skeleton);
+
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bone_name"), "set_bone_name", "get_bone_name");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_idx"), "set_bone_idx", "get_bone_idx");
}
diff --git a/scene/3d/bone_attachment_3d.h b/scene/3d/bone_attachment_3d.h
index 0c6d5f12b1..cf681cace8 100644
--- a/scene/3d/bone_attachment_3d.h
+++ b/scene/3d/bone_attachment_3d.h
@@ -38,20 +38,59 @@ class BoneAttachment3D : public Node3D {
bool bound = false;
String bone_name;
+ int bone_idx = -1;
+
+ bool override_pose = false;
+ int override_mode = 0;
+ bool _override_dirty = false;
+
+ enum OVERRIDE_MODES {
+ MODE_GLOBAL_POSE,
+ MODE_LOCAL_POSE,
+ MODE_CUSTOM_POSE
+ };
+
+ bool use_external_skeleton = false;
+ NodePath external_skeleton_node;
+ ObjectID external_skeleton_node_cache;
void _check_bind();
void _check_unbind();
+ void _transform_changed();
+ void _update_external_skeleton_cache();
+ Skeleton3D *_get_skeleton3d();
+
protected:
virtual void _validate_property(PropertyInfo &property) const override;
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+ bool _set(const StringName &p_path, const Variant &p_value);
+ void _get_property_list(List<PropertyInfo> *p_list) const;
void _notification(int p_what);
static void _bind_methods();
public:
+ virtual TypedArray<String> get_configuration_warnings() const override;
+
void set_bone_name(const String &p_name);
String get_bone_name() const;
+ void set_bone_idx(const int &p_idx);
+ int get_bone_idx() const;
+
+ void set_override_pose(bool p_override);
+ bool get_override_pose() const;
+ void set_override_mode(int p_mode);
+ int get_override_mode() const;
+
+ void set_use_external_skeleton(bool p_external_skeleton);
+ bool get_use_external_skeleton() const;
+ void set_external_skeleton(NodePath p_skeleton);
+ NodePath get_external_skeleton() const;
+
+ virtual void on_bone_pose_update(int p_bone_index);
+
BoneAttachment3D();
};
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index 2e962b96c3..61d73ff1e2 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -31,10 +31,8 @@
#include "camera_3d.h"
#include "collision_object_3d.h"
-#include "core/config/engine.h"
#include "core/math/camera_matrix.h"
-#include "scene/resources/material.h"
-#include "scene/resources/surface_tool.h"
+#include "scene/main/viewport.h"
void Camera3D::_update_audio_listener_state() {
}
@@ -153,7 +151,7 @@ Transform3D Camera3D::get_camera_transform() const {
return tr;
}
-void Camera3D::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) {
+void Camera3D::set_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far) {
if (!force_change && fov == p_fovy_degrees && p_z_near == near && p_z_far == far && mode == PROJECTION_PERSPECTIVE) {
return;
}
@@ -168,7 +166,7 @@ void Camera3D::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_f
force_change = false;
}
-void Camera3D::set_orthogonal(float p_size, float p_z_near, float p_z_far) {
+void Camera3D::set_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far) {
if (!force_change && size == p_size && p_z_near == near && p_z_far == far && mode == PROJECTION_ORTHOGONAL) {
return;
}
@@ -184,7 +182,7 @@ void Camera3D::set_orthogonal(float p_size, float p_z_near, float p_z_far) {
update_gizmos();
}
-void Camera3D::set_frustum(float p_size, Vector2 p_offset, float p_z_near, float p_z_far) {
+void Camera3D::set_frustum(real_t p_size, Vector2 p_offset, real_t p_z_near, real_t p_z_far) {
if (!force_change && size == p_size && frustum_offset == p_offset && p_z_near == near && p_z_far == far && mode == PROJECTION_FRUSTUM) {
return;
}
@@ -256,10 +254,6 @@ bool Camera3D::is_current() const {
}
}
-bool Camera3D::_can_gizmo_scale() const {
- return false;
-}
-
Vector3 Camera3D::project_ray_normal(const Point2 &p_pos) const {
Vector3 ray = project_local_ray_normal(p_pos);
return get_camera_transform().basis.xform(ray).normalized();
@@ -295,7 +289,7 @@ Vector3 Camera3D::project_ray_origin(const Point2 &p_pos) const {
return get_camera_transform().origin;
} else {
Vector2 pos = cpos / viewport_size;
- float vsize, hsize;
+ real_t vsize, hsize;
if (keep_aspect == KEEP_WIDTH) {
vsize = size / viewport_size.aspect();
hsize = size;
@@ -368,7 +362,7 @@ Point2 Camera3D::unproject_position(const Vector3 &p_pos) const {
return res;
}
-Vector3 Camera3D::project_position(const Point2 &p_point, float p_z_depth) const {
+Vector3 Camera3D::project_position(const Point2 &p_point, real_t p_z_depth) const {
ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector3(), "Camera is not inside scene.");
if (p_z_depth == 0 && mode != PROJECTION_ORTHOGONAL) {
@@ -498,9 +492,10 @@ void Camera3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_frustum"), &Camera3D::get_frustum);
ClassDB::bind_method(D_METHOD("is_position_in_frustum", "world_point"), &Camera3D::is_position_in_frustum);
ClassDB::bind_method(D_METHOD("get_camera_rid"), &Camera3D::get_camera);
+ ClassDB::bind_method(D_METHOD("get_pyramid_shape_rid"), &Camera3D::get_pyramid_shape_rid);
- ClassDB::bind_method(D_METHOD("set_cull_mask_bit", "layer", "enable"), &Camera3D::set_cull_mask_bit);
- ClassDB::bind_method(D_METHOD("get_cull_mask_bit", "layer"), &Camera3D::get_cull_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_cull_mask_value", "layer_number", "value"), &Camera3D::set_cull_mask_value);
+ ClassDB::bind_method(D_METHOD("get_cull_mask_value", "layer_number"), &Camera3D::get_cull_mask_value);
//ClassDB::bind_method(D_METHOD("_camera_make_current"),&Camera::_camera_make_current );
@@ -531,15 +526,15 @@ void Camera3D::_bind_methods() {
BIND_ENUM_CONSTANT(DOPPLER_TRACKING_PHYSICS_STEP);
}
-float Camera3D::get_fov() const {
+real_t Camera3D::get_fov() const {
return fov;
}
-float Camera3D::get_size() const {
+real_t Camera3D::get_size() const {
return size;
}
-float Camera3D::get_near() const {
+real_t Camera3D::get_near() const {
return near;
}
@@ -547,7 +542,7 @@ Vector2 Camera3D::get_frustum_offset() const {
return frustum_offset;
}
-float Camera3D::get_far() const {
+real_t Camera3D::get_far() const {
return far;
}
@@ -555,19 +550,19 @@ Camera3D::Projection Camera3D::get_projection() const {
return mode;
}
-void Camera3D::set_fov(float p_fov) {
+void Camera3D::set_fov(real_t p_fov) {
ERR_FAIL_COND(p_fov < 1 || p_fov > 179);
fov = p_fov;
_update_camera_mode();
}
-void Camera3D::set_size(float p_size) {
+void Camera3D::set_size(real_t p_size) {
ERR_FAIL_COND(p_size < 0.1 || p_size > 16384);
size = p_size;
_update_camera_mode();
}
-void Camera3D::set_near(float p_near) {
+void Camera3D::set_near(real_t p_near) {
near = p_near;
_update_camera_mode();
}
@@ -577,7 +572,7 @@ void Camera3D::set_frustum_offset(Vector2 p_offset) {
_update_camera_mode();
}
-void Camera3D::set_far(float p_far) {
+void Camera3D::set_far(real_t p_far) {
far = p_far;
_update_camera_mode();
}
@@ -592,18 +587,22 @@ uint32_t Camera3D::get_cull_mask() const {
return layers;
}
-void Camera3D::set_cull_mask_bit(int p_layer, bool p_enable) {
- ERR_FAIL_INDEX(p_layer, 32);
- if (p_enable) {
- set_cull_mask(layers | (1 << p_layer));
+void Camera3D::set_cull_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Render layer number must be between 1 and 20 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 20, "Render layer number must be between 1 and 20 inclusive.");
+ uint32_t mask = get_cull_mask();
+ if (p_value) {
+ mask |= 1 << (p_layer_number - 1);
} else {
- set_cull_mask(layers & (~(1 << p_layer)));
+ mask &= ~(1 << (p_layer_number - 1));
}
+ set_cull_mask(mask);
}
-bool Camera3D::get_cull_mask_bit(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, 32, false);
- return (layers & (1 << p_layer));
+bool Camera3D::get_cull_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Render layer number must be between 1 and 20 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 20, false, "Render layer number must be between 1 and 20 inclusive.");
+ return layers & (1 << (p_layer_number - 1));
}
Vector<Plane> Camera3D::get_frustum() const {
@@ -630,21 +629,21 @@ bool Camera3D::is_position_in_frustum(const Vector3 &p_position) const {
return true;
}
-void Camera3D::set_v_offset(float p_offset) {
+void Camera3D::set_v_offset(real_t p_offset) {
v_offset = p_offset;
_update_camera();
}
-float Camera3D::get_v_offset() const {
+real_t Camera3D::get_v_offset() const {
return v_offset;
}
-void Camera3D::set_h_offset(float p_offset) {
+void Camera3D::set_h_offset(real_t p_offset) {
h_offset = p_offset;
_update_camera();
}
-float Camera3D::get_h_offset() const {
+real_t Camera3D::get_h_offset() const {
return h_offset;
}
@@ -656,231 +655,46 @@ Vector3 Camera3D::get_doppler_tracked_velocity() const {
}
}
-Camera3D::Camera3D() {
- camera = RenderingServer::get_singleton()->camera_create();
- set_perspective(75.0, 0.05, 4000.0);
- RenderingServer::get_singleton()->camera_set_cull_mask(camera, layers);
- //active=false;
- velocity_tracker.instantiate();
- set_notify_transform(true);
- set_disable_scale(true);
-}
-
-Camera3D::~Camera3D() {
- RenderingServer::get_singleton()->free(camera);
-}
+RID Camera3D::get_pyramid_shape_rid() {
+ if (pyramid_shape == RID()) {
+ pyramid_shape_points = get_near_plane_points();
+ pyramid_shape = PhysicsServer3D::get_singleton()->convex_polygon_shape_create();
+ PhysicsServer3D::get_singleton()->shape_set_data(pyramid_shape, pyramid_shape_points);
-////////////////////////////////////////
+ } else { //check if points changed
+ Vector<Vector3> local_points = get_near_plane_points();
-void ClippedCamera3D::set_margin(float p_margin) {
- margin = p_margin;
-}
+ bool all_equal = true;
-float ClippedCamera3D::get_margin() const {
- return margin;
-}
-
-void ClippedCamera3D::set_process_callback(ClipProcessCallback p_mode) {
- if (process_callback == p_mode) {
- return;
- }
- process_callback = p_mode;
- set_process_internal(process_callback == CLIP_PROCESS_IDLE);
- set_physics_process_internal(process_callback == CLIP_PROCESS_PHYSICS);
-}
-
-ClippedCamera3D::ClipProcessCallback ClippedCamera3D::get_process_callback() const {
- return process_callback;
-}
-
-Transform3D ClippedCamera3D::get_camera_transform() const {
- Transform3D t = Camera3D::get_camera_transform();
- t.origin += -t.basis.get_axis(Vector3::AXIS_Z).normalized() * clip_offset;
- return t;
-}
-
-void ClippedCamera3D::_notification(int p_what) {
- if (p_what == NOTIFICATION_INTERNAL_PROCESS || p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
- Node3D *parent = Object::cast_to<Node3D>(get_parent());
- if (!parent) {
- return;
- }
-
- PhysicsDirectSpaceState3D *dspace = get_world_3d()->get_direct_space_state();
- ERR_FAIL_COND(!dspace); // most likely physics set to threads
-
- Vector3 cam_fw = -get_global_transform().basis.get_axis(Vector3::AXIS_Z).normalized();
- Vector3 cam_pos = get_global_transform().origin;
- Vector3 parent_pos = parent->get_global_transform().origin;
-
- Plane parent_plane(parent_pos, cam_fw);
-
- if (parent_plane.is_point_over(cam_pos)) {
- //cam is beyond parent plane
- return;
- }
-
- Vector3 ray_from = parent_plane.project(cam_pos);
-
- clip_offset = 0; //reset by default
-
- { //check if points changed
- Vector<Vector3> local_points = get_near_plane_points();
-
- bool all_equal = true;
-
- for (int i = 0; i < 5; i++) {
- if (points[i] != local_points[i]) {
- all_equal = false;
- break;
- }
- }
-
- if (!all_equal) {
- PhysicsServer3D::get_singleton()->shape_set_data(pyramid_shape, local_points);
- points = local_points;
+ for (int i = 0; i < 5; i++) {
+ if (local_points[i] != pyramid_shape_points[i]) {
+ all_equal = false;
+ break;
}
}
- Transform3D xf = get_global_transform();
- xf.origin = ray_from;
- xf.orthonormalize();
-
- float closest_safe = 1.0f, closest_unsafe = 1.0f;
- if (dspace->cast_motion(pyramid_shape, xf, cam_pos - ray_from, margin, closest_safe, closest_unsafe, exclude, collision_mask, clip_to_bodies, clip_to_areas)) {
- clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from) * closest_safe);
+ if (!all_equal) {
+ PhysicsServer3D::get_singleton()->shape_set_data(pyramid_shape, local_points);
+ pyramid_shape_points = local_points;
}
-
- _update_camera();
- }
-
- if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
- update_gizmos();
- }
-}
-
-void ClippedCamera3D::set_collision_mask(uint32_t p_mask) {
- collision_mask = p_mask;
-}
-
-uint32_t ClippedCamera3D::get_collision_mask() const {
- return collision_mask;
-}
-
-void ClippedCamera3D::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
- uint32_t mask = get_collision_mask();
- if (p_value) {
- mask |= 1 << p_bit;
- } else {
- mask &= ~(1 << p_bit);
}
- set_collision_mask(mask);
-}
-bool ClippedCamera3D::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+ return pyramid_shape;
}
-void ClippedCamera3D::add_exception_rid(const RID &p_rid) {
- exclude.insert(p_rid);
-}
-
-void ClippedCamera3D::add_exception(const Object *p_object) {
- ERR_FAIL_NULL(p_object);
- const CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_object);
- if (!co) {
- return;
- }
- add_exception_rid(co->get_rid());
-}
-
-void ClippedCamera3D::remove_exception_rid(const RID &p_rid) {
- exclude.erase(p_rid);
+Camera3D::Camera3D() {
+ camera = RenderingServer::get_singleton()->camera_create();
+ set_perspective(75.0, 0.05, 4000.0);
+ RenderingServer::get_singleton()->camera_set_cull_mask(camera, layers);
+ //active=false;
+ velocity_tracker.instantiate();
+ set_notify_transform(true);
+ set_disable_scale(true);
}
-void ClippedCamera3D::remove_exception(const Object *p_object) {
- ERR_FAIL_NULL(p_object);
- const CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_object);
- if (!co) {
- return;
+Camera3D::~Camera3D() {
+ RenderingServer::get_singleton()->free(camera);
+ if (pyramid_shape.is_valid()) {
+ PhysicsServer3D::get_singleton()->free(pyramid_shape);
}
- remove_exception_rid(co->get_rid());
-}
-
-void ClippedCamera3D::clear_exceptions() {
- exclude.clear();
-}
-
-float ClippedCamera3D::get_clip_offset() const {
- return clip_offset;
-}
-
-void ClippedCamera3D::set_clip_to_areas(bool p_clip) {
- clip_to_areas = p_clip;
-}
-
-bool ClippedCamera3D::is_clip_to_areas_enabled() const {
- return clip_to_areas;
-}
-
-void ClippedCamera3D::set_clip_to_bodies(bool p_clip) {
- clip_to_bodies = p_clip;
-}
-
-bool ClippedCamera3D::is_clip_to_bodies_enabled() const {
- return clip_to_bodies;
-}
-
-void ClippedCamera3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_margin", "margin"), &ClippedCamera3D::set_margin);
- ClassDB::bind_method(D_METHOD("get_margin"), &ClippedCamera3D::get_margin);
-
- ClassDB::bind_method(D_METHOD("set_process_callback", "process_callback"), &ClippedCamera3D::set_process_callback);
- ClassDB::bind_method(D_METHOD("get_process_callback"), &ClippedCamera3D::get_process_callback);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &ClippedCamera3D::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &ClippedCamera3D::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &ClippedCamera3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &ClippedCamera3D::get_collision_mask_bit);
-
- ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &ClippedCamera3D::add_exception_rid);
- ClassDB::bind_method(D_METHOD("add_exception", "node"), &ClippedCamera3D::add_exception);
-
- ClassDB::bind_method(D_METHOD("remove_exception_rid", "rid"), &ClippedCamera3D::remove_exception_rid);
- ClassDB::bind_method(D_METHOD("remove_exception", "node"), &ClippedCamera3D::remove_exception);
-
- ClassDB::bind_method(D_METHOD("set_clip_to_areas", "enable"), &ClippedCamera3D::set_clip_to_areas);
- ClassDB::bind_method(D_METHOD("is_clip_to_areas_enabled"), &ClippedCamera3D::is_clip_to_areas_enabled);
-
- ClassDB::bind_method(D_METHOD("get_clip_offset"), &ClippedCamera3D::get_clip_offset);
-
- ClassDB::bind_method(D_METHOD("set_clip_to_bodies", "enable"), &ClippedCamera3D::set_clip_to_bodies);
- ClassDB::bind_method(D_METHOD("is_clip_to_bodies_enabled"), &ClippedCamera3D::is_clip_to_bodies_enabled);
-
- ClassDB::bind_method(D_METHOD("clear_exceptions"), &ClippedCamera3D::clear_exceptions);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_margin", "get_margin");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_callback", "get_process_callback");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
-
- ADD_GROUP("Clip To", "clip_to");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_areas", "is_clip_to_areas_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_bodies", "is_clip_to_bodies_enabled");
-
- BIND_ENUM_CONSTANT(CLIP_PROCESS_PHYSICS);
- BIND_ENUM_CONSTANT(CLIP_PROCESS_IDLE);
-}
-
-ClippedCamera3D::ClippedCamera3D() {
- set_physics_process_internal(true);
- set_notify_local_transform(Engine::get_singleton()->is_editor_hint());
- points.resize(5);
- pyramid_shape = PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CONVEX_POLYGON);
-}
-
-ClippedCamera3D::~ClippedCamera3D() {
- PhysicsServer3D::get_singleton()->free(pyramid_shape);
}
diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h
index c6efc8f9a9..6006a2ea3f 100644
--- a/scene/3d/camera_3d.h
+++ b/scene/3d/camera_3d.h
@@ -33,9 +33,6 @@
#include "scene/3d/node_3d.h"
#include "scene/3d/velocity_tracker_3d.h"
-#include "scene/main/window.h"
-#include "scene/resources/camera_effects.h"
-#include "scene/resources/environment.h"
class Camera3D : public Node3D {
GDCLASS(Camera3D, Node3D);
@@ -63,13 +60,13 @@ private:
Projection mode = PROJECTION_PERSPECTIVE;
- float fov = 0.0;
- float size = 1.0;
+ real_t fov = 0.0;
+ real_t size = 1.0;
Vector2 frustum_offset;
- float near = 0.0;
- float far = 0.0;
- float v_offset = 0.0;
- float h_offset = 0.0;
+ real_t near = 0.0;
+ real_t far = 0.0;
+ real_t v_offset = 0.0;
+ real_t h_offset = 0.0;
KeepAspect keep_aspect = KEEP_HEIGHT;
RID camera;
@@ -82,8 +79,6 @@ private:
Ref<Environment> environment;
Ref<CameraEffects> effects;
- virtual bool _can_gizmo_scale() const;
-
// void _camera_make_current(Node *p_camera);
friend class Viewport;
void _update_audio_listener_state();
@@ -91,6 +86,9 @@ private:
DopplerTracking doppler_tracking = DOPPLER_TRACKING_DISABLED;
Ref<VelocityTracker3D> velocity_tracker;
+ RID pyramid_shape;
+ Vector<Vector3> pyramid_shape_points;
+
protected:
void _update_camera();
virtual void _request_camera_update();
@@ -107,10 +105,9 @@ public:
NOTIFICATION_LOST_CURRENT = 51
};
- void set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far);
- void set_orthogonal(float p_size, float p_z_near, float p_z_far);
- void set_frustum(float p_size, Vector2 p_offset, float p_z_near,
- float p_z_far);
+ void set_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far);
+ void set_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far);
+ void set_frustum(real_t p_size, Vector2 p_offset, real_t p_z_near, real_t p_z_far);
void set_projection(Camera3D::Projection p_mode);
void make_current();
@@ -120,18 +117,18 @@ public:
RID get_camera() const;
- float get_fov() const;
- float get_size() const;
- float get_far() const;
- float get_near() const;
+ real_t get_fov() const;
+ real_t get_size() const;
+ real_t get_far() const;
+ real_t get_near() const;
Vector2 get_frustum_offset() const;
Projection get_projection() const;
- void set_fov(float p_fov);
- void set_size(float p_size);
- void set_far(float p_far);
- void set_near(float p_near);
+ void set_fov(real_t p_fov);
+ void set_size(real_t p_size);
+ void set_far(real_t p_far);
+ void set_near(real_t p_near);
void set_frustum_offset(Vector2 p_offset);
virtual Transform3D get_camera_transform() const;
@@ -141,16 +138,15 @@ public:
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,
- float p_z_depth) const;
+ virtual Vector3 project_position(const Point2 &p_point, real_t p_z_depth) const;
Vector<Vector3> get_near_plane_points() const;
void set_cull_mask(uint32_t p_layers);
uint32_t get_cull_mask() const;
- void set_cull_mask_bit(int p_layer, bool p_enable);
- bool get_cull_mask_bit(int p_layer) const;
+ void set_cull_mask_value(int p_layer_number, bool p_enable);
+ bool get_cull_mask_value(int p_layer_number) const;
virtual Vector<Plane> get_frustum() const;
bool is_position_in_frustum(const Vector3 &p_position) const;
@@ -164,17 +160,19 @@ public:
void set_keep_aspect_mode(KeepAspect p_aspect);
KeepAspect get_keep_aspect_mode() const;
- void set_v_offset(float p_offset);
- float get_v_offset() const;
+ void set_v_offset(real_t p_offset);
+ real_t get_v_offset() const;
- void set_h_offset(float p_offset);
- float get_h_offset() const;
+ void set_h_offset(real_t p_offset);
+ real_t get_h_offset() const;
void set_doppler_tracking(DopplerTracking p_tracking);
DopplerTracking get_doppler_tracking() const;
Vector3 get_doppler_tracked_velocity() const;
+ RID get_pyramid_shape_rid();
+
Camera3D();
~Camera3D();
};
@@ -183,63 +181,4 @@ VARIANT_ENUM_CAST(Camera3D::Projection);
VARIANT_ENUM_CAST(Camera3D::KeepAspect);
VARIANT_ENUM_CAST(Camera3D::DopplerTracking);
-class ClippedCamera3D : public Camera3D {
- GDCLASS(ClippedCamera3D, Camera3D);
-
-public:
- enum ClipProcessCallback {
- CLIP_PROCESS_PHYSICS,
- CLIP_PROCESS_IDLE,
- };
-
-private:
- ClipProcessCallback process_callback = CLIP_PROCESS_PHYSICS;
- RID pyramid_shape;
- float margin = 0.0;
- float clip_offset = 0.0;
- uint32_t collision_mask = 1;
- bool clip_to_areas = false;
- bool clip_to_bodies = true;
-
- Set<RID> exclude;
-
- Vector<Vector3> points;
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
- virtual Transform3D get_camera_transform() const override;
-
-public:
- void set_clip_to_areas(bool p_clip);
- bool is_clip_to_areas_enabled() const;
-
- void set_clip_to_bodies(bool p_clip);
- bool is_clip_to_bodies_enabled() const;
-
- void set_margin(float p_margin);
- float get_margin() const;
-
- void set_process_callback(ClipProcessCallback p_mode);
- ClipProcessCallback get_process_callback() const;
-
- void set_collision_mask(uint32_t p_mask);
- uint32_t get_collision_mask() const;
-
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
-
- void add_exception_rid(const RID &p_rid);
- void add_exception(const Object *p_object);
- void remove_exception_rid(const RID &p_rid);
- void remove_exception(const Object *p_object);
- void clear_exceptions();
-
- float get_clip_offset() const;
-
- ClippedCamera3D();
- ~ClippedCamera3D();
-};
-
-VARIANT_ENUM_CAST(ClippedCamera3D::ClipProcessCallback);
#endif
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index dd1f25da68..814ed5c2a7 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -30,7 +30,6 @@
#include "collision_object_3d.h"
-#include "core/config/engine.h"
#include "scene/scene_string_names.h"
void CollisionObject3D::_notification(int p_what) {
@@ -38,8 +37,8 @@ void CollisionObject3D::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
if (_are_collision_shapes_visible()) {
debug_shape_old_transform = get_global_transform();
- for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
- debug_shapes_to_update.insert(E->key());
+ for (const KeyValue<uint32_t, ShapeData> &E : shapes) {
+ debug_shapes_to_update.insert(E.key);
}
_update_debug_shapes();
}
@@ -146,36 +145,40 @@ uint32_t CollisionObject3D::get_collision_mask() const {
return collision_mask;
}
-void CollisionObject3D::set_collision_layer_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
+void CollisionObject3D::set_collision_layer_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t collision_layer = get_collision_layer();
if (p_value) {
- collision_layer |= 1 << p_bit;
+ collision_layer |= 1 << (p_layer_number - 1);
} else {
- collision_layer &= ~(1 << p_bit);
+ collision_layer &= ~(1 << (p_layer_number - 1));
}
set_collision_layer(collision_layer);
}
-bool CollisionObject3D::get_collision_layer_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
- return get_collision_layer() & (1 << p_bit);
+bool CollisionObject3D::get_collision_layer_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_layer() & (1 << (p_layer_number - 1));
}
-void CollisionObject3D::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
+void CollisionObject3D::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
- mask |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
set_collision_mask(mask);
}
-bool CollisionObject3D::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+bool CollisionObject3D::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
void CollisionObject3D::set_disable_mode(DisableMode p_mode) {
@@ -251,10 +254,8 @@ void CollisionObject3D::_apply_enabled() {
}
}
-void CollisionObject3D::_input_event(Node *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) {
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_input_event, p_camera, p_input_event, p_pos, p_normal, p_shape);
- }
+void CollisionObject3D::_input_event_call(Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) {
+ GDVIRTUAL_CALL(_input_event, p_camera, p_input_event, p_pos, p_normal, p_shape);
emit_signal(SceneStringNames::get_singleton()->input_event, p_camera, p_input_event, p_pos, p_normal, p_shape);
}
@@ -323,8 +324,8 @@ void CollisionObject3D::_update_shape_data(uint32_t p_owner) {
}
void CollisionObject3D::_shape_changed(const Ref<Shape3D> &p_shape) {
- for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
- ShapeData &shapedata = E->get();
+ for (KeyValue<uint32_t, ShapeData> &E : shapes) {
+ ShapeData &shapedata = E.value;
ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
for (int i = 0; i < shapedata.shapes.size(); i++) {
ShapeData::ShapeBase &s = shapes[i];
@@ -379,8 +380,8 @@ void CollisionObject3D::_update_debug_shapes() {
}
void CollisionObject3D::_clear_debug_shapes() {
- for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
- ShapeData &shapedata = E->get();
+ for (KeyValue<uint32_t, ShapeData> &E : shapes) {
+ ShapeData &shapedata = E.value;
ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
for (int i = 0; i < shapedata.shapes.size(); i++) {
ShapeData::ShapeBase &s = shapes[i];
@@ -399,8 +400,8 @@ void CollisionObject3D::_clear_debug_shapes() {
void CollisionObject3D::_on_transform_changed() {
if (debug_shapes_count > 0 && !debug_shape_old_transform.is_equal_approx(get_global_transform())) {
debug_shape_old_transform = get_global_transform();
- for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
- ShapeData &shapedata = E->get();
+ for (KeyValue<uint32_t, ShapeData> &E : shapes) {
+ ShapeData &shapedata = E.value;
const ShapeData::ShapeBase *shapes = shapedata.shapes.ptr();
for (int i = 0; i < shapedata.shapes.size(); i++) {
RS::get_singleton()->instance_set_transform(shapes[i].debug_shape, debug_shape_old_transform * shapedata.xform);
@@ -423,10 +424,10 @@ void CollisionObject3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_collision_layer"), &CollisionObject3D::get_collision_layer);
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CollisionObject3D::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &CollisionObject3D::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &CollisionObject3D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CollisionObject3D::get_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CollisionObject3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CollisionObject3D::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &CollisionObject3D::set_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &CollisionObject3D::get_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &CollisionObject3D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &CollisionObject3D::get_collision_mask_value);
ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &CollisionObject3D::set_disable_mode);
ClassDB::bind_method(D_METHOD("get_disable_mode"), &CollisionObject3D::get_disable_mode);
ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &CollisionObject3D::set_ray_pickable);
@@ -450,7 +451,7 @@ void CollisionObject3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("shape_owner_clear_shapes", "owner_id"), &CollisionObject3D::shape_owner_clear_shapes);
ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject3D::shape_find_owner);
- BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "position"), PropertyInfo(Variant::VECTOR3, "normal"), PropertyInfo(Variant::INT, "shape_idx")));
+ GDVIRTUAL_BIND(_input_event, "camera", "event", "position", "normal", "shape_idx");
ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "position"), PropertyInfo(Variant::VECTOR3, "normal"), PropertyInfo(Variant::INT, "shape_idx")));
ADD_SIGNAL(MethodInfo("mouse_entered"));
@@ -522,15 +523,15 @@ bool CollisionObject3D::is_shape_owner_disabled(uint32_t p_owner) const {
}
void CollisionObject3D::get_shape_owners(List<uint32_t> *r_owners) {
- for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
- r_owners->push_back(E->key());
+ for (const KeyValue<uint32_t, ShapeData> &E : shapes) {
+ r_owners->push_back(E.key);
}
}
Array CollisionObject3D::_get_shape_owners() {
Array ret;
- for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
- ret.push_back(E->key());
+ for (const KeyValue<uint32_t, ShapeData> &E : shapes) {
+ ret.push_back(E.key);
}
return ret;
@@ -627,10 +628,10 @@ void CollisionObject3D::shape_owner_remove_shape(uint32_t p_owner, int p_shape)
shapes[p_owner].shapes.remove(p_shape);
- for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
- for (int i = 0; i < E->get().shapes.size(); i++) {
- if (E->get().shapes[i].index > index_to_remove) {
- E->get().shapes.write[i].index -= 1;
+ for (KeyValue<uint32_t, ShapeData> &E : shapes) {
+ for (int i = 0; i < E.value.shapes.size(); i++) {
+ if (E.value.shapes[i].index > index_to_remove) {
+ E.value.shapes.write[i].index -= 1;
}
}
}
@@ -649,10 +650,10 @@ void CollisionObject3D::shape_owner_clear_shapes(uint32_t p_owner) {
uint32_t CollisionObject3D::shape_find_owner(int p_shape_index) const {
ERR_FAIL_INDEX_V(p_shape_index, total_subshapes, 0);
- for (const Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
- for (int i = 0; i < E->get().shapes.size(); i++) {
- if (E->get().shapes[i].index == p_shape_index) {
- return E->key();
+ for (const KeyValue<uint32_t, ShapeData> &E : shapes) {
+ for (int i = 0; i < E.value.shapes.size(); i++) {
+ if (E.value.shapes[i].index == p_shape_index) {
+ return E.key;
}
}
}
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
index 7c30a5cd98..1c7e205888 100644
--- a/scene/3d/collision_object_3d.h
+++ b/scene/3d/collision_object_3d.h
@@ -31,9 +31,8 @@
#ifndef COLLISION_OBJECT_3D_H
#define COLLISION_OBJECT_3D_H
+#include "scene/3d/camera_3d.h"
#include "scene/3d/node_3d.h"
-#include "scene/resources/shape_3d.h"
-#include "servers/physics_server_3d.h"
class CollisionObject3D : public Node3D {
GDCLASS(CollisionObject3D, Node3D);
@@ -103,7 +102,7 @@ protected:
void _on_transform_changed();
friend class Viewport;
- virtual void _input_event(Node *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
+ virtual void _input_event_call(Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
virtual void _mouse_enter();
virtual void _mouse_exit();
@@ -112,6 +111,7 @@ protected:
void set_only_update_transform_changes(bool p_enable);
bool is_only_update_transform_changes_enabled() const;
+ GDVIRTUAL5(_input_event, Camera3D *, Ref<InputEvent>, Vector3, Vector3, int)
public:
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
@@ -119,11 +119,11 @@ public:
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
+ void set_collision_layer_value(int p_layer_number, bool p_value);
+ bool get_collision_layer_value(int p_layer_number) const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void set_disable_mode(DisableMode p_mode);
DisableMode get_disable_mode() const;
diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp
index 42645f47d4..6328d9c67d 100644
--- a/scene/3d/collision_polygon_3d.cpp
+++ b/scene/3d/collision_polygon_3d.cpp
@@ -32,7 +32,6 @@
#include "collision_object_3d.h"
#include "core/math/geometry_2d.h"
-#include "scene/resources/concave_polygon_shape_3d.h"
#include "scene/resources/convex_polygon_shape_3d.h"
void CollisionPolygon3D::_build_polygon() {
@@ -171,7 +170,7 @@ TypedArray<String> CollisionPolygon3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- warnings.push_back(TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape."));
+ warnings.push_back(TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidDynamicBody3D, CharacterBody3D, etc. to give them a shape."));
}
if (polygon.is_empty()) {
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
index 9643d33c86..4e496fba47 100644
--- a/scene/3d/collision_shape_3d.cpp
+++ b/scene/3d/collision_shape_3d.cpp
@@ -30,19 +30,10 @@
#include "collision_shape_3d.h"
-#include "core/math/quick_hull.h"
#include "mesh_instance_3d.h"
#include "physics_body_3d.h"
-#include "scene/resources/box_shape_3d.h"
-#include "scene/resources/capsule_shape_3d.h"
#include "scene/resources/concave_polygon_shape_3d.h"
#include "scene/resources/convex_polygon_shape_3d.h"
-#include "scene/resources/ray_shape_3d.h"
-#include "scene/resources/sphere_shape_3d.h"
-#include "scene/resources/world_margin_shape_3d.h"
-#include "servers/rendering_server.h"
-
-//TODO: Implement CylinderShape and HeightMapShape?
void CollisionShape3D::make_convex_from_siblings() {
Node *p = get_parent();
@@ -124,7 +115,7 @@ TypedArray<String> CollisionShape3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- warnings.push_back(TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape."));
+ warnings.push_back(TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidDynamicBody3D, CharacterBody3D, etc. to give them a shape."));
}
if (!shape.is_valid()) {
@@ -132,10 +123,9 @@ TypedArray<String> CollisionShape3D::get_configuration_warnings() const {
}
if (shape.is_valid() &&
- Object::cast_to<RigidBody3D>(get_parent()) &&
- Object::cast_to<ConcavePolygonShape3D>(*shape) &&
- Object::cast_to<RigidBody3D>(get_parent())->get_mode() != RigidBody3D::MODE_STATIC) {
- warnings.push_back(TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static."));
+ Object::cast_to<RigidDynamicBody3D>(get_parent()) &&
+ Object::cast_to<ConcavePolygonShape3D>(*shape)) {
+ warnings.push_back(TTR("ConcavePolygonShape3D doesn't support RigidDynamicBody3D in another mode than static."));
}
return warnings;
diff --git a/scene/3d/collision_shape_3d.h b/scene/3d/collision_shape_3d.h
index f69c1e38eb..cb7fe21eae 100644
--- a/scene/3d/collision_shape_3d.h
+++ b/scene/3d/collision_shape_3d.h
@@ -33,6 +33,7 @@
#include "scene/3d/node_3d.h"
#include "scene/resources/shape_3d.h"
+
class CollisionObject3D;
class CollisionShape3D : public Node3D {
GDCLASS(CollisionShape3D, Node3D);
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index 60f8ad8f36..48ef41e015 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -32,8 +32,8 @@
#include "scene/3d/camera_3d.h"
#include "scene/3d/gpu_particles_3d.h"
+#include "scene/main/viewport.h"
#include "scene/resources/particles_material.h"
-#include "servers/rendering_server.h"
AABB CPUParticles3D::get_aabb() const {
return AABB();
@@ -78,7 +78,7 @@ void CPUParticles3D::set_amount(int p_amount) {
particle_order.resize(p_amount);
}
-void CPUParticles3D::set_lifetime(float p_lifetime) {
+void CPUParticles3D::set_lifetime(double p_lifetime) {
ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
lifetime = p_lifetime;
}
@@ -87,19 +87,19 @@ void CPUParticles3D::set_one_shot(bool p_one_shot) {
one_shot = p_one_shot;
}
-void CPUParticles3D::set_pre_process_time(float p_time) {
+void CPUParticles3D::set_pre_process_time(double p_time) {
pre_process_time = p_time;
}
-void CPUParticles3D::set_explosiveness_ratio(float p_ratio) {
+void CPUParticles3D::set_explosiveness_ratio(real_t p_ratio) {
explosiveness_ratio = p_ratio;
}
-void CPUParticles3D::set_randomness_ratio(float p_ratio) {
+void CPUParticles3D::set_randomness_ratio(real_t p_ratio) {
randomness_ratio = p_ratio;
}
-void CPUParticles3D::set_lifetime_randomness(float p_random) {
+void CPUParticles3D::set_lifetime_randomness(double p_random) {
lifetime_randomness = p_random;
}
@@ -107,7 +107,7 @@ void CPUParticles3D::set_use_local_coordinates(bool p_enable) {
local_coords = p_enable;
}
-void CPUParticles3D::set_speed_scale(float p_scale) {
+void CPUParticles3D::set_speed_scale(double p_scale) {
speed_scale = p_scale;
}
@@ -119,7 +119,7 @@ int CPUParticles3D::get_amount() const {
return particles.size();
}
-float CPUParticles3D::get_lifetime() const {
+double CPUParticles3D::get_lifetime() const {
return lifetime;
}
@@ -127,19 +127,19 @@ bool CPUParticles3D::get_one_shot() const {
return one_shot;
}
-float CPUParticles3D::get_pre_process_time() const {
+double CPUParticles3D::get_pre_process_time() const {
return pre_process_time;
}
-float CPUParticles3D::get_explosiveness_ratio() const {
+real_t CPUParticles3D::get_explosiveness_ratio() const {
return explosiveness_ratio;
}
-float CPUParticles3D::get_randomness_ratio() const {
+real_t CPUParticles3D::get_randomness_ratio() const {
return randomness_ratio;
}
-float CPUParticles3D::get_lifetime_randomness() const {
+double CPUParticles3D::get_lifetime_randomness() const {
return lifetime_randomness;
}
@@ -147,7 +147,7 @@ bool CPUParticles3D::get_use_local_coordinates() const {
return local_coords;
}
-float CPUParticles3D::get_speed_scale() const {
+double CPUParticles3D::get_speed_scale() const {
return speed_scale;
}
@@ -212,7 +212,7 @@ TypedArray<String> CPUParticles3D::get_configuration_warnings() const {
warnings.push_back(TTR("Nothing is visible because no mesh has been assigned."));
}
- if (!anim_material_found && (get_param(PARAM_ANIM_SPEED) != 0.0 || get_param(PARAM_ANIM_OFFSET) != 0.0 ||
+ if (!anim_material_found && (get_param_max(PARAM_ANIM_SPEED) != 0.0 || get_param_max(PARAM_ANIM_OFFSET) != 0.0 ||
get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid())) {
warnings.push_back(TTR("CPUParticles3D animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
}
@@ -247,47 +247,52 @@ Vector3 CPUParticles3D::get_direction() const {
return direction;
}
-void CPUParticles3D::set_spread(float p_spread) {
+void CPUParticles3D::set_spread(real_t p_spread) {
spread = p_spread;
}
-float CPUParticles3D::get_spread() const {
+real_t CPUParticles3D::get_spread() const {
return spread;
}
-void CPUParticles3D::set_flatness(float p_flatness) {
+void CPUParticles3D::set_flatness(real_t p_flatness) {
flatness = p_flatness;
}
-float CPUParticles3D::get_flatness() const {
+real_t CPUParticles3D::get_flatness() const {
return flatness;
}
-void CPUParticles3D::set_param(Parameter p_param, float p_value) {
+void CPUParticles3D::set_param_min(Parameter p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
- parameters[p_param] = p_value;
+ parameters_min[p_param] = p_value;
+ if (parameters_min[p_param] > parameters_max[p_param]) {
+ set_param_max(p_param, p_value);
+ }
}
-float CPUParticles3D::get_param(Parameter p_param) const {
+real_t CPUParticles3D::get_param_min(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return parameters[p_param];
+ return parameters_min[p_param];
}
-void CPUParticles3D::set_param_randomness(Parameter p_param, float p_value) {
+void CPUParticles3D::set_param_max(Parameter p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
-
- randomness[p_param] = p_value;
+ parameters_max[p_param] = p_value;
+ if (parameters_min[p_param] > parameters_max[p_param]) {
+ set_param_min(p_param, p_value);
+ }
}
-float CPUParticles3D::get_param_randomness(Parameter p_param) const {
+real_t CPUParticles3D::get_param_max(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return randomness[p_param];
+ return parameters_max[p_param];
}
-static void _adjust_curve_range(const Ref<Curve> &p_curve, float p_min, float p_max) {
+static void _adjust_curve_range(const Ref<Curve> &p_curve, real_t p_min, real_t p_max) {
Ref<Curve> curve = p_curve;
if (!curve.is_valid()) {
return;
@@ -381,7 +386,7 @@ void CPUParticles3D::set_emission_shape(EmissionShape p_shape) {
emission_shape = p_shape;
}
-void CPUParticles3D::set_emission_sphere_radius(float p_radius) {
+void CPUParticles3D::set_emission_sphere_radius(real_t p_radius) {
emission_sphere_radius = p_radius;
}
@@ -405,19 +410,36 @@ void CPUParticles3D::set_emission_ring_axis(Vector3 p_axis) {
emission_ring_axis = p_axis;
}
-void CPUParticles3D::set_emission_ring_height(float p_height) {
+void CPUParticles3D::set_emission_ring_height(real_t p_height) {
emission_ring_height = p_height;
}
-void CPUParticles3D::set_emission_ring_radius(float p_radius) {
+void CPUParticles3D::set_emission_ring_radius(real_t p_radius) {
emission_ring_radius = p_radius;
}
-void CPUParticles3D::set_emission_ring_inner_radius(float p_radius) {
+void CPUParticles3D::set_emission_ring_inner_radius(real_t p_radius) {
emission_ring_inner_radius = p_radius;
}
-float CPUParticles3D::get_emission_sphere_radius() const {
+void CPUParticles3D::set_scale_curve_x(Ref<Curve> p_scale_curve) {
+ scale_curve_x = p_scale_curve;
+}
+
+void CPUParticles3D::set_scale_curve_y(Ref<Curve> p_scale_curve) {
+ scale_curve_y = p_scale_curve;
+}
+
+void CPUParticles3D::set_scale_curve_z(Ref<Curve> p_scale_curve) {
+ scale_curve_z = p_scale_curve;
+}
+
+void CPUParticles3D::set_split_scale(bool p_split_scale) {
+ split_scale = p_split_scale;
+ notify_property_list_changed();
+}
+
+real_t CPUParticles3D::get_emission_sphere_radius() const {
return emission_sphere_radius;
}
@@ -441,15 +463,15 @@ Vector3 CPUParticles3D::get_emission_ring_axis() const {
return emission_ring_axis;
}
-float CPUParticles3D::get_emission_ring_height() const {
+real_t CPUParticles3D::get_emission_ring_height() const {
return emission_ring_height;
}
-float CPUParticles3D::get_emission_ring_radius() const {
+real_t CPUParticles3D::get_emission_ring_radius() const {
return emission_ring_radius;
}
-float CPUParticles3D::get_emission_ring_inner_radius() const {
+real_t CPUParticles3D::get_emission_ring_inner_radius() const {
return emission_ring_inner_radius;
}
@@ -465,6 +487,22 @@ Vector3 CPUParticles3D::get_gravity() const {
return gravity;
}
+Ref<Curve> CPUParticles3D::get_scale_curve_x() const {
+ return scale_curve_x;
+}
+
+Ref<Curve> CPUParticles3D::get_scale_curve_y() const {
+ return scale_curve_y;
+}
+
+Ref<Curve> CPUParticles3D::get_scale_curve_z() const {
+ return scale_curve_z;
+}
+
+bool CPUParticles3D::get_split_scale() {
+ return split_scale;
+}
+
void CPUParticles3D::_validate_property(PropertyInfo &property) const {
if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) {
property.usage = PROPERTY_USAGE_NONE;
@@ -489,6 +527,10 @@ void CPUParticles3D::_validate_property(PropertyInfo &property) const {
if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
property.usage = PROPERTY_USAGE_NONE;
}
+
+ if (property.name.begins_with("scale_curve_") && !split_scale) {
+ property.usage = PROPERTY_USAGE_NONE;
+ }
}
static uint32_t idhash(uint32_t x) {
@@ -498,7 +540,7 @@ static uint32_t idhash(uint32_t x) {
return x;
}
-static float rand_from_seed(uint32_t &seed) {
+static real_t rand_from_seed(uint32_t &seed) {
int k;
int s = int(seed);
if (s == 0) {
@@ -510,7 +552,7 @@ static float rand_from_seed(uint32_t &seed) {
s += 2147483647;
}
seed = uint32_t(s);
- return float(seed % uint32_t(65536)) / 65535.0;
+ return (seed % uint32_t(65536)) / 65535.0;
}
void CPUParticles3D::_update_internal() {
@@ -519,7 +561,7 @@ void CPUParticles3D::_update_internal() {
return;
}
- float delta = get_process_delta_time();
+ double delta = get_process_delta_time();
if (emitting) {
inactive_time = 0;
} else {
@@ -541,14 +583,14 @@ void CPUParticles3D::_update_internal() {
bool processed = false;
if (time == 0 && pre_process_time > 0.0) {
- float frame_time;
+ double frame_time;
if (fixed_fps > 0) {
frame_time = 1.0 / fixed_fps;
} else {
frame_time = 1.0 / 30.0;
}
- float todo = pre_process_time;
+ double todo = pre_process_time;
while (todo >= 0) {
_particles_process(frame_time);
@@ -558,16 +600,16 @@ void CPUParticles3D::_update_internal() {
}
if (fixed_fps > 0) {
- float frame_time = 1.0 / fixed_fps;
- float decr = frame_time;
+ double frame_time = 1.0 / fixed_fps;
+ double decr = frame_time;
- float ldelta = delta;
+ double ldelta = delta;
if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
ldelta = 0.1;
} else if (ldelta <= 0.0) { //unlikely but..
ldelta = 0.001;
}
- float todo = frame_remainder + ldelta;
+ double todo = frame_remainder + ldelta;
while (todo >= frame_time) {
_particles_process(frame_time);
@@ -587,7 +629,7 @@ void CPUParticles3D::_update_internal() {
}
}
-void CPUParticles3D::_particles_process(float p_delta) {
+void CPUParticles3D::_particles_process(double p_delta) {
p_delta *= speed_scale;
int pcount = particles.size();
@@ -595,7 +637,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
Particle *parray = w;
- float prev_time = time;
+ double prev_time = time;
time += p_delta;
if (time > lifetime) {
time = Math::fmod(time, lifetime);
@@ -613,7 +655,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
velocity_xform = emission_xform.basis;
}
- float system_phase = time / lifetime;
+ double system_phase = time / lifetime;
for (int i = 0; i < pcount; i++) {
Particle &p = parray[i];
@@ -622,12 +664,12 @@ void CPUParticles3D::_particles_process(float p_delta) {
continue;
}
- float local_delta = p_delta;
+ double local_delta = p_delta;
// The phase is a ratio between 0 (birth) and 1 (end of life) for each particle.
// While we use time in tests later on, for randomness we use the phase as done in the
// original shader code, and we later multiply by lifetime to get the time.
- float restart_phase = float(i) / float(pcount);
+ double restart_phase = double(i) / double(pcount);
if (randomness_ratio > 0.0) {
uint32_t seed = cycle;
@@ -636,12 +678,12 @@ void CPUParticles3D::_particles_process(float p_delta) {
}
seed *= uint32_t(pcount);
seed += uint32_t(i);
- float random = float(idhash(seed) % uint32_t(65536)) / 65536.0;
- restart_phase += randomness_ratio * random * 1.0 / float(pcount);
+ double random = double(idhash(seed) % uint32_t(65536)) / 65536.0;
+ restart_phase += randomness_ratio * random * 1.0 / double(pcount);
}
restart_phase *= (1.0 - explosiveness_ratio);
- float restart_time = restart_phase * lifetime;
+ double restart_time = restart_phase * lifetime;
bool restart = false;
if (time > prev_time) {
@@ -682,17 +724,17 @@ void CPUParticles3D::_particles_process(float p_delta) {
}
p.active = true;
- /*float tex_linear_velocity = 0;
+ /*real_t tex_linear_velocity = 0;
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(0);
}*/
- float tex_angle = 0.0;
+ real_t tex_angle = 0.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv);
}
- float tex_anim_offset = 0.0;
+ real_t tex_anim_offset = 0.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(tv);
}
@@ -705,26 +747,39 @@ void CPUParticles3D::_particles_process(float p_delta) {
p.anim_offset_rand = Math::randf();
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- float angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread);
+ real_t angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread);
Vector3 rot = Vector3(Math::cos(angle1_rad), Math::sin(angle1_rad), 0.0);
- p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
+ p.velocity = rot * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], Math::randf());
} else {
//initiate velocity spread in 3D
- float angle1_rad = Math::atan2(direction.x, direction.z) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread);
- float angle2_rad = Math::atan2(direction.y, Math::abs(direction.z)) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * (1.0 - flatness) * spread);
+ real_t angle1_rad = Math::deg2rad((Math::randf() * (real_t)2.0 - (real_t)1.0) * spread);
+ real_t angle2_rad = Math::deg2rad((Math::randf() * (real_t)2.0 - (real_t)1.0) * ((real_t)1.0 - flatness) * spread);
Vector3 direction_xz = Vector3(Math::sin(angle1_rad), 0, Math::cos(angle1_rad));
Vector3 direction_yz = Vector3(0, Math::sin(angle2_rad), Math::cos(angle2_rad));
- direction_yz.z = direction_yz.z / MAX(0.0001, Math::sqrt(ABS(direction_yz.z))); //better uniform distribution
- Vector3 direction = Vector3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);
- direction.normalize();
- p.velocity = direction * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
+ Vector3 spread_direction = Vector3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);
+ Vector3 direction_nrm = direction;
+ if (direction_nrm.length_squared() > 0) {
+ direction_nrm.normalize();
+ } else {
+ direction_nrm = Vector3(0, 0, 1);
+ }
+ // rotate spread to direction
+ Vector3 binormal = Vector3(0.0, 1.0, 0.0).cross(direction_nrm);
+ if (binormal.length_squared() < 0.00000001) {
+ // direction is parallel to Y. Choose Z as the binormal.
+ binormal = Vector3(0.0, 0.0, 1.0);
+ }
+ binormal.normalize();
+ Vector3 normal = binormal.cross(direction_nrm);
+ spread_direction = binormal * spread_direction.x + normal * spread_direction.y + direction_nrm * spread_direction.z;
+ p.velocity = spread_direction * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], float(Math::randf()));
}
- float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]);
+ real_t base_angle = tex_angle * Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
p.custom[0] = Math::deg2rad(base_angle); //angle
p.custom[1] = 0.0; //phase
- p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation offset (0-1)
+ p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand); //animation offset (0-1)
p.transform = Transform3D();
p.time = 0;
p.lifetime = lifetime * (1.0 - Math::randf() * lifetime_randomness);
@@ -783,8 +838,8 @@ void CPUParticles3D::_particles_process(float p_delta) {
}
} break;
case EMISSION_SHAPE_RING: {
- float ring_random_angle = Math::randf() * 2.0 * Math_PI;
- float ring_random_radius = Math::randf() * (emission_ring_radius - emission_ring_inner_radius) + emission_ring_inner_radius;
+ real_t ring_random_angle = Math::randf() * Math_TAU;
+ real_t ring_random_radius = Math::randf() * (emission_ring_radius - emission_ring_inner_radius) + emission_ring_inner_radius;
Vector3 axis = emission_ring_axis.normalized();
Vector3 ortho_axis = Vector3();
if (axis == Vector3(1.0, 0.0, 0.0)) {
@@ -824,53 +879,53 @@ void CPUParticles3D::_particles_process(float p_delta) {
p.custom[1] = p.time / lifetime;
tv = p.time / p.lifetime;
- float tex_linear_velocity = 0.0;
+ real_t tex_linear_velocity = 0.0;
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(tv);
}
- float tex_orbit_velocity = 0.0;
+ real_t tex_orbit_velocity = 0.0;
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(tv);
}
}
- float tex_angular_velocity = 0.0;
+ real_t tex_angular_velocity = 0.0;
if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) {
tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(tv);
}
- float tex_linear_accel = 0.0;
+ real_t tex_linear_accel = 0.0;
if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) {
tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(tv);
}
- float tex_tangential_accel = 0.0;
+ real_t tex_tangential_accel = 0.0;
if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) {
tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(tv);
}
- float tex_radial_accel = 0.0;
+ real_t tex_radial_accel = 0.0;
if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) {
tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(tv);
}
- float tex_damping = 0.0;
+ real_t tex_damping = 0.0;
if (curve_parameters[PARAM_DAMPING].is_valid()) {
tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(tv);
}
- float tex_angle = 0.0;
+ real_t tex_angle = 0.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv);
}
- float tex_anim_speed = 0.0;
+ real_t tex_anim_speed = 0.0;
if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) {
tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(tv);
}
- float tex_anim_offset = 0.0;
+ real_t tex_anim_offset = 0.0;
if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) {
tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(tv);
}
@@ -881,28 +936,27 @@ void CPUParticles3D::_particles_process(float p_delta) {
position.z = 0.0;
}
//apply linear acceleration
- force += p.velocity.length() > 0.0 ? p.velocity.normalized() * (parameters[PARAM_LINEAR_ACCEL] + tex_linear_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_LINEAR_ACCEL]) : Vector3();
+ force += p.velocity.length() > 0.0 ? p.velocity.normalized() * tex_linear_accel * Math::lerp(parameters_min[PARAM_LINEAR_ACCEL], parameters_max[PARAM_LINEAR_ACCEL], rand_from_seed(alt_seed)) : Vector3();
//apply radial acceleration
Vector3 org = emission_xform.origin;
Vector3 diff = position - org;
- force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector3();
- //apply tangential acceleration;
+ force += diff.length() > 0.0 ? diff.normalized() * (tex_radial_accel)*Math::lerp(parameters_min[PARAM_RADIAL_ACCEL], parameters_max[PARAM_RADIAL_ACCEL], rand_from_seed(alt_seed)) : Vector3();
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
Vector2 yx = Vector2(diff.y, diff.x);
Vector2 yx2 = (yx * Vector2(-1.0, 1.0)).normalized();
- force += yx.length() > 0.0 ? Vector3(yx2.x, yx2.y, 0.0) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3();
+ force += yx.length() > 0.0 ? Vector3(yx2.x, yx2.y, 0.0) * (tex_tangential_accel * Math::lerp(parameters_min[PARAM_TANGENTIAL_ACCEL], parameters_max[PARAM_TANGENTIAL_ACCEL], rand_from_seed(alt_seed))) : Vector3();
} else {
Vector3 crossDiff = diff.normalized().cross(gravity.normalized());
- force += crossDiff.length() > 0.0 ? crossDiff.normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3();
+ force += crossDiff.length() > 0.0 ? crossDiff.normalized() * (tex_tangential_accel * Math::lerp(parameters_min[PARAM_TANGENTIAL_ACCEL], parameters_max[PARAM_TANGENTIAL_ACCEL], rand_from_seed(alt_seed))) : Vector3();
}
//apply attractor forces
p.velocity += force * local_delta;
//orbit velocity
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- float orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]);
+ real_t orbit_amount = tex_orbit_velocity * Math::lerp(parameters_min[PARAM_ORBIT_VELOCITY], parameters_max[PARAM_ORBIT_VELOCITY], rand_from_seed(alt_seed));
if (orbit_amount != 0.0) {
- float ang = orbit_amount * local_delta * Math_TAU;
+ real_t ang = orbit_amount * local_delta * Math_TAU;
// Not sure why the ParticlesMaterial code uses a clockwise rotation matrix,
// but we use -ang here to reproduce its behavior.
Transform2D rot = Transform2D(-ang, Vector2());
@@ -914,9 +968,10 @@ void CPUParticles3D::_particles_process(float p_delta) {
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
p.velocity = p.velocity.normalized() * tex_linear_velocity;
}
- if (parameters[PARAM_DAMPING] + tex_damping > 0.0) {
- float v = p.velocity.length();
- float damp = (parameters[PARAM_DAMPING] + tex_damping) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_DAMPING]);
+
+ if (parameters_max[PARAM_DAMPING] + tex_damping > 0.0) {
+ real_t v = p.velocity.length();
+ real_t damp = tex_damping * Math::lerp(parameters_min[PARAM_DAMPING], parameters_max[PARAM_DAMPING], rand_from_seed(alt_seed));
v -= damp * local_delta;
if (v < 0.0) {
p.velocity = Vector3();
@@ -924,27 +979,48 @@ void CPUParticles3D::_particles_process(float p_delta) {
p.velocity = p.velocity.normalized() * v;
}
}
- float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]);
- base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]);
+ real_t base_angle = (tex_angle)*Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
+ base_angle += p.custom[1] * lifetime * tex_angular_velocity * Math::lerp(parameters_min[PARAM_ANGULAR_VELOCITY], parameters_max[PARAM_ANGULAR_VELOCITY], rand_from_seed(alt_seed));
p.custom[0] = Math::deg2rad(base_angle); //angle
- p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]); //angle
+ p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand) + p.custom[1] * tex_anim_speed * Math::lerp(parameters_min[PARAM_ANIM_SPEED], parameters_max[PARAM_ANIM_SPEED], rand_from_seed(alt_seed)); //angle
}
//apply color
//apply hue rotation
- float tex_scale = 1.0;
- if (curve_parameters[PARAM_SCALE].is_valid()) {
- tex_scale = curve_parameters[PARAM_SCALE]->interpolate(tv);
+ Vector3 tex_scale = Vector3(1.0, 1.0, 1.0);
+ if (split_scale) {
+ if (scale_curve_x.is_valid()) {
+ tex_scale.x = scale_curve_x->interpolate(tv);
+ } else {
+ tex_scale.x = 1.0;
+ }
+ if (scale_curve_y.is_valid()) {
+ tex_scale.y = scale_curve_y->interpolate(tv);
+ } else {
+ tex_scale.y = 1.0;
+ }
+ if (scale_curve_z.is_valid()) {
+ tex_scale.z = scale_curve_z->interpolate(tv);
+ } else {
+ tex_scale.z = 1.0;
+ }
+ } else {
+ if (curve_parameters[PARAM_SCALE].is_valid()) {
+ float tmp_scale = curve_parameters[PARAM_SCALE]->interpolate(tv);
+ tex_scale.x = tmp_scale;
+ tex_scale.y = tmp_scale;
+ tex_scale.z = tmp_scale;
+ }
}
- float tex_hue_variation = 0.0;
+ real_t tex_hue_variation = 0.0;
if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) {
tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(tv);
}
- float hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_TAU * Math::lerp(1.0f, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]);
- float hue_rot_c = Math::cos(hue_rot_angle);
- float hue_rot_s = Math::sin(hue_rot_angle);
+ real_t hue_rot_angle = (tex_hue_variation)*Math_TAU * Math::lerp(parameters_min[PARAM_HUE_VARIATION], parameters_max[PARAM_HUE_VARIATION], p.hue_rot_rand);
+ real_t hue_rot_c = Math::cos(hue_rot_angle);
+ real_t hue_rot_s = Math::sin(hue_rot_angle);
Basis hue_rot_mat;
{
@@ -1012,13 +1088,21 @@ void CPUParticles3D::_particles_process(float p_delta) {
}
}
+ p.transform.basis = p.transform.basis.orthonormalized();
//scale by scale
- float base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], 1.0f, p.scale_rand * randomness[PARAM_SCALE]);
- if (base_scale < 0.000001) {
- base_scale = 0.000001;
+
+ Vector3 base_scale = tex_scale * Math::lerp(parameters_min[PARAM_SCALE], parameters_max[PARAM_SCALE], p.scale_rand);
+ if (base_scale.x < CMP_EPSILON) {
+ base_scale.x = CMP_EPSILON;
+ }
+ if (base_scale.y < CMP_EPSILON) {
+ base_scale.y = CMP_EPSILON;
+ }
+ if (base_scale.z < CMP_EPSILON) {
+ base_scale.z = CMP_EPSILON;
}
- p.transform.basis.scale(Vector3(1, 1, 1) * base_scale);
+ p.transform.basis.scale(base_scale);
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
p.velocity.z = 0.0;
@@ -1097,7 +1181,7 @@ void CPUParticles3D::_update_particle_data_buffer() {
ptr[10] = t.basis.elements[2][2];
ptr[11] = t.origin.z;
} else {
- memset(ptr, 0, sizeof(float) * 12);
+ memset(ptr, 0, sizeof(Transform3D));
}
Color c = r[idx].color;
@@ -1254,18 +1338,25 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) {
set_emission_shape(EmissionShape(material->get_emission_shape()));
set_emission_sphere_radius(material->get_emission_sphere_radius());
set_emission_box_extents(material->get_emission_box_extents());
+ Ref<CurveXYZTexture> scale3D = material->get_param_texture(ParticlesMaterial::PARAM_SCALE);
+ if (scale3D.is_valid()) {
+ split_scale = true;
+ scale_curve_x = scale3D->get_curve_x();
+ scale_curve_y = scale3D->get_curve_y();
+ scale_curve_z = scale3D->get_curve_z();
+ }
set_gravity(material->get_gravity());
set_lifetime_randomness(material->get_lifetime_randomness());
#define CONVERT_PARAM(m_param) \
- set_param(m_param, material->get_param(ParticlesMaterial::m_param)); \
+ set_param_min(m_param, material->get_param_min(ParticlesMaterial::m_param)); \
{ \
Ref<CurveTexture> ctex = material->get_param_texture(ParticlesMaterial::m_param); \
if (ctex.is_valid()) \
set_param_curve(m_param, ctex->get_curve()); \
} \
- set_param_randomness(m_param, material->get_param_randomness(ParticlesMaterial::m_param));
+ set_param_max(m_param, material->get_param_max(ParticlesMaterial::m_param));
CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY);
CONVERT_PARAM(PARAM_ANGULAR_VELOCITY);
@@ -1351,11 +1442,11 @@ void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &CPUParticles3D::set_flatness);
ClassDB::bind_method(D_METHOD("get_flatness"), &CPUParticles3D::get_flatness);
- ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &CPUParticles3D::set_param);
- ClassDB::bind_method(D_METHOD("get_param", "param"), &CPUParticles3D::get_param);
+ ClassDB::bind_method(D_METHOD("set_param_min", "param", "value"), &CPUParticles3D::set_param_min);
+ ClassDB::bind_method(D_METHOD("get_param_min", "param"), &CPUParticles3D::get_param_min);
- ClassDB::bind_method(D_METHOD("set_param_randomness", "param", "randomness"), &CPUParticles3D::set_param_randomness);
- ClassDB::bind_method(D_METHOD("get_param_randomness", "param"), &CPUParticles3D::get_param_randomness);
+ ClassDB::bind_method(D_METHOD("set_param_max", "param", "value"), &CPUParticles3D::set_param_max);
+ ClassDB::bind_method(D_METHOD("get_param_max", "param"), &CPUParticles3D::get_param_max);
ClassDB::bind_method(D_METHOD("set_param_curve", "param", "curve"), &CPUParticles3D::set_param_curve);
ClassDB::bind_method(D_METHOD("get_param_curve", "param"), &CPUParticles3D::get_param_curve);
@@ -1402,6 +1493,18 @@ void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_gravity"), &CPUParticles3D::get_gravity);
ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &CPUParticles3D::set_gravity);
+ ClassDB::bind_method(D_METHOD("get_split_scale"), &CPUParticles3D::get_split_scale);
+ ClassDB::bind_method(D_METHOD("set_split_scale", "split_scale"), &CPUParticles3D::set_split_scale);
+
+ ClassDB::bind_method(D_METHOD("get_scale_curve_x"), &CPUParticles3D::get_scale_curve_x);
+ ClassDB::bind_method(D_METHOD("set_scale_curve_x", "scale_curve"), &CPUParticles3D::set_scale_curve_x);
+
+ ClassDB::bind_method(D_METHOD("get_scale_curve_y"), &CPUParticles3D::get_scale_curve_y);
+ ClassDB::bind_method(D_METHOD("set_scale_curve_y", "scale_curve"), &CPUParticles3D::set_scale_curve_y);
+
+ ClassDB::bind_method(D_METHOD("get_scale_curve_z"), &CPUParticles3D::get_scale_curve_z);
+ ClassDB::bind_method(D_METHOD("set_scale_curve_z", "scale_curve"), &CPUParticles3D::set_scale_curve_z);
+
ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles3D::convert_from_particles);
ADD_GROUP("Emission Shape", "emission_");
@@ -1426,54 +1529,58 @@ void CPUParticles3D::_bind_methods() {
ADD_GROUP("Gravity", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity");
ADD_GROUP("Initial Velocity", "initial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY);
ADD_GROUP("Orbit Velocity", "orbit_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY);
ADD_GROUP("Linear Accel", "linear_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL);
ADD_GROUP("Radial Accel", "radial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_RADIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL);
ADD_GROUP("Tangential Accel", "tangential_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL);
ADD_GROUP("Damping", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param", "get_param", PARAM_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_min", "get_param_min", PARAM_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_max", "get_param_max", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING);
ADD_GROUP("Angle", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param", "get_param", PARAM_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE);
ADD_GROUP("Scale", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_SCALE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_amount_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_SCALE);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "split_scale"), "set_split_scale", "get_split_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scale_curve_x", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_scale_curve_x", "get_scale_curve_x");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scale_curve_y", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_scale_curve_y", "get_scale_curve_y");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scale_curve_z", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_scale_curve_z", "get_scale_curve_z");
ADD_GROUP("Color", "");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp");
ADD_GROUP("Hue Variation", "hue_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param", "get_param", PARAM_HUE_VARIATION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_min", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_min", "get_param_min", PARAM_HUE_VARIATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION);
ADD_GROUP("Animation", "anim_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_param", "get_param", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_OFFSET);
BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
@@ -1514,18 +1621,30 @@ CPUParticles3D::CPUParticles3D() {
set_emitting(true);
set_amount(8);
- set_param(PARAM_INITIAL_LINEAR_VELOCITY, 0);
- set_param(PARAM_ANGULAR_VELOCITY, 0);
- set_param(PARAM_ORBIT_VELOCITY, 0);
- set_param(PARAM_LINEAR_ACCEL, 0);
- set_param(PARAM_RADIAL_ACCEL, 0);
- set_param(PARAM_TANGENTIAL_ACCEL, 0);
- set_param(PARAM_DAMPING, 0);
- set_param(PARAM_ANGLE, 0);
- set_param(PARAM_SCALE, 1);
- set_param(PARAM_HUE_VARIATION, 0);
- set_param(PARAM_ANIM_SPEED, 0);
- set_param(PARAM_ANIM_OFFSET, 0);
+ set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0);
+ set_param_min(PARAM_ANGULAR_VELOCITY, 0);
+ set_param_min(PARAM_ORBIT_VELOCITY, 0);
+ set_param_min(PARAM_LINEAR_ACCEL, 0);
+ set_param_min(PARAM_RADIAL_ACCEL, 0);
+ set_param_min(PARAM_TANGENTIAL_ACCEL, 0);
+ set_param_min(PARAM_DAMPING, 0);
+ set_param_min(PARAM_ANGLE, 0);
+ set_param_min(PARAM_SCALE, 1);
+ set_param_min(PARAM_HUE_VARIATION, 0);
+ set_param_min(PARAM_ANIM_SPEED, 0);
+ set_param_min(PARAM_ANIM_OFFSET, 0);
+ set_param_max(PARAM_INITIAL_LINEAR_VELOCITY, 0);
+ set_param_max(PARAM_ANGULAR_VELOCITY, 0);
+ set_param_max(PARAM_ORBIT_VELOCITY, 0);
+ set_param_max(PARAM_LINEAR_ACCEL, 0);
+ set_param_max(PARAM_RADIAL_ACCEL, 0);
+ set_param_max(PARAM_TANGENTIAL_ACCEL, 0);
+ set_param_max(PARAM_DAMPING, 0);
+ set_param_max(PARAM_ANGLE, 0);
+ set_param_max(PARAM_SCALE, 1);
+ set_param_max(PARAM_HUE_VARIATION, 0);
+ set_param_max(PARAM_ANIM_SPEED, 0);
+ set_param_max(PARAM_ANIM_OFFSET, 0);
set_emission_shape(EMISSION_SHAPE_POINT);
set_emission_sphere_radius(1);
set_emission_box_extents(Vector3(1, 1, 1));
@@ -1536,10 +1655,6 @@ CPUParticles3D::CPUParticles3D() {
set_gravity(Vector3(0, -9.8, 0));
- for (int i = 0; i < PARAM_MAX; i++) {
- set_param_randomness(Parameter(i), 0);
- }
-
for (int i = 0; i < PARTICLE_FLAG_MAX; i++) {
particle_flags[i] = false;
}
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index 07d345ba2c..160814ead4 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -31,8 +31,6 @@
#ifndef CPU_PARTICLES_H
#define CPU_PARTICLES_H
-#include "core/templates/rid.h"
-#include "core/templates/safe_refcount.h"
#include "scene/3d/visual_instance_3d.h"
class CPUParticles3D : public GeometryInstance3D {
@@ -86,23 +84,23 @@ private:
struct Particle {
Transform3D transform;
Color color;
- float custom[4] = {};
+ real_t custom[4] = {};
Vector3 velocity;
bool active = false;
- float angle_rand = 0.0;
- float scale_rand = 0.0;
- float hue_rot_rand = 0.0;
- float anim_offset_rand = 0.0;
- float time = 0.0;
- float lifetime = 0.0;
+ real_t angle_rand = 0.0;
+ real_t scale_rand = 0.0;
+ real_t hue_rot_rand = 0.0;
+ real_t anim_offset_rand = 0.0;
+ double time = 0.0;
+ double lifetime = 0.0;
Color base_color;
uint32_t seed = 0;
};
- float time = 0.0;
- float inactive_time = 0.0;
- float frame_remainder = 0.0;
+ double time = 0.0;
+ double inactive_time = 0.0;
+ double frame_remainder = 0.0;
int cycle = 0;
bool redraw = false;
@@ -132,12 +130,12 @@ private:
bool one_shot = false;
- float lifetime = 1.0;
- float pre_process_time = 0.0;
- float explosiveness_ratio = 0.0;
- float randomness_ratio = 0.0;
- float lifetime_randomness = 0.0;
- float speed_scale = 1.0;
+ double lifetime = 1.0;
+ double pre_process_time = 0.0;
+ real_t explosiveness_ratio = 0.0;
+ real_t randomness_ratio = 0.0;
+ double lifetime_randomness = 0.0;
+ double speed_scale = 1.0;
bool local_coords = true;
int fixed_fps = 0;
bool fractional_delta = true;
@@ -153,11 +151,11 @@ private:
////////
Vector3 direction = Vector3(1, 0, 0);
- float spread = 45.0;
- float flatness = 0.0;
+ real_t spread = 45.0;
+ real_t flatness = 0.0;
- float parameters[PARAM_MAX];
- float randomness[PARAM_MAX] = {};
+ real_t parameters_min[PARAM_MAX];
+ real_t parameters_max[PARAM_MAX] = {};
Ref<Curve> curve_parameters[PARAM_MAX];
Color color = Color(1, 1, 1, 1);
@@ -166,21 +164,26 @@ private:
bool particle_flags[PARTICLE_FLAG_MAX] = {};
EmissionShape emission_shape = EMISSION_SHAPE_POINT;
- float emission_sphere_radius = 1.0;
+ real_t emission_sphere_radius = 1.0;
Vector3 emission_box_extents = Vector3(1, 1, 1);
Vector<Vector3> emission_points;
Vector<Vector3> emission_normals;
Vector<Color> emission_colors;
int emission_point_count = 0;
Vector3 emission_ring_axis;
- float emission_ring_height;
- float emission_ring_radius;
- float emission_ring_inner_radius;
+ real_t emission_ring_height;
+ real_t emission_ring_radius;
+ real_t emission_ring_inner_radius;
+
+ Ref<Curve> scale_curve_x;
+ Ref<Curve> scale_curve_y;
+ Ref<Curve> scale_curve_z;
+ bool split_scale = false;
Vector3 gravity = Vector3(0, -9.8, 0);
void _update_internal();
- void _particles_process(float p_delta);
+ void _particles_process(double p_delta);
void _update_particle_data_buffer();
Mutex update_mutex;
@@ -200,27 +203,27 @@ public:
void set_emitting(bool p_emitting);
void set_amount(int p_amount);
- void set_lifetime(float p_lifetime);
+ void set_lifetime(double p_lifetime);
void set_one_shot(bool p_one_shot);
- void set_pre_process_time(float p_time);
- void set_explosiveness_ratio(float p_ratio);
- void set_randomness_ratio(float p_ratio);
- void set_lifetime_randomness(float p_random);
+ void set_pre_process_time(double p_time);
+ void set_explosiveness_ratio(real_t p_ratio);
+ void set_randomness_ratio(real_t p_ratio);
+ void set_lifetime_randomness(double p_random);
void set_visibility_aabb(const AABB &p_aabb);
void set_use_local_coordinates(bool p_enable);
- void set_speed_scale(float p_scale);
+ void set_speed_scale(double p_scale);
bool is_emitting() const;
int get_amount() const;
- float get_lifetime() const;
+ double get_lifetime() const;
bool get_one_shot() const;
- float get_pre_process_time() const;
- float get_explosiveness_ratio() const;
- float get_randomness_ratio() const;
- float get_lifetime_randomness() const;
+ double get_pre_process_time() const;
+ real_t get_explosiveness_ratio() const;
+ real_t get_randomness_ratio() const;
+ double get_lifetime_randomness() const;
AABB get_visibility_aabb() const;
bool get_use_local_coordinates() const;
- float get_speed_scale() const;
+ double get_speed_scale() const;
void set_fixed_fps(int p_count);
int get_fixed_fps() const;
@@ -242,17 +245,17 @@ public:
void set_direction(Vector3 p_direction);
Vector3 get_direction() const;
- void set_spread(float p_spread);
- float get_spread() const;
+ void set_spread(real_t p_spread);
+ real_t get_spread() const;
- void set_flatness(float p_flatness);
- float get_flatness() const;
+ void set_flatness(real_t p_flatness);
+ real_t get_flatness() const;
- void set_param(Parameter p_param, float p_value);
- float get_param(Parameter p_param) const;
+ void set_param_min(Parameter p_param, real_t p_value);
+ real_t get_param_min(Parameter p_param) const;
- void set_param_randomness(Parameter p_param, float p_value);
- float get_param_randomness(Parameter p_param) const;
+ void set_param_max(Parameter p_param, real_t p_value);
+ real_t get_param_max(Parameter p_param) const;
void set_param_curve(Parameter p_param, const Ref<Curve> &p_curve);
Ref<Curve> get_param_curve(Parameter p_param) const;
@@ -267,28 +270,36 @@ public:
bool get_particle_flag(ParticleFlags p_particle_flag) const;
void set_emission_shape(EmissionShape p_shape);
- void set_emission_sphere_radius(float p_radius);
+ void set_emission_sphere_radius(real_t p_radius);
void set_emission_box_extents(Vector3 p_extents);
void set_emission_points(const Vector<Vector3> &p_points);
void set_emission_normals(const Vector<Vector3> &p_normals);
void set_emission_colors(const Vector<Color> &p_colors);
void set_emission_point_count(int p_count);
void set_emission_ring_axis(Vector3 p_axis);
- void set_emission_ring_height(float p_height);
- void set_emission_ring_radius(float p_radius);
- void set_emission_ring_inner_radius(float p_radius);
+ void set_emission_ring_height(real_t p_height);
+ void set_emission_ring_radius(real_t p_radius);
+ void set_emission_ring_inner_radius(real_t p_radius);
+ void set_scale_curve_x(Ref<Curve> p_scale_curve);
+ void set_scale_curve_y(Ref<Curve> p_scale_curve);
+ void set_scale_curve_z(Ref<Curve> p_scale_curve);
+ void set_split_scale(bool p_split_scale);
EmissionShape get_emission_shape() const;
- float get_emission_sphere_radius() const;
+ real_t get_emission_sphere_radius() const;
Vector3 get_emission_box_extents() const;
Vector<Vector3> get_emission_points() const;
Vector<Vector3> get_emission_normals() const;
Vector<Color> get_emission_colors() const;
int get_emission_point_count() const;
Vector3 get_emission_ring_axis() const;
- float get_emission_ring_height() const;
- float get_emission_ring_radius() const;
- float get_emission_ring_inner_radius() const;
+ real_t get_emission_ring_height() const;
+ real_t get_emission_ring_radius() const;
+ real_t get_emission_ring_inner_radius() const;
+ Ref<Curve> get_scale_curve_x() const;
+ Ref<Curve> get_scale_curve_y() const;
+ Ref<Curve> get_scale_curve_z() const;
+ bool get_split_scale();
void set_gravity(const Vector3 &p_gravity);
Vector3 get_gravity() const;
diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp
index 05f023721b..c94a99a203 100644
--- a/scene/3d/decal.cpp
+++ b/scene/3d/decal.cpp
@@ -53,48 +53,48 @@ Ref<Texture2D> Decal::get_texture(DecalTexture p_type) const {
return textures[p_type];
}
-void Decal::set_emission_energy(float p_energy) {
+void Decal::set_emission_energy(real_t p_energy) {
emission_energy = p_energy;
RS::get_singleton()->decal_set_emission_energy(decal, emission_energy);
}
-float Decal::get_emission_energy() const {
+real_t Decal::get_emission_energy() const {
return emission_energy;
}
-void Decal::set_albedo_mix(float p_mix) {
+void Decal::set_albedo_mix(real_t p_mix) {
albedo_mix = p_mix;
RS::get_singleton()->decal_set_albedo_mix(decal, albedo_mix);
}
-float Decal::get_albedo_mix() const {
+real_t Decal::get_albedo_mix() const {
return albedo_mix;
}
-void Decal::set_upper_fade(float p_fade) {
+void Decal::set_upper_fade(real_t p_fade) {
upper_fade = p_fade;
RS::get_singleton()->decal_set_fade(decal, upper_fade, lower_fade);
}
-float Decal::get_upper_fade() const {
+real_t Decal::get_upper_fade() const {
return upper_fade;
}
-void Decal::set_lower_fade(float p_fade) {
+void Decal::set_lower_fade(real_t p_fade) {
lower_fade = p_fade;
RS::get_singleton()->decal_set_fade(decal, upper_fade, lower_fade);
}
-float Decal::get_lower_fade() const {
+real_t Decal::get_lower_fade() const {
return lower_fade;
}
-void Decal::set_normal_fade(float p_fade) {
+void Decal::set_normal_fade(real_t p_fade) {
normal_fade = p_fade;
RS::get_singleton()->decal_set_normal_fade(decal, normal_fade);
}
-float Decal::get_normal_fade() const {
+real_t Decal::get_normal_fade() const {
return normal_fade;
}
@@ -117,21 +117,21 @@ bool Decal::is_distance_fade_enabled() const {
return distance_fade_enabled;
}
-void Decal::set_distance_fade_begin(float p_distance) {
+void Decal::set_distance_fade_begin(real_t p_distance) {
distance_fade_begin = p_distance;
RS::get_singleton()->decal_set_distance_fade(decal, distance_fade_enabled, distance_fade_begin, distance_fade_length);
}
-float Decal::get_distance_fade_begin() const {
+real_t Decal::get_distance_fade_begin() const {
return distance_fade_begin;
}
-void Decal::set_distance_fade_length(float p_length) {
+void Decal::set_distance_fade_length(real_t p_length) {
distance_fade_length = p_length;
RS::get_singleton()->decal_set_distance_fade(decal, distance_fade_enabled, distance_fade_begin, distance_fade_length);
}
-float Decal::get_distance_fade_length() const {
+real_t Decal::get_distance_fade_length() const {
return distance_fade_length;
}
diff --git a/scene/3d/decal.h b/scene/3d/decal.h
index 31a6315213..e9bda3276d 100644
--- a/scene/3d/decal.h
+++ b/scene/3d/decal.h
@@ -32,8 +32,6 @@
#define DECAL_H
#include "scene/3d/visual_instance_3d.h"
-#include "scene/resources/texture.h"
-#include "servers/rendering_server.h"
class Decal : public VisualInstance3D {
GDCLASS(Decal, VisualInstance3D);
@@ -51,16 +49,16 @@ private:
RID decal;
Vector3 extents = Vector3(1, 1, 1);
Ref<Texture2D> textures[TEXTURE_MAX];
- float emission_energy = 1.0;
- float albedo_mix = 1.0;
+ real_t emission_energy = 1.0;
+ real_t albedo_mix = 1.0;
Color modulate = Color(1, 1, 1, 1);
uint32_t cull_mask = (1 << 20) - 1;
- float normal_fade = 0.0;
- float upper_fade = 0.3;
- float lower_fade = 0.3;
+ real_t normal_fade = 0.0;
+ real_t upper_fade = 0.3;
+ real_t lower_fade = 0.3;
bool distance_fade_enabled = false;
- float distance_fade_begin = 10.0;
- float distance_fade_length = 1.0;
+ real_t distance_fade_begin = 10.0;
+ real_t distance_fade_length = 1.0;
protected:
static void _bind_methods();
@@ -75,32 +73,32 @@ public:
void set_texture(DecalTexture p_type, const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_texture(DecalTexture p_type) const;
- void set_emission_energy(float p_energy);
- float get_emission_energy() const;
+ void set_emission_energy(real_t p_energy);
+ real_t get_emission_energy() const;
- void set_albedo_mix(float p_mix);
- float get_albedo_mix() const;
+ void set_albedo_mix(real_t p_mix);
+ real_t get_albedo_mix() const;
void set_modulate(Color p_modulate);
Color get_modulate() const;
- void set_upper_fade(float p_energy);
- float get_upper_fade() const;
+ void set_upper_fade(real_t p_energy);
+ real_t get_upper_fade() const;
- void set_lower_fade(float p_fade);
- float get_lower_fade() const;
+ void set_lower_fade(real_t p_fade);
+ real_t get_lower_fade() const;
- void set_normal_fade(float p_fade);
- float get_normal_fade() const;
+ void set_normal_fade(real_t p_fade);
+ real_t get_normal_fade() const;
void set_enable_distance_fade(bool p_enable);
bool is_distance_fade_enabled() const;
- void set_distance_fade_begin(float p_distance);
- float get_distance_fade_begin() const;
+ void set_distance_fade_begin(real_t p_distance);
+ real_t get_distance_fade_begin() const;
- void set_distance_fade_length(float p_length);
- float get_distance_fade_length() const;
+ void set_distance_fade_length(real_t p_length);
+ real_t get_distance_fade_length() const;
void set_cull_mask(uint32_t p_layers);
uint32_t get_cull_mask() const;
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index 44cd7c10d8..32a62d8c7e 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -30,11 +30,8 @@
#include "gpu_particles_3d.h"
-#include "core/os/os.h"
#include "scene/resources/particles_material.h"
-#include "servers/rendering_server.h"
-
AABB GPUParticles3D::get_aabb() const {
return AABB();
}
@@ -59,7 +56,7 @@ void GPUParticles3D::set_amount(int p_amount) {
RS::get_singleton()->particles_set_amount(particles, amount);
}
-void GPUParticles3D::set_lifetime(float p_lifetime) {
+void GPUParticles3D::set_lifetime(double p_lifetime) {
ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
lifetime = p_lifetime;
RS::get_singleton()->particles_set_lifetime(particles, lifetime);
@@ -81,17 +78,17 @@ void GPUParticles3D::set_one_shot(bool p_one_shot) {
}
}
-void GPUParticles3D::set_pre_process_time(float p_time) {
+void GPUParticles3D::set_pre_process_time(double p_time) {
pre_process_time = p_time;
RS::get_singleton()->particles_set_pre_process_time(particles, pre_process_time);
}
-void GPUParticles3D::set_explosiveness_ratio(float p_ratio) {
+void GPUParticles3D::set_explosiveness_ratio(real_t p_ratio) {
explosiveness_ratio = p_ratio;
RS::get_singleton()->particles_set_explosiveness_ratio(particles, explosiveness_ratio);
}
-void GPUParticles3D::set_randomness_ratio(float p_ratio) {
+void GPUParticles3D::set_randomness_ratio(real_t p_ratio) {
randomness_ratio = p_ratio;
RS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio);
}
@@ -118,12 +115,12 @@ void GPUParticles3D::set_process_material(const Ref<Material> &p_material) {
update_configuration_warnings();
}
-void GPUParticles3D::set_speed_scale(float p_scale) {
+void GPUParticles3D::set_speed_scale(double p_scale) {
speed_scale = p_scale;
RS::get_singleton()->particles_set_speed_scale(particles, p_scale);
}
-void GPUParticles3D::set_collision_base_size(float p_size) {
+void GPUParticles3D::set_collision_base_size(real_t p_size) {
collision_base_size = p_size;
RS::get_singleton()->particles_set_collision_base_size(particles, p_size);
}
@@ -136,7 +133,7 @@ int GPUParticles3D::get_amount() const {
return amount;
}
-float GPUParticles3D::get_lifetime() const {
+double GPUParticles3D::get_lifetime() const {
return lifetime;
}
@@ -144,15 +141,15 @@ bool GPUParticles3D::get_one_shot() const {
return one_shot;
}
-float GPUParticles3D::get_pre_process_time() const {
+double GPUParticles3D::get_pre_process_time() const {
return pre_process_time;
}
-float GPUParticles3D::get_explosiveness_ratio() const {
+real_t GPUParticles3D::get_explosiveness_ratio() const {
return explosiveness_ratio;
}
-float GPUParticles3D::get_randomness_ratio() const {
+real_t GPUParticles3D::get_randomness_ratio() const {
return randomness_ratio;
}
@@ -168,11 +165,11 @@ Ref<Material> GPUParticles3D::get_process_material() const {
return process_material;
}
-float GPUParticles3D::get_speed_scale() const {
+double GPUParticles3D::get_speed_scale() const {
return speed_scale;
}
-float GPUParticles3D::get_collision_base_size() const {
+real_t GPUParticles3D::get_collision_base_size() const {
return collision_base_size;
}
@@ -186,7 +183,8 @@ void GPUParticles3D::set_trail_enabled(bool p_enabled) {
RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
update_configuration_warnings();
}
-void GPUParticles3D::set_trail_length(float p_seconds) {
+
+void GPUParticles3D::set_trail_length(double p_seconds) {
ERR_FAIL_COND(p_seconds < 0.001);
trail_length = p_seconds;
RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
@@ -195,7 +193,8 @@ void GPUParticles3D::set_trail_length(float p_seconds) {
bool GPUParticles3D::is_trail_enabled() const {
return trail_enabled;
}
-float GPUParticles3D::get_trail_length() const {
+
+double GPUParticles3D::get_trail_length() const {
return trail_length;
}
@@ -313,7 +312,7 @@ TypedArray<String> GPUParticles3D::get_configuration_warnings() const {
} else {
const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
if (!anim_material_found && process &&
- (process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
+ (process->get_param_max(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
warnings.push_back(TTR("Particles animation requires the usage of a BaseMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
}
@@ -470,7 +469,7 @@ void GPUParticles3D::_skinning_changed() {
if (draw_pass.is_valid() && draw_pass->get_builtin_bind_pose_count() > 0) {
xforms.resize(draw_pass->get_builtin_bind_pose_count());
for (int j = 0; j < draw_pass->get_builtin_bind_pose_count(); j++) {
- xforms.write[i] = draw_pass->get_builtin_bind_pose(j);
+ xforms.write[j] = draw_pass->get_builtin_bind_pose(j);
}
break;
}
@@ -485,6 +484,7 @@ void GPUParticles3D::set_skin(const Ref<Skin> &p_skin) {
skin = p_skin;
_skinning_changed();
}
+
Ref<Skin> GPUParticles3D::get_skin() const {
return skin;
}
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index 7b21cf03f1..5e96f660da 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -31,9 +31,7 @@
#ifndef PARTICLES_H
#define PARTICLES_H
-#include "core/templates/rid.h"
#include "scene/3d/visual_instance_3d.h"
-#include "scene/resources/material.h"
#include "scene/resources/skin.h"
class GPUParticles3D : public GeometryInstance3D {
@@ -64,21 +62,21 @@ private:
bool one_shot;
int amount;
- float lifetime;
- float pre_process_time;
- float explosiveness_ratio;
- float randomness_ratio;
- float speed_scale;
+ double lifetime;
+ double pre_process_time;
+ real_t explosiveness_ratio;
+ real_t randomness_ratio;
+ double speed_scale;
AABB visibility_aabb;
bool local_coords;
int fixed_fps;
bool fractional_delta;
bool interpolate = true;
NodePath sub_emitter;
- float collision_base_size = 0.01;
+ real_t collision_base_size = 0.01;
bool trail_enabled = false;
- float trail_length = 0.3;
+ double trail_length = 0.3;
TransformAlign transform_align = TRANSFORM_ALIGN_DISABLED;
@@ -104,33 +102,33 @@ public:
void set_emitting(bool p_emitting);
void set_amount(int p_amount);
- void set_lifetime(float p_lifetime);
+ void set_lifetime(double p_lifetime);
void set_one_shot(bool p_one_shot);
- void set_pre_process_time(float p_time);
- void set_explosiveness_ratio(float p_ratio);
- void set_randomness_ratio(float p_ratio);
+ void set_pre_process_time(double p_time);
+ void set_explosiveness_ratio(real_t p_ratio);
+ void set_randomness_ratio(real_t p_ratio);
void set_visibility_aabb(const AABB &p_aabb);
void set_use_local_coordinates(bool p_enable);
void set_process_material(const Ref<Material> &p_material);
- void set_speed_scale(float p_scale);
- void set_collision_base_size(float p_ratio);
+ void set_speed_scale(double p_scale);
+ void set_collision_base_size(real_t p_ratio);
void set_trail_enabled(bool p_enabled);
- void set_trail_length(float p_seconds);
+ void set_trail_length(double p_seconds);
bool is_emitting() const;
int get_amount() const;
- float get_lifetime() const;
+ double get_lifetime() const;
bool get_one_shot() const;
- float get_pre_process_time() const;
- float get_explosiveness_ratio() const;
- float get_randomness_ratio() const;
+ double get_pre_process_time() const;
+ real_t get_explosiveness_ratio() const;
+ real_t get_randomness_ratio() const;
AABB get_visibility_aabb() const;
bool get_use_local_coordinates() const;
Ref<Material> get_process_material() const;
- float get_speed_scale() const;
- float get_collision_base_size() const;
+ double get_speed_scale() const;
+ real_t get_collision_base_size() const;
bool is_trail_enabled() const;
- float get_trail_length() const;
+ double get_trail_length() const;
void set_fixed_fps(int p_count);
int get_fixed_fps() const;
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index cc1b620025..4fa34615bf 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -30,7 +30,6 @@
#include "gpu_particles_collision_3d.h"
-#include "core/templates/thread_work_pool.h"
#include "mesh_instance_3d.h"
#include "scene/3d/camera_3d.h"
#include "scene/main/viewport.h"
@@ -70,13 +69,13 @@ void GPUParticlesCollisionSphere::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_radius", "get_radius");
}
-void GPUParticlesCollisionSphere::set_radius(float p_radius) {
+void GPUParticlesCollisionSphere::set_radius(real_t p_radius) {
radius = p_radius;
RS::get_singleton()->particles_collision_set_sphere_radius(_get_collision(), radius);
update_gizmos();
}
-float GPUParticlesCollisionSphere::get_radius() const {
+real_t GPUParticlesCollisionSphere::get_radius() const {
return radius;
}
@@ -217,7 +216,7 @@ uint32_t GPUParticlesCollisionSDF::_create_bvh(LocalVector<BVH> &bvh_tree, FaceP
return index;
}
-static _FORCE_INLINE_ float Vector3_dot2(const Vector3 &p_vec3) {
+static _FORCE_INLINE_ real_t Vector3_dot2(const Vector3 &p_vec3) {
return p_vec3.dot(p_vec3);
}
@@ -421,7 +420,7 @@ Ref<Image> GPUParticlesCollisionSDF::bake() {
}
//test against original bounds
- if (!Geometry3D::triangle_box_overlap(aabb.position + aabb.size * 0.5, aabb.size * 0.5, face.vertex)) {
+ if (!Geometry3D::triangle_box_overlap(aabb.get_center(), aabb.size * 0.5, face.vertex)) {
continue;
}
@@ -439,7 +438,7 @@ Ref<Image> GPUParticlesCollisionSDF::bake() {
}
//test against original bounds
- if (!Geometry3D::triangle_box_overlap(aabb.position + aabb.size * 0.5, aabb.size * 0.5, face.vertex)) {
+ if (!Geometry3D::triangle_box_overlap(aabb.get_center(), aabb.size * 0.5, face.vertex)) {
continue;
}
@@ -738,31 +737,31 @@ uint32_t GPUParticlesAttractor3D::get_cull_mask() const {
return cull_mask;
}
-void GPUParticlesAttractor3D::set_strength(float p_strength) {
+void GPUParticlesAttractor3D::set_strength(real_t p_strength) {
strength = p_strength;
RS::get_singleton()->particles_collision_set_attractor_strength(collision, p_strength);
}
-float GPUParticlesAttractor3D::get_strength() const {
+real_t GPUParticlesAttractor3D::get_strength() const {
return strength;
}
-void GPUParticlesAttractor3D::set_attenuation(float p_attenuation) {
+void GPUParticlesAttractor3D::set_attenuation(real_t p_attenuation) {
attenuation = p_attenuation;
RS::get_singleton()->particles_collision_set_attractor_attenuation(collision, p_attenuation);
}
-float GPUParticlesAttractor3D::get_attenuation() const {
+real_t GPUParticlesAttractor3D::get_attenuation() const {
return attenuation;
}
-void GPUParticlesAttractor3D::set_directionality(float p_directionality) {
+void GPUParticlesAttractor3D::set_directionality(real_t p_directionality) {
directionality = p_directionality;
RS::get_singleton()->particles_collision_set_attractor_directionality(collision, p_directionality);
update_gizmos();
}
-float GPUParticlesAttractor3D::get_directionality() const {
+real_t GPUParticlesAttractor3D::get_directionality() const {
return directionality;
}
@@ -803,13 +802,13 @@ void GPUParticlesAttractorSphere::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_radius", "get_radius");
}
-void GPUParticlesAttractorSphere::set_radius(float p_radius) {
+void GPUParticlesAttractorSphere::set_radius(real_t p_radius) {
radius = p_radius;
RS::get_singleton()->particles_collision_set_sphere_radius(_get_collision(), radius);
update_gizmos();
}
-float GPUParticlesAttractorSphere::get_radius() const {
+real_t GPUParticlesAttractorSphere::get_radius() const {
return radius;
}
diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h
index c55463378d..fbf68ed6df 100644
--- a/scene/3d/gpu_particles_collision_3d.h
+++ b/scene/3d/gpu_particles_collision_3d.h
@@ -32,9 +32,7 @@
#define GPU_PARTICLES_COLLISION_3D_H
#include "core/templates/local_vector.h"
-#include "core/templates/rid.h"
#include "scene/3d/visual_instance_3d.h"
-#include "scene/resources/material.h"
class GPUParticlesCollision3D : public VisualInstance3D {
GDCLASS(GPUParticlesCollision3D, VisualInstance3D);
@@ -60,14 +58,14 @@ public:
class GPUParticlesCollisionSphere : public GPUParticlesCollision3D {
GDCLASS(GPUParticlesCollisionSphere, GPUParticlesCollision3D);
- float radius = 1.0;
+ real_t radius = 1.0;
protected:
static void _bind_methods();
public:
- void set_radius(float p_radius);
- float get_radius() const;
+ void set_radius(real_t p_radius);
+ real_t get_radius() const;
virtual AABB get_aabb() const override;
@@ -253,9 +251,9 @@ class GPUParticlesAttractor3D : public VisualInstance3D {
uint32_t cull_mask = 0xFFFFFFFF;
RID collision;
- float strength = 1.0;
- float attenuation = 1.0;
- float directionality = 0.0;
+ real_t strength = 1.0;
+ real_t attenuation = 1.0;
+ real_t directionality = 0.0;
protected:
_FORCE_INLINE_ RID _get_collision() { return collision; }
@@ -267,14 +265,14 @@ public:
void set_cull_mask(uint32_t p_cull_mask);
uint32_t get_cull_mask() const;
- void set_strength(float p_strength);
- float get_strength() const;
+ void set_strength(real_t p_strength);
+ real_t get_strength() const;
- void set_attenuation(float p_attenuation);
- float get_attenuation() const;
+ void set_attenuation(real_t p_attenuation);
+ real_t get_attenuation() const;
- void set_directionality(float p_directionality);
- float get_directionality() const;
+ void set_directionality(real_t p_directionality);
+ real_t get_directionality() const;
virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override { return Vector<Face3>(); }
@@ -284,14 +282,14 @@ public:
class GPUParticlesAttractorSphere : public GPUParticlesAttractor3D {
GDCLASS(GPUParticlesAttractorSphere, GPUParticlesAttractor3D);
- float radius = 1.0;
+ real_t radius = 1.0;
protected:
static void _bind_methods();
public:
- void set_radius(float p_radius);
- float get_radius() const;
+ void set_radius(real_t p_radius);
+ real_t get_radius() const;
virtual AABB get_aabb() const override;
diff --git a/scene/3d/importer_mesh_instance_3d.cpp b/scene/3d/importer_mesh_instance_3d.cpp
new file mode 100644
index 0000000000..748a2e5092
--- /dev/null
+++ b/scene/3d/importer_mesh_instance_3d.cpp
@@ -0,0 +1,85 @@
+/*************************************************************************/
+/* importer_mesh_instance_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "importer_mesh_instance_3d.h"
+
+#include "scene/resources/importer_mesh.h"
+
+void ImporterMeshInstance3D::set_mesh(const Ref<ImporterMesh> &p_mesh) {
+ mesh = p_mesh;
+}
+Ref<ImporterMesh> ImporterMeshInstance3D::get_mesh() const {
+ return mesh;
+}
+
+void ImporterMeshInstance3D::set_skin(const Ref<Skin> &p_skin) {
+ skin = p_skin;
+}
+Ref<Skin> ImporterMeshInstance3D::get_skin() const {
+ return skin;
+}
+
+void ImporterMeshInstance3D::set_surface_material(int p_idx, const Ref<Material> &p_material) {
+ ERR_FAIL_COND(p_idx < 0);
+ if (p_idx >= surface_materials.size()) {
+ surface_materials.resize(p_idx + 1);
+ }
+
+ surface_materials.write[p_idx] = p_material;
+}
+Ref<Material> ImporterMeshInstance3D::get_surface_material(int p_idx) const {
+ ERR_FAIL_COND_V(p_idx < 0, Ref<Material>());
+ if (p_idx >= surface_materials.size()) {
+ return Ref<Material>();
+ }
+ return surface_materials[p_idx];
+}
+
+void ImporterMeshInstance3D::set_skeleton_path(const NodePath &p_path) {
+ skeleton_path = p_path;
+}
+NodePath ImporterMeshInstance3D::get_skeleton_path() const {
+ return skeleton_path;
+}
+
+void ImporterMeshInstance3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &ImporterMeshInstance3D::set_mesh);
+ ClassDB::bind_method(D_METHOD("get_mesh"), &ImporterMeshInstance3D::get_mesh);
+
+ ClassDB::bind_method(D_METHOD("set_skin", "skin"), &ImporterMeshInstance3D::set_skin);
+ ClassDB::bind_method(D_METHOD("get_skin"), &ImporterMeshInstance3D::get_skin);
+
+ ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &ImporterMeshInstance3D::set_skeleton_path);
+ ClassDB::bind_method(D_METHOD("get_skeleton_path"), &ImporterMeshInstance3D::get_skeleton_path);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "ImporterMesh"), "set_mesh", "get_mesh");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path");
+}
diff --git a/scene/3d/importer_mesh_instance_3d.h b/scene/3d/importer_mesh_instance_3d.h
new file mode 100644
index 0000000000..0cf7dbe86b
--- /dev/null
+++ b/scene/3d/importer_mesh_instance_3d.h
@@ -0,0 +1,64 @@
+/*************************************************************************/
+/* importer_mesh_instance_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SCENE_IMPORTER_MESH_INSTANCE_3D_H
+#define SCENE_IMPORTER_MESH_INSTANCE_3D_H
+
+#include "scene/3d/node_3d.h"
+#include "scene/resources/immediate_mesh.h"
+#include "scene/resources/skin.h"
+
+class ImporterMesh;
+
+class ImporterMeshInstance3D : public Node3D {
+ GDCLASS(ImporterMeshInstance3D, Node3D)
+
+ Ref<ImporterMesh> mesh;
+ Ref<Skin> skin;
+ NodePath skeleton_path;
+ Vector<Ref<Material>> surface_materials;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_mesh(const Ref<ImporterMesh> &p_mesh);
+ Ref<ImporterMesh> get_mesh() const;
+
+ void set_skin(const Ref<Skin> &p_skin);
+ Ref<Skin> get_skin() const;
+
+ void set_surface_material(int p_idx, const Ref<Material> &p_material);
+ Ref<Material> get_surface_material(int p_idx) const;
+
+ void set_skeleton_path(const NodePath &p_path);
+ NodePath get_skeleton_path() const;
+};
+#endif
diff --git a/scene/3d/physics_joint_3d.cpp b/scene/3d/joint_3d.cpp
index 59440bd1a8..aa5ca85bdf 100644
--- a/scene/3d/physics_joint_3d.cpp
+++ b/scene/3d/joint_3d.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* physics_joint_3d.cpp */
+/* joint_3d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "physics_joint_3d.h"
+#include "joint_3d.h"
#include "scene/scene_string_names.h"
@@ -259,11 +259,11 @@ real_t PinJoint3D::get_param(Param p_param) const {
void PinJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
Vector3 pinpos = get_global_transform().origin;
- Vector3 local_a = body_a->get_global_transform().affine_inverse().xform(pinpos);
+ Vector3 local_a = body_a->to_local(pinpos);
Vector3 local_b;
if (body_b) {
- local_b = body_b->get_global_transform().affine_inverse().xform(pinpos);
+ local_b = body_b->to_local(pinpos);
} else {
local_b = pinpos;
}
diff --git a/scene/3d/physics_joint_3d.h b/scene/3d/joint_3d.h
index 3e0ea38a5c..211cf8e071 100644
--- a/scene/3d/physics_joint_3d.h
+++ b/scene/3d/joint_3d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* physics_joint_3d.h */
+/* joint_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef PHYSICS_JOINT_H
-#define PHYSICS_JOINT_H
+#ifndef JOINT_3D_H
+#define JOINT_3D_H
#include "scene/3d/node_3d.h"
#include "scene/3d/physics_body_3d.h"
@@ -334,4 +334,4 @@ public:
VARIANT_ENUM_CAST(Generic6DOFJoint3D::Param);
VARIANT_ENUM_CAST(Generic6DOFJoint3D::Flag);
-#endif // PHYSICS_JOINT_H
+#endif // JOINT_3D_H
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index c2943a9606..c787ba5087 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -30,15 +30,7 @@
#include "light_3d.h"
-#include "core/config/engine.h"
-#include "core/config/project_settings.h"
-#include "scene/resources/surface_tool.h"
-
-bool Light3D::_can_gizmo_scale() const {
- return false;
-}
-
-void Light3D::set_param(Param p_param, float p_value) {
+void Light3D::set_param(Param p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
param[p_param] = p_value;
@@ -53,7 +45,7 @@ void Light3D::set_param(Param p_param, float p_value) {
}
}
-float Light3D::get_param(Param p_param) const {
+real_t Light3D::get_param(Param p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
return param[p_param];
}
@@ -128,8 +120,8 @@ AABB Light3D::get_aabb() const {
return AABB(Vector3(-1, -1, -1) * param[PARAM_RANGE], Vector3(2, 2, 2) * param[PARAM_RANGE]);
} else if (type == RenderingServer::LIGHT_SPOT) {
- float len = param[PARAM_RANGE];
- float size = Math::tan(Math::deg2rad(param[PARAM_SPOT_ANGLE])) * len;
+ real_t len = param[PARAM_RANGE];
+ real_t size = Math::tan(Math::deg2rad(param[PARAM_SPOT_ANGLE])) * len;
return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len));
}
@@ -344,7 +336,7 @@ Light3D::Light3D(RenderingServer::LightType p_type) {
set_param(PARAM_SHADOW_FADE_START, 0.8);
set_param(PARAM_SHADOW_PANCAKE_SIZE, 20.0);
set_param(PARAM_SHADOW_BLUR, 1.0);
- set_param(PARAM_SHADOW_BIAS, 0.02);
+ set_param(PARAM_SHADOW_BIAS, 0.03);
set_param(PARAM_SHADOW_NORMAL_BIAS, 1.0);
set_param(PARAM_TRANSMITTANCE_BIAS, 0.05);
set_param(PARAM_SHADOW_VOLUMETRIC_FOG_FADE, 0.1);
@@ -425,8 +417,7 @@ DirectionalLight3D::DirectionalLight3D() :
set_param(PARAM_SHADOW_MAX_DISTANCE, 100);
set_param(PARAM_SHADOW_FADE_START, 0.8);
// Increase the default shadow bias to better suit most scenes.
- // Leave normal bias untouched as it doesn't benefit DirectionalLight3D as much as OmniLight3D.
- set_param(PARAM_SHADOW_BIAS, 0.05);
+ set_param(PARAM_SHADOW_BIAS, 0.1);
set_shadow_mode(SHADOW_PARALLEL_4_SPLITS);
blend_splits = false;
}
@@ -467,8 +458,7 @@ OmniLight3D::OmniLight3D() :
Light3D(RenderingServer::LIGHT_OMNI) {
set_shadow_mode(SHADOW_CUBE);
// Increase the default shadow biases to better suit most scenes.
- set_param(PARAM_SHADOW_BIAS, 0.1);
- set_param(PARAM_SHADOW_NORMAL_BIAS, 2.0);
+ set_param(PARAM_SHADOW_BIAS, 0.2);
}
TypedArray<String> SpotLight3D::get_configuration_warnings() const {
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index d0308a3025..f788c323f7 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -32,8 +32,6 @@
#define LIGHT_3D_H
#include "scene/3d/visual_instance_3d.h"
-#include "scene/resources/texture.h"
-#include "servers/rendering_server.h"
class Light3D : public VisualInstance3D {
GDCLASS(Light3D, VisualInstance3D);
@@ -71,7 +69,7 @@ public:
private:
Color color;
- float param[PARAM_MAX] = {};
+ real_t param[PARAM_MAX] = {};
Color shadow_color;
bool shadow = false;
bool negative = false;
@@ -88,8 +86,6 @@ private:
protected:
RID light;
- virtual bool _can_gizmo_scale() const;
-
static void _bind_methods();
void _notification(int p_what);
virtual void _validate_property(PropertyInfo &property) const override;
@@ -102,8 +98,8 @@ public:
void set_editor_only(bool p_editor_only);
bool is_editor_only() const;
- void set_param(Param p_param, float p_value);
- float get_param(Param p_param) const;
+ void set_param(Param p_param, real_t p_value);
+ real_t get_param(Param p_param) const;
void set_shadow(bool p_enable);
bool has_shadow() const;
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index 0085c8933d..b56f0fd145 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -31,14 +31,9 @@
#include "lightmap_gi.h"
#include "core/io/config_file.h"
-#include "core/io/dir_access.h"
-#include "core/io/file_access.h"
-#include "core/io/resource_saver.h"
-#include "core/math/camera_matrix.h"
#include "core/math/delaunay_3d.h"
-#include "core/os/os.h"
-#include "core/templates/sort_array.h"
#include "lightmap_probe.h"
+#include "scene/3d/mesh_instance_3d.h"
void LightmapGIData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance) {
User user;
@@ -472,7 +467,7 @@ int32_t LightmapGI::_compute_bsp_tree(const Vector<Vector3> &p_points, const Loc
}
}
if (i == 0) {
- centers.push_back(bounds.position + bounds.size * 0.5);
+ centers.push_back(bounds.get_center());
} else {
bounds_all.merge_with(bounds);
}
@@ -560,7 +555,7 @@ void LightmapGI::_plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cel
subcell.position = Vector3(pos) * p_cell_size;
subcell.size = Vector3(half_size, half_size, half_size) * p_cell_size;
- if (!Geometry3D::triangle_box_overlap(subcell.position + subcell.size * 0.5, subcell.size * 0.5, p_triangle)) {
+ if (!Geometry3D::triangle_box_overlap(subcell.get_center(), subcell.size * 0.5, p_triangle)) {
continue;
}
diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h
index 8a54512383..e73350fd64 100644
--- a/scene/3d/lightmap_gi.h
+++ b/scene/3d/lightmap_gi.h
@@ -34,10 +34,7 @@
#include "core/templates/local_vector.h"
#include "scene/3d/light_3d.h"
#include "scene/3d/lightmapper.h"
-#include "scene/3d/mesh_instance_3d.h"
-#include "scene/3d/multimesh_instance_3d.h"
#include "scene/3d/visual_instance_3d.h"
-#include "scene/resources/sky.h"
class LightmapGIData : public Resource {
GDCLASS(LightmapGIData, Resource);
diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h
index 3a6a88d435..d028628901 100644
--- a/scene/3d/lightmapper.h
+++ b/scene/3d/lightmapper.h
@@ -31,8 +31,9 @@
#ifndef LIGHTMAPPER_H
#define LIGHTMAPPER_H
-#include "scene/resources/mesh.h"
-#include "servers/rendering/rendering_device.h"
+#include "core/object/ref_counted.h"
+
+class Image;
#if !defined(__aligned)
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index 9ca1d55d0b..67f4a88228 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -33,8 +33,6 @@
#include "collision_shape_3d.h"
#include "core/core_string_names.h"
#include "physics_body_3d.h"
-#include "scene/resources/material.h"
-#include "skeleton_3d.h"
bool MeshInstance3D::_set(const StringName &p_name, const Variant &p_value) {
//this is not _too_ bad performance wise, really. it only arrives here if the property was not set anywhere else.
@@ -88,8 +86,8 @@ bool MeshInstance3D::_get(const StringName &p_name, Variant &r_ret) const {
void MeshInstance3D::_get_property_list(List<PropertyInfo> *p_list) const {
List<String> ls;
- for (const Map<StringName, BlendShapeTrack>::Element *E = blend_shape_tracks.front(); E; E = E->next()) {
- ls.push_back(E->key());
+ for (const KeyValue<StringName, BlendShapeTrack> &E : blend_shape_tracks) {
+ ls.push_back(E.key);
}
ls.sort();
@@ -276,7 +274,8 @@ Node *MeshInstance3D::create_multiple_convex_collisions_node() {
return nullptr;
}
- Vector<Ref<Shape3D>> shapes = mesh->convex_decompose();
+ Mesh::ConvexDecompositionSettings settings;
+ Vector<Ref<Shape3D>> shapes = mesh->convex_decompose(settings);
if (!shapes.size()) {
return nullptr;
}
@@ -370,6 +369,8 @@ void MeshInstance3D::create_debug_tangents() {
for (int i = 0; i < mesh->get_surface_count(); i++) {
Array arrays = mesh->surface_get_arrays(i);
+ ERR_CONTINUE(arrays.size() != Mesh::ARRAY_MAX);
+
Vector<Vector3> verts = arrays[Mesh::ARRAY_VERTEX];
Vector<Vector3> norms = arrays[Mesh::ARRAY_NORMAL];
if (norms.size() == 0) {
diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h
index e2d20d0a90..beb7f6cf95 100644
--- a/scene/3d/mesh_instance_3d.h
+++ b/scene/3d/mesh_instance_3d.h
@@ -31,10 +31,10 @@
#ifndef MESH_INSTANCE_H
#define MESH_INSTANCE_H
-#include "scene/3d/skeleton_3d.h"
#include "scene/3d/visual_instance_3d.h"
-#include "scene/resources/mesh.h"
-#include "scene/resources/skin.h"
+
+class Skin;
+class SkinReference;
class MeshInstance3D : public GeometryInstance3D {
GDCLASS(MeshInstance3D, GeometryInstance3D);
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index f890ceeb95..c2d5c757db 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -30,7 +30,6 @@
#include "navigation_agent_3d.h"
-#include "core/config/engine.h"
#include "servers/navigation_server_3d.h"
void NavigationAgent3D::_bind_methods() {
diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h
index 56da2d1acf..bebfdc5f7e 100644
--- a/scene/3d/navigation_agent_3d.h
+++ b/scene/3d/navigation_agent_3d.h
@@ -31,7 +31,6 @@
#ifndef NAVIGATION_AGENT_H
#define NAVIGATION_AGENT_H
-#include "core/templates/vector.h"
#include "scene/main/node.h"
class Node3D;
diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h
index 2f78f624a4..ab0b158303 100644
--- a/scene/3d/navigation_obstacle_3d.h
+++ b/scene/3d/navigation_obstacle_3d.h
@@ -32,7 +32,6 @@
#define NAVIGATION_OBSTACLE_H
#include "scene/3d/node_3d.h"
-#include "scene/main/node.h"
class NavigationObstacle3D : public Node {
GDCLASS(NavigationObstacle3D, Node);
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 2976dad39d..8a51a259f7 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -30,7 +30,6 @@
#include "navigation_region_3d.h"
-#include "core/os/thread.h"
#include "mesh_instance_3d.h"
#include "servers/navigation_server_3d.h"
diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h
index c2045215b1..ec7761ef93 100644
--- a/scene/3d/navigation_region_3d.h
+++ b/scene/3d/navigation_region_3d.h
@@ -32,7 +32,6 @@
#define NAVIGATION_REGION_H
#include "scene/3d/node_3d.h"
-#include "scene/resources/mesh.h"
#include "scene/resources/navigation_mesh.h"
class NavigationRegion3D : public Node3D {
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index 0daee69ee5..12470939f5 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -30,11 +30,9 @@
#include "node_3d.h"
-#include "core/config/engine.h"
#include "core/object/message_queue.h"
#include "scene/3d/visual_instance_3d.h"
-#include "scene/main/scene_tree.h"
-#include "scene/main/window.h"
+#include "scene/main/viewport.h"
#include "scene/scene_string_names.h"
/*
@@ -588,31 +586,31 @@ bool Node3D::is_visible() const {
return data.visible;
}
-void Node3D::rotate_object_local(const Vector3 &p_axis, float p_angle) {
+void Node3D::rotate_object_local(const Vector3 &p_axis, real_t p_angle) {
Transform3D t = get_transform();
t.basis.rotate_local(p_axis, p_angle);
set_transform(t);
}
-void Node3D::rotate(const Vector3 &p_axis, float p_angle) {
+void Node3D::rotate(const Vector3 &p_axis, real_t p_angle) {
Transform3D t = get_transform();
t.basis.rotate(p_axis, p_angle);
set_transform(t);
}
-void Node3D::rotate_x(float p_angle) {
+void Node3D::rotate_x(real_t p_angle) {
Transform3D t = get_transform();
t.basis.rotate(Vector3(1, 0, 0), p_angle);
set_transform(t);
}
-void Node3D::rotate_y(float p_angle) {
+void Node3D::rotate_y(real_t p_angle) {
Transform3D t = get_transform();
t.basis.rotate(Vector3(0, 1, 0), p_angle);
set_transform(t);
}
-void Node3D::rotate_z(float p_angle) {
+void Node3D::rotate_z(real_t p_angle) {
Transform3D t = get_transform();
t.basis.rotate(Vector3(0, 0, 1), p_angle);
set_transform(t);
@@ -644,7 +642,7 @@ void Node3D::scale_object_local(const Vector3 &p_scale) {
set_transform(t);
}
-void Node3D::global_rotate(const Vector3 &p_axis, float p_angle) {
+void Node3D::global_rotate(const Vector3 &p_axis, real_t p_angle) {
Transform3D t = get_global_transform();
t.basis.rotate(p_axis, p_angle);
set_global_transform(t);
@@ -673,19 +671,17 @@ void Node3D::set_identity() {
}
void Node3D::look_at(const Vector3 &p_target, const Vector3 &p_up) {
- Vector3 origin(get_global_transform().origin);
+ Vector3 origin = get_global_transform().origin;
look_at_from_position(origin, p_target, p_up);
}
void Node3D::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) {
- ERR_FAIL_COND_MSG(p_pos == p_target, "Node origin and target are in the same position, look_at() failed.");
- ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos) == Vector3(), "Up vector and direction between node origin and target are aligned, look_at() failed.");
+ ERR_FAIL_COND_MSG(p_pos.is_equal_approx(p_target), "Node origin and target are in the same position, look_at() failed.");
+ ERR_FAIL_COND_MSG(p_up.is_equal_approx(Vector3()), "The up vector can't be zero, look_at() failed.");
+ ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos).is_equal_approx(Vector3()), "Up vector and direction between node origin and target are aligned, look_at() failed.");
- Transform3D lookat;
- lookat.origin = p_pos;
-
- Vector3 original_scale(get_scale());
- lookat = lookat.looking_at(p_target, p_up);
+ Transform3D lookat = Transform3D(Basis::looking_at(p_target - p_pos, p_up), p_pos);
+ Vector3 original_scale = get_scale();
set_global_transform(lookat);
set_scale(original_scale);
}
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index 282f4805cc..0fd0c4e205 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -32,7 +32,6 @@
#define NODE_3D_H
#include "scene/main/node.h"
-#include "scene/main/scene_tree.h"
class Node3DGizmo : public RefCounted {
GDCLASS(Node3DGizmo, RefCounted);
@@ -167,18 +166,18 @@ public:
Transform3D get_relative_transform(const Node *p_parent) const;
- void rotate(const Vector3 &p_axis, float p_angle);
- void rotate_x(float p_angle);
- void rotate_y(float p_angle);
- void rotate_z(float p_angle);
+ void rotate(const Vector3 &p_axis, real_t p_angle);
+ void rotate_x(real_t p_angle);
+ void rotate_y(real_t p_angle);
+ void rotate_z(real_t p_angle);
void translate(const Vector3 &p_offset);
void scale(const Vector3 &p_ratio);
- void rotate_object_local(const Vector3 &p_axis, float p_angle);
+ void rotate_object_local(const Vector3 &p_axis, real_t p_angle);
void scale_object_local(const Vector3 &p_scale);
void translate_object_local(const Vector3 &p_offset);
- void global_rotate(const Vector3 &p_axis, float p_angle);
+ void global_rotate(const Vector3 &p_axis, real_t p_angle);
void global_scale(const Vector3 &p_scale);
void global_translate(const Vector3 &p_offset);
diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp
index 3d1a27911b..f3e174c01b 100644
--- a/scene/3d/occluder_instance_3d.cpp
+++ b/scene/3d/occluder_instance_3d.cpp
@@ -195,18 +195,22 @@ uint32_t OccluderInstance3D::get_bake_mask() const {
return bake_mask;
}
-void OccluderInstance3D::set_bake_mask_bit(int p_layer, bool p_enable) {
- ERR_FAIL_INDEX(p_layer, 32);
- if (p_enable) {
- set_bake_mask(bake_mask | (1 << p_layer));
+void OccluderInstance3D::set_bake_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Render layer number must be between 1 and 20 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 20, "Render layer number must be between 1 and 20 inclusive.");
+ uint32_t mask = get_bake_mask();
+ if (p_value) {
+ mask |= 1 << (p_layer_number - 1);
} else {
- set_bake_mask(bake_mask & (~(1 << p_layer)));
+ mask &= ~(1 << (p_layer_number - 1));
}
+ set_bake_mask(mask);
}
-bool OccluderInstance3D::get_bake_mask_bit(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, 32, false);
- return (bake_mask & (1 << p_layer));
+bool OccluderInstance3D::get_bake_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Render layer number must be between 1 and 20 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 20, false, "Render layer number must be between 1 and 20 inclusive.");
+ return bake_mask & (1 << (p_layer_number - 1));
}
bool OccluderInstance3D::_bake_material_check(Ref<Material> p_material) {
@@ -345,8 +349,8 @@ TypedArray<String> OccluderInstance3D::get_configuration_warnings() const {
void OccluderInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bake_mask", "mask"), &OccluderInstance3D::set_bake_mask);
ClassDB::bind_method(D_METHOD("get_bake_mask"), &OccluderInstance3D::get_bake_mask);
- ClassDB::bind_method(D_METHOD("set_bake_mask_bit", "layer", "enabled"), &OccluderInstance3D::set_bake_mask_bit);
- ClassDB::bind_method(D_METHOD("get_bake_mask_bit", "layer"), &OccluderInstance3D::get_bake_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_bake_mask_value", "layer_number", "value"), &OccluderInstance3D::set_bake_mask_value);
+ ClassDB::bind_method(D_METHOD("get_bake_mask_value", "layer_number"), &OccluderInstance3D::get_bake_mask_value);
ClassDB::bind_method(D_METHOD("set_occluder", "occluder"), &OccluderInstance3D::set_occluder);
ClassDB::bind_method(D_METHOD("get_occluder"), &OccluderInstance3D::get_occluder);
diff --git a/scene/3d/occluder_instance_3d.h b/scene/3d/occluder_instance_3d.h
index d382cd090e..173614b80c 100644
--- a/scene/3d/occluder_instance_3d.h
+++ b/scene/3d/occluder_instance_3d.h
@@ -99,8 +99,9 @@ public:
void set_bake_mask(uint32_t p_mask);
uint32_t get_bake_mask() const;
- void set_bake_mask_bit(int p_layer, bool p_enable);
- bool get_bake_mask_bit(int p_layer) const;
+ void set_bake_mask_value(int p_layer_number, bool p_enable);
+ bool get_bake_mask_value(int p_layer_number) const;
+
BakeError bake(Node *p_from_node, String p_occluder_path = "");
OccluderInstance3D();
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index 589135710f..9ea37e4bfa 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -30,9 +30,6 @@
#include "path_3d.h"
-#include "core/config/engine.h"
-#include "scene/scene_string_names.h"
-
void Path3D::_notification(int p_what) {
}
@@ -94,13 +91,13 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
return;
}
- float bl = c->get_baked_length();
+ real_t bl = c->get_baked_length();
if (bl == 0.0) {
return;
}
- float bi = c->get_bake_interval();
- float o_next = offset + bi;
- float o_prev = offset - bi;
+ real_t bi = c->get_bake_interval();
+ real_t o_next = offset + bi;
+ real_t o_prev = offset - bi;
if (loop) {
o_next = Math::fposmod(o_next, bl);
@@ -169,8 +166,8 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
Vector3 t_cur = (c->interpolate_baked(offset + delta_offset, cubic) - pos).normalized();
Vector3 axis = t_prev.cross(t_cur);
- float dot = t_prev.dot(t_cur);
- float angle = Math::acos(CLAMP(dot, -1, 1));
+ real_t dot = t_prev.dot(t_cur);
+ real_t angle = Math::acos(CLAMP(dot, -1, 1));
if (likely(!Math::is_zero_approx(angle))) {
if (rotation_mode == ROTATION_Y) {
@@ -189,7 +186,7 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
}
// do the additional tilting
- float tilt_angle = c->interpolate_baked_tilt(offset);
+ real_t tilt_angle = c->interpolate_baked_tilt(offset);
Vector3 tilt_axis = t_cur; // not sure what tilt is supposed to do, is this correct??
if (likely(!Math::is_zero_approx(Math::abs(tilt_angle)))) {
@@ -244,7 +241,7 @@ bool PathFollow3D::get_cubic_interpolation() const {
void PathFollow3D::_validate_property(PropertyInfo &property) const {
if (property.name == "offset") {
- float max = 10000;
+ real_t max = 10000;
if (path && path->get_curve().is_valid()) {
max = path->get_curve()->get_baked_length();
}
@@ -307,13 +304,13 @@ void PathFollow3D::_bind_methods() {
BIND_ENUM_CONSTANT(ROTATION_ORIENTED);
}
-void PathFollow3D::set_offset(float p_offset) {
+void PathFollow3D::set_offset(real_t p_offset) {
delta_offset = p_offset - offset;
offset = p_offset;
if (path) {
if (path->get_curve().is_valid()) {
- float path_length = path->get_curve()->get_baked_length();
+ real_t path_length = path->get_curve()->get_baked_length();
if (loop) {
offset = Math::fposmod(offset, path_length);
@@ -329,39 +326,39 @@ void PathFollow3D::set_offset(float p_offset) {
}
}
-void PathFollow3D::set_h_offset(float p_h_offset) {
+void PathFollow3D::set_h_offset(real_t p_h_offset) {
h_offset = p_h_offset;
if (path) {
_update_transform();
}
}
-float PathFollow3D::get_h_offset() const {
+real_t PathFollow3D::get_h_offset() const {
return h_offset;
}
-void PathFollow3D::set_v_offset(float p_v_offset) {
+void PathFollow3D::set_v_offset(real_t p_v_offset) {
v_offset = p_v_offset;
if (path) {
_update_transform();
}
}
-float PathFollow3D::get_v_offset() const {
+real_t PathFollow3D::get_v_offset() const {
return v_offset;
}
-float PathFollow3D::get_offset() const {
+real_t PathFollow3D::get_offset() const {
return offset;
}
-void PathFollow3D::set_unit_offset(float p_unit_offset) {
+void PathFollow3D::set_unit_offset(real_t 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 PathFollow3D::get_unit_offset() const {
+real_t PathFollow3D::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 {
diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h
index 8545370a4a..1ffe291100 100644
--- a/scene/3d/path_3d.h
+++ b/scene/3d/path_3d.h
@@ -83,17 +83,17 @@ protected:
static void _bind_methods();
public:
- void set_offset(float p_offset);
- float get_offset() const;
+ void set_offset(real_t p_offset);
+ real_t get_offset() const;
- void set_h_offset(float p_h_offset);
- float get_h_offset() const;
+ void set_h_offset(real_t p_h_offset);
+ real_t get_h_offset() const;
- void set_v_offset(float p_v_offset);
- float get_v_offset() const;
+ void set_v_offset(real_t p_v_offset);
+ real_t get_v_offset() const;
- void set_unit_offset(float p_unit_offset);
- float get_unit_offset() const;
+ void set_unit_offset(real_t p_unit_offset);
+ real_t get_unit_offset() const;
void set_loop(bool p_loop);
bool has_loop() const;
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 100e3563a3..976bff4fbc 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -30,22 +30,12 @@
#include "physics_body_3d.h"
-#include "core/config/engine.h"
#include "core/core_string_names.h"
-#include "core/object/class_db.h"
-#include "core/templates/list.h"
-#include "core/templates/rid.h"
-#include "scene/3d/collision_shape_3d.h"
#include "scene/scene_string_names.h"
-#include "servers/navigation_server_3d.h"
-
-#ifdef TOOLS_ENABLED
-#include "editor/plugins/node_3d_editor_plugin.h"
-#endif
void PhysicsBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only", "safe_margin"), &PhysicsBody3D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false), DEFVAL(0.001));
- ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "collision", "safe_margin"), &PhysicsBody3D::test_move, DEFVAL(true), DEFVAL(true), DEFVAL(Variant()), DEFVAL(0.001));
+ ClassDB::bind_method(D_METHOD("move_and_collide", "linear_velocity", "test_only", "safe_margin", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(1));
+ ClassDB::bind_method(D_METHOD("test_move", "from", "linear_velocity", "collision", "safe_margin", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(1));
ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicsBody3D::set_axis_lock);
ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicsBody3D::get_axis_lock);
@@ -101,10 +91,17 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) {
PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid());
}
-Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only, real_t p_margin) {
+Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_linear_velocity, bool p_test_only, real_t p_margin, int p_max_collisions) {
+ // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
+ double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
+
+ PhysicsServer3D::MotionParameters parameters(get_global_transform(), p_linear_velocity * delta, p_margin);
+ parameters.max_collisions = p_max_collisions;
+
PhysicsServer3D::MotionResult result;
- if (move_and_collide(p_motion, p_infinite_inertia, result, p_margin, p_exclude_raycast_shapes, p_test_only)) {
- if (motion_cache.is_null()) {
+ if (move_and_collide(parameters, result, p_test_only)) {
+ // Create a new instance when the cached reference is invalid or still in use in script.
+ if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) {
motion_cache.instantiate();
motion_cache->owner = this;
}
@@ -117,15 +114,14 @@ Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_i
return Ref<KinematicCollision3D>();
}
-bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes, bool p_test_only, bool p_cancel_sliding) {
- Transform3D gt = get_global_transform();
- bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, p_margin, &r_result, p_exclude_raycast_shapes);
+bool PhysicsBody3D::move_and_collide(const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult &r_result, bool p_test_only, bool p_cancel_sliding) {
+ bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_parameters, &r_result);
// Restore direction of motion to be along original motion,
// in order to avoid sliding due to recovery,
// but only if collision depth is low enough to avoid tunneling.
if (p_cancel_sliding) {
- real_t motion_length = p_motion.length();
+ real_t motion_length = p_parameters.motion.length();
real_t precision = 0.001;
if (colliding) {
@@ -133,7 +129,7 @@ bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_in
// so even in normal resting cases the depth can be a bit more than the margin.
precision += motion_length * (r_result.collision_unsafe_fraction - r_result.collision_safe_fraction);
- if (r_result.collision_depth > (real_t)p_margin + precision) {
+ if (r_result.collisions[0].depth > p_parameters.margin + precision) {
p_cancel_sliding = false;
}
}
@@ -142,38 +138,39 @@ bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_in
// When motion is null, recovery is the resulting motion.
Vector3 motion_normal;
if (motion_length > CMP_EPSILON) {
- motion_normal = p_motion / motion_length;
+ motion_normal = p_parameters.motion / motion_length;
}
// Check depth of recovery.
- real_t projected_length = r_result.motion.dot(motion_normal);
- Vector3 recovery = r_result.motion - motion_normal * projected_length;
+ real_t projected_length = r_result.travel.dot(motion_normal);
+ Vector3 recovery = r_result.travel - motion_normal * projected_length;
real_t recovery_length = recovery.length();
// Fixes cases where canceling slide causes the motion to go too deep into the ground,
// because we're only taking rest information into account and not general recovery.
- if (recovery_length < (real_t)p_margin + precision) {
+ if (recovery_length < p_parameters.margin + precision) {
// Apply adjustment to motion.
- r_result.motion = motion_normal * projected_length;
- r_result.remainder = p_motion - r_result.motion;
+ r_result.travel = motion_normal * projected_length;
+ r_result.remainder = p_parameters.motion - r_result.travel;
}
}
}
for (int i = 0; i < 3; i++) {
if (locked_axis & (1 << i)) {
- r_result.motion[i] = 0;
+ r_result.travel[i] = 0;
}
}
if (!p_test_only) {
- gt.origin += r_result.motion;
+ Transform3D gt = p_parameters.from;
+ gt.origin += r_result.travel;
set_global_transform(gt);
}
return colliding;
}
-bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, const Ref<KinematicCollision3D> &r_collision, real_t p_margin) {
+bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_linear_velocity, const Ref<KinematicCollision3D> &r_collision, real_t p_margin, int p_max_collisions) {
ERR_FAIL_COND_V(!is_inside_tree(), false);
PhysicsServer3D::MotionResult *r = nullptr;
@@ -182,7 +179,12 @@ bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion
r = const_cast<PhysicsServer3D::MotionResult *>(&r_collision->result);
}
- return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, p_margin, r, p_exclude_raycast_shapes);
+ // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
+ double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
+
+ PhysicsServer3D::MotionParameters parameters(p_from, p_linear_velocity * delta, p_margin);
+
+ return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), parameters, r);
}
void PhysicsBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) {
@@ -229,141 +231,128 @@ Ref<PhysicsMaterial> StaticBody3D::get_physics_material_override() const {
return physics_material_override;
}
-void StaticBody3D::set_kinematic_motion_enabled(bool p_enabled) {
- if (p_enabled == kinematic_motion) {
- return;
- }
+void StaticBody3D::set_constant_linear_velocity(const Vector3 &p_vel) {
+ constant_linear_velocity = p_vel;
- kinematic_motion = p_enabled;
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity);
+}
- if (kinematic_motion) {
- set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC);
- } else {
- set_body_mode(PhysicsServer3D::BODY_MODE_STATIC);
- }
+void StaticBody3D::set_constant_angular_velocity(const Vector3 &p_vel) {
+ constant_angular_velocity = p_vel;
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warnings();
- return;
- }
-#endif
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity);
+}
- _update_kinematic_motion();
+Vector3 StaticBody3D::get_constant_linear_velocity() const {
+ return constant_linear_velocity;
}
-bool StaticBody3D::is_kinematic_motion_enabled() const {
- return kinematic_motion;
+Vector3 StaticBody3D::get_constant_angular_velocity() const {
+ return constant_angular_velocity;
}
-void StaticBody3D::set_constant_linear_velocity(const Vector3 &p_vel) {
- constant_linear_velocity = p_vel;
+void StaticBody3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody3D::set_constant_linear_velocity);
+ ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody3D::set_constant_angular_velocity);
+ ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody3D::get_constant_linear_velocity);
+ ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody3D::get_constant_angular_velocity);
+
+ ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody3D::set_physics_material_override);
+ ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody3D::get_physics_material_override);
- if (kinematic_motion) {
- _update_kinematic_motion();
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
+}
+
+StaticBody3D::StaticBody3D(PhysicsServer3D::BodyMode p_mode) :
+ PhysicsBody3D(p_mode) {
+}
+
+void StaticBody3D::_reload_physics_characteristics() {
+ if (physics_material_override.is_null()) {
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, 0);
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, 1);
} else {
- PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity);
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
}
}
-void StaticBody3D::set_sync_to_physics(bool p_enable) {
+Vector3 AnimatableBody3D::get_linear_velocity() const {
+ return linear_velocity;
+}
+
+Vector3 AnimatableBody3D::get_angular_velocity() const {
+ return angular_velocity;
+}
+
+void AnimatableBody3D::set_sync_to_physics(bool p_enable) {
if (sync_to_physics == p_enable) {
return;
}
sync_to_physics = p_enable;
+ _update_kinematic_motion();
+}
+
+bool AnimatableBody3D::is_sync_to_physics_enabled() const {
+ return sync_to_physics;
+}
+
+void AnimatableBody3D::_update_kinematic_motion() {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warnings();
return;
}
#endif
- if (kinematic_motion) {
- _update_kinematic_motion();
+ if (sync_to_physics) {
+ set_only_update_transform_changes(true);
+ set_notify_local_transform(true);
+ } else {
+ set_only_update_transform_changes(false);
+ set_notify_local_transform(false);
}
}
-bool StaticBody3D::is_sync_to_physics_enabled() const {
- return sync_to_physics;
+void AnimatableBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
+ AnimatableBody3D *body = (AnimatableBody3D *)p_instance;
+ body->_body_state_changed(p_state);
}
-void StaticBody3D::_direct_state_changed(Object *p_state) {
- PhysicsDirectBodyState3D *state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
- ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
-
- linear_velocity = state->get_linear_velocity();
- angular_velocity = state->get_angular_velocity();
+void AnimatableBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
+ linear_velocity = p_state->get_linear_velocity();
+ angular_velocity = p_state->get_angular_velocity();
if (!sync_to_physics) {
return;
}
- last_valid_transform = state->get_transform();
+ last_valid_transform = p_state->get_transform();
set_notify_local_transform(false);
set_global_transform(last_valid_transform);
set_notify_local_transform(true);
_on_transform_changed();
}
-TypedArray<String> StaticBody3D::get_configuration_warnings() const {
- TypedArray<String> warnings = PhysicsBody3D::get_configuration_warnings();
-
- if (sync_to_physics && !kinematic_motion) {
- warnings.push_back(TTR("Sync to physics works only when kinematic motion is enabled."));
- }
-
- return warnings;
-}
-
-void StaticBody3D::set_constant_angular_velocity(const Vector3 &p_vel) {
- constant_angular_velocity = p_vel;
-
- if (kinematic_motion) {
- _update_kinematic_motion();
- } else {
- PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity);
- }
-}
-
-Vector3 StaticBody3D::get_constant_linear_velocity() const {
- return constant_linear_velocity;
-}
-
-Vector3 StaticBody3D::get_constant_angular_velocity() const {
- return constant_angular_velocity;
-}
-
-Vector3 StaticBody3D::get_linear_velocity() const {
- return linear_velocity;
-}
-
-Vector3 StaticBody3D::get_angular_velocity() const {
- return angular_velocity;
-}
-
-void StaticBody3D::_notification(int p_what) {
+void AnimatableBody3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
last_valid_transform = get_global_transform();
+ _update_kinematic_motion();
+ } break;
+
+ case NOTIFICATION_EXIT_TREE: {
+ set_only_update_transform_changes(false);
+ set_notify_local_transform(false);
} break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
// Used by sync to physics, send the new transform to the physics...
Transform3D new_transform = get_global_transform();
- real_t delta_time = get_physics_process_delta_time();
- new_transform.origin += constant_linear_velocity * delta_time;
-
- real_t ang_vel = constant_angular_velocity.length();
- if (!Math::is_zero_approx(ang_vel)) {
- Vector3 ang_vel_axis = constant_angular_velocity / ang_vel;
- Basis rot(ang_vel_axis, ang_vel * delta_time);
- new_transform.basis = rot * new_transform.basis;
- new_transform.orthonormalize();
- }
-
PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_TRANSFORM, new_transform);
// ... but then revert changes.
@@ -372,111 +361,22 @@ void StaticBody3D::_notification(int p_what) {
set_notify_local_transform(true);
_on_transform_changed();
} break;
-
- case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
- return;
- }
-#endif
-
- ERR_FAIL_COND(!kinematic_motion);
-
- Transform3D new_transform = get_global_transform();
-
- real_t delta_time = get_physics_process_delta_time();
- new_transform.origin += constant_linear_velocity * delta_time;
-
- real_t ang_vel = constant_angular_velocity.length();
- if (!Math::is_zero_approx(ang_vel)) {
- Vector3 ang_vel_axis = constant_angular_velocity / ang_vel;
- Basis rot(ang_vel_axis, ang_vel * delta_time);
- new_transform.basis = rot * new_transform.basis;
- new_transform.orthonormalize();
- }
-
- if (sync_to_physics) {
- // Propagate transform change to node.
- set_global_transform(new_transform);
- } else {
- PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_TRANSFORM, new_transform);
-
- // Propagate transform change to node.
- set_ignore_transform_notification(true);
- set_global_transform(new_transform);
- set_ignore_transform_notification(false);
- _on_transform_changed();
- }
- } break;
}
}
-void StaticBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody3D::set_constant_linear_velocity);
- ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody3D::set_constant_angular_velocity);
- ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody3D::get_constant_linear_velocity);
- ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody3D::get_constant_angular_velocity);
-
- ClassDB::bind_method(D_METHOD("set_kinematic_motion_enabled", "enabled"), &StaticBody3D::set_kinematic_motion_enabled);
- ClassDB::bind_method(D_METHOD("is_kinematic_motion_enabled"), &StaticBody3D::is_kinematic_motion_enabled);
-
- ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody3D::set_physics_material_override);
- ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody3D::get_physics_material_override);
-
- ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &StaticBody3D::set_sync_to_physics);
- ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &StaticBody3D::is_sync_to_physics_enabled);
+void AnimatableBody3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &AnimatableBody3D::set_sync_to_physics);
+ ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &AnimatableBody3D::is_sync_to_physics_enabled);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "kinematic_motion"), "set_kinematic_motion_enabled", "is_kinematic_motion_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled");
}
-StaticBody3D::StaticBody3D() :
- PhysicsBody3D(PhysicsServer3D::BODY_MODE_STATIC) {
-}
-
-void StaticBody3D::_reload_physics_characteristics() {
- if (physics_material_override.is_null()) {
- PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, 0);
- PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, 1);
- } else {
- PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
- PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
- }
+AnimatableBody3D::AnimatableBody3D() :
+ StaticBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
}
-void StaticBody3D::_update_kinematic_motion() {
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
- return;
- }
-#endif
-
- if (kinematic_motion && sync_to_physics) {
- set_only_update_transform_changes(true);
- set_notify_local_transform(true);
- } else {
- set_only_update_transform_changes(false);
- set_notify_local_transform(false);
- }
-
- bool needs_physics_process = false;
- if (kinematic_motion) {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &StaticBody3D::_direct_state_changed));
-
- if (!constant_angular_velocity.is_equal_approx(Vector3()) || !constant_linear_velocity.is_equal_approx(Vector3())) {
- needs_physics_process = true;
- }
- } else {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
- }
-
- set_physics_process_internal(needs_physics_process);
-}
-
-void RigidBody3D::_body_enter_tree(ObjectID p_id) {
+void RigidDynamicBody3D::_body_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
@@ -499,7 +399,7 @@ void RigidBody3D::_body_enter_tree(ObjectID p_id) {
contact_monitor->locked = false;
}
-void RigidBody3D::_body_exit_tree(ObjectID p_id) {
+void RigidDynamicBody3D::_body_exit_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
@@ -520,7 +420,7 @@ void RigidBody3D::_body_exit_tree(ObjectID p_id) {
contact_monitor->locked = false;
}
-void RigidBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) {
+void RigidDynamicBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) {
bool body_in = p_status == 1;
ObjectID objid = p_instance;
@@ -539,8 +439,8 @@ void RigidBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instan
//E->get().rc=0;
E->get().in_tree = node && node->is_inside_tree();
if (node) {
- node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree), make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree), make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody3D::_body_enter_tree), make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody3D::_body_exit_tree), make_binds(objid));
if (E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
}
@@ -566,8 +466,8 @@ void RigidBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instan
if (E->get().shapes.is_empty()) {
if (node) {
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody3D::_body_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody3D::_body_exit_tree));
if (in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_exited, node);
}
@@ -581,33 +481,34 @@ void RigidBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instan
}
}
-struct _RigidBodyInOut {
+struct _RigidDynamicBodyInOut {
RID rid;
ObjectID id;
int shape = 0;
int local_shape = 0;
};
-void RigidBody3D::_direct_state_changed(Object *p_state) {
-#ifdef DEBUG_ENABLED
- state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
- ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
-#else
- state = (PhysicsDirectBodyState3D *)p_state; //trust it
-#endif
+void RigidDynamicBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
+ RigidDynamicBody3D *body = (RigidDynamicBody3D *)p_instance;
+ body->_body_state_changed(p_state);
+}
+void RigidDynamicBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
set_ignore_transform_notification(true);
- set_global_transform(state->get_transform());
- linear_velocity = state->get_linear_velocity();
- angular_velocity = state->get_angular_velocity();
- inverse_inertia_tensor = state->get_inverse_inertia_tensor();
- if (sleeping != state->is_sleeping()) {
- sleeping = state->is_sleeping();
+ set_global_transform(p_state->get_transform());
+
+ linear_velocity = p_state->get_linear_velocity();
+ angular_velocity = p_state->get_angular_velocity();
+
+ inverse_inertia_tensor = p_state->get_inverse_inertia_tensor();
+
+ if (sleeping != p_state->is_sleeping()) {
+ sleeping = p_state->is_sleeping();
emit_signal(SceneStringNames::get_singleton()->sleeping_state_changed);
}
- if (get_script_instance()) {
- get_script_instance()->call("_integrate_forces", state);
- }
+
+ GDVIRTUAL_CALL(_integrate_forces, p_state);
+
set_ignore_transform_notification(false);
_on_transform_changed();
@@ -616,25 +517,25 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
//untag all
int rc = 0;
- for (Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) {
- for (int i = 0; i < E->get().shapes.size(); i++) {
- E->get().shapes[i].tagged = false;
+ for (KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) {
+ for (int i = 0; i < E.value.shapes.size(); i++) {
+ E.value.shapes[i].tagged = false;
rc++;
}
}
- _RigidBodyInOut *toadd = (_RigidBodyInOut *)alloca(state->get_contact_count() * sizeof(_RigidBodyInOut));
+ _RigidDynamicBodyInOut *toadd = (_RigidDynamicBodyInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidDynamicBodyInOut));
int toadd_count = 0; //state->get_contact_count();
- RigidBody3D_RemoveAction *toremove = (RigidBody3D_RemoveAction *)alloca(rc * sizeof(RigidBody3D_RemoveAction));
+ RigidDynamicBody3D_RemoveAction *toremove = (RigidDynamicBody3D_RemoveAction *)alloca(rc * sizeof(RigidDynamicBody3D_RemoveAction));
int toremove_count = 0;
//put the ones to add
- for (int i = 0; i < state->get_contact_count(); i++) {
- RID rid = state->get_contact_collider(i);
- ObjectID obj = state->get_contact_collider_id(i);
- int local_shape = state->get_contact_local_shape(i);
- int shape = state->get_contact_collider_shape(i);
+ for (int i = 0; i < p_state->get_contact_count(); i++) {
+ RID rid = p_state->get_contact_collider(i);
+ ObjectID obj = p_state->get_contact_collider_id(i);
+ int local_shape = p_state->get_contact_local_shape(i);
+ int shape = p_state->get_contact_collider_shape(i);
//bool found=false;
@@ -664,12 +565,12 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
//put the ones to remove
- for (Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) {
- for (int i = 0; i < E->get().shapes.size(); i++) {
- if (!E->get().shapes[i].tagged) {
- toremove[toremove_count].rid = E->get().rid;
- toremove[toremove_count].body_id = E->key();
- toremove[toremove_count].pair = E->get().shapes[i];
+ for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) {
+ for (int i = 0; i < E.value.shapes.size(); i++) {
+ if (!E.value.shapes[i].tagged) {
+ toremove[toremove_count].rid = E.value.rid;
+ toremove[toremove_count].body_id = E.key;
+ toremove[toremove_count].pair = E.value.shapes[i];
toremove_count++;
}
}
@@ -689,11 +590,9 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
contact_monitor->locked = false;
}
-
- state = nullptr;
}
-void RigidBody3D::_notification(int p_what) {
+void RigidDynamicBody3D::_notification(int p_what) {
#ifdef TOOLS_ENABLED
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -711,131 +610,204 @@ void RigidBody3D::_notification(int p_what) {
#endif
}
-void RigidBody3D::set_mode(Mode p_mode) {
- mode = p_mode;
- switch (p_mode) {
- case MODE_DYNAMIC: {
- set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC);
- } break;
- case MODE_STATIC: {
- set_body_mode(PhysicsServer3D::BODY_MODE_STATIC);
- } break;
- case MODE_DYNAMIC_LOCKED: {
- set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED);
- } break;
- case MODE_KINEMATIC: {
- set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC);
- } break;
+void RigidDynamicBody3D::_apply_body_mode() {
+ if (freeze) {
+ switch (freeze_mode) {
+ case FREEZE_MODE_STATIC: {
+ set_body_mode(PhysicsServer3D::BODY_MODE_STATIC);
+ } break;
+ case FREEZE_MODE_KINEMATIC: {
+ set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC);
+ } break;
+ }
+ } else if (lock_rotation) {
+ set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC_LINEAR);
+ } else {
+ set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC);
+ }
+}
+
+void RigidDynamicBody3D::set_lock_rotation_enabled(bool p_lock_rotation) {
+ if (p_lock_rotation == lock_rotation) {
+ return;
+ }
+
+ lock_rotation = p_lock_rotation;
+ _apply_body_mode();
+}
+
+bool RigidDynamicBody3D::is_lock_rotation_enabled() const {
+ return lock_rotation;
+}
+
+void RigidDynamicBody3D::set_freeze_enabled(bool p_freeze) {
+ if (p_freeze == freeze) {
+ return;
}
- update_configuration_warnings();
+
+ freeze = p_freeze;
+ _apply_body_mode();
+}
+
+bool RigidDynamicBody3D::is_freeze_enabled() const {
+ return freeze;
}
-RigidBody3D::Mode RigidBody3D::get_mode() const {
- return mode;
+void RigidDynamicBody3D::set_freeze_mode(FreezeMode p_freeze_mode) {
+ if (p_freeze_mode == freeze_mode) {
+ return;
+ }
+
+ freeze_mode = p_freeze_mode;
+ _apply_body_mode();
}
-void RigidBody3D::set_mass(real_t p_mass) {
+RigidDynamicBody3D::FreezeMode RigidDynamicBody3D::get_freeze_mode() const {
+ return freeze_mode;
+}
+
+void RigidDynamicBody3D::set_mass(real_t p_mass) {
ERR_FAIL_COND(p_mass <= 0);
mass = p_mass;
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_MASS, mass);
}
-real_t RigidBody3D::get_mass() const {
+real_t RigidDynamicBody3D::get_mass() const {
return mass;
}
-void RigidBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+void RigidDynamicBody3D::set_inertia(const Vector3 &p_inertia) {
+ ERR_FAIL_COND(p_inertia.x < 0);
+ ERR_FAIL_COND(p_inertia.y < 0);
+ ERR_FAIL_COND(p_inertia.z < 0);
+
+ inertia = p_inertia;
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_INERTIA, inertia);
+}
+
+const Vector3 &RigidDynamicBody3D::get_inertia() const {
+ return inertia;
+}
+
+void RigidDynamicBody3D::set_center_of_mass_mode(CenterOfMassMode p_mode) {
+ if (center_of_mass_mode == p_mode) {
+ return;
+ }
+
+ center_of_mass_mode = p_mode;
+
+ switch (center_of_mass_mode) {
+ case CENTER_OF_MASS_MODE_AUTO: {
+ center_of_mass = Vector3();
+ PhysicsServer3D::get_singleton()->body_reset_mass_properties(get_rid());
+ if (inertia != Vector3()) {
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_INERTIA, inertia);
+ }
+ } break;
+
+ case CENTER_OF_MASS_MODE_CUSTOM: {
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS, center_of_mass);
+ } break;
+ }
+}
+
+RigidDynamicBody3D::CenterOfMassMode RigidDynamicBody3D::get_center_of_mass_mode() const {
+ return center_of_mass_mode;
+}
+
+void RigidDynamicBody3D::set_center_of_mass(const Vector3 &p_center_of_mass) {
+ if (center_of_mass == p_center_of_mass) {
+ return;
+ }
+
+ ERR_FAIL_COND(center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM);
+ center_of_mass = p_center_of_mass;
+
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS, center_of_mass);
+}
+
+const Vector3 &RigidDynamicBody3D::get_center_of_mass() const {
+ return center_of_mass;
+}
+
+void RigidDynamicBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
if (physics_material_override.is_valid()) {
- if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics))) {
- physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics));
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidDynamicBody3D::_reload_physics_characteristics))) {
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidDynamicBody3D::_reload_physics_characteristics));
}
}
physics_material_override = p_physics_material_override;
if (physics_material_override.is_valid()) {
- physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics));
+ physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidDynamicBody3D::_reload_physics_characteristics));
}
_reload_physics_characteristics();
}
-Ref<PhysicsMaterial> RigidBody3D::get_physics_material_override() const {
+Ref<PhysicsMaterial> RigidDynamicBody3D::get_physics_material_override() const {
return physics_material_override;
}
-void RigidBody3D::set_gravity_scale(real_t p_gravity_scale) {
+void RigidDynamicBody3D::set_gravity_scale(real_t p_gravity_scale) {
gravity_scale = p_gravity_scale;
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE, gravity_scale);
}
-real_t RigidBody3D::get_gravity_scale() const {
+real_t RigidDynamicBody3D::get_gravity_scale() const {
return gravity_scale;
}
-void RigidBody3D::set_linear_damp(real_t p_linear_damp) {
+void RigidDynamicBody3D::set_linear_damp(real_t p_linear_damp) {
ERR_FAIL_COND(p_linear_damp < -1);
linear_damp = p_linear_damp;
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_LINEAR_DAMP, linear_damp);
}
-real_t RigidBody3D::get_linear_damp() const {
+real_t RigidDynamicBody3D::get_linear_damp() const {
return linear_damp;
}
-void RigidBody3D::set_angular_damp(real_t p_angular_damp) {
+void RigidDynamicBody3D::set_angular_damp(real_t p_angular_damp) {
ERR_FAIL_COND(p_angular_damp < -1);
angular_damp = p_angular_damp;
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP, angular_damp);
}
-real_t RigidBody3D::get_angular_damp() const {
+real_t RigidDynamicBody3D::get_angular_damp() const {
return angular_damp;
}
-void RigidBody3D::set_axis_velocity(const Vector3 &p_axis) {
- Vector3 v = state ? state->get_linear_velocity() : linear_velocity;
+void RigidDynamicBody3D::set_axis_velocity(const Vector3 &p_axis) {
Vector3 axis = p_axis.normalized();
- v -= axis * axis.dot(v);
- v += p_axis;
- if (state) {
- set_linear_velocity(v);
- } else {
- PhysicsServer3D::get_singleton()->body_set_axis_velocity(get_rid(), p_axis);
- linear_velocity = v;
- }
+ linear_velocity -= axis * axis.dot(linear_velocity);
+ linear_velocity += p_axis;
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
-void RigidBody3D::set_linear_velocity(const Vector3 &p_velocity) {
+void RigidDynamicBody3D::set_linear_velocity(const Vector3 &p_velocity) {
linear_velocity = p_velocity;
- if (state) {
- state->set_linear_velocity(linear_velocity);
- } else {
- PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
- }
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
-Vector3 RigidBody3D::get_linear_velocity() const {
+Vector3 RigidDynamicBody3D::get_linear_velocity() const {
return linear_velocity;
}
-void RigidBody3D::set_angular_velocity(const Vector3 &p_velocity) {
+void RigidDynamicBody3D::set_angular_velocity(const Vector3 &p_velocity) {
angular_velocity = p_velocity;
- if (state) {
- state->set_angular_velocity(angular_velocity);
- } else {
- PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
- }
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
}
-Vector3 RigidBody3D::get_angular_velocity() const {
+Vector3 RigidDynamicBody3D::get_angular_velocity() const {
return angular_velocity;
}
-Basis RigidBody3D::get_inverse_inertia_tensor() const {
+Basis RigidDynamicBody3D::get_inverse_inertia_tensor() const {
return inverse_inertia_tensor;
}
-void RigidBody3D::set_use_custom_integrator(bool p_enable) {
+void RigidDynamicBody3D::set_use_custom_integrator(bool p_enable) {
if (custom_integrator == p_enable) {
return;
}
@@ -844,73 +816,73 @@ void RigidBody3D::set_use_custom_integrator(bool p_enable) {
PhysicsServer3D::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable);
}
-bool RigidBody3D::is_using_custom_integrator() {
+bool RigidDynamicBody3D::is_using_custom_integrator() {
return custom_integrator;
}
-void RigidBody3D::set_sleeping(bool p_sleeping) {
+void RigidDynamicBody3D::set_sleeping(bool p_sleeping) {
sleeping = p_sleeping;
PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_SLEEPING, sleeping);
}
-void RigidBody3D::set_can_sleep(bool p_active) {
+void RigidDynamicBody3D::set_can_sleep(bool p_active) {
can_sleep = p_active;
PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_CAN_SLEEP, p_active);
}
-bool RigidBody3D::is_able_to_sleep() const {
+bool RigidDynamicBody3D::is_able_to_sleep() const {
return can_sleep;
}
-bool RigidBody3D::is_sleeping() const {
+bool RigidDynamicBody3D::is_sleeping() const {
return sleeping;
}
-void RigidBody3D::set_max_contacts_reported(int p_amount) {
+void RigidDynamicBody3D::set_max_contacts_reported(int p_amount) {
max_contacts_reported = p_amount;
PhysicsServer3D::get_singleton()->body_set_max_contacts_reported(get_rid(), p_amount);
}
-int RigidBody3D::get_max_contacts_reported() const {
+int RigidDynamicBody3D::get_max_contacts_reported() const {
return max_contacts_reported;
}
-void RigidBody3D::add_central_force(const Vector3 &p_force) {
+void RigidDynamicBody3D::add_central_force(const Vector3 &p_force) {
PhysicsServer3D::get_singleton()->body_add_central_force(get_rid(), p_force);
}
-void RigidBody3D::add_force(const Vector3 &p_force, const Vector3 &p_position) {
+void RigidDynamicBody3D::add_force(const Vector3 &p_force, const Vector3 &p_position) {
PhysicsServer3D *singleton = PhysicsServer3D::get_singleton();
singleton->body_add_force(get_rid(), p_force, p_position);
}
-void RigidBody3D::add_torque(const Vector3 &p_torque) {
+void RigidDynamicBody3D::add_torque(const Vector3 &p_torque) {
PhysicsServer3D::get_singleton()->body_add_torque(get_rid(), p_torque);
}
-void RigidBody3D::apply_central_impulse(const Vector3 &p_impulse) {
+void RigidDynamicBody3D::apply_central_impulse(const Vector3 &p_impulse) {
PhysicsServer3D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse);
}
-void RigidBody3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) {
+void RigidDynamicBody3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) {
PhysicsServer3D *singleton = PhysicsServer3D::get_singleton();
singleton->body_apply_impulse(get_rid(), p_impulse, p_position);
}
-void RigidBody3D::apply_torque_impulse(const Vector3 &p_impulse) {
+void RigidDynamicBody3D::apply_torque_impulse(const Vector3 &p_impulse) {
PhysicsServer3D::get_singleton()->body_apply_torque_impulse(get_rid(), p_impulse);
}
-void RigidBody3D::set_use_continuous_collision_detection(bool p_enable) {
+void RigidDynamicBody3D::set_use_continuous_collision_detection(bool p_enable) {
ccd = p_enable;
PhysicsServer3D::get_singleton()->body_set_enable_continuous_collision_detection(get_rid(), p_enable);
}
-bool RigidBody3D::is_using_continuous_collision_detection() const {
+bool RigidDynamicBody3D::is_using_continuous_collision_detection() const {
return ccd;
}
-void RigidBody3D::set_contact_monitor(bool p_enabled) {
+void RigidDynamicBody3D::set_contact_monitor(bool p_enabled) {
if (p_enabled == is_contact_monitor_enabled()) {
return;
}
@@ -918,14 +890,14 @@ void RigidBody3D::set_contact_monitor(bool p_enabled) {
if (!p_enabled) {
ERR_FAIL_COND_MSG(contact_monitor->locked, "Can't disable contact monitoring during in/out callback. Use call_deferred(\"set_contact_monitor\", false) instead.");
- for (Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) {
+ for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) {
//clean up mess
- Object *obj = ObjectDB::get_instance(E->key());
+ Object *obj = ObjectDB::get_instance(E.key);
Node *node = Object::cast_to<Node>(obj);
if (node) {
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody3D::_body_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody3D::_body_exit_tree));
}
}
@@ -937,18 +909,18 @@ void RigidBody3D::set_contact_monitor(bool p_enabled) {
}
}
-bool RigidBody3D::is_contact_monitor_enabled() const {
+bool RigidDynamicBody3D::is_contact_monitor_enabled() const {
return contact_monitor != nullptr;
}
-Array RigidBody3D::get_colliding_bodies() const {
+Array RigidDynamicBody3D::get_colliding_bodies() const {
ERR_FAIL_COND_V(!contact_monitor, Array());
Array ret;
ret.resize(contact_monitor->body_map.size());
int idx = 0;
- for (const Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) {
- Object *obj = ObjectDB::get_instance(E->key());
+ for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) {
+ Object *obj = ObjectDB::get_instance(E.key);
if (!obj) {
ret.resize(ret.size() - 1); //ops
} else {
@@ -959,79 +931,97 @@ Array RigidBody3D::get_colliding_bodies() const {
return ret;
}
-TypedArray<String> RigidBody3D::get_configuration_warnings() const {
+TypedArray<String> RigidDynamicBody3D::get_configuration_warnings() const {
Transform3D t = get_transform();
TypedArray<String> warnings = Node::get_configuration_warnings();
- if ((get_mode() == MODE_DYNAMIC || get_mode() == MODE_DYNAMIC_LOCKED) && (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)) {
- warnings.push_back(TTR("Size changes to RigidBody3D (in dynamic modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
+ if (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) {
+ warnings.push_back(TTR("Size changes to RigidDynamicBody will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
return warnings;
}
-void RigidBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_mode", "mode"), &RigidBody3D::set_mode);
- ClassDB::bind_method(D_METHOD("get_mode"), &RigidBody3D::get_mode);
+void RigidDynamicBody3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidDynamicBody3D::set_mass);
+ ClassDB::bind_method(D_METHOD("get_mass"), &RigidDynamicBody3D::get_mass);
+
+ ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidDynamicBody3D::set_inertia);
+ ClassDB::bind_method(D_METHOD("get_inertia"), &RigidDynamicBody3D::get_inertia);
+
+ ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidDynamicBody3D::set_center_of_mass_mode);
+ ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidDynamicBody3D::get_center_of_mass_mode);
- ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidBody3D::set_mass);
- ClassDB::bind_method(D_METHOD("get_mass"), &RigidBody3D::get_mass);
+ ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidDynamicBody3D::set_center_of_mass);
+ ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidDynamicBody3D::get_center_of_mass);
- ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody3D::set_physics_material_override);
- ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody3D::get_physics_material_override);
+ ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidDynamicBody3D::set_physics_material_override);
+ ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidDynamicBody3D::get_physics_material_override);
- ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody3D::set_linear_velocity);
- ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody3D::get_linear_velocity);
+ ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidDynamicBody3D::set_linear_velocity);
+ ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidDynamicBody3D::get_linear_velocity);
- ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidBody3D::set_angular_velocity);
- ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidBody3D::get_angular_velocity);
+ ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidDynamicBody3D::set_angular_velocity);
+ ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidDynamicBody3D::get_angular_velocity);
- ClassDB::bind_method(D_METHOD("get_inverse_inertia_tensor"), &RigidBody3D::get_inverse_inertia_tensor);
+ ClassDB::bind_method(D_METHOD("get_inverse_inertia_tensor"), &RigidDynamicBody3D::get_inverse_inertia_tensor);
- ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody3D::set_gravity_scale);
- ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody3D::get_gravity_scale);
+ ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidDynamicBody3D::set_gravity_scale);
+ ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidDynamicBody3D::get_gravity_scale);
- ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &RigidBody3D::set_linear_damp);
- ClassDB::bind_method(D_METHOD("get_linear_damp"), &RigidBody3D::get_linear_damp);
+ ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &RigidDynamicBody3D::set_linear_damp);
+ ClassDB::bind_method(D_METHOD("get_linear_damp"), &RigidDynamicBody3D::get_linear_damp);
- ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &RigidBody3D::set_angular_damp);
- ClassDB::bind_method(D_METHOD("get_angular_damp"), &RigidBody3D::get_angular_damp);
+ ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &RigidDynamicBody3D::set_angular_damp);
+ ClassDB::bind_method(D_METHOD("get_angular_damp"), &RigidDynamicBody3D::get_angular_damp);
- ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidBody3D::set_max_contacts_reported);
- ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidBody3D::get_max_contacts_reported);
+ ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidDynamicBody3D::set_max_contacts_reported);
+ ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidDynamicBody3D::get_max_contacts_reported);
- ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidBody3D::set_use_custom_integrator);
- ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidBody3D::is_using_custom_integrator);
+ ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidDynamicBody3D::set_use_custom_integrator);
+ ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidDynamicBody3D::is_using_custom_integrator);
- ClassDB::bind_method(D_METHOD("set_contact_monitor", "enabled"), &RigidBody3D::set_contact_monitor);
- ClassDB::bind_method(D_METHOD("is_contact_monitor_enabled"), &RigidBody3D::is_contact_monitor_enabled);
+ ClassDB::bind_method(D_METHOD("set_contact_monitor", "enabled"), &RigidDynamicBody3D::set_contact_monitor);
+ ClassDB::bind_method(D_METHOD("is_contact_monitor_enabled"), &RigidDynamicBody3D::is_contact_monitor_enabled);
- ClassDB::bind_method(D_METHOD("set_use_continuous_collision_detection", "enable"), &RigidBody3D::set_use_continuous_collision_detection);
- ClassDB::bind_method(D_METHOD("is_using_continuous_collision_detection"), &RigidBody3D::is_using_continuous_collision_detection);
+ ClassDB::bind_method(D_METHOD("set_use_continuous_collision_detection", "enable"), &RigidDynamicBody3D::set_use_continuous_collision_detection);
+ ClassDB::bind_method(D_METHOD("is_using_continuous_collision_detection"), &RigidDynamicBody3D::is_using_continuous_collision_detection);
- ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody3D::set_axis_velocity);
+ ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidDynamicBody3D::set_axis_velocity);
- ClassDB::bind_method(D_METHOD("add_central_force", "force"), &RigidBody3D::add_central_force);
- ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &RigidBody3D::add_force, Vector3());
- ClassDB::bind_method(D_METHOD("add_torque", "torque"), &RigidBody3D::add_torque);
+ ClassDB::bind_method(D_METHOD("add_central_force", "force"), &RigidDynamicBody3D::add_central_force);
+ ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &RigidDynamicBody3D::add_force, Vector3());
+ ClassDB::bind_method(D_METHOD("add_torque", "torque"), &RigidDynamicBody3D::add_torque);
- ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody3D::apply_central_impulse);
- ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &RigidBody3D::apply_impulse, Vector3());
- ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &RigidBody3D::apply_torque_impulse);
+ ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidDynamicBody3D::apply_central_impulse);
+ ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &RigidDynamicBody3D::apply_impulse, Vector3());
+ ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &RigidDynamicBody3D::apply_torque_impulse);
- ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidBody3D::set_sleeping);
- ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidBody3D::is_sleeping);
+ ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidDynamicBody3D::set_sleeping);
+ ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidDynamicBody3D::is_sleeping);
- ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody3D::set_can_sleep);
- ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody3D::is_able_to_sleep);
+ ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidDynamicBody3D::set_can_sleep);
+ ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidDynamicBody3D::is_able_to_sleep);
- ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody3D::get_colliding_bodies);
+ ClassDB::bind_method(D_METHOD("set_lock_rotation_enabled", "lock_rotation"), &RigidDynamicBody3D::set_lock_rotation_enabled);
+ ClassDB::bind_method(D_METHOD("is_lock_rotation_enabled"), &RigidDynamicBody3D::is_lock_rotation_enabled);
- BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState3D")));
+ ClassDB::bind_method(D_METHOD("set_freeze_enabled", "freeze_mode"), &RigidDynamicBody3D::set_freeze_enabled);
+ ClassDB::bind_method(D_METHOD("is_freeze_enabled"), &RigidDynamicBody3D::is_freeze_enabled);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Dynamic,Static,DynamicLocked,Kinematic"), "set_mode", "get_mode");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,65535,0.01,exp"), "set_mass", "get_mass");
+ ClassDB::bind_method(D_METHOD("set_freeze_mode", "freeze_mode"), &RigidDynamicBody3D::set_freeze_mode);
+ ClassDB::bind_method(D_METHOD("get_freeze_mode"), &RigidDynamicBody3D::get_freeze_mode);
+
+ ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidDynamicBody3D::get_colliding_bodies);
+
+ GDVIRTUAL_BIND(_integrate_forces, "state");
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp"), "set_mass", "get_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "inertia", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,exp"), "set_inertia", "get_inertia");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_lesser,or_greater"), "set_center_of_mass", "get_center_of_mass");
+ ADD_LINKED_PROPERTY("center_of_mass_mode", "center_of_mass");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
@@ -1040,6 +1030,9 @@ void RigidBody3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "lock_rotation"), "set_lock_rotation_enabled", "is_lock_rotation_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "freeze"), "set_freeze_enabled", "is_freeze_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "freeze_mode", PROPERTY_HINT_ENUM, "Static,Kinematic"), "set_freeze_mode", "get_freeze_mode");
ADD_GROUP("Linear", "linear_");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp");
@@ -1053,24 +1046,33 @@ void RigidBody3D::_bind_methods() {
ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("sleeping_state_changed"));
- BIND_ENUM_CONSTANT(MODE_DYNAMIC);
- BIND_ENUM_CONSTANT(MODE_STATIC);
- BIND_ENUM_CONSTANT(MODE_DYNAMIC_LOCKED);
- BIND_ENUM_CONSTANT(MODE_KINEMATIC);
+ BIND_ENUM_CONSTANT(FREEZE_MODE_STATIC);
+ BIND_ENUM_CONSTANT(FREEZE_MODE_KINEMATIC);
+
+ BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_AUTO);
+ BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_CUSTOM);
+}
+
+void RigidDynamicBody3D::_validate_property(PropertyInfo &property) const {
+ if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) {
+ if (property.name == "center_of_mass") {
+ property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
+ }
+ }
}
-RigidBody3D::RigidBody3D() :
+RigidDynamicBody3D::RigidDynamicBody3D() :
PhysicsBody3D(PhysicsServer3D::BODY_MODE_DYNAMIC) {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &RigidBody3D::_direct_state_changed));
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
}
-RigidBody3D::~RigidBody3D() {
+RigidDynamicBody3D::~RigidDynamicBody3D() {
if (contact_monitor) {
memdelete(contact_monitor);
}
}
-void RigidBody3D::_reload_physics_characteristics() {
+void RigidDynamicBody3D::_reload_physics_characteristics() {
if (physics_material_override.is_null()) {
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, 0);
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, 1);
@@ -1085,188 +1087,540 @@ void RigidBody3D::_reload_physics_characteristics() {
//so, if you pass 45 as limit, avoid numerical precision errors when angle is 45.
#define FLOOR_ANGLE_THRESHOLD 0.01
-void CharacterBody3D::move_and_slide() {
- Vector3 body_velocity_normal = linear_velocity.normalized();
-
- bool was_on_floor = on_floor;
+bool CharacterBody3D::move_and_slide() {
+ // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
+ double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
for (int i = 0; i < 3; i++) {
if (locked_axis & (1 << i)) {
- linear_velocity[i] = 0.0;
+ motion_velocity[i] = 0.0;
}
}
- Vector3 current_floor_velocity = floor_velocity;
- if (on_floor && on_floor_body.is_valid()) {
- //this approach makes sure there is less delay between the actual body velocity and the one we saved
- PhysicsDirectBodyState3D *bs = PhysicsServer3D::get_singleton()->body_get_direct_state(on_floor_body);
- if (bs) {
- current_floor_velocity = bs->get_linear_velocity();
+ Transform3D gt = get_global_transform();
+ previous_position = gt.origin;
+
+ Vector3 current_platform_velocity = platform_velocity;
+
+ if ((collision_state.floor || collision_state.wall) && platform_rid.is_valid()) {
+ bool excluded = false;
+ if (collision_state.floor) {
+ excluded = (moving_platform_floor_layers & platform_layer) == 0;
+ } else if (collision_state.wall) {
+ excluded = (moving_platform_wall_layers & platform_layer) == 0;
+ }
+ if (!excluded) {
+ //this approach makes sure there is less delay between the actual body velocity and the one we saved
+ PhysicsDirectBodyState3D *bs = PhysicsServer3D::get_singleton()->body_get_direct_state(platform_rid);
+ if (bs) {
+ Vector3 local_position = gt.origin - bs->get_transform().origin;
+ current_platform_velocity = bs->get_velocity_at_local_position(local_position);
+ }
+ } else {
+ current_platform_velocity = Vector3();
}
}
- // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
- Vector3 motion = (floor_velocity + linear_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time());
-
- on_floor = false;
- on_floor_body = RID();
- on_ceiling = false;
- on_wall = false;
motion_results.clear();
+
+ bool was_on_floor = collision_state.floor;
+ collision_state.state = 0;
+
+ last_motion = Vector3();
+
+ if (!current_platform_velocity.is_equal_approx(Vector3())) {
+ PhysicsServer3D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin);
+ parameters.exclude_bodies.insert(platform_rid);
+ if (platform_object_id.is_valid()) {
+ parameters.exclude_objects.insert(platform_object_id);
+ }
+
+ PhysicsServer3D::MotionResult floor_result;
+ if (move_and_collide(parameters, floor_result, false, false)) {
+ motion_results.push_back(floor_result);
+
+ CollisionState result_state;
+ _set_collision_direction(floor_result, result_state);
+ }
+ }
+
+ if (motion_mode == MOTION_MODE_GROUNDED) {
+ _move_and_slide_grounded(delta, was_on_floor);
+ } else {
+ _move_and_slide_free(delta);
+ }
+
+ // Compute real velocity.
+ real_velocity = get_position_delta() / delta;
+
+ if (moving_platform_apply_velocity_on_leave != PLATFORM_VEL_ON_LEAVE_NEVER) {
+ // Add last platform velocity when just left a moving platform.
+ if (!collision_state.floor && !collision_state.wall) {
+ if (moving_platform_apply_velocity_on_leave == PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY && current_platform_velocity.dot(up_direction) < 0) {
+ current_platform_velocity = current_platform_velocity.slide(up_direction);
+ }
+ motion_velocity += current_platform_velocity;
+ }
+ }
+
+ return motion_results.size() > 0;
+}
+
+void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor) {
+ Vector3 motion = motion_velocity * p_delta;
+ Vector3 motion_slide_up = motion.slide(up_direction);
+ Vector3 prev_floor_normal = floor_normal;
+
+ platform_rid = RID();
+ platform_object_id = ObjectID();
+ platform_velocity = Vector3();
+ platform_ceiling_velocity = Vector3();
floor_normal = Vector3();
- floor_velocity = Vector3();
+ wall_normal = Vector3();
+ ceiling_normal = Vector3();
// No sliding on first attempt to keep floor motion stable when possible,
- // when stop on slope is enabled.
- bool sliding_enabled = !stop_on_slope;
+ // When stop on slope is enabled or when there is no up direction.
+ bool sliding_enabled = !floor_stop_on_slope;
+ // Constant speed can be applied only the first time sliding is enabled.
+ bool can_apply_constant_speed = sliding_enabled;
+ // If the platform's ceiling push down the body.
+ bool apply_ceiling_velocity = false;
+ bool first_slide = true;
+ bool vel_dir_facing_up = motion_velocity.dot(up_direction) > 0;
+ Vector3 total_travel;
+
for (int iteration = 0; iteration < max_slides; ++iteration) {
+ PhysicsServer3D::MotionParameters parameters(get_global_transform(), motion, margin);
+ parameters.max_collisions = 4;
+
PhysicsServer3D::MotionResult result;
- bool found_collision = false;
-
- for (int i = 0; i < 2; ++i) {
- bool collided;
- if (i == 0) { //collide
- collided = move_and_collide(motion, infinite_inertia, result, margin, true, false, !sliding_enabled);
- if (!collided) {
- motion = Vector3(); //clear because no collision happened and motion completed
+ bool collided = move_and_collide(parameters, result, false, !sliding_enabled);
+
+ last_motion = result.travel;
+
+ if (collided) {
+ motion_results.push_back(result);
+
+ CollisionState previous_state = collision_state;
+
+ CollisionState result_state;
+ _set_collision_direction(result, result_state);
+
+ // If we hit a ceiling platform, we set the vertical motion_velocity to at least the platform one.
+ if (collision_state.ceiling && platform_ceiling_velocity != Vector3() && platform_ceiling_velocity.dot(up_direction) < 0) {
+ // If ceiling sliding is on, only apply when the ceiling is flat or when the motion is upward.
+ if (!slide_on_ceiling || motion.dot(up_direction) < 0 || (ceiling_normal + up_direction).length() < 0.01) {
+ apply_ceiling_velocity = true;
+ Vector3 ceiling_vertical_velocity = up_direction * up_direction.dot(platform_ceiling_velocity);
+ Vector3 motion_vertical_velocity = up_direction * up_direction.dot(motion_velocity);
+ if (motion_vertical_velocity.dot(up_direction) > 0 || ceiling_vertical_velocity.length_squared() > motion_vertical_velocity.length_squared()) {
+ motion_velocity = ceiling_vertical_velocity + motion_velocity.slide(up_direction);
+ }
}
- } else { //separate raycasts (if any)
- collided = separate_raycast_shapes(result);
- if (collided) {
- result.remainder = motion; //keep
- result.motion = Vector3();
+ }
+
+ if (collision_state.floor && floor_stop_on_slope && (motion_velocity.normalized() + up_direction).length() < 0.01) {
+ Transform3D gt = get_global_transform();
+ if (result.travel.length() <= margin + CMP_EPSILON) {
+ gt.origin -= result.travel;
}
+ set_global_transform(gt);
+ motion_velocity = Vector3();
+ motion = Vector3();
+ last_motion = Vector3();
+ break;
}
- if (collided) {
- found_collision = true;
+ if (result.remainder.is_equal_approx(Vector3())) {
+ motion = Vector3();
+ break;
+ }
- motion_results.push_back(result);
+ // Apply regular sliding by default.
+ bool apply_default_sliding = true;
+
+ // Wall collision checks.
+ if (result_state.wall && (motion_slide_up.dot(wall_normal) <= 0)) {
+ // Move on floor only checks.
+ if (floor_block_on_wall) {
+ // Needs horizontal motion from current motion instead of motion_slide_up
+ // to properly test the angle and avoid standing on slopes
+ Vector3 horizontal_motion = motion.slide(up_direction);
+ Vector3 horizontal_normal = wall_normal.slide(up_direction).normalized();
+ real_t motion_angle = Math::abs(Math::acos(-horizontal_normal.dot(horizontal_motion.normalized())));
+
+ // Avoid to move forward on a wall if floor_block_on_wall is true.
+ // Applies only when the motion angle is under 90 degrees,
+ // in order to avoid blocking lateral motion along a wall.
+ if (motion_angle < .5 * Math_PI) {
+ apply_default_sliding = false;
+
+ if (p_was_on_floor && !vel_dir_facing_up) {
+ // Cancel the motion.
+ Transform3D gt = get_global_transform();
+ real_t travel_total = result.travel.length();
+ real_t cancel_dist_max = MIN(0.1, margin * 20);
+ if (travel_total <= margin + CMP_EPSILON) {
+ gt.origin -= result.travel;
+ } else if (travel_total < cancel_dist_max) { // If the movement is large the body can be prevented from reaching the walls.
+ gt.origin -= result.travel.slide(up_direction);
+ // Keep remaining motion in sync with amount canceled.
+ motion = motion.slide(up_direction);
+ }
+ set_global_transform(gt);
+ result.travel = Vector3(); // Cancel for constant speed computation.
+
+ // Determines if you are on the ground, and limits the possibility of climbing on the walls because of the approximations.
+ _snap_on_floor(true, false);
+ } else {
+ // If the movement is not cancelled we only keep the remaining.
+ motion = result.remainder;
+ }
- if (up_direction == Vector3()) {
- //all is a wall
- on_wall = true;
- } else {
- if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
-
- on_floor = true;
- floor_normal = result.collision_normal;
- on_floor_body = result.collider;
- floor_velocity = result.collider_velocity;
-
- if (stop_on_slope) {
- if ((body_velocity_normal + up_direction).length() < 0.01) {
- Transform3D gt = get_global_transform();
- if (result.motion.length() > margin) {
- gt.origin -= result.motion.slide(up_direction);
- } else {
- gt.origin -= result.motion;
- }
- set_global_transform(gt);
- linear_velocity = Vector3();
- return;
+ // Apply slide on forward in order to allow only lateral motion on next step.
+ Vector3 forward = wall_normal.slide(up_direction).normalized();
+ motion = motion.slide(forward);
+ // Avoid accelerating when you jump on the wall and smooth falling.
+ motion_velocity = motion_velocity.slide(forward);
+
+ // Allow only lateral motion along previous floor when already on floor.
+ // Fixes slowing down when moving in diagonal against an inclined wall.
+ if (p_was_on_floor && !vel_dir_facing_up && (motion.dot(up_direction) > 0.0)) {
+ // Slide along the corner between the wall and previous floor.
+ Vector3 floor_side = prev_floor_normal.cross(wall_normal);
+ if (floor_side != Vector3()) {
+ motion = floor_side * motion.dot(floor_side);
}
}
- } else if (Math::acos(result.collision_normal.dot(-up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
- on_ceiling = true;
- } else {
- on_wall = true;
+
+ // Stop all motion when a second wall is hit (unless sliding down or jumping),
+ // in order to avoid jittering in corner cases.
+ bool stop_all_motion = previous_state.wall && !vel_dir_facing_up;
+
+ // Allow sliding when the body falls.
+ if (!collision_state.floor && motion.dot(up_direction) < 0) {
+ Vector3 slide_motion = motion.slide(wall_normal);
+ // Test again to allow sliding only if the result goes downwards.
+ // Fixes jittering issues at the bottom of inclined walls.
+ if (slide_motion.dot(up_direction) < 0) {
+ stop_all_motion = false;
+ motion = slide_motion;
+ }
+ }
+
+ if (stop_all_motion) {
+ motion = Vector3();
+ motion_velocity = Vector3();
+ }
+ }
+ }
+
+ // Stop horizontal motion when under wall slide threshold.
+ if (p_was_on_floor && (wall_min_slide_angle > 0.0) && result_state.wall) {
+ Vector3 horizontal_normal = wall_normal.slide(up_direction).normalized();
+ real_t motion_angle = Math::abs(Math::acos(-horizontal_normal.dot(motion_slide_up.normalized())));
+ if (motion_angle < wall_min_slide_angle) {
+ motion = up_direction * motion.dot(up_direction);
+ motion_velocity = up_direction * motion_velocity.dot(up_direction);
+
+ apply_default_sliding = false;
}
}
+ }
+
+ if (apply_default_sliding) {
+ // Regular sliding, the last part of the test handle the case when you don't want to slide on the ceiling.
+ if ((sliding_enabled || !collision_state.floor) && (!collision_state.ceiling || slide_on_ceiling || !vel_dir_facing_up) && !apply_ceiling_velocity) {
+ const PhysicsServer3D::MotionCollision &collision = result.collisions[0];
+
+ Vector3 slide_motion = result.remainder.slide(collision.normal);
+ if (collision_state.floor && !collision_state.wall) {
+ // Slide using the intersection between the motion plane and the floor plane,
+ // in order to keep the direction intact.
+ real_t motion_length = slide_motion.length();
+ slide_motion = up_direction.cross(result.remainder).cross(floor_normal);
+
+ // Keep the length from default slide to change speed in slopes by default,
+ // when constant speed is not enabled.
+ slide_motion.normalize();
+ slide_motion *= motion_length;
+ }
- if (sliding_enabled || !on_floor) {
- motion = result.remainder.slide(result.collision_normal);
- linear_velocity = linear_velocity.slide(result.collision_normal);
+ if (slide_motion.dot(motion_velocity) > 0.0) {
+ motion = slide_motion;
+ } else {
+ motion = Vector3();
+ }
- for (int j = 0; j < 3; j++) {
- if (locked_axis & (1 << j)) {
- linear_velocity[j] = 0.0;
+ if (slide_on_ceiling && result_state.ceiling) {
+ // Apply slide only in the direction of the input motion, otherwise just stop to avoid jittering when moving against a wall.
+ if (vel_dir_facing_up) {
+ motion_velocity = motion_velocity.slide(collision.normal);
+ } else {
+ // Avoid acceleration in slope when falling.
+ motion_velocity = up_direction * up_direction.dot(motion_velocity);
}
}
- } else {
+ }
+ // No sliding on first attempt to keep floor motion stable when possible.
+ else {
motion = result.remainder;
+ if (result_state.ceiling && !slide_on_ceiling && vel_dir_facing_up) {
+ motion_velocity = motion_velocity.slide(up_direction);
+ motion = motion.slide(up_direction);
+ }
}
}
+ total_travel += result.travel;
+
+ // Apply Constant Speed.
+ if (p_was_on_floor && floor_constant_speed && can_apply_constant_speed && collision_state.floor && !motion.is_equal_approx(Vector3())) {
+ Vector3 travel_slide_up = total_travel.slide(up_direction);
+ motion = motion.normalized() * MAX(0, (motion_slide_up.length() - travel_slide_up.length()));
+ }
+ }
+ // When you move forward in a downward slope you don’t collide because you will be in the air.
+ // This test ensures that constant speed is applied, only if the player is still on the ground after the snap is applied.
+ else if (floor_constant_speed && first_slide && _on_floor_if_snapped(p_was_on_floor, vel_dir_facing_up)) {
+ can_apply_constant_speed = false;
sliding_enabled = true;
+ Transform3D gt = get_global_transform();
+ gt.origin = gt.origin - result.travel;
+ set_global_transform(gt);
+
+ // Slide using the intersection between the motion plane and the floor plane,
+ // in order to keep the direction intact.
+ Vector3 motion_slide_norm = up_direction.cross(motion).cross(prev_floor_normal);
+ motion_slide_norm.normalize();
+
+ motion = motion_slide_norm * (motion_slide_up.length());
+ collided = true;
}
- if (!found_collision || motion == Vector3()) {
+ if (!collided || motion.is_equal_approx(Vector3())) {
break;
}
+
+ can_apply_constant_speed = !can_apply_constant_speed && !sliding_enabled;
+ sliding_enabled = true;
+ first_slide = false;
}
- if (!was_on_floor || snap == Vector3()) {
- return;
+ _snap_on_floor(p_was_on_floor, vel_dir_facing_up);
+
+ // Reset the gravity accumulation when touching the ground.
+ if (collision_state.floor && !vel_dir_facing_up) {
+ motion_velocity = motion_velocity.slide(up_direction);
}
+}
- // Apply snap.
- Transform3D gt = get_global_transform();
- PhysicsServer3D::MotionResult result;
- if (move_and_collide(snap, infinite_inertia, result, margin, false, true, false)) {
- bool apply = true;
- if (up_direction != Vector3()) {
- if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
- on_floor = true;
- floor_normal = result.collision_normal;
- on_floor_body = result.collider;
- floor_velocity = result.collider_velocity;
- if (stop_on_slope) {
- // move and collide may stray the object a bit because of pre un-stucking,
- // so only ensure that motion happens on floor direction in this case.
- if (result.motion.length() > margin) {
- result.motion = result.motion.project(up_direction);
- } else {
- result.motion = Vector3();
- }
+void CharacterBody3D::_move_and_slide_free(double p_delta) {
+ Vector3 motion = motion_velocity * p_delta;
+
+ platform_rid = RID();
+ platform_object_id = ObjectID();
+ floor_normal = Vector3();
+ platform_velocity = Vector3();
+
+ bool first_slide = true;
+ for (int iteration = 0; iteration < max_slides; ++iteration) {
+ PhysicsServer3D::MotionParameters parameters(get_global_transform(), motion, margin);
+
+ PhysicsServer3D::MotionResult result;
+ bool collided = move_and_collide(parameters, result, false, false);
+
+ last_motion = result.travel;
+
+ if (collided) {
+ motion_results.push_back(result);
+
+ CollisionState result_state;
+ _set_collision_direction(result, result_state);
+
+ if (result.remainder.is_equal_approx(Vector3())) {
+ motion = Vector3();
+ break;
+ }
+
+ if (wall_min_slide_angle != 0 && Math::acos(wall_normal.dot(-motion_velocity.normalized())) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) {
+ motion = Vector3();
+ if (result.travel.length() < margin + CMP_EPSILON) {
+ Transform3D gt = get_global_transform();
+ gt.origin -= result.travel;
+ set_global_transform(gt);
}
+ } else if (first_slide) {
+ Vector3 motion_slide_norm = result.remainder.slide(wall_normal).normalized();
+ motion = motion_slide_norm * (motion.length() - result.travel.length());
} else {
- apply = false; //snapped with floor direction, but did not snap to a floor, do not snap.
+ motion = result.remainder.slide(wall_normal);
+ }
+
+ if (motion.dot(motion_velocity) <= 0.0) {
+ motion = Vector3();
}
}
- if (apply) {
- gt.origin += result.motion;
- set_global_transform(gt);
+
+ if (!collided || motion.is_equal_approx(Vector3())) {
+ break;
}
+
+ first_slide = false;
}
}
-bool CharacterBody3D::separate_raycast_shapes(PhysicsServer3D::MotionResult &r_result) {
- PhysicsServer3D::SeparationResult sep_res[8]; //max 8 rays
+void CharacterBody3D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up) {
+ if (collision_state.floor || !was_on_floor || vel_dir_facing_up) {
+ return;
+ }
- Transform3D gt = get_global_transform();
+ // Snap by at least collision margin to keep floor state consistent.
+ real_t length = MAX(floor_snap_length, margin);
+
+ PhysicsServer3D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin);
+ parameters.max_collisions = 4;
+ parameters.collide_separation_ray = true;
- Vector3 recover;
- int hits = PhysicsServer3D::get_singleton()->body_test_ray_separation(get_rid(), gt, infinite_inertia, recover, sep_res, 8, margin);
- int deepest = -1;
- real_t deepest_depth;
- for (int i = 0; i < hits; i++) {
- if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) {
- deepest = i;
- deepest_depth = sep_res[i].collision_depth;
+ PhysicsServer3D::MotionResult result;
+ if (move_and_collide(parameters, result, true, false)) {
+ CollisionState result_state;
+ // Apply direction for floor only.
+ _set_collision_direction(result, result_state, CollisionState(true, false, false));
+
+ if (result_state.floor) {
+ if (floor_stop_on_slope) {
+ // move and collide may stray the object a bit because of pre un-stucking,
+ // so only ensure that motion happens on floor direction in this case.
+ if (result.travel.length() > margin) {
+ result.travel = up_direction * up_direction.dot(result.travel);
+ } else {
+ result.travel = Vector3();
+ }
+ }
+
+ parameters.from.origin += result.travel;
+ set_global_transform(parameters.from);
}
}
+}
+
+bool CharacterBody3D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facing_up) {
+ if (up_direction == Vector3() || collision_state.floor || !was_on_floor || vel_dir_facing_up) {
+ return false;
+ }
- gt.origin += recover;
- set_global_transform(gt);
+ // Snap by at least collision margin to keep floor state consistent.
+ real_t length = MAX(floor_snap_length, margin);
- if (deepest != -1) {
- r_result.collider_id = sep_res[deepest].collider_id;
- r_result.collider_metadata = sep_res[deepest].collider_metadata;
- r_result.collider_shape = sep_res[deepest].collider_shape;
- r_result.collider_velocity = sep_res[deepest].collider_velocity;
- r_result.collision_point = sep_res[deepest].collision_point;
- r_result.collision_normal = sep_res[deepest].collision_normal;
- r_result.collision_local_shape = sep_res[deepest].collision_local_shape;
- r_result.motion = recover;
- r_result.remainder = Vector3();
+ PhysicsServer3D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin);
+ parameters.max_collisions = 4;
+ parameters.collide_separation_ray = true;
- return true;
- } else {
- return false;
+ PhysicsServer3D::MotionResult result;
+ if (move_and_collide(parameters, result, true, false)) {
+ CollisionState result_state;
+ // Don't apply direction for any type.
+ _set_collision_direction(result, result_state, CollisionState());
+
+ return result_state.floor;
+ }
+
+ return false;
+}
+
+void CharacterBody3D::_set_collision_direction(const PhysicsServer3D::MotionResult &p_result, CollisionState &r_state, CollisionState p_apply_state) {
+ r_state.state = 0;
+
+ real_t wall_depth = -1.0;
+ real_t floor_depth = -1.0;
+
+ bool was_on_wall = collision_state.wall;
+ Vector3 prev_wall_normal = wall_normal;
+ int wall_collision_count = 0;
+ Vector3 combined_wall_normal;
+
+ for (int i = p_result.collision_count - 1; i >= 0; i--) {
+ const PhysicsServer3D::MotionCollision &collision = p_result.collisions[i];
+
+ if (motion_mode == MOTION_MODE_GROUNDED) {
+ // Check if any collision is floor.
+ real_t floor_angle = collision.get_angle(up_direction);
+ if (floor_angle <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
+ r_state.floor = true;
+ if (p_apply_state.floor && collision.depth > floor_depth) {
+ collision_state.floor = true;
+ floor_normal = collision.normal;
+ floor_depth = collision.depth;
+ _set_platform_data(collision);
+ }
+ continue;
+ }
+
+ // Check if any collision is ceiling.
+ real_t ceiling_angle = collision.get_angle(-up_direction);
+ if (ceiling_angle <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
+ r_state.ceiling = true;
+ if (p_apply_state.ceiling) {
+ platform_ceiling_velocity = collision.collider_velocity;
+ ceiling_normal = collision.normal;
+ collision_state.ceiling = true;
+ }
+ continue;
+ }
+ }
+
+ // Collision is wall by default.
+ r_state.wall = true;
+
+ if (p_apply_state.wall && collision.depth > wall_depth) {
+ collision_state.wall = true;
+ wall_depth = collision.depth;
+ wall_normal = collision.normal;
+
+ // Don't apply wall velocity when the collider is a CharacterBody3D.
+ if (Object::cast_to<CharacterBody3D>(ObjectDB::get_instance(collision.collider_id)) == nullptr) {
+ _set_platform_data(collision);
+ }
+ }
+
+ // Collect normal for calculating average.
+ combined_wall_normal += collision.normal;
+ wall_collision_count++;
+ }
+
+ if (r_state.wall) {
+ if (wall_collision_count > 1 && !r_state.floor) {
+ // Check if wall normals cancel out to floor support.
+ if (!r_state.floor && motion_mode == MOTION_MODE_GROUNDED) {
+ combined_wall_normal.normalize();
+ real_t floor_angle = Math::acos(combined_wall_normal.dot(up_direction));
+ if (floor_angle <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
+ r_state.floor = true;
+ r_state.wall = false;
+ if (p_apply_state.floor) {
+ collision_state.floor = true;
+ floor_normal = combined_wall_normal;
+ }
+ if (p_apply_state.wall) {
+ collision_state.wall = was_on_wall;
+ wall_normal = prev_wall_normal;
+ }
+ return;
+ }
+ }
+ }
}
}
+void CharacterBody3D::_set_platform_data(const PhysicsServer3D::MotionCollision &p_collision) {
+ platform_rid = p_collision.collider;
+ platform_object_id = p_collision.collider_id;
+ platform_velocity = p_collision.collider_velocity;
+ platform_layer = PhysicsServer3D::get_singleton()->body_get_collision_layer(platform_rid);
+}
+
void CharacterBody3D::set_safe_margin(real_t p_margin) {
margin = p_margin;
}
@@ -1275,35 +1629,72 @@ real_t CharacterBody3D::get_safe_margin() const {
return margin;
}
-Vector3 CharacterBody3D::get_linear_velocity() const {
- return linear_velocity;
+const Vector3 &CharacterBody3D::get_motion_velocity() const {
+ return motion_velocity;
}
-void CharacterBody3D::set_linear_velocity(const Vector3 &p_velocity) {
- linear_velocity = p_velocity;
+void CharacterBody3D::set_motion_velocity(const Vector3 &p_velocity) {
+ motion_velocity = p_velocity;
}
bool CharacterBody3D::is_on_floor() const {
- return on_floor;
+ return collision_state.floor;
+}
+
+bool CharacterBody3D::is_on_floor_only() const {
+ return collision_state.floor && !collision_state.wall && !collision_state.ceiling;
}
bool CharacterBody3D::is_on_wall() const {
- return on_wall;
+ return collision_state.wall;
+}
+
+bool CharacterBody3D::is_on_wall_only() const {
+ return collision_state.wall && !collision_state.floor && !collision_state.ceiling;
}
bool CharacterBody3D::is_on_ceiling() const {
- return on_ceiling;
+ return collision_state.ceiling;
}
-Vector3 CharacterBody3D::get_floor_normal() const {
+bool CharacterBody3D::is_on_ceiling_only() const {
+ return collision_state.ceiling && !collision_state.floor && !collision_state.wall;
+}
+
+const Vector3 &CharacterBody3D::get_floor_normal() const {
return floor_normal;
}
-Vector3 CharacterBody3D::get_floor_velocity() const {
- return floor_velocity;
+const Vector3 &CharacterBody3D::get_wall_normal() const {
+ return wall_normal;
+}
+
+const Vector3 &CharacterBody3D::get_last_motion() const {
+ return last_motion;
}
-int CharacterBody3D::get_slide_count() const {
+Vector3 CharacterBody3D::get_position_delta() const {
+ return get_transform().origin - previous_position;
+}
+
+const Vector3 &CharacterBody3D::get_real_velocity() const {
+ return real_velocity;
+}
+
+real_t CharacterBody3D::get_floor_angle(const Vector3 &p_up_direction) const {
+ ERR_FAIL_COND_V(p_up_direction == Vector3(), 0);
+ return Math::acos(floor_normal.dot(p_up_direction));
+}
+
+const Vector3 &CharacterBody3D::get_platform_velocity() const {
+ return platform_velocity;
+}
+
+Vector3 CharacterBody3D::get_linear_velocity() const {
+ return get_real_velocity();
+}
+
+int CharacterBody3D::get_slide_collision_count() const {
return motion_results.size();
}
@@ -1318,7 +1709,8 @@ Ref<KinematicCollision3D> CharacterBody3D::_get_slide_collision(int p_bounce) {
slide_colliders.resize(p_bounce + 1);
}
- if (slide_colliders[p_bounce].is_null()) {
+ // Create a new instance when the cached reference is invalid or still in use in script.
+ if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->reference_get_count() > 1) {
slide_colliders.write[p_bounce].instantiate();
slide_colliders.write[p_bounce]->owner = this;
}
@@ -1327,19 +1719,75 @@ Ref<KinematicCollision3D> CharacterBody3D::_get_slide_collision(int p_bounce) {
return slide_colliders[p_bounce];
}
-bool CharacterBody3D::is_stop_on_slope_enabled() const {
- return stop_on_slope;
+Ref<KinematicCollision3D> CharacterBody3D::_get_last_slide_collision() {
+ if (motion_results.size() == 0) {
+ return Ref<KinematicCollision3D>();
+ }
+ return _get_slide_collision(motion_results.size() - 1);
+}
+
+bool CharacterBody3D::is_floor_stop_on_slope_enabled() const {
+ return floor_stop_on_slope;
}
-void CharacterBody3D::set_stop_on_slope_enabled(bool p_enabled) {
- stop_on_slope = p_enabled;
+void CharacterBody3D::set_floor_stop_on_slope_enabled(bool p_enabled) {
+ floor_stop_on_slope = p_enabled;
}
-bool CharacterBody3D::is_infinite_inertia_enabled() const {
- return infinite_inertia;
+bool CharacterBody3D::is_floor_constant_speed_enabled() const {
+ return floor_constant_speed;
}
-void CharacterBody3D::set_infinite_inertia_enabled(bool p_enabled) {
- infinite_inertia = p_enabled;
+
+void CharacterBody3D::set_floor_constant_speed_enabled(bool p_enabled) {
+ floor_constant_speed = p_enabled;
+}
+
+bool CharacterBody3D::is_floor_block_on_wall_enabled() const {
+ return floor_block_on_wall;
+}
+
+void CharacterBody3D::set_floor_block_on_wall_enabled(bool p_enabled) {
+ floor_block_on_wall = p_enabled;
+}
+
+bool CharacterBody3D::is_slide_on_ceiling_enabled() const {
+ return slide_on_ceiling;
+}
+
+void CharacterBody3D::set_slide_on_ceiling_enabled(bool p_enabled) {
+ slide_on_ceiling = p_enabled;
+}
+
+uint32_t CharacterBody3D::get_moving_platform_floor_layers() const {
+ return moving_platform_floor_layers;
+}
+
+void CharacterBody3D::set_moving_platform_floor_layers(uint32_t p_exclude_layers) {
+ moving_platform_floor_layers = p_exclude_layers;
+}
+
+uint32_t CharacterBody3D::get_moving_platform_wall_layers() const {
+ return moving_platform_wall_layers;
+}
+
+void CharacterBody3D::set_moving_platform_wall_layers(uint32_t p_exclude_layers) {
+ moving_platform_wall_layers = p_exclude_layers;
+}
+
+void CharacterBody3D::set_motion_mode(MotionMode p_mode) {
+ motion_mode = p_mode;
+}
+
+CharacterBody3D::MotionMode CharacterBody3D::get_motion_mode() const {
+ return motion_mode;
+}
+
+void CharacterBody3D::set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_apply_velocity) {
+ moving_platform_apply_velocity_on_leave = p_on_leave_apply_velocity;
+}
+
+CharacterBody3D::MovingPlatformApplyVelocityOnLeave CharacterBody3D::get_moving_platform_apply_velocity_on_leave() const {
+ return moving_platform_apply_velocity_on_leave;
}
int CharacterBody3D::get_max_slides() const {
@@ -1359,12 +1807,21 @@ void CharacterBody3D::set_floor_max_angle(real_t p_radians) {
floor_max_angle = p_radians;
}
-const Vector3 &CharacterBody3D::get_snap() const {
- return snap;
+real_t CharacterBody3D::get_floor_snap_length() {
+ return floor_snap_length;
}
-void CharacterBody3D::set_snap(const Vector3 &p_snap) {
- snap = p_snap;
+void CharacterBody3D::set_floor_snap_length(real_t p_floor_snap_length) {
+ ERR_FAIL_COND(p_floor_snap_length < 0);
+ floor_snap_length = p_floor_snap_length;
+}
+
+real_t CharacterBody3D::get_wall_min_slide_angle() const {
+ return wall_min_slide_angle;
+}
+
+void CharacterBody3D::set_wall_min_slide_angle(real_t p_radians) {
+ wall_min_slide_angle = p_radians;
}
const Vector3 &CharacterBody3D::get_up_direction() const {
@@ -1372,6 +1829,7 @@ const Vector3 &CharacterBody3D::get_up_direction() const {
}
void CharacterBody3D::set_up_direction(const Vector3 &p_up_direction) {
+ ERR_FAIL_COND_MSG(p_up_direction == Vector3(), "up_direction can't be equal to Vector3.ZERO, consider using Free motion mode instead.");
up_direction = p_up_direction.normalized();
}
@@ -1379,12 +1837,11 @@ void CharacterBody3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
// Reset move_and_slide() data.
- on_floor = false;
- on_floor_body = RID();
- on_ceiling = false;
- on_wall = false;
+ collision_state.state = 0;
+ platform_rid = RID();
+ platform_object_id = ObjectID();
motion_results.clear();
- floor_velocity = Vector3();
+ platform_velocity = Vector3();
} break;
}
}
@@ -1392,41 +1849,90 @@ void CharacterBody3D::_notification(int p_what) {
void CharacterBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody3D::move_and_slide);
- ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &CharacterBody3D::set_linear_velocity);
- ClassDB::bind_method(D_METHOD("get_linear_velocity"), &CharacterBody3D::get_linear_velocity);
+ ClassDB::bind_method(D_METHOD("set_motion_velocity", "motion_velocity"), &CharacterBody3D::set_motion_velocity);
+ ClassDB::bind_method(D_METHOD("get_motion_velocity"), &CharacterBody3D::get_motion_velocity);
ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody3D::set_safe_margin);
ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody3D::get_safe_margin);
- ClassDB::bind_method(D_METHOD("is_stop_on_slope_enabled"), &CharacterBody3D::is_stop_on_slope_enabled);
- ClassDB::bind_method(D_METHOD("set_stop_on_slope_enabled", "enabled"), &CharacterBody3D::set_stop_on_slope_enabled);
- ClassDB::bind_method(D_METHOD("is_infinite_inertia_enabled"), &CharacterBody3D::is_infinite_inertia_enabled);
- ClassDB::bind_method(D_METHOD("set_infinite_inertia_enabled", "enabled"), &CharacterBody3D::set_infinite_inertia_enabled);
+ ClassDB::bind_method(D_METHOD("is_floor_stop_on_slope_enabled"), &CharacterBody3D::is_floor_stop_on_slope_enabled);
+ ClassDB::bind_method(D_METHOD("set_floor_stop_on_slope_enabled", "enabled"), &CharacterBody3D::set_floor_stop_on_slope_enabled);
+ ClassDB::bind_method(D_METHOD("set_floor_constant_speed_enabled", "enabled"), &CharacterBody3D::set_floor_constant_speed_enabled);
+ ClassDB::bind_method(D_METHOD("is_floor_constant_speed_enabled"), &CharacterBody3D::is_floor_constant_speed_enabled);
+ ClassDB::bind_method(D_METHOD("set_floor_block_on_wall_enabled", "enabled"), &CharacterBody3D::set_floor_block_on_wall_enabled);
+ ClassDB::bind_method(D_METHOD("is_floor_block_on_wall_enabled"), &CharacterBody3D::is_floor_block_on_wall_enabled);
+ ClassDB::bind_method(D_METHOD("set_slide_on_ceiling_enabled", "enabled"), &CharacterBody3D::set_slide_on_ceiling_enabled);
+ ClassDB::bind_method(D_METHOD("is_slide_on_ceiling_enabled"), &CharacterBody3D::is_slide_on_ceiling_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_moving_platform_floor_layers", "exclude_layer"), &CharacterBody3D::set_moving_platform_floor_layers);
+ ClassDB::bind_method(D_METHOD("get_moving_platform_floor_layers"), &CharacterBody3D::get_moving_platform_floor_layers);
+ ClassDB::bind_method(D_METHOD("set_moving_platform_wall_layers", "exclude_layer"), &CharacterBody3D::set_moving_platform_wall_layers);
+ ClassDB::bind_method(D_METHOD("get_moving_platform_wall_layers"), &CharacterBody3D::get_moving_platform_wall_layers);
+
ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody3D::get_max_slides);
ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody3D::set_max_slides);
ClassDB::bind_method(D_METHOD("get_floor_max_angle"), &CharacterBody3D::get_floor_max_angle);
ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody3D::set_floor_max_angle);
- ClassDB::bind_method(D_METHOD("get_snap"), &CharacterBody3D::get_snap);
- ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CharacterBody3D::set_snap);
+ ClassDB::bind_method(D_METHOD("get_floor_snap_length"), &CharacterBody3D::get_floor_snap_length);
+ ClassDB::bind_method(D_METHOD("set_floor_snap_length", "floor_snap_length"), &CharacterBody3D::set_floor_snap_length);
+ ClassDB::bind_method(D_METHOD("get_wall_min_slide_angle"), &CharacterBody3D::get_wall_min_slide_angle);
+ ClassDB::bind_method(D_METHOD("set_wall_min_slide_angle", "radians"), &CharacterBody3D::set_wall_min_slide_angle);
ClassDB::bind_method(D_METHOD("get_up_direction"), &CharacterBody3D::get_up_direction);
ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody3D::set_up_direction);
+ ClassDB::bind_method(D_METHOD("set_motion_mode", "mode"), &CharacterBody3D::set_motion_mode);
+ ClassDB::bind_method(D_METHOD("get_motion_mode"), &CharacterBody3D::get_motion_mode);
+ ClassDB::bind_method(D_METHOD("set_moving_platform_apply_velocity_on_leave", "on_leave_apply_velocity"), &CharacterBody3D::set_moving_platform_apply_velocity_on_leave);
+ ClassDB::bind_method(D_METHOD("get_moving_platform_apply_velocity_on_leave"), &CharacterBody3D::get_moving_platform_apply_velocity_on_leave);
ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody3D::is_on_floor);
+ ClassDB::bind_method(D_METHOD("is_on_floor_only"), &CharacterBody3D::is_on_floor_only);
ClassDB::bind_method(D_METHOD("is_on_ceiling"), &CharacterBody3D::is_on_ceiling);
+ ClassDB::bind_method(D_METHOD("is_on_ceiling_only"), &CharacterBody3D::is_on_ceiling_only);
ClassDB::bind_method(D_METHOD("is_on_wall"), &CharacterBody3D::is_on_wall);
+ ClassDB::bind_method(D_METHOD("is_on_wall_only"), &CharacterBody3D::is_on_wall_only);
ClassDB::bind_method(D_METHOD("get_floor_normal"), &CharacterBody3D::get_floor_normal);
- ClassDB::bind_method(D_METHOD("get_floor_velocity"), &CharacterBody3D::get_floor_velocity);
-
- ClassDB::bind_method(D_METHOD("get_slide_count"), &CharacterBody3D::get_slide_count);
+ ClassDB::bind_method(D_METHOD("get_wall_normal"), &CharacterBody3D::get_wall_normal);
+ ClassDB::bind_method(D_METHOD("get_last_motion"), &CharacterBody3D::get_last_motion);
+ ClassDB::bind_method(D_METHOD("get_position_delta"), &CharacterBody3D::get_position_delta);
+ ClassDB::bind_method(D_METHOD("get_real_velocity"), &CharacterBody3D::get_real_velocity);
+ ClassDB::bind_method(D_METHOD("get_floor_angle", "up_direction"), &CharacterBody3D::get_floor_angle, DEFVAL(Vector3(0.0, 1.0, 0.0)));
+ ClassDB::bind_method(D_METHOD("get_platform_velocity"), &CharacterBody3D::get_platform_velocity);
+ ClassDB::bind_method(D_METHOD("get_slide_collision_count"), &CharacterBody3D::get_slide_collision_count);
ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody3D::_get_slide_collision);
+ ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &CharacterBody3D::_get_last_slide_collision);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stop_on_slope"), "set_stop_on_slope_enabled", "is_stop_on_slope_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "infinite_inertia"), "set_infinite_inertia_enabled", "is_infinite_inertia_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_RANGE, "1,8,1,or_greater"), "set_max_slides", "get_max_slides");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "snap"), "set_snap", "get_snap");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Free", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "up_direction"), "set_up_direction", "get_up_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "motion_velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_motion_velocity", "get_motion_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_max_slides", "get_max_slides");
+ ADD_GROUP("Free Mode", "free_mode_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle");
+ ADD_GROUP("Floor", "floor_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_stop_on_slope"), "set_floor_stop_on_slope_enabled", "is_floor_stop_on_slope_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_constant_speed"), "set_floor_constant_speed_enabled", "is_floor_constant_speed_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_block_on_wall"), "set_floor_block_on_wall_enabled", "is_floor_block_on_wall_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,1,0.01,or_greater"), "set_floor_snap_length", "get_floor_snap_length");
+ ADD_GROUP("Moving platform", "moving_platform");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_apply_velocity_on_leave", PROPERTY_HINT_ENUM, "Always,Upward Only,Never", PROPERTY_USAGE_DEFAULT), "set_moving_platform_apply_velocity_on_leave", "get_moving_platform_apply_velocity_on_leave");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_floor_layers", "get_moving_platform_floor_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_wall_layers", "get_moving_platform_wall_layers");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
+
+ BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED);
+ BIND_ENUM_CONSTANT(MOTION_MODE_FREE);
+
+ BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_ALWAYS);
+ BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY);
+ BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_NEVER);
+}
+
+void CharacterBody3D::_validate_property(PropertyInfo &property) const {
+ if (motion_mode == MOTION_MODE_FREE) {
+ if (property.name.begins_with("floor_") || property.name == "up_direction" || property.name == "slide_on_ceiling") {
+ property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
+ }
+ }
}
CharacterBody3D::CharacterBody3D() :
@@ -1443,52 +1949,68 @@ CharacterBody3D::~CharacterBody3D() {
///////////////////////////////////////
-Vector3 KinematicCollision3D::get_position() const {
- return result.collision_point;
+Vector3 KinematicCollision3D::get_travel() const {
+ return result.travel;
}
-Vector3 KinematicCollision3D::get_normal() const {
- return result.collision_normal;
+Vector3 KinematicCollision3D::get_remainder() const {
+ return result.remainder;
}
-Vector3 KinematicCollision3D::get_travel() const {
- return result.motion;
+int KinematicCollision3D::get_collision_count() const {
+ return result.collision_count;
}
-Vector3 KinematicCollision3D::get_remainder() const {
- return result.remainder;
+Vector3 KinematicCollision3D::get_position(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3());
+ return result.collisions[p_collision_index].position;
}
-Object *KinematicCollision3D::get_local_shape() const {
+Vector3 KinematicCollision3D::get_normal(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3());
+ return result.collisions[p_collision_index].normal;
+}
+
+real_t KinematicCollision3D::get_angle(int p_collision_index, const Vector3 &p_up_direction) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, 0.0);
+ ERR_FAIL_COND_V(p_up_direction == Vector3(), 0);
+ return result.collisions[p_collision_index].get_angle(p_up_direction);
+}
+
+Object *KinematicCollision3D::get_local_shape(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, nullptr);
if (!owner) {
return nullptr;
}
- uint32_t ownerid = owner->shape_find_owner(result.collision_local_shape);
+ uint32_t ownerid = owner->shape_find_owner(result.collisions[p_collision_index].local_shape);
return owner->shape_owner_get_owner(ownerid);
}
-Object *KinematicCollision3D::get_collider() const {
- if (result.collider_id.is_valid()) {
- return ObjectDB::get_instance(result.collider_id);
+Object *KinematicCollision3D::get_collider(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, nullptr);
+ if (result.collisions[p_collision_index].collider_id.is_valid()) {
+ return ObjectDB::get_instance(result.collisions[p_collision_index].collider_id);
}
return nullptr;
}
-ObjectID KinematicCollision3D::get_collider_id() const {
- return result.collider_id;
+ObjectID KinematicCollision3D::get_collider_id(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, ObjectID());
+ return result.collisions[p_collision_index].collider_id;
}
-RID KinematicCollision3D::get_collider_rid() const {
- return result.collider;
+RID KinematicCollision3D::get_collider_rid(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, RID());
+ return result.collisions[p_collision_index].collider;
}
-Object *KinematicCollision3D::get_collider_shape() const {
- Object *collider = get_collider();
+Object *KinematicCollision3D::get_collider_shape(int p_collision_index) const {
+ Object *collider = get_collider(p_collision_index);
if (collider) {
CollisionObject3D *obj2d = Object::cast_to<CollisionObject3D>(collider);
if (obj2d) {
- uint32_t ownerid = obj2d->shape_find_owner(result.collider_shape);
+ uint32_t ownerid = obj2d->shape_find_owner(result.collisions[p_collision_index].collider_shape);
return obj2d->shape_owner_get_owner(ownerid);
}
}
@@ -1496,44 +2018,30 @@ Object *KinematicCollision3D::get_collider_shape() const {
return nullptr;
}
-int KinematicCollision3D::get_collider_shape_index() const {
- return result.collider_shape;
+int KinematicCollision3D::get_collider_shape_index(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, 0);
+ return result.collisions[p_collision_index].collider_shape;
}
-Vector3 KinematicCollision3D::get_collider_velocity() const {
- return result.collider_velocity;
-}
-
-Variant KinematicCollision3D::get_collider_metadata() const {
- return Variant();
+Vector3 KinematicCollision3D::get_collider_velocity(int p_collision_index) const {
+ ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3());
+ return result.collisions[p_collision_index].collider_velocity;
}
void KinematicCollision3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_position"), &KinematicCollision3D::get_position);
- ClassDB::bind_method(D_METHOD("get_normal"), &KinematicCollision3D::get_normal);
ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision3D::get_travel);
ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision3D::get_remainder);
- ClassDB::bind_method(D_METHOD("get_local_shape"), &KinematicCollision3D::get_local_shape);
- ClassDB::bind_method(D_METHOD("get_collider"), &KinematicCollision3D::get_collider);
- ClassDB::bind_method(D_METHOD("get_collider_id"), &KinematicCollision3D::get_collider_id);
- ClassDB::bind_method(D_METHOD("get_collider_rid"), &KinematicCollision3D::get_collider_rid);
- ClassDB::bind_method(D_METHOD("get_collider_shape"), &KinematicCollision3D::get_collider_shape);
- ClassDB::bind_method(D_METHOD("get_collider_shape_index"), &KinematicCollision3D::get_collider_shape_index);
- ClassDB::bind_method(D_METHOD("get_collider_velocity"), &KinematicCollision3D::get_collider_velocity);
- ClassDB::bind_method(D_METHOD("get_collider_metadata"), &KinematicCollision3D::get_collider_metadata);
-
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position"), "", "get_position");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "normal"), "", "get_normal");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "travel"), "", "get_travel");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "remainder"), "", "get_remainder");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "local_shape"), "", "get_local_shape");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id"), "", "get_collider_id");
- ADD_PROPERTY(PropertyInfo(Variant::RID, "collider_rid"), "", "get_collider_rid");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider_shape"), "", "get_collider_shape");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape_index"), "", "get_collider_shape_index");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collider_velocity"), "", "get_collider_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::NIL, "collider_metadata", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "", "get_collider_metadata");
+ ClassDB::bind_method(D_METHOD("get_collision_count"), &KinematicCollision3D::get_collision_count);
+ ClassDB::bind_method(D_METHOD("get_position", "collision_index"), &KinematicCollision3D::get_position, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_normal", "collision_index"), &KinematicCollision3D::get_normal, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_angle", "collision_index", "up_direction"), &KinematicCollision3D::get_angle, DEFVAL(0), DEFVAL(Vector3(0.0, 1.0, 0.0)));
+ ClassDB::bind_method(D_METHOD("get_local_shape", "collision_index"), &KinematicCollision3D::get_local_shape, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_collider", "collision_index"), &KinematicCollision3D::get_collider, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_collider_id", "collision_index"), &KinematicCollision3D::get_collider_id, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_collider_rid", "collision_index"), &KinematicCollision3D::get_collider_rid, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_collider_shape", "collision_index"), &KinematicCollision3D::get_collider_shape, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_collider_shape_index", "collision_index"), &KinematicCollision3D::get_collider_shape_index, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_collider_velocity", "collision_index"), &KinematicCollision3D::get_collider_velocity, DEFVAL(0));
}
///////////////////////////////////////
@@ -2240,7 +2748,6 @@ void PhysicalBone3D::_notification(int p_what) {
if (parent_skeleton) {
if (-1 != bone_id) {
parent_skeleton->unbind_physical_bone_from_bone(bone_id);
- parent_skeleton->unbind_child_node_from_bone(bone_id, this);
bone_id = -1;
}
}
@@ -2256,23 +2763,19 @@ void PhysicalBone3D::_notification(int p_what) {
}
}
-void PhysicalBone3D::_direct_state_changed(Object *p_state) {
+void PhysicalBone3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
+ PhysicalBone3D *bone = (PhysicalBone3D *)p_instance;
+ bone->_body_state_changed(p_state);
+}
+
+void PhysicalBone3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
if (!simulate_physics || !_internal_simulate_physics) {
return;
}
- /// Update bone transform
+ /// Update bone transform.
- PhysicsDirectBodyState3D *state;
-
-#ifdef DEBUG_ENABLED
- state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
- ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
-#else
- state = (PhysicsDirectBodyState3D *)p_state; //trust it
-#endif
-
- Transform3D global_transform(state->get_transform());
+ Transform3D global_transform(p_state->get_transform());
set_ignore_transform_notification(true);
set_global_transform(global_transform);
@@ -2336,7 +2839,7 @@ void PhysicalBone3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "body_offset"), "set_body_offset", "get_body_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,65535,0.01,exp"), "set_mass", "get_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp"), "set_mass", "get_mass");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-10,10,0.01"), "set_gravity_scale", "get_gravity_scale");
@@ -2477,14 +2980,11 @@ void PhysicalBone3D::_on_bone_parent_changed() {
_reload_joint();
}
-void PhysicalBone3D::_set_gizmo_move_joint(bool p_move_joint) {
#ifdef TOOLS_ENABLED
+void PhysicalBone3D::_set_gizmo_move_joint(bool p_move_joint) {
gizmo_move_joint = p_move_joint;
- Node3DEditor::get_singleton()->update_transform_gizmo();
-#endif
}
-#ifdef TOOLS_ENABLED
Transform3D PhysicalBone3D::get_global_gizmo_transform() const {
return gizmo_move_joint ? get_global_transform() * joint_offset : get_global_transform();
}
@@ -2697,7 +3197,6 @@ void PhysicalBone3D::update_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;
@@ -2735,7 +3234,7 @@ void PhysicalBone3D::_start_physics_simulation() {
set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC);
PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &PhysicalBone3D::_direct_state_changed));
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
set_as_top_level(true);
_internal_simulate_physics = true;
}
@@ -2754,7 +3253,7 @@ void PhysicalBone3D::_stop_physics_simulation() {
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0);
}
if (_internal_simulate_physics) {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), nullptr, nullptr);
parent_skeleton->set_bone_global_pose_override(bone_id, Transform3D(), 0.0, false);
set_as_top_level(false);
_internal_simulate_physics = false;
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 0ef9c78f3b..5677df730c 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -50,11 +50,11 @@ protected:
uint16_t locked_axis = 0;
- Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false, real_t p_margin = 0.001);
+ Ref<KinematicCollision3D> _move(const Vector3 &p_linear_velocity, bool p_test_only = false, real_t p_margin = 0.001, int p_max_collisions = 1);
public:
- bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes = true, bool p_test_only = false, bool p_cancel_sliding = true);
- bool test_move(const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001);
+ bool move_and_collide(const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true);
+ bool test_move(const Transform3D &p_from, const Vector3 &p_linear_velocity, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001, int p_max_collisions = 1);
void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const;
@@ -73,23 +73,13 @@ public:
class StaticBody3D : public PhysicsBody3D {
GDCLASS(StaticBody3D, PhysicsBody3D);
+private:
Vector3 constant_linear_velocity;
Vector3 constant_angular_velocity;
- Vector3 linear_velocity;
- Vector3 angular_velocity;
-
Ref<PhysicsMaterial> physics_material_override;
- bool kinematic_motion = false;
- bool sync_to_physics = false;
-
- Transform3D last_valid_transform;
-
- void _direct_state_changed(Object *p_state);
-
protected:
- void _notification(int p_what);
static void _bind_methods();
public:
@@ -102,42 +92,68 @@ public:
Vector3 get_constant_linear_velocity() const;
Vector3 get_constant_angular_velocity() const;
- virtual Vector3 get_linear_velocity() const override;
- virtual Vector3 get_angular_velocity() const override;
+ StaticBody3D(PhysicsServer3D::BodyMode p_mode = PhysicsServer3D::BODY_MODE_STATIC);
- virtual TypedArray<String> get_configuration_warnings() const override;
+private:
+ void _reload_physics_characteristics();
+};
- StaticBody3D();
+class AnimatableBody3D : public StaticBody3D {
+ GDCLASS(AnimatableBody3D, StaticBody3D);
private:
- void _reload_physics_characteristics();
+ Vector3 linear_velocity;
+ Vector3 angular_velocity;
- void _update_kinematic_motion();
+ bool sync_to_physics = true;
+
+ Transform3D last_valid_transform;
+
+ static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state);
+ void _body_state_changed(PhysicsDirectBodyState3D *p_state);
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
- void set_kinematic_motion_enabled(bool p_enabled);
- bool is_kinematic_motion_enabled() const;
+public:
+ virtual Vector3 get_linear_velocity() const override;
+ virtual Vector3 get_angular_velocity() const override;
+
+ AnimatableBody3D();
+
+private:
+ void _update_kinematic_motion();
void set_sync_to_physics(bool p_enable);
bool is_sync_to_physics_enabled() const;
};
-class RigidBody3D : public PhysicsBody3D {
- GDCLASS(RigidBody3D, PhysicsBody3D);
+class RigidDynamicBody3D : public PhysicsBody3D {
+ GDCLASS(RigidDynamicBody3D, PhysicsBody3D);
public:
- enum Mode {
- MODE_DYNAMIC,
- MODE_STATIC,
- MODE_DYNAMIC_LOCKED,
- MODE_KINEMATIC,
+ enum FreezeMode {
+ FREEZE_MODE_STATIC,
+ FREEZE_MODE_KINEMATIC,
};
-protected:
+ enum CenterOfMassMode {
+ CENTER_OF_MASS_MODE_AUTO,
+ CENTER_OF_MASS_MODE_CUSTOM,
+ };
+
+private:
bool can_sleep = true;
- PhysicsDirectBodyState3D *state = nullptr;
- Mode mode = MODE_DYNAMIC;
+ bool lock_rotation = false;
+ bool freeze = false;
+ FreezeMode freeze_mode = FREEZE_MODE_STATIC;
real_t mass = 1.0;
+ Vector3 inertia;
+ CenterOfMassMode center_of_mass_mode = CENTER_OF_MASS_MODE_AUTO;
+ Vector3 center_of_mass;
+
Ref<PhysicsMaterial> physics_material_override;
Vector3 linear_velocity;
@@ -173,7 +189,7 @@ protected:
tagged = false;
}
};
- struct RigidBody3D_RemoveAction {
+ struct RigidDynamicBody3D_RemoveAction {
RID rid;
ObjectID body_id;
ShapePair pair;
@@ -195,20 +211,44 @@ protected:
void _body_exit_tree(ObjectID p_id);
void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape);
- virtual void _direct_state_changed(Object *p_state);
+ static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state);
+protected:
void _notification(int p_what);
static void _bind_methods();
+ virtual void _validate_property(PropertyInfo &property) const override;
+
+ GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState3D *)
+
+ virtual void _body_state_changed(PhysicsDirectBodyState3D *p_state);
+
+ void _apply_body_mode();
+
public:
- void set_mode(Mode p_mode);
- Mode get_mode() const;
+ void set_lock_rotation_enabled(bool p_lock_rotation);
+ bool is_lock_rotation_enabled() const;
+
+ void set_freeze_enabled(bool p_freeze);
+ bool is_freeze_enabled() const;
+
+ void set_freeze_mode(FreezeMode p_freeze_mode);
+ FreezeMode get_freeze_mode() const;
void set_mass(real_t p_mass);
real_t get_mass() const;
virtual real_t get_inverse_mass() const override { return 1.0 / mass; }
+ void set_inertia(const Vector3 &p_inertia);
+ const Vector3 &get_inertia() const;
+
+ void set_center_of_mass_mode(CenterOfMassMode p_mode);
+ CenterOfMassMode get_center_of_mass_mode() const;
+
+ void set_center_of_mass(const Vector3 &p_center_of_mass);
+ const Vector3 &get_center_of_mass() const;
+
void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
Ref<PhysicsMaterial> get_physics_material_override() const;
@@ -261,53 +301,122 @@ public:
virtual TypedArray<String> get_configuration_warnings() const override;
- RigidBody3D();
- ~RigidBody3D();
+ RigidDynamicBody3D();
+ ~RigidDynamicBody3D();
private:
void _reload_physics_characteristics();
};
-VARIANT_ENUM_CAST(RigidBody3D::Mode);
+VARIANT_ENUM_CAST(RigidDynamicBody3D::FreezeMode);
+VARIANT_ENUM_CAST(RigidDynamicBody3D::CenterOfMassMode);
class KinematicCollision3D;
class CharacterBody3D : public PhysicsBody3D {
GDCLASS(CharacterBody3D, PhysicsBody3D);
+public:
+ enum MotionMode {
+ MOTION_MODE_GROUNDED,
+ MOTION_MODE_FREE,
+ };
+ enum MovingPlatformApplyVelocityOnLeave {
+ PLATFORM_VEL_ON_LEAVE_ALWAYS,
+ PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY,
+ PLATFORM_VEL_ON_LEAVE_NEVER,
+ };
+ bool move_and_slide();
+
+ const Vector3 &get_motion_velocity() const;
+ void set_motion_velocity(const Vector3 &p_velocity);
+
+ bool is_on_floor() const;
+ bool is_on_floor_only() const;
+ bool is_on_wall() const;
+ bool is_on_wall_only() const;
+ bool is_on_ceiling() const;
+ bool is_on_ceiling_only() const;
+ const Vector3 &get_last_motion() const;
+ Vector3 get_position_delta() const;
+ const Vector3 &get_floor_normal() const;
+ const Vector3 &get_wall_normal() const;
+ const Vector3 &get_real_velocity() const;
+ real_t get_floor_angle(const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
+ const Vector3 &get_platform_velocity() const;
+
+ virtual Vector3 get_linear_velocity() const override;
+
+ int get_slide_collision_count() const;
+ PhysicsServer3D::MotionResult get_slide_collision(int p_bounce) const;
+
+ CharacterBody3D();
+ ~CharacterBody3D();
+
private:
real_t margin = 0.001;
+ MotionMode motion_mode = MOTION_MODE_GROUNDED;
+ MovingPlatformApplyVelocityOnLeave moving_platform_apply_velocity_on_leave = PLATFORM_VEL_ON_LEAVE_ALWAYS;
+ union CollisionState {
+ uint32_t state = 0;
+ struct {
+ bool floor;
+ bool wall;
+ bool ceiling;
+ };
- bool stop_on_slope = false;
- bool infinite_inertia = true;
- int max_slides = 4;
- real_t floor_max_angle = Math::deg2rad((real_t)45.0);
- Vector3 snap;
- Vector3 up_direction = Vector3(0.0, 1.0, 0.0);
+ CollisionState() {
+ }
- Vector3 linear_velocity;
+ CollisionState(bool p_floor, bool p_wall, bool p_ceiling) {
+ floor = p_floor;
+ wall = p_wall;
+ ceiling = p_ceiling;
+ }
+ };
+ CollisionState collision_state;
+ bool floor_constant_speed = false;
+ bool floor_stop_on_slope = true;
+ bool floor_block_on_wall = true;
+ bool slide_on_ceiling = true;
+ int max_slides = 6;
+ int platform_layer = 0;
+ RID platform_rid;
+ ObjectID platform_object_id;
+ uint32_t moving_platform_floor_layers = UINT32_MAX;
+ uint32_t moving_platform_wall_layers = 0;
+ real_t floor_snap_length = 0.1;
+ real_t floor_max_angle = Math::deg2rad((real_t)45.0);
+ real_t wall_min_slide_angle = Math::deg2rad((real_t)15.0);
+ Vector3 up_direction = Vector3(0.0, 1.0, 0.0);
+ Vector3 motion_velocity;
Vector3 floor_normal;
- Vector3 floor_velocity;
- RID on_floor_body;
- bool on_floor = false;
- bool on_ceiling = false;
- bool on_wall = false;
+ Vector3 wall_normal;
+ Vector3 ceiling_normal;
+ Vector3 last_motion;
+ Vector3 platform_velocity;
+ Vector3 platform_ceiling_velocity;
+ Vector3 previous_position;
+ Vector3 real_velocity;
+
Vector<PhysicsServer3D::MotionResult> motion_results;
Vector<Ref<KinematicCollision3D>> slide_colliders;
- Ref<KinematicCollision3D> _get_slide_collision(int p_bounce);
-
- bool separate_raycast_shapes(PhysicsServer3D::MotionResult &r_result);
-
void set_safe_margin(real_t p_margin);
real_t get_safe_margin() const;
- bool is_stop_on_slope_enabled() const;
- void set_stop_on_slope_enabled(bool p_enabled);
+ bool is_floor_stop_on_slope_enabled() const;
+ void set_floor_stop_on_slope_enabled(bool p_enabled);
+
+ bool is_floor_constant_speed_enabled() const;
+ void set_floor_constant_speed_enabled(bool p_enabled);
- bool is_infinite_inertia_enabled() const;
- void set_infinite_inertia_enabled(bool p_enabled);
+ bool is_floor_block_on_wall_enabled() const;
+ void set_floor_block_on_wall_enabled(bool p_enabled);
+
+ bool is_slide_on_ceiling_enabled() const;
+ void set_slide_on_ceiling_enabled(bool p_enabled);
int get_max_slides() const;
void set_max_slides(int p_max_slides);
@@ -315,35 +424,45 @@ private:
real_t get_floor_max_angle() const;
void set_floor_max_angle(real_t p_radians);
- const Vector3 &get_snap() const;
- void set_snap(const Vector3 &p_snap);
+ real_t get_floor_snap_length();
+ void set_floor_snap_length(real_t p_floor_snap_length);
- const Vector3 &get_up_direction() const;
- void set_up_direction(const Vector3 &p_up_direction);
+ real_t get_wall_min_slide_angle() const;
+ void set_wall_min_slide_angle(real_t p_radians);
-protected:
- void _notification(int p_what);
- static void _bind_methods();
+ uint32_t get_moving_platform_floor_layers() const;
+ void set_moving_platform_floor_layers(const uint32_t p_exclude_layer);
-public:
- void move_and_slide();
+ uint32_t get_moving_platform_wall_layers() const;
+ void set_moving_platform_wall_layers(const uint32_t p_exclude_layer);
- virtual Vector3 get_linear_velocity() const override;
- void set_linear_velocity(const Vector3 &p_velocity);
+ void set_motion_mode(MotionMode p_mode);
+ MotionMode get_motion_mode() const;
- bool is_on_floor() const;
- bool is_on_wall() const;
- bool is_on_ceiling() const;
- Vector3 get_floor_normal() const;
- Vector3 get_floor_velocity() const;
+ void set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_velocity);
+ MovingPlatformApplyVelocityOnLeave get_moving_platform_apply_velocity_on_leave() const;
- int get_slide_count() const;
- PhysicsServer3D::MotionResult get_slide_collision(int p_bounce) const;
+ void _move_and_slide_free(double p_delta);
+ void _move_and_slide_grounded(double p_delta, bool p_was_on_floor);
- CharacterBody3D();
- ~CharacterBody3D();
+ Ref<KinematicCollision3D> _get_slide_collision(int p_bounce);
+ Ref<KinematicCollision3D> _get_last_slide_collision();
+ const Vector3 &get_up_direction() const;
+ bool _on_floor_if_snapped(bool was_on_floor, bool vel_dir_facing_up);
+ void set_up_direction(const Vector3 &p_up_direction);
+ void _set_collision_direction(const PhysicsServer3D::MotionResult &p_result, CollisionState &r_state, CollisionState p_apply_state = CollisionState(true, true, true));
+ void _set_platform_data(const PhysicsServer3D::MotionCollision &p_collision);
+ void _snap_on_floor(bool was_on_floor, bool vel_dir_facing_up);
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+ virtual void _validate_property(PropertyInfo &property) const override;
};
+VARIANT_ENUM_CAST(CharacterBody3D::MotionMode);
+VARIANT_ENUM_CAST(CharacterBody3D::MovingPlatformApplyVelocityOnLeave);
+
class KinematicCollision3D : public RefCounted {
GDCLASS(KinematicCollision3D, RefCounted);
@@ -356,18 +475,19 @@ protected:
static void _bind_methods();
public:
- Vector3 get_position() const;
- Vector3 get_normal() const;
Vector3 get_travel() const;
Vector3 get_remainder() const;
- Object *get_local_shape() const;
- Object *get_collider() const;
- ObjectID get_collider_id() const;
- RID get_collider_rid() const;
- Object *get_collider_shape() const;
- int get_collider_shape_index() const;
- Vector3 get_collider_velocity() const;
- Variant get_collider_metadata() const;
+ int get_collision_count() const;
+ Vector3 get_position(int p_collision_index = 0) const;
+ Vector3 get_normal(int p_collision_index = 0) const;
+ real_t get_angle(int p_collision_index = 0, const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
+ Object *get_local_shape(int p_collision_index = 0) const;
+ Object *get_collider(int p_collision_index = 0) const;
+ ObjectID get_collider_id(int p_collision_index = 0) const;
+ RID get_collider_rid(int p_collision_index = 0) const;
+ Object *get_collider_shape(int p_collision_index = 0) const;
+ int get_collider_shape_index(int p_collision_index = 0) const;
+ Vector3 get_collider_velocity(int p_collision_index = 0) const;
};
class PhysicalBone3D : public PhysicsBody3D {
@@ -521,7 +641,8 @@ protected:
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 _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state);
+ void _body_state_changed(PhysicsDirectBodyState3D *p_state);
static void _bind_methods();
@@ -534,10 +655,9 @@ private:
public:
void _on_bone_parent_changed();
- void _set_gizmo_move_joint(bool p_move_joint);
-public:
#ifdef TOOLS_ENABLED
+ void _set_gizmo_move_joint(bool p_move_joint);
virtual Transform3D get_global_gizmo_transform() const override;
virtual Transform3D get_local_gizmo_transform() const override;
#endif
diff --git a/scene/3d/position_3d.cpp b/scene/3d/position_3d.cpp
index b231ba0df7..9747465103 100644
--- a/scene/3d/position_3d.cpp
+++ b/scene/3d/position_3d.cpp
@@ -29,7 +29,6 @@
/*************************************************************************/
#include "position_3d.h"
-#include "scene/resources/mesh.h"
Position3D::Position3D() {
}
diff --git a/scene/3d/proximity_group_3d.h b/scene/3d/proximity_group_3d.h
index 05aa00b228..e45adc3040 100644
--- a/scene/3d/proximity_group_3d.h
+++ b/scene/3d/proximity_group_3d.h
@@ -49,7 +49,7 @@ private:
DispatchMode dispatch_mode = MODE_PROXY;
Vector3 grid_radius = Vector3(1, 1, 1);
- float cell_size = 1.0;
+ real_t cell_size = 1.0;
uint32_t group_version = 0;
void _clear_groups();
diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp
index 7356ce478b..fd4c6e7416 100644
--- a/scene/3d/ray_cast_3d.cpp
+++ b/scene/3d/ray_cast_3d.cpp
@@ -31,9 +31,7 @@
#include "ray_cast_3d.h"
#include "collision_object_3d.h"
-#include "core/config/engine.h"
#include "mesh_instance_3d.h"
-#include "servers/physics_server_3d.h"
void RayCast3D::set_target_position(const Vector3 &p_point) {
target_position = p_point;
@@ -60,20 +58,22 @@ uint32_t RayCast3D::get_collision_mask() const {
return collision_mask;
}
-void RayCast3D::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
+void RayCast3D::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
- mask |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
set_collision_mask(mask);
}
-bool RayCast3D::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+bool RayCast3D::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
bool RayCast3D::is_colliding() const {
@@ -303,8 +303,8 @@ void RayCast3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &RayCast3D::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &RayCast3D::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &RayCast3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &RayCast3D::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &RayCast3D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &RayCast3D::get_collision_mask_value);
ClassDB::bind_method(D_METHOD("set_exclude_parent_body", "mask"), &RayCast3D::set_exclude_parent_body);
ClassDB::bind_method(D_METHOD("get_exclude_parent_body"), &RayCast3D::get_exclude_parent_body);
diff --git a/scene/3d/ray_cast_3d.h b/scene/3d/ray_cast_3d.h
index 968cede9f2..3828bfb4c4 100644
--- a/scene/3d/ray_cast_3d.h
+++ b/scene/3d/ray_cast_3d.h
@@ -86,8 +86,8 @@ public:
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void set_exclude_parent_body(bool p_exclude_parent_body);
bool get_exclude_parent_body() const;
diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h
index 4bf20c89c5..d1b9b12f65 100644
--- a/scene/3d/reflection_probe.h
+++ b/scene/3d/reflection_probe.h
@@ -32,9 +32,6 @@
#define REFLECTIONPROBE_H
#include "scene/3d/visual_instance_3d.h"
-#include "scene/resources/sky.h"
-#include "scene/resources/texture.h"
-#include "servers/rendering_server.h"
class ReflectionProbe : public VisualInstance3D {
GDCLASS(ReflectionProbe, VisualInstance3D);
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 9ce4c37457..b7a79a2645 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -30,11 +30,10 @@
#include "skeleton_3d.h"
-#include "core/config/engine.h"
-#include "core/config/project_settings.h"
#include "core/object/message_queue.h"
#include "core/variant/type_info.h"
#include "scene/3d/physics_body_3d.h"
+#include "scene/resources/skeleton_modification_3d.h"
#include "scene/resources/surface_tool.h"
#include "scene/scene_string_names.h"
@@ -72,6 +71,13 @@ SkinReference::~SkinReference() {
bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) {
String path = p_path;
+#ifndef _3D_DISABLED
+ if (path.begins_with("modification_stack")) {
+ set_modification_stack(p_value);
+ return true;
+ }
+#endif //_3D_DISABLED
+
if (!path.begins_with("bones/")) {
return false;
}
@@ -104,6 +110,13 @@ bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) {
bool Skeleton3D::_get(const StringName &p_path, Variant &r_ret) const {
String path = p_path;
+#ifndef _3D_DISABLED
+ if (path.begins_with("modification_stack")) {
+ r_ret = modification_stack;
+ return true;
+ }
+#endif //_3D_DISABLED
+
if (!path.begins_with("bones/")) {
return false;
}
@@ -139,6 +152,14 @@ void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
+
+#ifndef _3D_DISABLED
+ p_list->push_back(
+ PropertyInfo(Variant::OBJECT, "modification_stack",
+ PROPERTY_HINT_RESOURCE_TYPE,
+ "SkeletonModificationStack3D",
+ PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
+#endif //_3D_DISABLED
}
void Skeleton3D::_update_process_order() {
@@ -149,47 +170,32 @@ void Skeleton3D::_update_process_order() {
Bone *bonesptr = bones.ptrw();
int len = bones.size();
- process_order.resize(len);
- int *order = process_order.ptrw();
+ parentless_bones.clear();
+
+ for (int i = 0; i < len; i++) {
+ bonesptr[i].child_bones.clear();
+ }
+
for (int i = 0; i < len; i++) {
if (bonesptr[i].parent >= len) {
//validate this just in case
ERR_PRINT("Bone " + itos(i) + " has invalid parent: " + itos(bonesptr[i].parent));
bonesptr[i].parent = -1;
}
- order[i] = i;
- bonesptr[i].sort_index = i;
- }
- //now check process order
- int pass_count = 0;
- while (pass_count < len * len) {
- //using bubblesort because of simplicity, it won't run every frame though.
- //bublesort worst case is O(n^2), and this may be an infinite loop if cyclic
- bool swapped = false;
- for (int i = 0; i < len; i++) {
- int parent_idx = bonesptr[order[i]].parent;
- if (parent_idx < 0) {
- continue; //do nothing because it has no parent
- }
- //swap indices
- int parent_order = bonesptr[parent_idx].sort_index;
- if (parent_order > i) {
- bonesptr[order[i]].sort_index = parent_order;
- bonesptr[parent_idx].sort_index = i;
- //swap order
- SWAP(order[i], order[parent_order]);
- swapped = true;
- }
- }
- if (!swapped) {
- break;
- }
- pass_count++;
- }
+ if (bonesptr[i].parent != -1) {
+ int parent_bone_idx = bonesptr[i].parent;
- if (pass_count == len * len) {
- ERR_PRINT("Skeleton3D parenthood graph is cyclic");
+ // Check to see if this node is already added to the parent:
+ if (bonesptr[parent_bone_idx].child_bones.find(i) < 0) {
+ // Add the child node
+ bonesptr[parent_bone_idx].child_bones.push_back(i);
+ } else {
+ ERR_PRINT("Skeleton3D parenthood graph is cyclic");
+ }
+ } else {
+ parentless_bones.push_back(i);
+ }
}
process_order_dirty = false;
@@ -200,78 +206,12 @@ void Skeleton3D::_notification(int p_what) {
case NOTIFICATION_UPDATE_SKELETON: {
RenderingServer *rs = RenderingServer::get_singleton();
Bone *bonesptr = bones.ptrw();
- int len = bones.size();
- _update_process_order();
-
- const int *order = process_order.ptr();
-
- for (int i = 0; i < len; i++) {
- Bone &b = bonesptr[order[i]];
-
- if (b.disable_rest) {
- if (b.enabled) {
- Transform3D pose = b.pose;
- if (b.custom_pose_enable) {
- pose = b.custom_pose * pose;
- }
- if (b.parent >= 0) {
- b.pose_global = bonesptr[b.parent].pose_global * pose;
- b.pose_global_no_override = bonesptr[b.parent].pose_global * pose;
- } else {
- b.pose_global = pose;
- b.pose_global_no_override = pose;
- }
- } else {
- if (b.parent >= 0) {
- b.pose_global = bonesptr[b.parent].pose_global;
- b.pose_global_no_override = bonesptr[b.parent].pose_global;
- } else {
- b.pose_global = Transform3D();
- b.pose_global_no_override = Transform3D();
- }
- }
-
- } else {
- if (b.enabled) {
- Transform3D pose = b.pose;
- if (b.custom_pose_enable) {
- pose = b.custom_pose * pose;
- }
- if (b.parent >= 0) {
- b.pose_global = bonesptr[b.parent].pose_global * (b.rest * pose);
- b.pose_global_no_override = bonesptr[b.parent].pose_global * (b.rest * pose);
- } else {
- b.pose_global = b.rest * pose;
- b.pose_global_no_override = b.rest * pose;
- }
- } else {
- if (b.parent >= 0) {
- b.pose_global = bonesptr[b.parent].pose_global * b.rest;
- b.pose_global_no_override = bonesptr[b.parent].pose_global * b.rest;
- } else {
- b.pose_global = b.rest;
- b.pose_global_no_override = b.rest;
- }
- }
- }
-
- if (b.global_pose_override_amount >= CMP_EPSILON) {
- b.pose_global = b.pose_global.interpolate_with(b.global_pose_override, b.global_pose_override_amount);
- }
-
- if (b.global_pose_override_reset) {
- b.global_pose_override_amount = 0.0;
- }
+ int len = bones.size();
+ dirty = false;
- for (const ObjectID &E : b.nodes_bound) {
- Object *obj = ObjectDB::get_instance(E);
- ERR_CONTINUE(!obj);
- Node3D *node_3d = Object::cast_to<Node3D>(obj);
- ERR_CONTINUE(!node_3d);
- node_3d->set_transform(b.pose_global);
- }
- }
+ // Update bone transforms
+ force_update_all_bone_transforms();
//update skins
for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
@@ -329,32 +269,53 @@ void Skeleton3D::_notification(int p_what) {
}
}
- dirty = false;
-
#ifdef TOOLS_ENABLED
emit_signal(SceneStringNames::get_singleton()->pose_updated);
#endif // TOOLS_ENABLED
} break;
+#ifndef _3D_DISABLED
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
// This is active only if the skeleton animates the physical bones
// and the state of the bone is not active.
- if (animate_physical_bones) {
- for (int i = 0; i < bones.size(); i += 1) {
- if (bones[i].physical_bone) {
- if (bones[i].physical_bone->is_simulating_physics() == false) {
- bones[i].physical_bone->reset_to_rest_position();
+ if (Engine::get_singleton()->is_editor_hint()) {
+ if (animate_physical_bones) {
+ for (int i = 0; i < bones.size(); i += 1) {
+ if (bones[i].physical_bone) {
+ if (bones[i].physical_bone->is_simulating_physics() == false) {
+ bones[i].physical_bone->reset_to_rest_position();
+ }
}
}
}
}
+
+ if (modification_stack.is_valid()) {
+ execute_modifications(get_physics_process_delta_time(), SkeletonModificationStack3D::EXECUTION_MODE::execution_mode_physics_process);
+ }
+
+ } break;
+#endif // _3D_DISABLED
+
+#ifndef _3D_DISABLED
+ case NOTIFICATION_INTERNAL_PROCESS: {
+ if (modification_stack.is_valid()) {
+ execute_modifications(get_process_delta_time(), SkeletonModificationStack3D::EXECUTION_MODE::execution_mode_process);
+ }
} break;
+#endif // _3D_DISABLED
+
+#ifndef _3D_DISABLED
case NOTIFICATION_READY: {
- if (Engine::get_singleton()->is_editor_hint()) {
- set_physics_process_internal(true);
+ set_physics_process_internal(true);
+ set_process_internal(true);
+
+ if (modification_stack.is_valid()) {
+ set_modification_stack(modification_stack);
}
} break;
+#endif // _3D_DISABLED
}
}
@@ -366,16 +327,24 @@ void Skeleton3D::clear_bones_global_pose_override() {
_make_dirty();
}
-void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, float p_amount, bool p_persistent) {
- ERR_FAIL_INDEX(p_bone, bones.size());
+void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
bones.write[p_bone].global_pose_override_amount = p_amount;
bones.write[p_bone].global_pose_override = p_pose;
bones.write[p_bone].global_pose_override_reset = !p_persistent;
_make_dirty();
}
+Transform3D Skeleton3D::get_bone_global_pose_override(int p_bone) const {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D());
+ return bones[p_bone].global_pose_override;
+}
+
Transform3D Skeleton3D::get_bone_global_pose(int p_bone) const {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D());
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D());
if (dirty) {
const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON);
}
@@ -383,13 +352,107 @@ Transform3D Skeleton3D::get_bone_global_pose(int p_bone) const {
}
Transform3D Skeleton3D::get_bone_global_pose_no_override(int p_bone) const {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D());
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D());
if (dirty) {
const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON);
}
return bones[p_bone].pose_global_no_override;
}
+void Skeleton3D::clear_bones_local_pose_override() {
+ for (int i = 0; i < bones.size(); i += 1) {
+ bones.write[i].local_pose_override_amount = 0;
+ }
+ _make_dirty();
+}
+
+void Skeleton3D::set_bone_local_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
+ bones.write[p_bone].local_pose_override_amount = p_amount;
+ bones.write[p_bone].local_pose_override = p_pose;
+ bones.write[p_bone].local_pose_override_reset = !p_persistent;
+ _make_dirty();
+}
+
+Transform3D Skeleton3D::get_bone_local_pose_override(int p_bone) const {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D());
+ return bones[p_bone].local_pose_override;
+}
+
+void Skeleton3D::update_bone_rest_forward_vector(int p_bone, bool p_force_update) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
+
+ if (bones[p_bone].rest_bone_forward_vector.length_squared() > 0 && p_force_update == false) {
+ update_bone_rest_forward_axis(p_bone, p_force_update);
+ }
+
+ // If it is a child/leaf bone...
+ if (get_bone_parent(p_bone) > 0) {
+ bones.write[p_bone].rest_bone_forward_vector = bones[p_bone].rest.origin.normalized();
+ } else {
+ // If it has children...
+ Vector<int> child_bones = get_bone_children(p_bone);
+ if (child_bones.size() > 0) {
+ Vector3 combined_child_dir = Vector3(0, 0, 0);
+ for (int i = 0; i < child_bones.size(); i++) {
+ combined_child_dir += bones[child_bones[i]].rest.origin.normalized();
+ }
+ combined_child_dir = combined_child_dir / child_bones.size();
+ bones.write[p_bone].rest_bone_forward_vector = combined_child_dir.normalized();
+ } else {
+ WARN_PRINT_ONCE("Cannot calculate forward direction for bone " + itos(p_bone));
+ WARN_PRINT_ONCE("Assuming direction of (0, 1, 0) for bone");
+ bones.write[p_bone].rest_bone_forward_vector = Vector3(0, 1, 0);
+ }
+ }
+ update_bone_rest_forward_axis(p_bone, p_force_update);
+}
+
+void Skeleton3D::update_bone_rest_forward_axis(int p_bone, bool p_force_update) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
+ if (bones[p_bone].rest_bone_forward_axis > -1 && p_force_update == false) {
+ return;
+ }
+
+ Vector3 forward_axis_absolute = bones[p_bone].rest_bone_forward_vector.abs();
+ if (forward_axis_absolute.x > forward_axis_absolute.y && forward_axis_absolute.x > forward_axis_absolute.z) {
+ if (bones[p_bone].rest_bone_forward_vector.x > 0) {
+ bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_X_FORWARD;
+ } else {
+ bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_NEGATIVE_X_FORWARD;
+ }
+ } else if (forward_axis_absolute.y > forward_axis_absolute.x && forward_axis_absolute.y > forward_axis_absolute.z) {
+ if (bones[p_bone].rest_bone_forward_vector.y > 0) {
+ bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_Y_FORWARD;
+ } else {
+ bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_NEGATIVE_Y_FORWARD;
+ }
+ } else {
+ if (bones[p_bone].rest_bone_forward_vector.z > 0) {
+ bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_Z_FORWARD;
+ } else {
+ bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_NEGATIVE_Z_FORWARD;
+ }
+ }
+}
+
+Vector3 Skeleton3D::get_bone_axis_forward_vector(int p_bone) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, Vector3(0, 0, 0));
+ return bones[p_bone].rest_bone_forward_vector;
+}
+
+int Skeleton3D::get_bone_axis_forward_enum(int p_bone) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, -1);
+ return bones[p_bone].rest_bone_forward_axis;
+}
+
// skeleton creation api
void Skeleton3D::add_bone(const String &p_name) {
ERR_FAIL_COND(p_name == "" || p_name.find(":") != -1 || p_name.find("/") != -1);
@@ -418,14 +481,15 @@ int Skeleton3D::find_bone(const String &p_name) const {
}
String Skeleton3D::get_bone_name(int p_bone) const {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), "");
-
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, "");
return bones[p_bone].name;
}
void Skeleton3D::set_bone_name(int p_bone, const String &p_name) {
- ERR_FAIL_INDEX(p_bone, bones.size());
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
- for (int i = 0; i < bones.size(); i++) {
+ for (int i = 0; i < bone_size; i++) {
if (i != p_bone) {
ERR_FAIL_COND(bones[i].name == p_name);
}
@@ -453,8 +517,10 @@ int Skeleton3D::get_bone_count() const {
}
void Skeleton3D::set_bone_parent(int p_bone, int p_parent) {
- ERR_FAIL_INDEX(p_bone, bones.size());
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
ERR_FAIL_COND(p_parent != -1 && (p_parent < 0));
+ ERR_FAIL_COND(p_bone == p_parent);
bones.write[p_bone].parent = p_parent;
process_order_dirty = true;
@@ -462,7 +528,8 @@ void Skeleton3D::set_bone_parent(int p_bone, int p_parent) {
}
void Skeleton3D::unparent_bone_and_rest(int p_bone) {
- ERR_FAIL_INDEX(p_bone, bones.size());
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
_update_process_order();
@@ -479,76 +546,93 @@ void Skeleton3D::unparent_bone_and_rest(int p_bone) {
}
void Skeleton3D::set_bone_disable_rest(int p_bone, bool p_disable) {
- ERR_FAIL_INDEX(p_bone, bones.size());
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
bones.write[p_bone].disable_rest = p_disable;
}
bool Skeleton3D::is_bone_rest_disabled(int p_bone) const {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), false);
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, false);
return bones[p_bone].disable_rest;
}
int Skeleton3D::get_bone_parent(int p_bone) const {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), -1);
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, -1);
return bones[p_bone].parent;
}
-void Skeleton3D::set_bone_rest(int p_bone, const Transform3D &p_rest) {
- ERR_FAIL_INDEX(p_bone, bones.size());
+Vector<int> Skeleton3D::get_bone_children(int p_bone) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, Vector<int>());
+ return bones[p_bone].child_bones;
+}
- bones.write[p_bone].rest = p_rest;
+void Skeleton3D::set_bone_children(int p_bone, Vector<int> p_children) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
+ bones.write[p_bone].child_bones = p_children;
+
+ process_order_dirty = true;
_make_dirty();
}
-Transform3D Skeleton3D::get_bone_rest(int p_bone) const {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D());
- return bones[p_bone].rest;
+void Skeleton3D::add_bone_child(int p_bone, int p_child) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
+ bones.write[p_bone].child_bones.push_back(p_child);
+
+ process_order_dirty = true;
+ _make_dirty();
}
-void Skeleton3D::set_bone_enabled(int p_bone, bool p_enabled) {
- ERR_FAIL_INDEX(p_bone, bones.size());
+void Skeleton3D::remove_bone_child(int p_bone, int p_child) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
- bones.write[p_bone].enabled = p_enabled;
+ int child_idx = bones[p_bone].child_bones.find(p_child);
+ if (child_idx >= 0) {
+ bones.write[p_bone].child_bones.remove(child_idx);
+ } else {
+ WARN_PRINT("Cannot remove child bone: Child bone not found.");
+ }
+
+ process_order_dirty = true;
_make_dirty();
}
-bool Skeleton3D::is_bone_enabled(int p_bone) const {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), false);
- return bones[p_bone].enabled;
+Vector<int> Skeleton3D::get_parentless_bones() {
+ return parentless_bones;
}
-void Skeleton3D::bind_child_node_to_bone(int p_bone, Node *p_node) {
- ERR_FAIL_NULL(p_node);
- ERR_FAIL_INDEX(p_bone, bones.size());
-
- ObjectID id = p_node->get_instance_id();
+void Skeleton3D::set_bone_rest(int p_bone, const Transform3D &p_rest) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
- for (const ObjectID &E : bones[p_bone].nodes_bound) {
- if (E == id) {
- return; // already here
- }
- }
+ bones.write[p_bone].rest = p_rest;
+ _make_dirty();
+}
+Transform3D Skeleton3D::get_bone_rest(int p_bone) const {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D());
- bones.write[p_bone].nodes_bound.push_back(id);
+ return bones[p_bone].rest;
}
-void Skeleton3D::unbind_child_node_from_bone(int p_bone, Node *p_node) {
- ERR_FAIL_NULL(p_node);
- ERR_FAIL_INDEX(p_bone, bones.size());
+void Skeleton3D::set_bone_enabled(int p_bone, bool p_enabled) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
- ObjectID id = p_node->get_instance_id();
- bones.write[p_bone].nodes_bound.erase(id);
+ bones.write[p_bone].enabled = p_enabled;
+ _make_dirty();
}
-void Skeleton3D::get_bound_child_nodes_to_bone(int p_bone, List<Node *> *p_bound) const {
- ERR_FAIL_INDEX(p_bone, bones.size());
-
- for (const ObjectID &E : bones[p_bone].nodes_bound) {
- Object *obj = ObjectDB::get_instance(E);
- ERR_CONTINUE(!obj);
- p_bound->push_back(Object::cast_to<Node>(obj));
- }
+bool Skeleton3D::is_bone_enabled(int p_bone) const {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, false);
+ return bones[p_bone].enabled;
}
void Skeleton3D::clear_bones() {
@@ -561,7 +645,8 @@ void Skeleton3D::clear_bones() {
// posing api
void Skeleton3D::set_bone_pose(int p_bone, const Transform3D &p_pose) {
- ERR_FAIL_INDEX(p_bone, bones.size());
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
bones.write[p_bone].pose = p_pose;
if (is_inside_tree()) {
@@ -569,12 +654,14 @@ void Skeleton3D::set_bone_pose(int p_bone, const Transform3D &p_pose) {
}
}
Transform3D Skeleton3D::get_bone_pose(int p_bone) const {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D());
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D());
return bones[p_bone].pose;
}
void Skeleton3D::set_bone_custom_pose(int p_bone, const Transform3D &p_custom_pose) {
- ERR_FAIL_INDEX(p_bone, bones.size());
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
//ERR_FAIL_COND( !is_inside_scene() );
bones.write[p_bone].custom_pose_enable = (p_custom_pose != Transform3D());
@@ -584,7 +671,8 @@ void Skeleton3D::set_bone_custom_pose(int p_bone, const Transform3D &p_custom_po
}
Transform3D Skeleton3D::get_bone_custom_pose(int p_bone) const {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D());
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D());
return bones[p_bone].custom_pose;
}
@@ -597,24 +685,22 @@ void Skeleton3D::_make_dirty() {
dirty = true;
}
-int Skeleton3D::get_process_order(int p_idx) {
- ERR_FAIL_INDEX_V(p_idx, bones.size(), -1);
+void Skeleton3D::localize_rests() {
_update_process_order();
- return process_order[p_idx];
-}
-Vector<int> Skeleton3D::get_bone_process_orders() {
- _update_process_order();
- return process_order;
-}
+ Vector<int> bones_to_process = get_parentless_bones();
+ while (bones_to_process.size() > 0) {
+ int current_bone_idx = bones_to_process[0];
+ bones_to_process.erase(current_bone_idx);
-void Skeleton3D::localize_rests() {
- _update_process_order();
+ if (bones[current_bone_idx].parent >= 0) {
+ set_bone_rest(current_bone_idx, bones[bones[current_bone_idx].parent].rest.affine_inverse() * bones[current_bone_idx].rest);
+ }
- for (int i = bones.size() - 1; i >= 0; i--) {
- int idx = process_order[i];
- if (bones[idx].parent >= 0) {
- set_bone_rest(idx, bones[bones[idx].parent].rest.affine_inverse() * bones[idx].rest);
+ // Add the bone's children to the list of bones to be processed
+ int child_bone_size = bones[current_bone_idx].child_bones.size();
+ for (int i = 0; i < child_bone_size; i++) {
+ bones_to_process.push_back(bones[current_bone_idx].child_bones[i]);
}
}
}
@@ -641,7 +727,8 @@ bool Skeleton3D::get_animate_physical_bones() const {
}
void Skeleton3D::bind_physical_bone_to_bone(int p_bone, PhysicalBone3D *p_physical_bone) {
- ERR_FAIL_INDEX(p_bone, bones.size());
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
ERR_FAIL_COND(bones[p_bone].physical_bone);
ERR_FAIL_COND(!p_physical_bone);
bones.write[p_bone].physical_bone = p_physical_bone;
@@ -650,20 +737,23 @@ void Skeleton3D::bind_physical_bone_to_bone(int p_bone, PhysicalBone3D *p_physic
}
void Skeleton3D::unbind_physical_bone_from_bone(int p_bone) {
- ERR_FAIL_INDEX(p_bone, bones.size());
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
bones.write[p_bone].physical_bone = nullptr;
_rebuild_physical_bones_cache();
}
PhysicalBone3D *Skeleton3D::get_physical_bone(int p_bone) {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), nullptr);
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, nullptr);
return bones[p_bone].physical_bone;
}
PhysicalBone3D *Skeleton3D::get_physical_bone_parent(int p_bone) {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), nullptr);
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, nullptr);
if (bones[p_bone].cache_parent_physical_bone) {
return bones[p_bone].cache_parent_physical_bone;
@@ -673,7 +763,8 @@ PhysicalBone3D *Skeleton3D::get_physical_bone_parent(int p_bone) {
}
PhysicalBone3D *Skeleton3D::_get_physical_bone_parent(int p_bone) {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), nullptr);
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone, bone_size, nullptr);
const int parent_bone = bones[p_bone].parent;
if (0 > parent_bone) {
@@ -804,15 +895,26 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
// pose changed, rebuild cache of inverses
const Bone *bonesptr = bones.ptr();
int len = bones.size();
- const int *order = process_order.ptr();
// calculate global rests and invert them
- for (int i = 0; i < len; i++) {
- const Bone &b = bonesptr[order[i]];
- if (b.parent >= 0) {
- skin->set_bind_pose(order[i], skin->get_bind_pose(b.parent) * b.rest);
- } else {
- skin->set_bind_pose(order[i], b.rest);
+ LocalVector<int> bones_to_process;
+ bones_to_process = get_parentless_bones();
+ while (bones_to_process.size() > 0) {
+ int current_bone_idx = bones_to_process[0];
+ const Bone &b = bonesptr[current_bone_idx];
+ bones_to_process.erase(current_bone_idx);
+ LocalVector<int> child_bones_vector;
+ child_bones_vector = get_bone_children(current_bone_idx);
+ int child_bones_size = child_bones_vector.size();
+ if (b.parent < 0) {
+ skin->set_bind_pose(current_bone_idx, b.rest);
+ }
+ for (int i = 0; i < child_bones_size; i++) {
+ int child_bone_idx = child_bones_vector[i];
+ const Bone &cb = bonesptr[child_bone_idx];
+ skin->set_bind_pose(child_bone_idx, skin->get_bind_pose(current_bone_idx) * cb.rest);
+ // Add the bone's children to the list of bones to be processed.
+ bones_to_process.push_back(child_bones_vector[i]);
}
}
@@ -843,17 +945,202 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
return skin_ref;
}
+void Skeleton3D::force_update_all_bone_transforms() {
+ _update_process_order();
+
+ for (int i = 0; i < parentless_bones.size(); i++) {
+ force_update_bone_children_transforms(parentless_bones[i]);
+ }
+}
+
+void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone_idx, bone_size);
+
+ Bone *bonesptr = bones.ptrw();
+ List<int> bones_to_process = List<int>();
+ bones_to_process.push_back(p_bone_idx);
+
+ while (bones_to_process.size() > 0) {
+ int current_bone_idx = bones_to_process[0];
+ bones_to_process.erase(current_bone_idx);
+
+ Bone &b = bonesptr[current_bone_idx];
+
+ if (b.disable_rest) {
+ if (b.enabled) {
+ Transform3D pose = b.pose;
+ if (b.custom_pose_enable) {
+ pose = b.custom_pose * pose;
+ }
+ if (b.parent >= 0) {
+ b.pose_global = bonesptr[b.parent].pose_global * pose;
+ b.pose_global_no_override = b.pose_global;
+ } else {
+ b.pose_global = pose;
+ b.pose_global_no_override = b.pose_global;
+ }
+ } else {
+ if (b.parent >= 0) {
+ b.pose_global = bonesptr[b.parent].pose_global;
+ b.pose_global_no_override = b.pose_global;
+ } else {
+ b.pose_global = Transform3D();
+ b.pose_global_no_override = b.pose_global;
+ }
+ }
+
+ } else {
+ if (b.enabled) {
+ Transform3D pose = b.pose;
+ if (b.custom_pose_enable) {
+ pose = b.custom_pose * pose;
+ }
+ if (b.parent >= 0) {
+ b.pose_global = bonesptr[b.parent].pose_global * (b.rest * pose);
+ b.pose_global_no_override = b.pose_global;
+ } else {
+ b.pose_global = b.rest * pose;
+ b.pose_global_no_override = b.pose_global;
+ }
+ } else {
+ if (b.parent >= 0) {
+ b.pose_global = bonesptr[b.parent].pose_global * b.rest;
+ b.pose_global_no_override = b.pose_global;
+ } else {
+ b.pose_global = b.rest;
+ b.pose_global_no_override = b.pose_global;
+ }
+ }
+ }
+
+ if (b.local_pose_override_amount >= CMP_EPSILON) {
+ Transform3D override_local_pose;
+ if (b.parent >= 0) {
+ override_local_pose = bonesptr[b.parent].pose_global * (b.rest * b.local_pose_override);
+ } else {
+ override_local_pose = (b.rest * b.local_pose_override);
+ }
+ b.pose_global = b.pose_global.interpolate_with(override_local_pose, b.local_pose_override_amount);
+ }
+
+ if (b.global_pose_override_amount >= CMP_EPSILON) {
+ b.pose_global = b.pose_global.interpolate_with(b.global_pose_override, b.global_pose_override_amount);
+ }
+
+ if (b.local_pose_override_reset) {
+ b.local_pose_override_amount = 0.0;
+ }
+ if (b.global_pose_override_reset) {
+ b.global_pose_override_amount = 0.0;
+ }
+
+ // Add the bone's children to the list of bones to be processed
+ int child_bone_size = b.child_bones.size();
+ for (int i = 0; i < child_bone_size; i++) {
+ bones_to_process.push_back(b.child_bones[i]);
+ }
+
+ emit_signal(SceneStringNames::get_singleton()->bone_pose_changed, current_bone_idx);
+ }
+}
+
// helper functions
-Transform3D Skeleton3D::bone_transform_to_world_transform(Transform3D p_bone_transform) {
- return get_global_transform() * p_bone_transform;
+
+Transform3D Skeleton3D::global_pose_to_world_transform(Transform3D p_global_pose) {
+ return get_global_transform() * p_global_pose;
}
-Transform3D Skeleton3D::world_transform_to_bone_transform(Transform3D p_world_transform) {
+Transform3D Skeleton3D::world_transform_to_global_pose(Transform3D p_world_transform) {
return get_global_transform().affine_inverse() * p_world_transform;
}
+Transform3D Skeleton3D::global_pose_to_local_pose(int p_bone_idx, Transform3D p_global_pose) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Transform3D());
+ if (bones[p_bone_idx].parent >= 0) {
+ int parent_bone_idx = bones[p_bone_idx].parent;
+ Transform3D conversion_transform = (bones[parent_bone_idx].pose_global * bones[p_bone_idx].rest);
+ return conversion_transform.affine_inverse() * p_global_pose;
+ } else {
+ return p_global_pose;
+ }
+}
+
+Transform3D Skeleton3D::local_pose_to_global_pose(int p_bone_idx, Transform3D p_local_pose) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Transform3D());
+ if (bones[p_bone_idx].parent >= 0) {
+ int parent_bone_idx = bones[p_bone_idx].parent;
+ Transform3D conversion_transform = (bones[parent_bone_idx].pose_global * bones[p_bone_idx].rest);
+ return conversion_transform * p_local_pose;
+ } else {
+ return p_local_pose;
+ }
+}
+
+Basis Skeleton3D::global_pose_z_forward_to_bone_forward(int p_bone_idx, Basis p_basis) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Basis());
+ Basis return_basis = p_basis;
+
+ if (bones[p_bone_idx].rest_bone_forward_axis < 0) {
+ update_bone_rest_forward_vector(p_bone_idx, true);
+ }
+
+ if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_X_FORWARD) {
+ return_basis.rotate_local(Vector3(0, 1, 0), (Math_PI / 2.0));
+ } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_NEGATIVE_X_FORWARD) {
+ return_basis.rotate_local(Vector3(0, 1, 0), -(Math_PI / 2.0));
+ } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_Y_FORWARD) {
+ return_basis.rotate_local(Vector3(1, 0, 0), -(Math_PI / 2.0));
+ } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_NEGATIVE_Y_FORWARD) {
+ return_basis.rotate_local(Vector3(1, 0, 0), (Math_PI / 2.0));
+ } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_Z_FORWARD) {
+ // Do nothing!
+ } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_NEGATIVE_Z_FORWARD) {
+ return_basis.rotate_local(Vector3(0, 0, 1), Math_PI);
+ }
+
+ return return_basis;
+}
+
+// Modifications
+
+#ifndef _3D_DISABLED
+
+void Skeleton3D::set_modification_stack(Ref<SkeletonModificationStack3D> p_stack) {
+ if (modification_stack.is_valid()) {
+ modification_stack->is_setup = false;
+ modification_stack->set_skeleton(nullptr);
+ }
+
+ modification_stack = p_stack;
+ if (modification_stack.is_valid()) {
+ modification_stack->set_skeleton(this);
+ modification_stack->setup();
+ }
+}
+Ref<SkeletonModificationStack3D> Skeleton3D::get_modification_stack() {
+ return modification_stack;
+}
+
+void Skeleton3D::execute_modifications(real_t p_delta, int p_execution_mode) {
+ if (!modification_stack.is_valid()) {
+ return;
+ }
+
+ // Needed to avoid the issue where the stack looses reference to the skeleton when the scene is saved.
+ if (modification_stack->skeleton != this) {
+ modification_stack->set_skeleton(this);
+ }
+
+ modification_stack->execute(p_delta, p_execution_mode);
+}
+
+#endif // _3D_DISABLED
+
void Skeleton3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_bone_process_orders"), &Skeleton3D::get_bone_process_orders);
ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton3D::add_bone);
ClassDB::bind_method(D_METHOD("find_bone", "name"), &Skeleton3D::find_bone);
ClassDB::bind_method(D_METHOD("get_bone_name", "bone_idx"), &Skeleton3D::get_bone_name);
@@ -866,6 +1153,13 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("unparent_bone_and_rest", "bone_idx"), &Skeleton3D::unparent_bone_and_rest);
+ ClassDB::bind_method(D_METHOD("get_bone_children", "bone_idx"), &Skeleton3D::get_bone_children);
+ ClassDB::bind_method(D_METHOD("set_bone_children", "bone_idx", "bone_children"), &Skeleton3D::set_bone_children);
+ ClassDB::bind_method(D_METHOD("add_bone_child", "bone_idx", "child_bone_idx"), &Skeleton3D::add_bone_child);
+ ClassDB::bind_method(D_METHOD("remove_bone_child", "bone_idx", "child_bone_idx"), &Skeleton3D::remove_bone_child);
+
+ ClassDB::bind_method(D_METHOD("get_parentless_bones"), &Skeleton3D::get_parentless_bones);
+
ClassDB::bind_method(D_METHOD("get_bone_rest", "bone_idx"), &Skeleton3D::get_bone_rest);
ClassDB::bind_method(D_METHOD("set_bone_rest", "bone_idx", "rest"), &Skeleton3D::set_bone_rest);
@@ -883,14 +1177,26 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_bones_global_pose_override"), &Skeleton3D::clear_bones_global_pose_override);
ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton3D::set_bone_global_pose_override, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_bone_global_pose_override", "bone_idx"), &Skeleton3D::get_bone_global_pose_override);
ClassDB::bind_method(D_METHOD("get_bone_global_pose", "bone_idx"), &Skeleton3D::get_bone_global_pose);
ClassDB::bind_method(D_METHOD("get_bone_global_pose_no_override", "bone_idx"), &Skeleton3D::get_bone_global_pose_no_override);
+ ClassDB::bind_method(D_METHOD("clear_bones_local_pose_override"), &Skeleton3D::clear_bones_local_pose_override);
+ ClassDB::bind_method(D_METHOD("set_bone_local_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton3D::set_bone_local_pose_override, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_bone_local_pose_override", "bone_idx"), &Skeleton3D::get_bone_local_pose_override);
+
ClassDB::bind_method(D_METHOD("get_bone_custom_pose", "bone_idx"), &Skeleton3D::get_bone_custom_pose);
ClassDB::bind_method(D_METHOD("set_bone_custom_pose", "bone_idx", "custom_pose"), &Skeleton3D::set_bone_custom_pose);
- ClassDB::bind_method(D_METHOD("bone_transform_to_world_transform", "bone_transform"), &Skeleton3D::bone_transform_to_world_transform);
- ClassDB::bind_method(D_METHOD("world_transform_to_bone_transform", "world_transform"), &Skeleton3D::world_transform_to_bone_transform);
+ ClassDB::bind_method(D_METHOD("force_update_all_bone_transforms"), &Skeleton3D::force_update_all_bone_transforms);
+ ClassDB::bind_method(D_METHOD("force_update_bone_child_transform", "bone_idx"), &Skeleton3D::force_update_bone_children_transforms);
+
+ // Helper functions
+ ClassDB::bind_method(D_METHOD("global_pose_to_world_transform", "global_pose"), &Skeleton3D::global_pose_to_world_transform);
+ ClassDB::bind_method(D_METHOD("world_transform_to_global_pose", "world_transform"), &Skeleton3D::world_transform_to_global_pose);
+ ClassDB::bind_method(D_METHOD("global_pose_to_local_pose", "bone_idx", "global_pose"), &Skeleton3D::global_pose_to_local_pose);
+ ClassDB::bind_method(D_METHOD("local_pose_to_global_pose", "bone_idx", "local_pose"), &Skeleton3D::local_pose_to_global_pose);
+ ClassDB::bind_method(D_METHOD("global_pose_z_forward_to_bone_forward", "bone_idx", "basis"), &Skeleton3D::global_pose_z_forward_to_bone_forward);
ClassDB::bind_method(D_METHOD("set_animate_physical_bones"), &Skeleton3D::set_animate_physical_bones);
ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton3D::get_animate_physical_bones);
@@ -900,12 +1206,21 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton3D::physical_bones_add_collision_exception);
ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton3D::physical_bones_remove_collision_exception);
+ // Modifications
+ ClassDB::bind_method(D_METHOD("set_modification_stack", "modification_stack"), &Skeleton3D::set_modification_stack);
+ ClassDB::bind_method(D_METHOD("get_modification_stack"), &Skeleton3D::get_modification_stack);
+ ClassDB::bind_method(D_METHOD("execute_modifications", "delta", "execution_mode"), &Skeleton3D::execute_modifications);
+
+#ifndef _3D_DISABLED
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "animate_physical_bones"), "set_animate_physical_bones", "get_animate_physical_bones");
+#endif // _3D_DISABLED
#ifdef TOOLS_ENABLED
ADD_SIGNAL(MethodInfo("pose_updated"));
#endif // TOOLS_ENABLED
+ ADD_SIGNAL(MethodInfo("bone_pose_changed", PropertyInfo(Variant::INT, "bone_idx")));
+
BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
}
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index 2f6e416c8c..c8a19db813 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -31,8 +31,8 @@
#ifndef SKELETON_3D_H
#define SKELETON_3D_H
-#include "core/templates/rid.h"
#include "scene/3d/node_3d.h"
+#include "scene/resources/skeleton_modification_3d.h"
#include "scene/resources/skin.h"
typedef int BoneId;
@@ -62,6 +62,8 @@ public:
~SkinReference();
};
+class SkeletonModificationStack3D;
+
class Skeleton3D : public Node3D {
GDCLASS(Skeleton3D, Node3D);
@@ -71,9 +73,8 @@ private:
struct Bone {
String name;
- bool enabled = true;
- int parent = -1;
- int sort_index = 0; //used for re-sorting process order
+ bool enabled;
+ int parent;
bool disable_rest = false;
Transform3D rest;
@@ -85,14 +86,42 @@ private:
bool custom_pose_enable = false;
Transform3D custom_pose;
- float global_pose_override_amount = 0.0;
+ real_t global_pose_override_amount = 0.0;
bool global_pose_override_reset = false;
Transform3D global_pose_override;
PhysicalBone3D *physical_bone = nullptr;
PhysicalBone3D *cache_parent_physical_bone = nullptr;
- List<ObjectID> nodes_bound;
+ real_t local_pose_override_amount;
+ bool local_pose_override_reset;
+ Transform3D local_pose_override;
+
+ Vector<int> child_bones;
+
+ // The forward direction vector and rest bone forward axis are cached because they do not change
+ // 99% of the time, but recalculating them can be expensive on models with many bones.
+ Vector3 rest_bone_forward_vector;
+ int rest_bone_forward_axis = -1;
+
+ Bone() {
+ parent = -1;
+ enabled = true;
+ disable_rest = false;
+ custom_pose_enable = false;
+ global_pose_override_amount = 0;
+ global_pose_override_reset = false;
+#ifndef _3D_DISABLED
+ physical_bone = nullptr;
+ cache_parent_physical_bone = nullptr;
+#endif // _3D_DISABLED
+ local_pose_override_amount = 0;
+ local_pose_override_reset = false;
+ child_bones = Vector<int>();
+
+ rest_bone_forward_vector = Vector3(0, 0, 0);
+ rest_bone_forward_axis = -1;
+ }
};
Set<SkinReference *> skin_bindings;
@@ -101,8 +130,9 @@ private:
bool animate_physical_bones = true;
Vector<Bone> bones;
- Vector<int> process_order;
- bool process_order_dirty = true;
+ bool process_order_dirty;
+
+ Vector<int> parentless_bones;
void _make_dirty();
bool dirty = false;
@@ -118,7 +148,20 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+#ifndef _3D_DISABLED
+ Ref<SkeletonModificationStack3D> modification_stack;
+#endif // _3D_DISABLED
+
public:
+ enum Bone_Forward_Axis {
+ BONE_AXIS_X_FORWARD = 0,
+ BONE_AXIS_Y_FORWARD = 1,
+ BONE_AXIS_Z_FORWARD = 2,
+ BONE_AXIS_NEGATIVE_X_FORWARD = 3,
+ BONE_AXIS_NEGATIVE_Y_FORWARD = 4,
+ BONE_AXIS_NEGATIVE_Z_FORWARD = 5,
+ };
+
enum {
NOTIFICATION_UPDATE_SKELETON = 50
};
@@ -136,6 +179,12 @@ public:
void unparent_bone_and_rest(int p_bone);
+ Vector<int> get_bone_children(int p_bone);
+ void set_bone_children(int p_bone, Vector<int> p_children);
+ void add_bone_child(int p_bone, int p_child);
+ void remove_bone_child(int p_bone, int p_child);
+ Vector<int> get_parentless_bones();
+
void set_bone_disable_rest(int p_bone, bool p_disable);
bool is_bone_rest_disabled(int p_bone) const;
@@ -146,16 +195,8 @@ public:
Transform3D get_bone_global_pose(int p_bone) const;
Transform3D get_bone_global_pose_no_override(int p_bone) const;
- void clear_bones_global_pose_override();
- void set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, float p_amount, bool p_persistent = false);
-
void set_bone_enabled(int p_bone, bool p_enabled);
bool is_bone_enabled(int p_bone) const;
-
- void bind_child_node_to_bone(int p_bone, Node *p_node);
- void unbind_child_node_from_bone(int p_bone, Node *p_node);
- void get_bound_child_nodes_to_bone(int p_bone, List<Node *> *p_bound) const;
-
void clear_bones();
// posing api
@@ -166,15 +207,40 @@ public:
void set_bone_custom_pose(int p_bone, const Transform3D &p_custom_pose);
Transform3D get_bone_custom_pose(int p_bone) const;
+ void clear_bones_global_pose_override();
+ Transform3D get_bone_global_pose_override(int p_bone) const;
+ void set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent = false);
+
+ void clear_bones_local_pose_override();
+ Transform3D get_bone_local_pose_override(int p_bone) const;
+ void set_bone_local_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent = false);
+
void localize_rests(); // used for loaders and tools
- int get_process_order(int p_idx);
- Vector<int> get_bone_process_orders();
Ref<SkinReference> register_skin(const Ref<Skin> &p_skin);
+ void force_update_all_bone_transforms();
+ void force_update_bone_children_transforms(int bone_idx);
+
+ void update_bone_rest_forward_vector(int p_bone, bool p_force_update = false);
+ void update_bone_rest_forward_axis(int p_bone, bool p_force_update = false);
+ Vector3 get_bone_axis_forward_vector(int p_bone);
+ int get_bone_axis_forward_enum(int p_bone);
+
// Helper functions
- Transform3D bone_transform_to_world_transform(Transform3D p_transform);
- Transform3D world_transform_to_bone_transform(Transform3D p_transform);
+ Transform3D global_pose_to_world_transform(Transform3D p_global_pose);
+ Transform3D world_transform_to_global_pose(Transform3D p_transform);
+ Transform3D global_pose_to_local_pose(int p_bone_idx, Transform3D p_global_pose);
+ Transform3D local_pose_to_global_pose(int p_bone_idx, Transform3D p_local_pose);
+
+ Basis global_pose_z_forward_to_bone_forward(int p_bone_idx, Basis p_basis);
+
+ // Modifications
+#ifndef _3D_DISABLED
+ Ref<SkeletonModificationStack3D> get_modification_stack();
+ void set_modification_stack(Ref<SkeletonModificationStack3D> p_stack);
+ void execute_modifications(real_t p_delta, int p_execution_mode);
+#endif // _3D_DISABLED
// Physical bone API
diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp
index 1005d51e63..2e788051f4 100644
--- a/scene/3d/skeleton_ik_3d.cpp
+++ b/scene/3d/skeleton_ik_3d.cpp
@@ -85,7 +85,7 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain
chain_sub_tip = p_task->skeleton->get_bone_parent(chain_sub_tip);
}
- BoneId middle_chain_item_id = (((float)sub_chain_size) * 0.5);
+ BoneId middle_chain_item_id = (BoneId)(sub_chain_size * 0.5);
// Build chain by reading chain ids in reverse order
// For each chain item id will be created a ChainItem if doesn't exists
@@ -99,7 +99,7 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain
child_ci->current_pos = child_ci->initial_transform.origin;
if (child_ci->parent_item) {
- child_ci->length = (child_ci->current_pos - child_ci->parent_item->current_pos).length();
+ child_ci->length = child_ci->parent_item->current_pos.distance_to(child_ci->current_pos);
}
}
@@ -140,7 +140,7 @@ void FabrikInverseKinematic::solve_simple(Task *p_task, bool p_solve_magnet, Vec
solve_simple_backwards(p_task->chain, p_solve_magnet);
solve_simple_forwards(p_task->chain, p_solve_magnet, p_origin_pos);
- distance_to_goal = (p_task->chain.tips[0].chain_item->current_pos - p_task->chain.tips[0].end_effector->goal_transform.origin).length();
+ distance_to_goal = p_task->chain.tips[0].end_effector->goal_transform.origin.distance_to(p_task->chain.tips[0].chain_item->current_pos);
}
}
@@ -291,14 +291,10 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove
new_bone_pose.origin = ci->current_pos;
if (!ci->children.is_empty()) {
- /// Rotate basis
- const Vector3 initial_ori((ci->children[0].initial_transform.origin - ci->initial_transform.origin).normalized());
- const Vector3 rot_axis(initial_ori.cross(ci->current_ori).normalized());
-
- if (rot_axis[0] != 0 && rot_axis[1] != 0 && rot_axis[2] != 0) {
- const real_t rot_angle(Math::acos(CLAMP(initial_ori.dot(ci->current_ori), -1, 1)));
- new_bone_pose.basis.rotate(rot_axis, rot_angle);
- }
+ p_task->skeleton->update_bone_rest_forward_vector(ci->bone);
+ Vector3 forward_vector = p_task->skeleton->get_bone_axis_forward_vector(ci->bone);
+ // Rotate the bone towards the next bone in the chain:
+ new_bone_pose.basis.rotate_to_align(forward_vector, new_bone_pose.origin.direction_to(ci->children[0].current_pos));
} else {
// Set target orientation to tip
@@ -542,7 +538,7 @@ Transform3D SkeletonIK3D::_get_target_transform() {
target_node_override = Object::cast_to<Node3D>(get_node(target_node_path_override));
}
- if (target_node_override) {
+ if (target_node_override && target_node_override->is_inside_tree()) {
return target_node_override->get_global_transform();
} else {
return target;
diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h
index 81dfe675c3..4cf08e7c99 100644
--- a/scene/3d/skeleton_ik_3d.h
+++ b/scene/3d/skeleton_ik_3d.h
@@ -33,11 +33,6 @@
#ifndef _3D_DISABLED
-/**
- * @author AndreaCatania
- */
-
-#include "core/math/transform_3d.h"
#include "scene/3d/skeleton_3d.h"
class FabrikInverseKinematic {
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_dynamic_body_3d.cpp
index a7ff0842d2..21f9b0a35d 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_dynamic_body_3d.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* soft_body_3d.cpp */
+/* soft_dynamic_body_3d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,19 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "soft_body_3d.h"
+#include "soft_dynamic_body_3d.h"
-#include "core/object/class_db.h"
-#include "core/os/os.h"
-#include "core/templates/list.h"
-#include "core/templates/rid.h"
-#include "scene/3d/collision_object_3d.h"
#include "scene/3d/physics_body_3d.h"
-#include "scene/3d/skeleton_3d.h"
-SoftBodyRenderingServerHandler::SoftBodyRenderingServerHandler() {}
+SoftDynamicBodyRenderingServerHandler::SoftDynamicBodyRenderingServerHandler() {}
-void SoftBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) {
+void SoftDynamicBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) {
clear();
ERR_FAIL_COND(!p_mesh.is_valid());
@@ -62,7 +56,7 @@ void SoftBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) {
offset_normal = surface_offsets[RS::ARRAY_NORMAL];
}
-void SoftBodyRenderingServerHandler::clear() {
+void SoftDynamicBodyRenderingServerHandler::clear() {
buffer.resize(0);
stride = 0;
offset_vertices = 0;
@@ -72,41 +66,41 @@ void SoftBodyRenderingServerHandler::clear() {
mesh = RID();
}
-void SoftBodyRenderingServerHandler::open() {
+void SoftDynamicBodyRenderingServerHandler::open() {
write_buffer = buffer.ptrw();
}
-void SoftBodyRenderingServerHandler::close() {
+void SoftDynamicBodyRenderingServerHandler::close() {
write_buffer = nullptr;
}
-void SoftBodyRenderingServerHandler::commit_changes() {
+void SoftDynamicBodyRenderingServerHandler::commit_changes() {
RS::get_singleton()->mesh_surface_update_vertex_region(mesh, surface, 0, buffer);
}
-void SoftBodyRenderingServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
+void SoftDynamicBodyRenderingServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
memcpy(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3);
}
-void SoftBodyRenderingServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
+void SoftDynamicBodyRenderingServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
memcpy(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3);
}
-void SoftBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
+void SoftDynamicBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
RS::get_singleton()->mesh_set_custom_aabb(mesh, p_aabb);
}
-SoftBody3D::PinnedPoint::PinnedPoint() {
+SoftDynamicBody3D::PinnedPoint::PinnedPoint() {
}
-SoftBody3D::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) {
+SoftDynamicBody3D::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) {
point_index = obj_tocopy.point_index;
spatial_attachment_path = obj_tocopy.spatial_attachment_path;
spatial_attachment = obj_tocopy.spatial_attachment;
offset = obj_tocopy.offset;
}
-SoftBody3D::PinnedPoint &SoftBody3D::PinnedPoint::operator=(const PinnedPoint &obj) {
+SoftDynamicBody3D::PinnedPoint &SoftDynamicBody3D::PinnedPoint::operator=(const PinnedPoint &obj) {
point_index = obj.point_index;
spatial_attachment_path = obj.spatial_attachment_path;
spatial_attachment = obj.spatial_attachment;
@@ -114,7 +108,7 @@ SoftBody3D::PinnedPoint &SoftBody3D::PinnedPoint::operator=(const PinnedPoint &o
return *this;
}
-void SoftBody3D::_update_pickable() {
+void SoftDynamicBody3D::_update_pickable() {
if (!is_inside_tree()) {
return;
}
@@ -122,7 +116,7 @@ void SoftBody3D::_update_pickable() {
PhysicsServer3D::get_singleton()->soft_body_set_ray_pickable(physics_rid, pickable);
}
-bool SoftBody3D::_set(const StringName &p_name, const Variant &p_value) {
+bool SoftDynamicBody3D::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
String which = name.get_slicec('/', 0);
@@ -139,7 +133,7 @@ bool SoftBody3D::_set(const StringName &p_name, const Variant &p_value) {
return false;
}
-bool SoftBody3D::_get(const StringName &p_name, Variant &r_ret) const {
+bool SoftDynamicBody3D::_get(const StringName &p_name, Variant &r_ret) const {
String name = p_name;
String which = name.get_slicec('/', 0);
@@ -166,7 +160,7 @@ bool SoftBody3D::_get(const StringName &p_name, Variant &r_ret) const {
return false;
}
-void SoftBody3D::_get_property_list(List<PropertyInfo> *p_list) const {
+void SoftDynamicBody3D::_get_property_list(List<PropertyInfo> *p_list) const {
const int pinned_points_indices_size = pinned_points.size();
p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "pinned_points"));
@@ -178,7 +172,7 @@ void SoftBody3D::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-bool SoftBody3D::_set_property_pinned_points_indices(const Array &p_indices) {
+bool SoftDynamicBody3D::_set_property_pinned_points_indices(const Array &p_indices) {
const int p_indices_size = p_indices.size();
{ // Remove the pined points on physics server that will be removed by resize
@@ -207,7 +201,7 @@ bool SoftBody3D::_set_property_pinned_points_indices(const Array &p_indices) {
return true;
}
-bool SoftBody3D::_set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value) {
+bool SoftDynamicBody3D::_set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value) {
if (pinned_points.size() <= p_item) {
return false;
}
@@ -226,7 +220,7 @@ bool SoftBody3D::_set_property_pinned_points_attachment(int p_item, const String
return true;
}
-bool SoftBody3D::_get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const {
+bool SoftDynamicBody3D::_get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const {
if (pinned_points.size() <= p_item) {
return false;
}
@@ -245,15 +239,7 @@ bool SoftBody3D::_get_property_pinned_points(int p_item, const String &p_what, V
return true;
}
-void SoftBody3D::_softbody_changed() {
- prepare_physics_server();
- _reset_points_offsets();
-#ifdef TOOLS_ENABLED
- update_configuration_warnings();
-#endif
-}
-
-void SoftBody3D::_notification(int p_what) {
+void SoftDynamicBody3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_WORLD: {
if (Engine::get_singleton()->is_editor_hint()) {
@@ -318,51 +304,56 @@ void SoftBody3D::_notification(int p_what) {
}
}
-void SoftBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_physics_rid"), &SoftBody3D::get_physics_rid);
+void SoftDynamicBody3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_physics_rid"), &SoftDynamicBody3D::get_physics_rid);
- ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftBody3D::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftBody3D::get_collision_mask);
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftDynamicBody3D::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftDynamicBody3D::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &SoftBody3D::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &SoftBody3D::get_collision_layer);
+ ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &SoftDynamicBody3D::set_collision_layer);
+ ClassDB::bind_method(D_METHOD("get_collision_layer"), &SoftDynamicBody3D::get_collision_layer);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &SoftBody3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &SoftBody3D::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &SoftDynamicBody3D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &SoftDynamicBody3D::get_collision_mask_value);
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &SoftBody3D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &SoftBody3D::get_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &SoftDynamicBody3D::set_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &SoftDynamicBody3D::get_collision_layer_value);
- ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftBody3D::set_parent_collision_ignore);
- ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftBody3D::get_parent_collision_ignore);
+ ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftDynamicBody3D::set_parent_collision_ignore);
+ ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftDynamicBody3D::get_parent_collision_ignore);
- ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &SoftBody3D::set_disable_mode);
- ClassDB::bind_method(D_METHOD("get_disable_mode"), &SoftBody3D::get_disable_mode);
+ ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &SoftDynamicBody3D::set_disable_mode);
+ ClassDB::bind_method(D_METHOD("get_disable_mode"), &SoftDynamicBody3D::get_disable_mode);
- ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &SoftBody3D::get_collision_exceptions);
- ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftBody3D::add_collision_exception_with);
- ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftBody3D::remove_collision_exception_with);
+ ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &SoftDynamicBody3D::get_collision_exceptions);
+ ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftDynamicBody3D::add_collision_exception_with);
+ ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftDynamicBody3D::remove_collision_exception_with);
- ClassDB::bind_method(D_METHOD("set_simulation_precision", "simulation_precision"), &SoftBody3D::set_simulation_precision);
- ClassDB::bind_method(D_METHOD("get_simulation_precision"), &SoftBody3D::get_simulation_precision);
+ ClassDB::bind_method(D_METHOD("set_simulation_precision", "simulation_precision"), &SoftDynamicBody3D::set_simulation_precision);
+ ClassDB::bind_method(D_METHOD("get_simulation_precision"), &SoftDynamicBody3D::get_simulation_precision);
- ClassDB::bind_method(D_METHOD("set_total_mass", "mass"), &SoftBody3D::set_total_mass);
- ClassDB::bind_method(D_METHOD("get_total_mass"), &SoftBody3D::get_total_mass);
+ ClassDB::bind_method(D_METHOD("set_total_mass", "mass"), &SoftDynamicBody3D::set_total_mass);
+ ClassDB::bind_method(D_METHOD("get_total_mass"), &SoftDynamicBody3D::get_total_mass);
- ClassDB::bind_method(D_METHOD("set_linear_stiffness", "linear_stiffness"), &SoftBody3D::set_linear_stiffness);
- ClassDB::bind_method(D_METHOD("get_linear_stiffness"), &SoftBody3D::get_linear_stiffness);
+ ClassDB::bind_method(D_METHOD("set_linear_stiffness", "linear_stiffness"), &SoftDynamicBody3D::set_linear_stiffness);
+ ClassDB::bind_method(D_METHOD("get_linear_stiffness"), &SoftDynamicBody3D::get_linear_stiffness);
- ClassDB::bind_method(D_METHOD("set_pressure_coefficient", "pressure_coefficient"), &SoftBody3D::set_pressure_coefficient);
- ClassDB::bind_method(D_METHOD("get_pressure_coefficient"), &SoftBody3D::get_pressure_coefficient);
+ ClassDB::bind_method(D_METHOD("set_pressure_coefficient", "pressure_coefficient"), &SoftDynamicBody3D::set_pressure_coefficient);
+ ClassDB::bind_method(D_METHOD("get_pressure_coefficient"), &SoftDynamicBody3D::get_pressure_coefficient);
- ClassDB::bind_method(D_METHOD("set_damping_coefficient", "damping_coefficient"), &SoftBody3D::set_damping_coefficient);
- ClassDB::bind_method(D_METHOD("get_damping_coefficient"), &SoftBody3D::get_damping_coefficient);
+ ClassDB::bind_method(D_METHOD("set_damping_coefficient", "damping_coefficient"), &SoftDynamicBody3D::set_damping_coefficient);
+ ClassDB::bind_method(D_METHOD("get_damping_coefficient"), &SoftDynamicBody3D::get_damping_coefficient);
- ClassDB::bind_method(D_METHOD("set_drag_coefficient", "drag_coefficient"), &SoftBody3D::set_drag_coefficient);
- ClassDB::bind_method(D_METHOD("get_drag_coefficient"), &SoftBody3D::get_drag_coefficient);
+ ClassDB::bind_method(D_METHOD("set_drag_coefficient", "drag_coefficient"), &SoftDynamicBody3D::set_drag_coefficient);
+ ClassDB::bind_method(D_METHOD("get_drag_coefficient"), &SoftDynamicBody3D::get_drag_coefficient);
- ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &SoftBody3D::set_ray_pickable);
- ClassDB::bind_method(D_METHOD("is_ray_pickable"), &SoftBody3D::is_ray_pickable);
+ ClassDB::bind_method(D_METHOD("get_point_transform", "point_index"), &SoftDynamicBody3D::get_point_transform);
+
+ ClassDB::bind_method(D_METHOD("set_point_pinned", "point_index", "pinned", "attachment_path"), &SoftDynamicBody3D::pin_point, DEFVAL(NodePath()));
+ ClassDB::bind_method(D_METHOD("is_point_pinned", "point_index"), &SoftDynamicBody3D::is_point_pinned);
+
+ ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &SoftDynamicBody3D::set_ray_pickable);
+ ClassDB::bind_method(D_METHOD("is_ray_pickable"), &SoftDynamicBody3D::is_ray_pickable);
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
@@ -384,7 +375,7 @@ void SoftBody3D::_bind_methods() {
BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE);
}
-TypedArray<String> SoftBody3D::get_configuration_warnings() const {
+TypedArray<String> SoftDynamicBody3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (get_mesh().is_null()) {
@@ -393,13 +384,13 @@ TypedArray<String> SoftBody3D::get_configuration_warnings() const {
Transform3D t = get_transform();
if ((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)) {
- warnings.push_back(TTR("Size changes to SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
+ warnings.push_back(TTR("Size changes to SoftDynamicBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
return warnings;
}
-void SoftBody3D::_update_physics_server() {
+void SoftDynamicBody3D::_update_physics_server() {
if (!simulation_started) {
return;
}
@@ -415,7 +406,7 @@ void SoftBody3D::_update_physics_server() {
}
}
-void SoftBody3D::_draw_soft_mesh() {
+void SoftDynamicBody3D::_draw_soft_mesh() {
if (get_mesh().is_null()) {
return;
}
@@ -438,13 +429,13 @@ void SoftBody3D::_draw_soft_mesh() {
rendering_server_handler.commit_changes();
}
-void SoftBody3D::prepare_physics_server() {
+void SoftDynamicBody3D::prepare_physics_server() {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
if (get_mesh().is_valid()) {
- PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh());
+ PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()->get_rid());
} else {
- PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, nullptr);
+ PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, RID());
}
return;
@@ -453,17 +444,17 @@ void SoftBody3D::prepare_physics_server() {
if (get_mesh().is_valid() && (is_enabled() || (disable_mode != DISABLE_MODE_REMOVE))) {
become_mesh_owner();
- PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh());
- RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh));
+ PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()->get_rid());
+ RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &SoftDynamicBody3D::_draw_soft_mesh));
} else {
- PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, nullptr);
- if (RS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh))) {
- RS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh));
+ PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, RID());
+ if (RS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &SoftDynamicBody3D::_draw_soft_mesh))) {
+ RS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &SoftDynamicBody3D::_draw_soft_mesh));
}
}
}
-void SoftBody3D::become_mesh_owner() {
+void SoftDynamicBody3D::become_mesh_owner() {
if (mesh.is_null()) {
return;
}
@@ -476,7 +467,7 @@ void SoftBody3D::become_mesh_owner() {
ERR_FAIL_COND(!mesh->get_surface_count());
- // Get current mesh array and create new mesh array with necessary flag for softbody
+ // Get current mesh array and create new mesh array with necessary flag for SoftDynamicBody
Array surface_arrays = mesh->surface_get_arrays(0);
Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0);
Dictionary surface_lods = mesh->surface_get_lods(0);
@@ -497,57 +488,61 @@ void SoftBody3D::become_mesh_owner() {
}
}
-void SoftBody3D::set_collision_mask(uint32_t p_mask) {
+void SoftDynamicBody3D::set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
PhysicsServer3D::get_singleton()->soft_body_set_collision_mask(physics_rid, p_mask);
}
-uint32_t SoftBody3D::get_collision_mask() const {
+uint32_t SoftDynamicBody3D::get_collision_mask() const {
return collision_mask;
}
-void SoftBody3D::set_collision_layer(uint32_t p_layer) {
+void SoftDynamicBody3D::set_collision_layer(uint32_t p_layer) {
collision_layer = p_layer;
PhysicsServer3D::get_singleton()->soft_body_set_collision_layer(physics_rid, p_layer);
}
-uint32_t SoftBody3D::get_collision_layer() const {
+uint32_t SoftDynamicBody3D::get_collision_layer() const {
return collision_layer;
}
-void SoftBody3D::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
- uint32_t mask = get_collision_mask();
+void SoftDynamicBody3D::set_collision_layer_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
+ uint32_t collision_layer = get_collision_layer();
if (p_value) {
- mask |= 1 << p_bit;
+ collision_layer |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ collision_layer &= ~(1 << (p_layer_number - 1));
}
- set_collision_mask(mask);
+ set_collision_layer(collision_layer);
}
-bool SoftBody3D::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+bool SoftDynamicBody3D::get_collision_layer_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_layer() & (1 << (p_layer_number - 1));
}
-void SoftBody3D::set_collision_layer_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
- uint32_t layer = get_collision_layer();
+void SoftDynamicBody3D::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
+ uint32_t mask = get_collision_mask();
if (p_value) {
- layer |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- layer &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
- set_collision_layer(layer);
+ set_collision_mask(mask);
}
-bool SoftBody3D::get_collision_layer_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
- return get_collision_layer() & (1 << p_bit);
+bool SoftDynamicBody3D::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
-void SoftBody3D::set_disable_mode(DisableMode p_mode) {
+void SoftDynamicBody3D::set_disable_mode(DisableMode p_mode) {
if (disable_mode == p_mode) {
return;
}
@@ -565,30 +560,30 @@ void SoftBody3D::set_disable_mode(DisableMode p_mode) {
}
}
-SoftBody3D::DisableMode SoftBody3D::get_disable_mode() const {
+SoftDynamicBody3D::DisableMode SoftDynamicBody3D::get_disable_mode() const {
return disable_mode;
}
-void SoftBody3D::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) {
+void SoftDynamicBody3D::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) {
parent_collision_ignore = p_parent_collision_ignore;
}
-const NodePath &SoftBody3D::get_parent_collision_ignore() const {
+const NodePath &SoftDynamicBody3D::get_parent_collision_ignore() const {
return parent_collision_ignore;
}
-void SoftBody3D::set_pinned_points_indices(Vector<SoftBody3D::PinnedPoint> p_pinned_points_indices) {
+void SoftDynamicBody3D::set_pinned_points_indices(Vector<SoftDynamicBody3D::PinnedPoint> p_pinned_points_indices) {
pinned_points = p_pinned_points_indices;
for (int i = pinned_points.size() - 1; 0 <= i; --i) {
pin_point(p_pinned_points_indices[i].point_index, true);
}
}
-Vector<SoftBody3D::PinnedPoint> SoftBody3D::get_pinned_points_indices() {
+Vector<SoftDynamicBody3D::PinnedPoint> SoftDynamicBody3D::get_pinned_points_indices() {
return pinned_points;
}
-Array SoftBody3D::get_collision_exceptions() {
+Array SoftDynamicBody3D::get_collision_exceptions() {
List<RID> exceptions;
PhysicsServer3D::get_singleton()->soft_body_get_collision_exceptions(physics_rid, &exceptions);
Array ret;
@@ -601,77 +596,77 @@ Array SoftBody3D::get_collision_exceptions() {
return ret;
}
-void SoftBody3D::add_collision_exception_with(Node *p_node) {
+void SoftDynamicBody3D::add_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node);
ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds.");
PhysicsServer3D::get_singleton()->soft_body_add_collision_exception(physics_rid, collision_object->get_rid());
}
-void SoftBody3D::remove_collision_exception_with(Node *p_node) {
+void SoftDynamicBody3D::remove_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node);
ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds.");
PhysicsServer3D::get_singleton()->soft_body_remove_collision_exception(physics_rid, collision_object->get_rid());
}
-int SoftBody3D::get_simulation_precision() {
+int SoftDynamicBody3D::get_simulation_precision() {
return PhysicsServer3D::get_singleton()->soft_body_get_simulation_precision(physics_rid);
}
-void SoftBody3D::set_simulation_precision(int p_simulation_precision) {
+void SoftDynamicBody3D::set_simulation_precision(int p_simulation_precision) {
PhysicsServer3D::get_singleton()->soft_body_set_simulation_precision(physics_rid, p_simulation_precision);
}
-real_t SoftBody3D::get_total_mass() {
+real_t SoftDynamicBody3D::get_total_mass() {
return PhysicsServer3D::get_singleton()->soft_body_get_total_mass(physics_rid);
}
-void SoftBody3D::set_total_mass(real_t p_total_mass) {
+void SoftDynamicBody3D::set_total_mass(real_t p_total_mass) {
PhysicsServer3D::get_singleton()->soft_body_set_total_mass(physics_rid, p_total_mass);
}
-void SoftBody3D::set_linear_stiffness(real_t p_linear_stiffness) {
+void SoftDynamicBody3D::set_linear_stiffness(real_t p_linear_stiffness) {
PhysicsServer3D::get_singleton()->soft_body_set_linear_stiffness(physics_rid, p_linear_stiffness);
}
-real_t SoftBody3D::get_linear_stiffness() {
+real_t SoftDynamicBody3D::get_linear_stiffness() {
return PhysicsServer3D::get_singleton()->soft_body_get_linear_stiffness(physics_rid);
}
-real_t SoftBody3D::get_pressure_coefficient() {
+real_t SoftDynamicBody3D::get_pressure_coefficient() {
return PhysicsServer3D::get_singleton()->soft_body_get_pressure_coefficient(physics_rid);
}
-void SoftBody3D::set_pressure_coefficient(real_t p_pressure_coefficient) {
+void SoftDynamicBody3D::set_pressure_coefficient(real_t p_pressure_coefficient) {
PhysicsServer3D::get_singleton()->soft_body_set_pressure_coefficient(physics_rid, p_pressure_coefficient);
}
-real_t SoftBody3D::get_damping_coefficient() {
+real_t SoftDynamicBody3D::get_damping_coefficient() {
return PhysicsServer3D::get_singleton()->soft_body_get_damping_coefficient(physics_rid);
}
-void SoftBody3D::set_damping_coefficient(real_t p_damping_coefficient) {
+void SoftDynamicBody3D::set_damping_coefficient(real_t p_damping_coefficient) {
PhysicsServer3D::get_singleton()->soft_body_set_damping_coefficient(physics_rid, p_damping_coefficient);
}
-real_t SoftBody3D::get_drag_coefficient() {
+real_t SoftDynamicBody3D::get_drag_coefficient() {
return PhysicsServer3D::get_singleton()->soft_body_get_drag_coefficient(physics_rid);
}
-void SoftBody3D::set_drag_coefficient(real_t p_drag_coefficient) {
+void SoftDynamicBody3D::set_drag_coefficient(real_t p_drag_coefficient) {
PhysicsServer3D::get_singleton()->soft_body_set_drag_coefficient(physics_rid, p_drag_coefficient);
}
-Vector3 SoftBody3D::get_point_transform(int p_point_index) {
+Vector3 SoftDynamicBody3D::get_point_transform(int p_point_index) {
return PhysicsServer3D::get_singleton()->soft_body_get_point_global_position(physics_rid, p_point_index);
}
-void SoftBody3D::pin_point_toggle(int p_point_index) {
+void SoftDynamicBody3D::pin_point_toggle(int p_point_index) {
pin_point(p_point_index, !(-1 != _has_pinned_point(p_point_index)));
}
-void SoftBody3D::pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path) {
+void SoftDynamicBody3D::pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path) {
_pin_point_on_physics_server(p_point_index, pin);
if (pin) {
_add_pinned_point(p_point_index, p_spatial_attachment_path);
@@ -680,41 +675,33 @@ void SoftBody3D::pin_point(int p_point_index, bool pin, const NodePath &p_spatia
}
}
-bool SoftBody3D::is_point_pinned(int p_point_index) const {
+bool SoftDynamicBody3D::is_point_pinned(int p_point_index) const {
return -1 != _has_pinned_point(p_point_index);
}
-void SoftBody3D::set_ray_pickable(bool p_ray_pickable) {
+void SoftDynamicBody3D::set_ray_pickable(bool p_ray_pickable) {
ray_pickable = p_ray_pickable;
_update_pickable();
}
-bool SoftBody3D::is_ray_pickable() const {
+bool SoftDynamicBody3D::is_ray_pickable() const {
return ray_pickable;
}
-SoftBody3D::SoftBody3D() :
+SoftDynamicBody3D::SoftDynamicBody3D() :
physics_rid(PhysicsServer3D::get_singleton()->soft_body_create()) {
PhysicsServer3D::get_singleton()->body_attach_object_instance_id(physics_rid, get_instance_id());
}
-SoftBody3D::~SoftBody3D() {
+SoftDynamicBody3D::~SoftDynamicBody3D() {
PhysicsServer3D::get_singleton()->free(physics_rid);
}
-void SoftBody3D::reset_softbody_pin() {
- PhysicsServer3D::get_singleton()->soft_body_remove_all_pinned_points(physics_rid);
- const PinnedPoint *pps = pinned_points.ptr();
- for (int i = pinned_points.size() - 1; 0 < i; --i) {
- PhysicsServer3D::get_singleton()->soft_body_pin_point(physics_rid, pps[i].point_index, true);
- }
-}
-
-void SoftBody3D::_make_cache_dirty() {
+void SoftDynamicBody3D::_make_cache_dirty() {
pinned_points_cache_dirty = true;
}
-void SoftBody3D::_update_cache_pin_points_datas() {
+void SoftDynamicBody3D::_update_cache_pin_points_datas() {
if (!pinned_points_cache_dirty) {
return;
}
@@ -727,17 +714,17 @@ void SoftBody3D::_update_cache_pin_points_datas() {
w[i].spatial_attachment = Object::cast_to<Node3D>(get_node(w[i].spatial_attachment_path));
}
if (!w[i].spatial_attachment) {
- ERR_PRINT("Node3D node not defined in the pinned point, this is undefined behavior for SoftBody3D!");
+ ERR_PRINT("Node3D node not defined in the pinned point, this is undefined behavior for SoftDynamicBody3D!");
}
}
}
-void SoftBody3D::_pin_point_on_physics_server(int p_point_index, bool pin) {
+void SoftDynamicBody3D::_pin_point_on_physics_server(int p_point_index, bool pin) {
PhysicsServer3D::get_singleton()->soft_body_pin_point(physics_rid, p_point_index, pin);
}
-void SoftBody3D::_add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path) {
- SoftBody3D::PinnedPoint *pinned_point;
+void SoftDynamicBody3D::_add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path) {
+ SoftDynamicBody3D::PinnedPoint *pinned_point;
if (-1 == _get_pinned_point(p_point_index, pinned_point)) {
// Create new
PinnedPoint pp;
@@ -762,7 +749,7 @@ void SoftBody3D::_add_pinned_point(int p_point_index, const NodePath &p_spatial_
}
}
-void SoftBody3D::_reset_points_offsets() {
+void SoftDynamicBody3D::_reset_points_offsets() {
if (!Engine::get_singleton()->is_editor_hint()) {
return;
}
@@ -784,25 +771,25 @@ void SoftBody3D::_reset_points_offsets() {
}
}
-void SoftBody3D::_remove_pinned_point(int p_point_index) {
+void SoftDynamicBody3D::_remove_pinned_point(int p_point_index) {
const int id(_has_pinned_point(p_point_index));
if (-1 != id) {
pinned_points.remove(id);
}
}
-int SoftBody3D::_get_pinned_point(int p_point_index, SoftBody3D::PinnedPoint *&r_point) const {
+int SoftDynamicBody3D::_get_pinned_point(int p_point_index, SoftDynamicBody3D::PinnedPoint *&r_point) const {
const int id = _has_pinned_point(p_point_index);
if (-1 == id) {
r_point = nullptr;
return -1;
} else {
- r_point = const_cast<SoftBody3D::PinnedPoint *>(&pinned_points.ptr()[id]);
+ r_point = const_cast<SoftDynamicBody3D::PinnedPoint *>(&pinned_points.ptr()[id]);
return id;
}
}
-int SoftBody3D::_has_pinned_point(int p_point_index) const {
+int SoftDynamicBody3D::_has_pinned_point(int p_point_index) const {
const PinnedPoint *r = pinned_points.ptr();
for (int i = pinned_points.size() - 1; 0 <= i; --i) {
if (p_point_index == r[i].point_index) {
diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_dynamic_body_3d.h
index 81aa0c10c6..0b4b3021cd 100644
--- a/scene/3d/soft_body_3d.h
+++ b/scene/3d/soft_dynamic_body_3d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* soft_body_3d.h */
+/* soft_dynamic_body_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,16 +28,16 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SOFT_PHYSICS_BODY_H
-#define SOFT_PHYSICS_BODY_H
+#ifndef SOFT_DYNAMIC_BODY_H
+#define SOFT_DYNAMIC_BODY_H
#include "scene/3d/mesh_instance_3d.h"
#include "servers/physics_server_3d.h"
-class SoftBody3D;
+class SoftDynamicBody3D;
-class SoftBodyRenderingServerHandler : public RenderingServerHandler {
- friend class SoftBody3D;
+class SoftDynamicBodyRenderingServerHandler : public RenderingServerHandler {
+ friend class SoftDynamicBody3D;
RID mesh;
int surface = 0;
@@ -49,7 +49,7 @@ class SoftBodyRenderingServerHandler : public RenderingServerHandler {
uint8_t *write_buffer = nullptr;
private:
- SoftBodyRenderingServerHandler();
+ SoftDynamicBodyRenderingServerHandler();
bool is_ready() { return mesh.is_valid(); }
void prepare(RID p_mesh_rid, int p_surface);
void clear();
@@ -63,8 +63,8 @@ public:
void set_aabb(const AABB &p_aabb) override;
};
-class SoftBody3D : public MeshInstance3D {
- GDCLASS(SoftBody3D, MeshInstance3D);
+class SoftDynamicBody3D : public MeshInstance3D {
+ GDCLASS(SoftDynamicBody3D, MeshInstance3D);
public:
enum DisableMode {
@@ -84,7 +84,7 @@ public:
};
private:
- SoftBodyRenderingServerHandler rendering_server_handler;
+ SoftDynamicBodyRenderingServerHandler rendering_server_handler;
RID physics_rid;
@@ -106,8 +106,6 @@ private:
void _update_pickable();
- void _softbody_changed();
-
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -138,11 +136,11 @@ public:
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_layer_value(int p_layer_number, bool p_value);
+ bool get_collision_layer_value(int p_layer_number) const;
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void set_disable_mode(DisableMode p_mode);
DisableMode get_disable_mode() const;
@@ -184,12 +182,10 @@ public:
void set_ray_pickable(bool p_ray_pickable);
bool is_ray_pickable() const;
- SoftBody3D();
- ~SoftBody3D();
+ SoftDynamicBody3D();
+ ~SoftDynamicBody3D();
private:
- void reset_softbody_pin();
-
void _make_cache_dirty();
void _update_cache_pin_points_datas();
@@ -202,6 +198,6 @@ private:
int _has_pinned_point(int p_point_index) const;
};
-VARIANT_ENUM_CAST(SoftBody3D::DisableMode);
+VARIANT_ENUM_CAST(SoftDynamicBody3D::DisableMode);
-#endif // SOFT_PHYSICS_BODY_H
+#endif // SOFT_DYNAMIC_BODY_H
diff --git a/scene/3d/spring_arm_3d.cpp b/scene/3d/spring_arm_3d.cpp
index 5e9265b4c3..116cab19b1 100644
--- a/scene/3d/spring_arm_3d.cpp
+++ b/scene/3d/spring_arm_3d.cpp
@@ -29,11 +29,7 @@
/*************************************************************************/
#include "spring_arm_3d.h"
-
-#include "core/config/engine.h"
-#include "scene/3d/collision_object_3d.h"
-#include "scene/resources/sphere_shape_3d.h"
-#include "servers/physics_server_3d.h"
+#include "scene/3d/camera_3d.h"
void SpringArm3D::_notification(int p_what) {
switch (p_what) {
@@ -138,17 +134,32 @@ void SpringArm3D::process_spring() {
Vector3 motion;
const Vector3 cast_direction(get_global_transform().basis.xform(Vector3(0, 0, 1)));
+ motion = Vector3(cast_direction * (spring_length));
+
if (shape.is_null()) {
- motion = Vector3(cast_direction * (spring_length));
- PhysicsDirectSpaceState3D::RayResult r;
- bool intersected = get_world_3d()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask);
- if (intersected) {
- real_t dist = get_global_transform().origin.distance_to(r.position);
- dist -= margin;
- motion_delta = dist / (spring_length);
+ Camera3D *camera = nullptr;
+ for (int i = get_child_count() - 1; 0 <= i; --i) {
+ camera = Object::cast_to<Camera3D>(get_child(i));
+ if (camera) {
+ break;
+ }
+ }
+
+ if (camera != nullptr) {
+ //use camera rotation, but spring arm position
+ Transform3D base_transform = camera->get_global_transform();
+ base_transform.origin = get_global_transform().origin;
+ get_world_3d()->get_direct_space_state()->cast_motion(camera->get_pyramid_shape_rid(), base_transform, motion, 0, motion_delta, motion_delta_unsafe, excluded_objects, mask);
+ } else {
+ PhysicsDirectSpaceState3D::RayResult r;
+ bool intersected = get_world_3d()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask);
+ if (intersected) {
+ real_t dist = get_global_transform().origin.distance_to(r.position);
+ dist -= margin;
+ motion_delta = dist / (spring_length);
+ }
}
} else {
- motion = Vector3(cast_direction * spring_length);
get_world_3d()->get_direct_space_state()->cast_motion(shape->get_rid(), get_global_transform(), motion, 0, motion_delta, motion_delta_unsafe, excluded_objects, mask);
}
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index a901920dbe..349a534680 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -132,12 +132,12 @@ Color SpriteBase3D::get_modulate() const {
return modulate;
}
-void SpriteBase3D::set_pixel_size(float p_amount) {
+void SpriteBase3D::set_pixel_size(real_t p_amount) {
pixel_size = p_amount;
_queue_update();
}
-float SpriteBase3D::get_pixel_size() const {
+real_t SpriteBase3D::get_pixel_size() const {
return pixel_size;
}
@@ -203,7 +203,7 @@ Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const {
return Ref<TriangleMesh>();
}
- float pixel_size = get_pixel_size();
+ real_t pixel_size = get_pixel_size();
Vector2 vertices[4] = {
@@ -470,7 +470,7 @@ void Sprite3D::_draw() {
Color color = _get_color_accum();
color.a *= get_opacity();
- float pixel_size = get_pixel_size();
+ real_t pixel_size = get_pixel_size();
Vector2 vertices[4] = {
@@ -712,7 +712,7 @@ Rect2 Sprite3D::get_item_rect() const {
return CanvasItem::get_item_rect();
*/
- Size2i s;
+ Size2 s;
if (region) {
s = region_rect.size;
@@ -807,22 +807,20 @@ void AnimatedSprite3D::_draw() {
set_base(RID());
return; //no texuture no life
}
- Vector2 tsize = texture->get_size();
+ Size2 tsize = texture->get_size();
if (tsize.x == 0 || tsize.y == 0) {
return;
}
- Size2i s = tsize;
Rect2 src_rect;
-
- src_rect.size = s;
+ src_rect.size = tsize;
Point2 ofs = get_offset();
if (is_centered()) {
- ofs -= s / 2;
+ ofs -= tsize / 2;
}
- Rect2 dst_rect(ofs, s);
+ Rect2 dst_rect(ofs, tsize);
Rect2 final_rect;
Rect2 final_src_rect;
@@ -837,7 +835,7 @@ void AnimatedSprite3D::_draw() {
Color color = _get_color_accum();
color.a *= get_opacity();
- float pixel_size = get_pixel_size();
+ real_t pixel_size = get_pixel_size();
Vector2 vertices[4] = {
@@ -1037,7 +1035,7 @@ void AnimatedSprite3D::_notification(int p_what) {
return; //do nothing
}
- float remaining = get_process_delta_time();
+ double remaining = get_process_delta_time();
while (remaining) {
if (timeout <= 0) {
@@ -1059,7 +1057,7 @@ void AnimatedSprite3D::_notification(int p_what) {
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
- float to_process = MIN(timeout, remaining);
+ double to_process = MIN(timeout, remaining);
remaining -= to_process;
timeout -= to_process;
}
@@ -1133,7 +1131,7 @@ Rect2 AnimatedSprite3D::get_item_rect() const {
if (t.is_null()) {
return Rect2(0, 0, 1, 1);
}
- Size2i s = t->get_size();
+ Size2 s = t->get_size();
Point2 ofs = get_offset();
if (centered) {
@@ -1177,7 +1175,7 @@ void AnimatedSprite3D::stop() {
}
bool AnimatedSprite3D::is_playing() const {
- return is_processing();
+ return playing;
}
void AnimatedSprite3D::_reset_timeout() {
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index 404ef57e6a..90c2a309e1 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -31,8 +31,8 @@
#ifndef SPRITE_3D_H
#define SPRITE_3D_H
-#include "scene/2d/animated_sprite_2d.h"
#include "scene/3d/visual_instance_3d.h"
+#include "scene/resources/sprite_frames.h"
class SpriteBase3D : public GeometryInstance3D {
GDCLASS(SpriteBase3D, GeometryInstance3D);
@@ -72,7 +72,7 @@ private:
float opacity = 1.0;
Vector3::Axis axis = Vector3::AXIS_Z;
- float pixel_size = 0.01;
+ real_t pixel_size = 0.01;
AABB aabb;
RID mesh;
@@ -130,8 +130,8 @@ public:
void set_opacity(float p_amount);
float get_opacity() const;
- void set_pixel_size(float p_amount);
- float get_pixel_size() const;
+ void set_pixel_size(real_t p_amount);
+ real_t get_pixel_size() const;
void set_axis(Vector3::Axis p_axis);
Vector3::Axis get_axis() const;
@@ -213,7 +213,7 @@ class AnimatedSprite3D : public SpriteBase3D {
bool centered = false;
- float timeout = 0;
+ double timeout = 0.0;
void _res_changed();
diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp
index 92c0e09947..9a2aaa8be2 100644
--- a/scene/3d/vehicle_body_3d.cpp
+++ b/scene/3d/vehicle_body_3d.cpp
@@ -470,7 +470,7 @@ real_t VehicleBody3D::_ray_cast(int p_idx, PhysicsDirectBodyState3D *s) {
}
void VehicleBody3D::_update_suspension(PhysicsDirectBodyState3D *s) {
- real_t chassisMass = mass;
+ real_t chassisMass = get_mass();
for (int w_it = 0; w_it < wheels.size(); w_it++) {
VehicleWheel3D &wheel_info = *wheels[w_it];
@@ -558,7 +558,7 @@ void VehicleBody3D::_resolve_single_bilateral(PhysicsDirectBodyState3D *s, const
rel_pos2,
normal,
s->get_inverse_inertia_tensor().get_main_diagonal(),
- 1.0 / mass,
+ 1.0 / get_mass(),
b2invinertia,
b2invmass);
@@ -584,7 +584,7 @@ void VehicleBody3D::_resolve_single_bilateral(PhysicsDirectBodyState3D *s, const
#define ONLY_USE_LINEAR_MASS
#ifdef ONLY_USE_LINEAR_MASS
- real_t massTerm = real_t(1.) / ((1.0 / mass) + b2invmass);
+ real_t massTerm = real_t(1.) / ((1.0 / get_mass()) + b2invmass);
impulse = -contactDamping * rel_vel * massTerm;
#else
real_t velocityImpulse = -contactDamping * rel_vel * jacDiagABInv;
@@ -802,24 +802,21 @@ void VehicleBody3D::_update_friction(PhysicsDirectBodyState3D *s) {
}
}
-void VehicleBody3D::_direct_state_changed(Object *p_state) {
- RigidBody3D::_direct_state_changed(p_state);
+void VehicleBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
+ RigidDynamicBody3D::_body_state_changed(p_state);
- state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
- ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
-
- real_t step = state->get_step();
+ real_t step = p_state->get_step();
for (int i = 0; i < wheels.size(); i++) {
- _update_wheel(i, state);
+ _update_wheel(i, p_state);
}
for (int i = 0; i < wheels.size(); i++) {
- _ray_cast(i, state);
- wheels[i]->set_transform(state->get_transform().inverse() * wheels[i]->m_worldTransform);
+ _ray_cast(i, p_state);
+ wheels[i]->set_transform(p_state->get_transform().inverse() * wheels[i]->m_worldTransform);
}
- _update_suspension(state);
+ _update_suspension(p_state);
for (int i = 0; i < wheels.size(); i++) {
//apply suspension force
@@ -831,20 +828,20 @@ void VehicleBody3D::_direct_state_changed(Object *p_state) {
suspensionForce = wheel.m_maxSuspensionForce;
}
Vector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step;
- Vector3 relative_position = wheel.m_raycastInfo.m_contactPointWS - state->get_transform().origin;
+ Vector3 relative_position = wheel.m_raycastInfo.m_contactPointWS - p_state->get_transform().origin;
- state->apply_impulse(impulse, relative_position);
+ p_state->apply_impulse(impulse, relative_position);
}
- _update_friction(state);
+ _update_friction(p_state);
for (int i = 0; i < wheels.size(); i++) {
VehicleWheel3D &wheel = *wheels[i];
- Vector3 relpos = wheel.m_raycastInfo.m_hardPointWS - state->get_transform().origin;
- Vector3 vel = state->get_linear_velocity() + (state->get_angular_velocity()).cross(relpos); // * mPos);
+ Vector3 relpos = wheel.m_raycastInfo.m_hardPointWS - p_state->get_transform().origin;
+ Vector3 vel = p_state->get_linear_velocity() + (p_state->get_angular_velocity()).cross(relpos); // * mPos);
if (wheel.m_raycastInfo.m_isInContact) {
- const Transform3D &chassisWorldTransform = state->get_transform();
+ const Transform3D &chassisWorldTransform = p_state->get_transform();
Vector3 fwd(
chassisWorldTransform.basis[0][Vector3::AXIS_Z],
@@ -864,8 +861,6 @@ void VehicleBody3D::_direct_state_changed(Object *p_state) {
wheel.m_deltaRotation *= real_t(0.99); //damping of rotation when not in contact
}
-
- state = nullptr;
}
void VehicleBody3D::set_engine_force(real_t p_engine_force) {
@@ -926,7 +921,5 @@ void VehicleBody3D::_bind_methods() {
VehicleBody3D::VehicleBody3D() {
exclude.insert(get_rid());
- //PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &VehicleBody3D::_direct_state_changed));
-
set_mass(40);
}
diff --git a/scene/3d/vehicle_body_3d.h b/scene/3d/vehicle_body_3d.h
index 2c10205ea3..a798c76c1f 100644
--- a/scene/3d/vehicle_body_3d.h
+++ b/scene/3d/vehicle_body_3d.h
@@ -150,8 +150,8 @@ public:
VehicleWheel3D();
};
-class VehicleBody3D : public RigidBody3D {
- GDCLASS(VehicleBody3D, RigidBody3D);
+class VehicleBody3D : public RigidDynamicBody3D {
+ GDCLASS(VehicleBody3D, RigidDynamicBody3D);
real_t engine_force = 0.0;
real_t brake = 0.0;
@@ -192,7 +192,8 @@ class VehicleBody3D : public RigidBody3D {
static void _bind_methods();
- void _direct_state_changed(Object *p_state) override;
+ static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state);
+ virtual void _body_state_changed(PhysicsDirectBodyState3D *p_state) override;
public:
void set_engine_force(real_t p_engine_force);
diff --git a/scene/3d/velocity_tracker_3d.cpp b/scene/3d/velocity_tracker_3d.cpp
index 5b5cc06456..200664a41b 100644
--- a/scene/3d/velocity_tracker_3d.cpp
+++ b/scene/3d/velocity_tracker_3d.cpp
@@ -29,7 +29,6 @@
/*************************************************************************/
#include "velocity_tracker_3d.h"
-#include "core/config/engine.h"
void VelocityTracker3D::set_track_physics_step(bool p_track_physics_step) {
physics_step = p_track_physics_step;
@@ -61,16 +60,16 @@ void VelocityTracker3D::update_position(const Vector3 &p_position) {
Vector3 VelocityTracker3D::get_tracked_linear_velocity() const {
Vector3 linear_velocity;
- float max_time = 1 / 5.0; //maximum time to interpolate a velocity
+ double max_time = 1 / 5.0; //maximum time to interpolate a velocity
Vector3 distance_accum;
- float time_accum = 0.0;
- float base_time = 0.0;
+ double time_accum = 0.0;
+ double base_time = 0.0;
if (position_history_len) {
if (physics_step) {
uint64_t base = Engine::get_singleton()->get_physics_frames();
- base_time = float(base - position_history[0].frame) / Engine::get_singleton()->get_iterations_per_second();
+ base_time = double(base - position_history[0].frame) / Engine::get_singleton()->get_physics_ticks_per_second();
} else {
uint64_t base = Engine::get_singleton()->get_frame_ticks();
base_time = double(base - position_history[0].frame) / 1000000.0;
@@ -78,12 +77,12 @@ Vector3 VelocityTracker3D::get_tracked_linear_velocity() const {
}
for (int i = 0; i < position_history_len - 1; i++) {
- float delta = 0.0;
+ double delta = 0.0;
uint64_t diff = position_history[i].frame - position_history[i + 1].frame;
Vector3 distance = position_history[i].position - position_history[i + 1].position;
if (physics_step) {
- delta = float(diff) / Engine::get_singleton()->get_iterations_per_second();
+ delta = double(diff) / Engine::get_singleton()->get_physics_ticks_per_second();
} else {
delta = double(diff) / 1000000.0;
}
diff --git a/scene/3d/visible_on_screen_notifier_3d.cpp b/scene/3d/visible_on_screen_notifier_3d.cpp
index 6a80aa3f45..3d0bc3df9c 100644
--- a/scene/3d/visible_on_screen_notifier_3d.cpp
+++ b/scene/3d/visible_on_screen_notifier_3d.cpp
@@ -30,10 +30,6 @@
#include "visible_on_screen_notifier_3d.h"
-#include "core/config/engine.h"
-#include "scene/3d/camera_3d.h"
-#include "scene/3d/physics_body_3d.h"
-#include "scene/animation/animation_player.h"
#include "scene/scene_string_names.h"
void VisibleOnScreenNotifier3D::_visibility_enter() {
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index c155819159..73c2887983 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -31,8 +31,6 @@
#include "visual_instance_3d.h"
#include "scene/scene_string_names.h"
-#include "servers/rendering_server.h"
-#include "skeleton_3d.h"
AABB VisualInstance3D::get_transformed_aabb() const {
return get_global_transform().xform(get_aabb());
@@ -93,18 +91,22 @@ uint32_t VisualInstance3D::get_layer_mask() const {
return layers;
}
-void VisualInstance3D::set_layer_mask_bit(int p_layer, bool p_enable) {
- ERR_FAIL_INDEX(p_layer, 32);
- if (p_enable) {
- set_layer_mask(layers | (1 << p_layer));
+void VisualInstance3D::set_layer_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Render layer number must be between 1 and 20 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 20, "Render layer number must be between 1 and 20 inclusive.");
+ uint32_t mask = get_layer_mask();
+ if (p_value) {
+ mask |= 1 << (p_layer_number - 1);
} else {
- set_layer_mask(layers & (~(1 << p_layer)));
+ mask &= ~(1 << (p_layer_number - 1));
}
+ set_layer_mask(mask);
}
-bool VisualInstance3D::get_layer_mask_bit(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, 32, false);
- return (layers & (1 << p_layer));
+bool VisualInstance3D::get_layer_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Render layer number must be between 1 and 20 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 20, false, "Render layer number must be between 1 and 20 inclusive.");
+ return layers & (1 << (p_layer_number - 1));
}
void VisualInstance3D::_bind_methods() {
@@ -114,8 +116,8 @@ void VisualInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_instance"), &VisualInstance3D::get_instance);
ClassDB::bind_method(D_METHOD("set_layer_mask", "mask"), &VisualInstance3D::set_layer_mask);
ClassDB::bind_method(D_METHOD("get_layer_mask"), &VisualInstance3D::get_layer_mask);
- ClassDB::bind_method(D_METHOD("set_layer_mask_bit", "layer", "enabled"), &VisualInstance3D::set_layer_mask_bit);
- ClassDB::bind_method(D_METHOD("get_layer_mask_bit", "layer"), &VisualInstance3D::get_layer_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_layer_mask_value", "layer_number", "value"), &VisualInstance3D::set_layer_mask_value);
+ ClassDB::bind_method(D_METHOD("get_layer_mask_value", "layer_number"), &VisualInstance3D::get_layer_mask_value);
ClassDB::bind_method(D_METHOD("get_transformed_aabb"), &VisualInstance3D::get_transformed_aabb);
@@ -412,7 +414,7 @@ void GeometryInstance3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_occlusion_culling"), "set_ignore_occlusion_culling", "is_ignoring_occlusion_culling");
ADD_GROUP("Global Illumination", "gi_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_mode", PROPERTY_HINT_ENUM, "Disabled,Baked,Dynamic"), "set_gi_mode", "get_gi_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_lightmap_scale", PROPERTY_HINT_ENUM, "1x,2x,4x,8x"), "set_lightmap_scale", "get_lightmap_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_lightmap_scale", PROPERTY_HINT_ENUM, String::utf8("1×,2×,4×,8×")), "set_lightmap_scale", "get_lightmap_scale");
ADD_GROUP("Visibility Range", "visibility_range_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_begin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01"), "set_visibility_range_begin", "get_visibility_range_begin");
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 97aac149a1..8d24e13d47 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -31,10 +31,7 @@
#ifndef VISUAL_INSTANCE_H
#define VISUAL_INSTANCE_H
-#include "core/math/face3.h"
-#include "core/templates/rid.h"
#include "scene/3d/node_3d.h"
-#include "scene/resources/material.h"
class VisualInstance3D : public Node3D {
GDCLASS(VisualInstance3D, Node3D);
@@ -72,8 +69,8 @@ public:
void set_layer_mask(uint32_t p_mask);
uint32_t get_layer_mask() const;
- void set_layer_mask_bit(int p_layer, bool p_enable);
- bool get_layer_mask_bit(int p_layer) const;
+ void set_layer_mask_value(int p_layer_number, bool p_enable);
+ bool get_layer_mask_value(int p_layer_number) const;
VisualInstance3D();
~VisualInstance3D();
diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp
index 5cf7522667..d3d12d94e9 100644
--- a/scene/3d/voxel_gi.cpp
+++ b/scene/3d/voxel_gi.cpp
@@ -30,9 +30,8 @@
#include "voxel_gi.h"
-#include "core/os/os.h"
-
#include "mesh_instance_3d.h"
+#include "multimesh_instance_3d.h"
#include "voxelizer.h"
void VoxelGIData::_set_data(const Dictionary &p_data) {
diff --git a/scene/3d/voxel_gi.h b/scene/3d/voxel_gi.h
index 434d209421..5d0dda1ba3 100644
--- a/scene/3d/voxel_gi.h
+++ b/scene/3d/voxel_gi.h
@@ -31,7 +31,6 @@
#ifndef VOXEL_GI_H
#define VOXEL_GI_H
-#include "multimesh_instance_3d.h"
#include "scene/3d/visual_instance_3d.h"
class VoxelGIData : public Resource {
diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp
index f1b9708f91..04f371f4b2 100644
--- a/scene/3d/voxelizer.cpp
+++ b/scene/3d/voxelizer.cpp
@@ -29,11 +29,6 @@
/*************************************************************************/
#include "voxelizer.h"
-#include "core/math/geometry_3d.h"
-#include "core/os/os.h"
-#include "core/os/threaded_array_processor.h"
-
-#include <stdlib.h>
static _FORCE_INLINE_ void get_uv_and_normal(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv, const Vector3 *p_normal, Vector2 &r_uv, Vector3 &r_normal) {
if (p_pos.is_equal_approx(p_vtx[0])) {
@@ -56,20 +51,20 @@ static _FORCE_INLINE_ void get_uv_and_normal(const Vector3 &p_pos, const Vector3
Vector3 v1 = p_vtx[2] - p_vtx[0];
Vector3 v2 = p_pos - p_vtx[0];
- float d00 = v0.dot(v0);
- float d01 = v0.dot(v1);
- float d11 = v1.dot(v1);
- float d20 = v2.dot(v0);
- float d21 = v2.dot(v1);
- float denom = (d00 * d11 - d01 * d01);
+ real_t d00 = v0.dot(v0);
+ real_t d01 = v0.dot(v1);
+ real_t d11 = v1.dot(v1);
+ real_t d20 = v2.dot(v0);
+ real_t d21 = v2.dot(v1);
+ real_t denom = (d00 * d11 - d01 * d01);
if (denom == 0) {
r_uv = p_uv[0];
r_normal = p_normal[0];
return;
}
- float v = (d11 * d20 - d01 * d21) / denom;
- float w = (d00 * d21 - d01 * d20) / denom;
- float u = 1.0f - v - w;
+ real_t v = (d11 * d20 - d01 * d21) / denom;
+ real_t w = (d00 * d21 - d01 * d20) / denom;
+ real_t u = 1.0f - v - w;
r_uv = p_uv[0] * u + p_uv[1] * v + p_uv[2] * w;
r_normal = (p_normal[0] * u + p_normal[1] * v + p_normal[2] * w).normalized();
@@ -81,7 +76,7 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co
//find best axis to map to, for scanning values
int closest_axis = 0;
- float closest_dot = 0;
+ real_t closest_dot = 0;
Plane plane = Plane(p_vtx[0], p_vtx[1], p_vtx[2]);
Vector3 normal = plane.normal;
@@ -89,7 +84,7 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co
for (int i = 0; i < 3; i++) {
Vector3 axis;
axis[i] = 1.0;
- float dot = ABS(normal.dot(axis));
+ real_t dot = ABS(normal.dot(axis));
if (i == 0 || dot > closest_dot) {
closest_axis = i;
closest_dot = dot;
@@ -103,8 +98,8 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co
Vector3 t2;
t2[(closest_axis + 2) % 3] = 1.0;
- t1 *= p_aabb.size[(closest_axis + 1) % 3] / float(color_scan_cell_width);
- t2 *= p_aabb.size[(closest_axis + 2) % 3] / float(color_scan_cell_width);
+ t1 *= p_aabb.size[(closest_axis + 1) % 3] / real_t(color_scan_cell_width);
+ t2 *= p_aabb.size[(closest_axis + 2) % 3] / real_t(color_scan_cell_width);
Color albedo_accum;
Color emission_accum;
@@ -114,10 +109,10 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co
//map to a grid average in the best axis for this face
for (int i = 0; i < color_scan_cell_width; i++) {
- Vector3 ofs_i = float(i) * t1;
+ Vector3 ofs_i = real_t(i) * t1;
for (int j = 0; j < color_scan_cell_width; j++) {
- Vector3 ofs_j = float(j) * t2;
+ Vector3 ofs_j = real_t(j) * t2;
Vector3 from = p_aabb.position + ofs_i + ofs_j;
Vector3 to = from + t1 + t2 + axis * p_aabb.size[closest_axis];
@@ -155,8 +150,8 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co
lnormal = normal;
}
- int uv_x = CLAMP(int(Math::fposmod(uv.x, 1.0f) * bake_texture_size), 0, bake_texture_size - 1);
- int uv_y = CLAMP(int(Math::fposmod(uv.y, 1.0f) * bake_texture_size), 0, bake_texture_size - 1);
+ int uv_x = CLAMP(int(Math::fposmod(uv.x, (real_t)1.0) * bake_texture_size), 0, bake_texture_size - 1);
+ int uv_y = CLAMP(int(Math::fposmod(uv.y, (real_t)1.0) * bake_texture_size), 0, bake_texture_size - 1);
int ofs = uv_y * bake_texture_size + uv_x;
albedo_accum.r += p_material.albedo[ofs].r;
@@ -178,7 +173,7 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co
//could not in any way get texture information.. so use closest point to center
Face3 f(p_vtx[0], p_vtx[1], p_vtx[2]);
- Vector3 inters = f.get_closest_point_to(p_aabb.position + p_aabb.size * 0.5);
+ Vector3 inters = f.get_closest_point_to(p_aabb.get_center());
Vector3 lnormal;
Vector2 uv;
@@ -187,8 +182,8 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co
lnormal = normal;
}
- int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1);
- int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1);
+ int uv_x = CLAMP(Math::fposmod(uv.x, (real_t)1.0) * bake_texture_size, 0, bake_texture_size - 1);
+ int uv_y = CLAMP(Math::fposmod(uv.y, (real_t)1.0) * bake_texture_size, 0, bake_texture_size - 1);
int ofs = uv_y * bake_texture_size + uv_x;
@@ -439,7 +434,7 @@ void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const V
}
//test against original bounds
- if (!Geometry3D::triangle_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs)) {
+ if (!Geometry3D::triangle_box_overlap(original_bounds.get_center(), original_bounds.size * 0.5, vtxs)) {
continue;
}
//plot
@@ -471,7 +466,7 @@ void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const V
}
//test against original bounds
- if (!Geometry3D::triangle_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs)) {
+ if (!Geometry3D::triangle_box_overlap(original_bounds.get_center(), original_bounds.size * 0.5, vtxs)) {
continue;
}
//plot face
@@ -636,7 +631,7 @@ void Voxelizer::begin_bake(int p_subdiv, const AABB &p_bounds) {
}
axis_cell_size[i] = axis_cell_size[longest_axis];
- float axis_size = po2_bounds.size[longest_axis];
+ real_t axis_size = po2_bounds.size[longest_axis];
//shrink until fit subdiv
while (axis_size / 2.0 >= po2_bounds.size[i]) {
@@ -890,7 +885,7 @@ Vector<uint8_t> Voxelizer::get_sdf_3d_image() const {
void Voxelizer::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx) {
if (p_level == cell_subdiv - 1) {
- Vector3 center = p_aabb.position + p_aabb.size * 0.5;
+ Vector3 center = p_aabb.get_center();
Transform3D xform;
xform.origin = center;
xform.basis.scale(p_aabb.size * 0.5);
@@ -954,7 +949,7 @@ Ref<MultiMesh> Voxelizer::create_debug_multimesh() {
Vector3 face_points[4];
for (int j = 0; j < 4; j++) {
- float v[3];
+ real_t v[3];
v[0] = 1.0;
v[1] = 1 - 2 * ((j >> 1) & 1);
v[2] = v[1] * (1 - 2 * (j & 1));
diff --git a/scene/3d/voxelizer.h b/scene/3d/voxelizer.h
index e500d2d4c3..09c126bc4e 100644
--- a/scene/3d/voxelizer.h
+++ b/scene/3d/voxelizer.h
@@ -31,8 +31,6 @@
#ifndef VOXEL_LIGHT_BAKER_H
#define VOXEL_LIGHT_BAKER_H
-#include "core/math/vector3i.h"
-#include "scene/3d/mesh_instance_3d.h"
#include "scene/resources/multimesh.h"
class Voxelizer {
diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp
index 352bef072f..26fa43b969 100644
--- a/scene/3d/world_environment.cpp
+++ b/scene/3d/world_environment.cpp
@@ -30,6 +30,7 @@
#include "world_environment.h"
+#include "scene/3d/node_3d.h"
#include "scene/main/window.h"
void WorldEnvironment::_notification(int p_what) {
diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h
index 9e85982381..310d1e96a5 100644
--- a/scene/3d/world_environment.h
+++ b/scene/3d/world_environment.h
@@ -31,7 +31,7 @@
#ifndef SCENARIO_FX_H
#define SCENARIO_FX_H
-#include "scene/3d/node_3d.h"
+#include "scene/main/node.h"
#include "scene/resources/camera_effects.h"
#include "scene/resources/environment.h"
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index b04c7e2858..ebfb58e9fe 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -30,9 +30,8 @@
#include "xr_nodes.h"
-#include "core/input/input.h"
+#include "scene/main/viewport.h"
#include "servers/xr/xr_interface.h"
-#include "servers/xr_server.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -124,7 +123,7 @@ Point2 XRCamera3D::unproject_position(const Vector3 &p_pos) const {
return res;
};
-Vector3 XRCamera3D::project_position(const Point2 &p_point, float p_z_depth) const {
+Vector3 XRCamera3D::project_position(const Point2 &p_point, real_t p_z_depth) const {
// get our XRServer
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, Vector3());
@@ -544,7 +543,7 @@ void XROrigin3D::clear_tracked_camera_if(XRCamera3D *p_tracked_camera) {
};
};
-float XROrigin3D::get_world_scale() const {
+real_t XROrigin3D::get_world_scale() const {
// get our XRServer
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, 1.0);
@@ -552,7 +551,7 @@ float XROrigin3D::get_world_scale() const {
return xr_server->get_world_scale();
};
-void XROrigin3D::set_world_scale(float p_world_scale) {
+void XROrigin3D::set_world_scale(real_t p_world_scale) {
// get our XRServer
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h
index 90079f5fe9..6e54ff83d7 100644
--- a/scene/3d/xr_nodes.h
+++ b/scene/3d/xr_nodes.h
@@ -32,8 +32,6 @@
#define XR_NODES_H
#include "scene/3d/camera_3d.h"
-#include "scene/3d/node_3d.h"
-#include "scene/resources/mesh.h"
#include "servers/xr/xr_positional_tracker.h"
/**
@@ -54,7 +52,7 @@ public:
virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const override;
virtual Point2 unproject_position(const Vector3 &p_pos) const override;
- virtual Vector3 project_position(const Point2 &p_point, float p_z_depth) const override;
+ virtual Vector3 project_position(const Point2 &p_point, real_t p_z_depth) const override;
virtual Vector<Plane> get_frustum() const override;
XRCamera3D() {}
@@ -163,8 +161,8 @@ public:
void set_tracked_camera(XRCamera3D *p_tracked_camera);
void clear_tracked_camera_if(XRCamera3D *p_tracked_camera);
- float get_world_scale() const;
- void set_world_scale(float p_world_scale);
+ real_t get_world_scale() const;
+ void set_world_scale(real_t p_world_scale);
XROrigin3D() {}
~XROrigin3D() {}