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.cpp100
-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.cpp740
-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.cpp373
-rw-r--r--scene/3d/camera_3d.h128
-rw-r--r--scene/3d/collision_object_3d.cpp245
-rw-r--r--scene/3d/collision_object_3d.h40
-rw-r--r--scene/3d/collision_polygon_3d.cpp9
-rw-r--r--scene/3d/collision_shape_3d.cpp24
-rw-r--r--scene/3d/collision_shape_3d.h1
-rw-r--r--scene/3d/cpu_particles_3d.cpp495
-rw-r--r--scene/3d/cpu_particles_3d.h116
-rw-r--r--scene/3d/decal.cpp57
-rw-r--r--scene/3d/decal.h46
-rw-r--r--scene/3d/gpu_particles_3d.cpp48
-rw-r--r--scene/3d/gpu_particles_3d.h44
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp55
-rw-r--r--scene/3d/gpu_particles_collision_3d.h32
-rw-r--r--scene/3d/immediate_geometry_3d.cpp157
-rw-r--r--scene/3d/importer_mesh_instance_3d.cpp85
-rw-r--r--scene/3d/importer_mesh_instance_3d.h (renamed from scene/3d/immediate_geometry_3d.h)54
-rw-r--r--scene/3d/joint_3d.cpp (renamed from scene/3d/physics_joint_3d.cpp)28
-rw-r--r--scene/3d/joint_3d.h (renamed from scene/3d/physics_joint_3d.h)8
-rw-r--r--scene/3d/light_3d.cpp65
-rw-r--r--scene/3d/light_3d.h20
-rw-r--r--scene/3d/lightmap_gi.cpp31
-rw-r--r--scene/3d/lightmap_gi.h3
-rw-r--r--scene/3d/lightmapper.h17
-rw-r--r--scene/3d/mesh_instance_3d.cpp35
-rw-r--r--scene/3d/mesh_instance_3d.h10
-rw-r--r--scene/3d/navigation_agent_3d.cpp9
-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.cpp15
-rw-r--r--scene/3d/navigation_region_3d.h1
-rw-r--r--scene/3d/node_3d.cpp269
-rw-r--r--scene/3d/node_3d.h55
-rw-r--r--scene/3d/occluder_instance_3d.cpp60
-rw-r--r--scene/3d/occluder_instance_3d.h7
-rw-r--r--scene/3d/path_3d.cpp55
-rw-r--r--scene/3d/path_3d.h16
-rw-r--r--scene/3d/physics_body_3d.cpp1772
-rw-r--r--scene/3d/physics_body_3d.h309
-rw-r--r--scene/3d/position_3d.cpp1
-rw-r--r--scene/3d/proximity_group_3d.cpp13
-rw-r--r--scene/3d/proximity_group_3d.h2
-rw-r--r--scene/3d/ray_cast_3d.cpp30
-rw-r--r--scene/3d/ray_cast_3d.h4
-rw-r--r--scene/3d/reflection_probe.cpp6
-rw-r--r--scene/3d/reflection_probe.h5
-rw-r--r--scene/3d/remote_transform_3d.cpp2
-rw-r--r--scene/3d/skeleton_3d.cpp782
-rw-r--r--scene/3d/skeleton_3d.h116
-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)363
-rw-r--r--scene/3d/soft_dynamic_body_3d.h (renamed from scene/3d/soft_body_3d.h)52
-rw-r--r--scene/3d/spring_arm_3d.cpp39
-rw-r--r--scene/3d/sprite_3d.cpp342
-rw-r--r--scene/3d/sprite_3d.h53
-rw-r--r--scene/3d/vehicle_body_3d.cpp86
-rw-r--r--scene/3d/vehicle_body_3d.h7
-rw-r--r--scene/3d/velocity_tracker_3d.cpp13
-rw-r--r--scene/3d/velocity_tracker_3d.h4
-rw-r--r--scene/3d/visibility_notifier_3d.cpp253
-rw-r--r--scene/3d/visible_on_screen_notifier_3d.cpp199
-rw-r--r--scene/3d/visible_on_screen_notifier_3d.h (renamed from scene/3d/visibility_notifier_3d.h)68
-rw-r--r--scene/3d/visual_instance_3d.cpp122
-rw-r--r--scene/3d/visual_instance_3d.h38
-rw-r--r--scene/3d/voxel_gi.cpp67
-rw-r--r--scene/3d/voxel_gi.h14
-rw-r--r--scene/3d/voxelizer.cpp70
-rw-r--r--scene/3d/voxelizer.h2
-rw-r--r--scene/3d/world_environment.cpp3
-rw-r--r--scene/3d/world_environment.h2
-rw-r--r--scene/3d/xr_nodes.cpp42
-rw-r--r--scene/3d/xr_nodes.h8
83 files changed, 5330 insertions, 3666 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 44708cddff..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);
@@ -601,11 +666,14 @@ void Area3D::_bind_methods() {
ADD_GROUP("Physics Overrides", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp"), "set_gravity_distance_scale", "get_gravity_distance_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_vec"), "set_gravity_vector", "get_gravity_vector");
ADD_PROPERTY(PropertyInfo(Variant::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 cad4330c17..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,284 +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;
-
- int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
+ while (stream_playbacks.size() > max_polyphony) {
+ AudioServer::get_singleton()->stop_playback_stream(stream_playbacks[0]);
+ stream_playbacks.remove(0);
+ }
+ }
+}
- //check if any area is diverting sound into a 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);
- PhysicsDirectSpaceState3D *space_state = PhysicsServer3D::get_singleton()->space_get_direct_state(world_3d->get_space());
+ Vector3 global_pos = get_global_transform().origin;
- PhysicsDirectSpaceState3D::ShapeResult sr[MAX_INTERSECT_AREAS];
+ PhysicsDirectSpaceState3D *space_state = PhysicsServer3D::get_singleton()->space_get_direct_state(world_3d->get_space());
- int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, false, true);
- Area3D *area = nullptr;
+ PhysicsDirectSpaceState3D::ShapeResult sr[MAX_INTERSECT_AREAS];
- for (int i = 0; i < areas; i++) {
- if (!sr[i].collider) {
- continue;
- }
+ int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, false, true);
- Area3D *tarea = Object::cast_to<Area3D>(sr[i].collider);
- if (!tarea) {
- continue;
- }
+ for (int i = 0; i < areas; i++) {
+ if (!sr[i].collider) {
+ continue;
+ }
- if (!tarea->is_overriding_audio_bus() && !tarea->is_using_reverb_bus()) {
- continue;
- }
+ Area3D *tarea = Object::cast_to<Area3D>(sr[i].collider);
+ if (!tarea) {
+ continue;
+ }
- area = tarea;
- break;
- }
+ if (!tarea->is_overriding_audio_bus() && !tarea->is_using_reverb_bus()) {
+ continue;
+ }
- List<Camera3D *> cameras;
- world_3d->get_camera_list(&cameras);
+ return tarea;
+ }
+ return nullptr;
+}
- for (List<Camera3D *>::Element *E = 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("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 {
@@ -677,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;
}
@@ -736,7 +602,7 @@ StringName AudioStreamPlayer3D::get_bus() const {
return bus;
}
}
- return "Master";
+ return SNAME("Master");
}
void AudioStreamPlayer3D::set_autoplay(bool p_enable) {
@@ -797,7 +663,7 @@ uint32_t AudioStreamPlayer3D::get_area_mask() const {
void AudioStreamPlayer3D::set_emission_angle_enabled(bool p_enable) {
emission_angle_enabled = p_enable;
- update_gizmo();
+ update_gizmos();
}
bool AudioStreamPlayer3D::is_emission_angle_enabled() const {
@@ -807,7 +673,7 @@ bool AudioStreamPlayer3D::is_emission_angle_enabled() const {
void AudioStreamPlayer3D::set_emission_angle(float p_angle) {
ERR_FAIL_COND(p_angle < 0 || p_angle > 90);
emission_angle = p_angle;
- update_gizmo();
+ update_gizmos();
}
float AudioStreamPlayer3D::get_emission_angle() const {
@@ -847,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;
@@ -879,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() {
@@ -950,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");
@@ -970,13 +843,13 @@ void AudioStreamPlayer3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,4096,1,or_greater"), "set_max_distance", "get_max_distance");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "out_of_range_mode", PROPERTY_HINT_ENUM, "Mix,Pause"), "set_out_of_range_mode", "get_out_of_range_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,4096,1,or_greater,exp"), "set_max_distance", "get_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_polyphony", PROPERTY_HINT_NONE, ""), "set_max_polyphony", "get_max_polyphony");
ADD_PROPERTY(PropertyInfo(Variant::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");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emission_angle_enabled"), "set_emission_angle_enabled", "is_emission_angle_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_angle_degrees", PROPERTY_HINT_RANGE, "0.1,90,0.1"), "set_emission_angle", "get_emission_angle");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_angle_degrees", PROPERTY_HINT_RANGE, "0.1,90,0.1,degrees"), "set_emission_angle", "get_emission_angle");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_angle_filter_attenuation_db", PROPERTY_HINT_RANGE, "-80,0,0.1"), "set_emission_angle_filter_attenuation_db", "get_emission_angle_filter_attenuation_db");
ADD_GROUP("Attenuation Filter", "attenuation_filter_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "attenuation_filter_cutoff_hz", PROPERTY_HINT_RANGE, "1,20500,1"), "set_attenuation_filter_cutoff_hz", "get_attenuation_filter_cutoff_hz");
@@ -989,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);
@@ -1000,7 +870,7 @@ void AudioStreamPlayer3D::_bind_methods() {
}
AudioStreamPlayer3D::AudioStreamPlayer3D() {
- velocity_tracker.instance();
+ velocity_tracker.instantiate();
AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer3D::_bus_layout_changed));
set_disable_scale(true);
}
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 1c9418ae83..18b7bcc789 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() {
}
@@ -85,18 +83,14 @@ void Camera3D::_update_camera() {
// here goes listener stuff
/*
if (viewport_ptr && is_inside_scene() && is_current())
- get_viewport()->_camera_transform_changed_notify();
+ get_viewport()->_camera_3d_transform_changed_notify();
*/
if (get_tree()->is_node_being_edited(this) || !is_current()) {
return;
}
- get_viewport()->_camera_transform_changed_notify();
-
- if (get_world_3d().is_valid()) {
- get_world_3d()->_update_camera(this);
- }
+ get_viewport()->_camera_3d_transform_changed_notify();
}
void Camera3D::_notification(int p_what) {
@@ -108,9 +102,9 @@ void Camera3D::_notification(int p_what) {
viewport = get_viewport();
ERR_FAIL_COND(!viewport);
- bool first_camera = viewport->_camera_add(this);
+ bool first_camera = viewport->_camera_3d_add(this);
if (current || first_camera) {
- viewport->_camera_set(this);
+ viewport->_camera_3d_set(this);
}
} break;
@@ -132,7 +126,7 @@ void Camera3D::_notification(int p_what) {
}
if (viewport) {
- viewport->_camera_remove(this);
+ viewport->_camera_3d_remove(this);
viewport = nullptr;
}
@@ -157,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,11 +162,11 @@ void Camera3D::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_f
mode = PROJECTION_PERSPECTIVE;
RenderingServer::get_singleton()->camera_set_perspective(camera, fov, near, far);
- update_gizmo();
+ update_gizmos();
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;
}
@@ -185,10 +179,10 @@ void Camera3D::set_orthogonal(float p_size, float p_z_near, float p_z_far) {
force_change = false;
RenderingServer::get_singleton()->camera_set_orthogonal(camera, size, near, far);
- update_gizmo();
+ 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;
}
@@ -202,7 +196,7 @@ void Camera3D::set_frustum(float p_size, Vector2 p_offset, float p_z_near, float
force_change = false;
RenderingServer::get_singleton()->camera_set_frustum(camera, size, frustum_offset, near, far);
- update_gizmo();
+ update_gizmos();
}
void Camera3D::set_projection(Camera3D::Projection p_mode) {
@@ -224,7 +218,7 @@ void Camera3D::make_current() {
return;
}
- get_viewport()->_camera_set(this);
+ get_viewport()->_camera_3d_set(this);
//get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,camera_group,"_camera_make_current",this);
}
@@ -235,17 +229,17 @@ void Camera3D::clear_current(bool p_enable_next) {
return;
}
- if (get_viewport()->get_camera() == this) {
- get_viewport()->_camera_set(nullptr);
+ if (get_viewport()->get_camera_3d() == this) {
+ get_viewport()->_camera_3d_set(nullptr);
if (p_enable_next) {
- get_viewport()->_camera_make_next_current(this);
+ get_viewport()->_camera_3d_make_next_current(this);
}
}
}
-void Camera3D::set_current(bool p_current) {
- if (p_current) {
+void Camera3D::set_current(bool p_enabled) {
+ if (p_enabled) {
make_current();
} else {
clear_current();
@@ -254,16 +248,12 @@ void Camera3D::set_current(bool p_current) {
bool Camera3D::is_current() const {
if (is_inside_tree() && !get_tree()->is_node_being_edited(this)) {
- return get_viewport()->get_camera() == this;
+ return get_viewport()->get_camera_3d() == this;
} else {
return current;
}
}
-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();
@@ -299,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;
@@ -372,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) {
@@ -470,7 +460,7 @@ void Camera3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_frustum", "size", "offset", "z_near", "z_far"), &Camera3D::set_frustum);
ClassDB::bind_method(D_METHOD("make_current"), &Camera3D::make_current);
ClassDB::bind_method(D_METHOD("clear_current", "enable_next"), &Camera3D::clear_current, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("set_current"), &Camera3D::set_current);
+ ClassDB::bind_method(D_METHOD("set_current", "enabled"), &Camera3D::set_current);
ClassDB::bind_method(D_METHOD("is_current"), &Camera3D::is_current);
ClassDB::bind_method(D_METHOD("get_camera_transform"), &Camera3D::get_camera_transform);
ClassDB::bind_method(D_METHOD("get_fov"), &Camera3D::get_fov);
@@ -478,13 +468,13 @@ void Camera3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_size"), &Camera3D::get_size);
ClassDB::bind_method(D_METHOD("get_far"), &Camera3D::get_far);
ClassDB::bind_method(D_METHOD("get_near"), &Camera3D::get_near);
- ClassDB::bind_method(D_METHOD("set_fov"), &Camera3D::set_fov);
- ClassDB::bind_method(D_METHOD("set_frustum_offset"), &Camera3D::set_frustum_offset);
- ClassDB::bind_method(D_METHOD("set_size"), &Camera3D::set_size);
- ClassDB::bind_method(D_METHOD("set_far"), &Camera3D::set_far);
- ClassDB::bind_method(D_METHOD("set_near"), &Camera3D::set_near);
+ ClassDB::bind_method(D_METHOD("set_fov", "fov"), &Camera3D::set_fov);
+ ClassDB::bind_method(D_METHOD("set_frustum_offset", "offset"), &Camera3D::set_frustum_offset);
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &Camera3D::set_size);
+ ClassDB::bind_method(D_METHOD("set_far", "far"), &Camera3D::set_far);
+ ClassDB::bind_method(D_METHOD("set_near", "near"), &Camera3D::set_near);
ClassDB::bind_method(D_METHOD("get_projection"), &Camera3D::get_projection);
- ClassDB::bind_method(D_METHOD("set_projection"), &Camera3D::set_projection);
+ ClassDB::bind_method(D_METHOD("set_projection", "mode"), &Camera3D::set_projection);
ClassDB::bind_method(D_METHOD("set_h_offset", "ofs"), &Camera3D::set_h_offset);
ClassDB::bind_method(D_METHOD("get_h_offset"), &Camera3D::get_h_offset);
ClassDB::bind_method(D_METHOD("set_v_offset", "ofs"), &Camera3D::set_v_offset);
@@ -500,10 +490,12 @@ void Camera3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera3D::set_doppler_tracking);
ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera3D::get_doppler_tracking);
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 );
@@ -516,11 +508,11 @@ void Camera3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"), "set_doppler_tracking", "get_doppler_tracking");
ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal,Frustum"), "set_projection", "get_projection");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov", PROPERTY_HINT_RANGE, "1,179,0.1,degrees"), "set_fov", "get_fov");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset"), "set_frustum_offset", "get_frustum_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_EXP_RANGE, "0.001,10,0.001,or_greater"), "set_near", "get_near");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_EXP_RANGE, "0.01,4000,0.01,or_greater"), "set_far", "get_far");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater,exp"), "set_near", "get_near");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_RANGE, "0.01,4000,0.01,or_greater,exp"), "set_far", "get_far");
BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE);
BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL);
@@ -534,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;
}
@@ -550,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;
}
@@ -558,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();
}
@@ -580,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();
}
@@ -595,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 {
@@ -623,21 +619,31 @@ Vector<Plane> Camera3D::get_frustum() const {
return cm.get_projection_planes(get_camera_transform());
}
-void Camera3D::set_v_offset(float p_offset) {
+bool Camera3D::is_position_in_frustum(const Vector3 &p_position) const {
+ Vector<Plane> frustum = get_frustum();
+ for (int i = 0; i < frustum.size(); i++) {
+ if (frustum[i].is_point_over(p_position)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+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;
}
@@ -649,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.instance();
- set_notify_transform(true);
- set_disable_scale(true);
-}
+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);
-Camera3D::~Camera3D() {
- RenderingServer::get_singleton()->free(camera);
-}
+ } else { //check if points changed
+ Vector<Vector3> local_points = get_near_plane_points();
-////////////////////////////////////////
+ bool all_equal = true;
-void ClippedCamera3D::set_margin(float p_margin) {
- margin = p_margin;
-}
-
-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_gizmo();
- }
-}
-
-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 d9ebe78f1a..73126611d5 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);
@@ -47,8 +44,10 @@ public:
PROJECTION_FRUSTUM
};
- enum KeepAspect { KEEP_WIDTH,
- KEEP_HEIGHT };
+ enum KeepAspect {
+ KEEP_WIDTH,
+ KEEP_HEIGHT
+ };
enum DopplerTracking {
DOPPLER_TRACKING_DISABLED,
@@ -63,13 +62,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 +81,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 +88,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,31 +107,30 @@ 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();
void clear_current(bool p_enable_next = true);
- void set_current(bool p_current);
+ void set_current(bool p_enabled);
bool is_current() const;
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,18 +140,18 @@ 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;
void set_environment(const Ref<Environment> &p_environment);
Ref<Environment> get_environment() const;
@@ -163,17 +162,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();
};
@@ -182,63 +183,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 a04667e53b..814ed5c2a7 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -30,17 +30,15 @@
#include "collision_object_3d.h"
-#include "core/config/engine.h"
#include "scene/scene_string_names.h"
-#include "servers/physics_server_3d.h"
void CollisionObject3D::_notification(int p_what) {
switch (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();
}
@@ -59,18 +57,29 @@ void CollisionObject3D::_notification(int p_what) {
PhysicsServer3D::get_singleton()->body_set_state(rid, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
}
- RID space = get_world_3d()->get_space();
- if (area) {
- PhysicsServer3D::get_singleton()->area_set_space(rid, space);
- } else {
- PhysicsServer3D::get_singleton()->body_set_space(rid, space);
+ bool disabled = !is_enabled();
+
+ if (disabled && (disable_mode != DISABLE_MODE_REMOVE)) {
+ _apply_disabled();
+ }
+
+ if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) {
+ RID space = get_world_3d()->get_space();
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_space(rid, space);
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_space(rid, space);
+ }
}
_update_pickable();
- //get space
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
+ if (only_update_transform_changes) {
+ return;
+ }
+
if (area) {
PhysicsServer3D::get_singleton()->area_set_transform(rid, get_global_transform());
} else {
@@ -78,19 +87,34 @@ void CollisionObject3D::_notification(int p_what) {
}
_on_transform_changed();
-
} break;
+
case NOTIFICATION_VISIBILITY_CHANGED: {
_update_pickable();
-
} break;
+
case NOTIFICATION_EXIT_WORLD: {
- if (area) {
- PhysicsServer3D::get_singleton()->area_set_space(rid, RID());
- } else {
- PhysicsServer3D::get_singleton()->body_set_space(rid, RID());
+ bool disabled = !is_enabled();
+
+ if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) {
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_space(rid, RID());
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_space(rid, RID());
+ }
+ }
+
+ if (disabled && (disable_mode != DISABLE_MODE_REMOVE)) {
+ _apply_enabled();
}
+ } break;
+
+ case NOTIFICATION_DISABLED: {
+ _apply_disabled();
+ } break;
+ case NOTIFICATION_ENABLED: {
+ _apply_enabled();
} break;
}
}
@@ -121,42 +145,117 @@ 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::_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::set_disable_mode(DisableMode p_mode) {
+ if (disable_mode == p_mode) {
+ return;
+ }
+
+ bool disabled = is_inside_tree() && !is_enabled();
+
+ if (disabled) {
+ // Cancel previous disable mode.
+ _apply_enabled();
+ }
+
+ disable_mode = p_mode;
+
+ if (disabled) {
+ // Apply new disable mode.
+ _apply_disabled();
+ }
+}
+
+CollisionObject3D::DisableMode CollisionObject3D::get_disable_mode() const {
+ return disable_mode;
+}
+
+void CollisionObject3D::_apply_disabled() {
+ switch (disable_mode) {
+ case DISABLE_MODE_REMOVE: {
+ if (is_inside_tree()) {
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_space(rid, RID());
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_space(rid, RID());
+ }
+ }
+ } break;
+
+ case DISABLE_MODE_MAKE_STATIC: {
+ if (!area && (body_mode != PhysicsServer3D::BODY_MODE_STATIC)) {
+ PhysicsServer3D::get_singleton()->body_set_mode(rid, PhysicsServer3D::BODY_MODE_STATIC);
+ }
+ } break;
+
+ case DISABLE_MODE_KEEP_ACTIVE: {
+ // Nothing to do.
+ } break;
+ }
+}
+
+void CollisionObject3D::_apply_enabled() {
+ switch (disable_mode) {
+ case DISABLE_MODE_REMOVE: {
+ if (is_inside_tree()) {
+ RID space = get_world_3d()->get_space();
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_space(rid, space);
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_space(rid, space);
+ }
+ }
+ } break;
+
+ case DISABLE_MODE_MAKE_STATIC: {
+ if (!area && (body_mode != PhysicsServer3D::BODY_MODE_STATIC)) {
+ PhysicsServer3D::get_singleton()->body_set_mode(rid, body_mode);
+ }
+ } break;
+
+ case DISABLE_MODE_KEEP_ACTIVE: {
+ // Nothing to do.
+ } break;
}
+}
+
+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);
}
@@ -174,6 +273,30 @@ void CollisionObject3D::_mouse_exit() {
emit_signal(SceneStringNames::get_singleton()->mouse_exited);
}
+void CollisionObject3D::set_body_mode(PhysicsServer3D::BodyMode p_mode) {
+ ERR_FAIL_COND(area);
+
+ if (body_mode == p_mode) {
+ return;
+ }
+
+ body_mode = p_mode;
+
+ if (is_inside_tree() && !is_enabled() && (disable_mode == DISABLE_MODE_MAKE_STATIC)) {
+ return;
+ }
+
+ PhysicsServer3D::get_singleton()->body_set_mode(rid, p_mode);
+}
+
+void CollisionObject3D::set_only_update_transform_changes(bool p_enable) {
+ only_update_transform_changes = p_enable;
+}
+
+bool CollisionObject3D::is_only_update_transform_changes_enabled() const {
+ return only_update_transform_changes;
+}
+
void CollisionObject3D::_update_pickable() {
if (!is_inside_tree()) {
return;
@@ -201,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];
@@ -257,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];
@@ -277,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);
@@ -301,10 +424,12 @@ 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);
ClassDB::bind_method(D_METHOD("is_ray_pickable"), &CollisionObject3D::is_ray_pickable);
ClassDB::bind_method(D_METHOD("set_capture_input_on_drag", "enable"), &CollisionObject3D::set_capture_input_on_drag);
@@ -326,12 +451,14 @@ 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"));
ADD_SIGNAL(MethodInfo("mouse_exited"));
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "disable_mode", PROPERTY_HINT_ENUM, "Remove,MakeStatic,KeepActive"), "set_disable_mode", "get_disable_mode");
+
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
@@ -339,6 +466,10 @@ void CollisionObject3D::_bind_methods() {
ADD_GROUP("Input", "input_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_ray_pickable"), "set_ray_pickable", "is_ray_pickable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_capture_on_drag"), "set_capture_input_on_drag", "get_capture_input_on_drag");
+
+ BIND_ENUM_CONSTANT(DISABLE_MODE_REMOVE);
+ BIND_ENUM_CONSTANT(DISABLE_MODE_MAKE_STATIC);
+ BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE);
}
uint32_t CollisionObject3D::create_shape_owner(Object *p_owner) {
@@ -392,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;
@@ -497,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;
}
}
}
@@ -519,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;
}
}
}
@@ -540,8 +671,8 @@ CollisionObject3D::CollisionObject3D(RID p_rid, bool p_area) {
PhysicsServer3D::get_singleton()->area_attach_object_instance_id(rid, get_instance_id());
} else {
PhysicsServer3D::get_singleton()->body_attach_object_instance_id(rid, get_instance_id());
+ PhysicsServer3D::get_singleton()->body_set_mode(rid, body_mode);
}
- //set_transform_notify(true);
}
void CollisionObject3D::set_capture_input_on_drag(bool p_capture) {
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
index 50a9b4fcd0..1c7e205888 100644
--- a/scene/3d/collision_object_3d.h
+++ b/scene/3d/collision_object_3d.h
@@ -31,12 +31,20 @@
#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"
class CollisionObject3D : public Node3D {
GDCLASS(CollisionObject3D, Node3D);
+public:
+ enum DisableMode {
+ DISABLE_MODE_REMOVE,
+ DISABLE_MODE_MAKE_STATIC,
+ DISABLE_MODE_KEEP_ACTIVE,
+ };
+
+private:
uint32_t collision_layer = 1;
uint32_t collision_mask = 1;
@@ -44,6 +52,10 @@ class CollisionObject3D : public Node3D {
RID rid;
+ DisableMode disable_mode = DISABLE_MODE_REMOVE;
+
+ PhysicsServer3D::BodyMode body_mode = PhysicsServer3D::BODY_MODE_STATIC;
+
struct ShapeData {
Object *owner = nullptr;
Transform3D xform;
@@ -61,6 +73,8 @@ class CollisionObject3D : public Node3D {
Map<uint32_t, ShapeData> shapes;
+ bool only_update_transform_changes = false; // This is used for sync to physics.
+
bool capture_input_on_drag = false;
bool ray_pickable = true;
@@ -76,6 +90,9 @@ class CollisionObject3D : public Node3D {
void _update_debug_shapes();
void _clear_debug_shapes();
+ void _apply_disabled();
+ void _apply_enabled();
+
protected:
CollisionObject3D(RID p_rid, bool p_area);
@@ -85,10 +102,16 @@ 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();
+ void set_body_mode(PhysicsServer3D::BodyMode p_mode);
+
+ 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;
@@ -96,11 +119,14 @@ 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;
uint32_t create_shape_owner(Object *p_owner);
void remove_shape_owner(uint32_t owner);
@@ -138,4 +164,6 @@ public:
~CollisionObject3D();
};
+VARIANT_ENUM_CAST(CollisionObject3D::DisableMode);
+
#endif // COLLISION_OBJECT__H
diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp
index 8a4f8b639b..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() {
@@ -122,7 +121,7 @@ void CollisionPolygon3D::set_polygon(const Vector<Point2> &p_polygon) {
_build_polygon();
}
update_configuration_warnings();
- update_gizmo();
+ update_gizmos();
}
Vector<Point2> CollisionPolygon3D::get_polygon() const {
@@ -136,7 +135,7 @@ AABB CollisionPolygon3D::get_item_rect() const {
void CollisionPolygon3D::set_depth(real_t p_depth) {
depth = p_depth;
_build_polygon();
- update_gizmo();
+ update_gizmos();
}
real_t CollisionPolygon3D::get_depth() const {
@@ -145,7 +144,7 @@ real_t CollisionPolygon3D::get_depth() const {
void CollisionPolygon3D::set_disabled(bool p_disabled) {
disabled = p_disabled;
- update_gizmo();
+ update_gizmos();
if (parent) {
parent->shape_owner_set_disabled(owner_id, p_disabled);
@@ -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 be3fde8013..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();
@@ -117,14 +108,14 @@ void CollisionShape3D::_notification(int p_what) {
}
void CollisionShape3D::resource_changed(RES res) {
- update_gizmo();
+ update_gizmos();
}
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;
@@ -166,7 +156,7 @@ void CollisionShape3D::set_shape(const Ref<Shape3D> &p_shape) {
if (!shape.is_null()) {
shape->register_owner(this);
}
- update_gizmo();
+ update_gizmos();
if (parent) {
parent->shape_owner_clear_shapes(owner_id);
if (shape.is_valid()) {
@@ -187,7 +177,7 @@ Ref<Shape3D> CollisionShape3D::get_shape() const {
void CollisionShape3D::set_disabled(bool p_disabled) {
disabled = p_disabled;
- update_gizmo();
+ update_gizmos();
if (parent) {
parent->shape_owner_set_disabled(owner_id, p_disabled);
}
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 2301fef651..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;
}
@@ -401,7 +406,40 @@ void CPUParticles3D::set_emission_colors(const Vector<Color> &p_colors) {
emission_colors = p_colors;
}
-float CPUParticles3D::get_emission_sphere_radius() const {
+void CPUParticles3D::set_emission_ring_axis(Vector3 p_axis) {
+ emission_ring_axis = p_axis;
+}
+
+void CPUParticles3D::set_emission_ring_height(real_t p_height) {
+ emission_ring_height = p_height;
+}
+
+void CPUParticles3D::set_emission_ring_radius(real_t p_radius) {
+ emission_ring_radius = p_radius;
+}
+
+void CPUParticles3D::set_emission_ring_inner_radius(real_t p_radius) {
+ emission_ring_inner_radius = p_radius;
+}
+
+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;
}
@@ -421,6 +459,22 @@ Vector<Color> CPUParticles3D::get_emission_colors() const {
return emission_colors;
}
+Vector3 CPUParticles3D::get_emission_ring_axis() const {
+ return emission_ring_axis;
+}
+
+real_t CPUParticles3D::get_emission_ring_height() const {
+ return emission_ring_height;
+}
+
+real_t CPUParticles3D::get_emission_ring_radius() const {
+ return emission_ring_radius;
+}
+
+real_t CPUParticles3D::get_emission_ring_inner_radius() const {
+ return emission_ring_inner_radius;
+}
+
CPUParticles3D::EmissionShape CPUParticles3D::get_emission_shape() const {
return emission_shape;
}
@@ -433,29 +487,49 @@ Vector3 CPUParticles3D::get_gravity() const {
return gravity;
}
-void CPUParticles3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "color" && color_ramp.is_valid()) {
- property.usage = 0;
- }
+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 = 0;
+ property.usage = PROPERTY_USAGE_NONE;
}
if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NONE;
}
- if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) {
- property.usage = 0;
+ if ((property.name == "emission_point_texture" || property.name == "emission_color_texture" || property.name == "emission_points") && (emission_shape != EMISSION_SHAPE_POINTS && (emission_shape != EMISSION_SHAPE_DIRECTED_POINTS))) {
+ property.usage = PROPERTY_USAGE_NONE;
}
if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NONE;
+ }
+
+ if (property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) {
+ property.usage = PROPERTY_USAGE_NONE;
}
if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NONE;
+ }
+
+ if (property.name.begins_with("scale_curve_") && !split_scale) {
+ property.usage = PROPERTY_USAGE_NONE;
}
}
@@ -466,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) {
@@ -478,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() {
@@ -487,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 {
@@ -509,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);
@@ -526,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);
@@ -555,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();
@@ -563,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);
@@ -581,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];
@@ -590,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;
@@ -604,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) {
@@ -650,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);
}
@@ -673,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);
@@ -750,6 +837,21 @@ void CPUParticles3D::_particles_process(float p_delta) {
p.base_color = emission_colors.get(random_idx);
}
} break;
+ case EMISSION_SHAPE_RING: {
+ 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)) {
+ ortho_axis = Vector3(0.0, 1.0, 0.0).cross(axis);
+ } else {
+ ortho_axis = Vector3(1.0, 0.0, 0.0).cross(axis);
+ }
+ ortho_axis = ortho_axis.normalized();
+ ortho_axis.rotate(axis, ring_random_angle);
+ ortho_axis = ortho_axis.normalized();
+ p.transform.origin = ortho_axis * ring_random_radius + (Math::randf() * emission_ring_height - emission_ring_height / 2.0) * axis;
+ } break;
case EMISSION_SHAPE_MAX: { // Max value for validity check.
break;
}
@@ -777,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);
}
@@ -834,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());
@@ -867,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();
@@ -877,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;
{
@@ -965,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;
@@ -1007,7 +1138,7 @@ void CPUParticles3D::_update_particle_data_buffer() {
sorter.sort(order, pc);
} else if (draw_order == DRAW_ORDER_VIEW_DEPTH) {
ERR_FAIL_NULL(get_viewport());
- Camera3D *c = get_viewport()->get_camera();
+ Camera3D *c = get_viewport()->get_camera_3d();
if (c) {
Vector3 dir = c->get_global_transform().basis.get_axis(2); //far away to close
@@ -1050,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;
@@ -1207,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);
@@ -1273,11 +1411,11 @@ void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("restart"), &CPUParticles3D::restart);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
ADD_GROUP("Time", "");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,exp"), "set_lifetime", "get_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01,exp"), "set_pre_process_time", "get_pre_process_time");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
@@ -1304,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);
@@ -1340,18 +1478,46 @@ void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emission_colors", "array"), &CPUParticles3D::set_emission_colors);
ClassDB::bind_method(D_METHOD("get_emission_colors"), &CPUParticles3D::get_emission_colors);
+ ClassDB::bind_method(D_METHOD("set_emission_ring_axis", "axis"), &CPUParticles3D::set_emission_ring_axis);
+ ClassDB::bind_method(D_METHOD("get_emission_ring_axis"), &CPUParticles3D::get_emission_ring_axis);
+
+ ClassDB::bind_method(D_METHOD("set_emission_ring_height", "height"), &CPUParticles3D::set_emission_ring_height);
+ ClassDB::bind_method(D_METHOD("get_emission_ring_height"), &CPUParticles3D::get_emission_ring_height);
+
+ ClassDB::bind_method(D_METHOD("set_emission_ring_radius", "radius"), &CPUParticles3D::set_emission_ring_radius);
+ ClassDB::bind_method(D_METHOD("get_emission_ring_radius"), &CPUParticles3D::get_emission_ring_radius);
+
+ ClassDB::bind_method(D_METHOD("set_emission_ring_inner_radius", "inner_radius"), &CPUParticles3D::set_emission_ring_inner_radius);
+ ClassDB::bind_method(D_METHOD("get_emission_ring_inner_radius"), &CPUParticles3D::get_emission_ring_inner_radius);
+
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_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points,Ring", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_points"), "set_emission_points", "get_emission_points");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_ring_axis"), "set_emission_ring_axis", "get_emission_ring_axis");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_height"), "set_emission_ring_height", "get_emission_ring_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_radius"), "set_emission_ring_radius", "get_emission_ring_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_inner_radius"), "set_emission_ring_inner_radius", "get_emission_ring_inner_radius");
ADD_GROUP("Particle Flags", "particle_flag_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_rotate_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ROTATE_Y);
@@ -1363,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"), "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);
@@ -1437,6 +1607,7 @@ void CPUParticles3D::_bind_methods() {
BIND_ENUM_CONSTANT(EMISSION_SHAPE_BOX);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_RING);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_MAX);
}
@@ -1450,28 +1621,40 @@ 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));
+ set_emission_ring_axis(Vector3(0, 0, 1.0));
+ set_emission_ring_height(1);
+ set_emission_ring_radius(1);
+ set_emission_ring_inner_radius(0);
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 b35e659757..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 {
@@ -76,6 +74,7 @@ public:
EMISSION_SHAPE_BOX,
EMISSION_SHAPE_POINTS,
EMISSION_SHAPE_DIRECTED_POINTS,
+ EMISSION_SHAPE_RING,
EMISSION_SHAPE_MAX
};
@@ -85,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;
@@ -131,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;
@@ -152,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);
@@ -165,17 +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;
+ 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;
@@ -195,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;
@@ -237,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;
@@ -262,20 +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(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;
+ 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 7d6abe458a..c94a99a203 100644
--- a/scene/3d/decal.cpp
+++ b/scene/3d/decal.cpp
@@ -33,7 +33,7 @@
void Decal::set_extents(const Vector3 &p_extents) {
extents = p_extents;
RS::get_singleton()->decal_set_extents(decal, p_extents);
- update_gizmo();
+ update_gizmos();
}
Vector3 Decal::get_extents() const {
@@ -45,6 +45,7 @@ void Decal::set_texture(DecalTexture p_type, const Ref<Texture2D> &p_texture) {
textures[p_type] = p_texture;
RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
RS::get_singleton()->decal_set_texture(decal, RS::DecalTexture(p_type), texture_rid);
+ update_configuration_warnings();
}
Ref<Texture2D> Decal::get_texture(DecalTexture p_type) const {
@@ -52,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;
}
@@ -116,27 +117,28 @@ 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;
}
void Decal::set_cull_mask(uint32_t p_layers) {
cull_mask = p_layers;
RS::get_singleton()->decal_set_cull_mask(decal, cull_mask);
+ update_configuration_warnings();
}
uint32_t Decal::get_cull_mask() const {
@@ -160,6 +162,27 @@ void Decal::_validate_property(PropertyInfo &property) const {
}
}
+TypedArray<String> Decal::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
+ if (textures[TEXTURE_ALBEDO].is_null() && textures[TEXTURE_NORMAL].is_null() && textures[TEXTURE_ORM].is_null() && textures[TEXTURE_EMISSION].is_null()) {
+ warnings.push_back(TTR("The decal has no textures loaded into any of its texture properties, and will therefore not be visible."));
+ }
+
+ if ((textures[TEXTURE_NORMAL].is_valid() || textures[TEXTURE_ORM].is_valid()) && textures[TEXTURE_ALBEDO].is_null()) {
+ warnings.push_back(TTR("The decal has a Normal and/or ORM texture, but no Albedo texture is set.\nAn Albedo texture with an alpha channel is required to blend the normal/ORM maps onto the underlying surface.\nIf you don't want the Albedo texture to be visible, set Albedo Mix to 0."));
+ }
+
+ if (cull_mask == 0) {
+ // NOTE: This warning will not be emitted if none of the 20 checkboxes
+ // exposed in the editor are checked. This is because there are
+ // currently 12 unexposed layers in the editor inspector.
+ warnings.push_back(TTR("The decal's Cull Mask has no bits enabled, which means the decal will not paint objects on any layer.\nTo resolve this, enable at least one bit in the Cull Mask property."));
+ }
+
+ return warnings;
+}
+
void Decal::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_extents", "extents"), &Decal::set_extents);
ClassDB::bind_method(D_METHOD("get_extents"), &Decal::get_extents);
@@ -207,7 +230,9 @@ void Decal::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_emission_energy", "get_emission_energy");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "albedo_mix", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_albedo_mix", "get_albedo_mix");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "normal_fade", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_normal_fade", "get_normal_fade");
+ // A Normal Fade of 1.0 causes the decal to be invisible even if fully perpendicular to a surface.
+ // Due to this, limit Normal Fade to 0.999.
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "normal_fade", PROPERTY_HINT_RANGE, "0,0.999,0.001"), "set_normal_fade", "get_normal_fade");
ADD_GROUP("Vertical Fade", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "upper_fade", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_upper_fade", "get_upper_fade");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lower_fade", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_lower_fade", "get_lower_fade");
diff --git a/scene/3d/decal.h b/scene/3d/decal.h
index ce19e76de1..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,54 +49,56 @@ 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();
void _validate_property(PropertyInfo &property) const override;
public:
+ virtual TypedArray<String> get_configuration_warnings() const override;
+
void set_extents(const Vector3 &p_extents);
Vector3 get_extents() const;
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 d7f4bfeb4e..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);
}
@@ -99,7 +96,7 @@ void GPUParticles3D::set_randomness_ratio(float p_ratio) {
void GPUParticles3D::set_visibility_aabb(const AABB &p_aabb) {
visibility_aabb = p_aabb;
RS::get_singleton()->particles_set_custom_aabb(particles, visibility_aabb);
- update_gizmo();
+ update_gizmos();
}
void GPUParticles3D::set_use_local_coordinates(bool p_enable) {
@@ -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\"."));
}
@@ -385,7 +384,7 @@ void GPUParticles3D::_validate_property(PropertyInfo &property) const {
if (property.name.begins_with("draw_pass_")) {
int index = property.name.get_slicec('_', 2).to_int() - 1;
if (index >= draw_passes.size()) {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NONE;
return;
}
}
@@ -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;
}
@@ -562,12 +562,12 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_transform_align"), &GPUParticles3D::get_transform_align);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "sub_emitter", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GPUParticles3D"), "set_sub_emitter", "get_sub_emitter");
ADD_GROUP("Time", "");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,exp"), "set_lifetime", "get_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01,exp"), "set_pre_process_time", "get_pre_process_time");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
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 322bc60fce..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_gizmo();
+ update_gizmos();
}
-float GPUParticlesCollisionSphere::get_radius() const {
+real_t GPUParticlesCollisionSphere::get_radius() const {
return radius;
}
@@ -103,7 +102,7 @@ void GPUParticlesCollisionBox::_bind_methods() {
void GPUParticlesCollisionBox::set_extents(const Vector3 &p_extents) {
extents = p_extents;
RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents);
- update_gizmo();
+ update_gizmos();
}
Vector3 GPUParticlesCollisionBox::get_extents() const {
@@ -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);
}
@@ -397,9 +396,7 @@ Ref<Image> GPUParticlesCollisionSDF::bake() {
bake_step_function(0, "Finding Meshes");
}
- for (List<PlotMesh>::Element *E = plot_meshes.front(); E; E = E->next()) {
- const PlotMesh &pm = E->get();
-
+ for (const PlotMesh &pm : plot_meshes) {
for (int i = 0; i < pm.mesh->get_surface_count(); i++) {
if (pm.mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
continue; //only triangles
@@ -423,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;
}
@@ -441,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;
}
@@ -495,7 +492,7 @@ Ref<Image> GPUParticlesCollisionSDF::bake() {
_compute_sdf(&params);
Ref<Image> ret;
- ret.instance();
+ ret.instantiate();
ret->create(sdf_size.x, sdf_size.y * sdf_size.z, false, Image::FORMAT_RF, data);
ret->convert(Image::FORMAT_RH); //convert to half, save space
ret->set_meta("depth", sdf_size.z); //hack, make sure to add to the docs of this function
@@ -545,7 +542,7 @@ float GPUParticlesCollisionSDF::get_thickness() const {
void GPUParticlesCollisionSDF::set_extents(const Vector3 &p_extents) {
extents = p_extents;
RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents);
- update_gizmo();
+ update_gizmos();
}
Vector3 GPUParticlesCollisionSDF::get_extents() const {
@@ -554,7 +551,7 @@ Vector3 GPUParticlesCollisionSDF::get_extents() const {
void GPUParticlesCollisionSDF::set_resolution(Resolution p_resolution) {
resolution = p_resolution;
- update_gizmo();
+ update_gizmos();
}
GPUParticlesCollisionSDF::Resolution GPUParticlesCollisionSDF::get_resolution() const {
@@ -596,7 +593,7 @@ void GPUParticlesCollisionHeightField::_notification(int p_what) {
}
if (follow_camera_mode && get_viewport()) {
- Camera3D *cam = get_viewport()->get_camera();
+ Camera3D *cam = get_viewport()->get_camera_3d();
if (cam) {
Transform3D xform = get_global_transform();
Vector3 x_axis = xform.basis.get_axis(Vector3::AXIS_X).normalized();
@@ -680,7 +677,7 @@ float GPUParticlesCollisionHeightField::get_follow_camera_push_ratio() const {
void GPUParticlesCollisionHeightField::set_extents(const Vector3 &p_extents) {
extents = p_extents;
RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents);
- update_gizmo();
+ update_gizmos();
RS::get_singleton()->particles_collision_height_field_update(_get_collision());
}
@@ -691,7 +688,7 @@ Vector3 GPUParticlesCollisionHeightField::get_extents() const {
void GPUParticlesCollisionHeightField::set_resolution(Resolution p_resolution) {
resolution = p_resolution;
RS::get_singleton()->particles_collision_set_height_field_resolution(_get_collision(), RS::ParticlesCollisionHeightfieldResolution(resolution));
- update_gizmo();
+ update_gizmos();
RS::get_singleton()->particles_collision_height_field_update(_get_collision());
}
@@ -740,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_gizmo();
+ update_gizmos();
}
-float GPUParticlesAttractor3D::get_directionality() const {
+real_t GPUParticlesAttractor3D::get_directionality() const {
return directionality;
}
@@ -805,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_gizmo();
+ update_gizmos();
}
-float GPUParticlesAttractorSphere::get_radius() const {
+real_t GPUParticlesAttractorSphere::get_radius() const {
return radius;
}
@@ -838,7 +835,7 @@ void GPUParticlesAttractorBox::_bind_methods() {
void GPUParticlesAttractorBox::set_extents(const Vector3 &p_extents) {
extents = p_extents;
RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents);
- update_gizmo();
+ update_gizmos();
}
Vector3 GPUParticlesAttractorBox::get_extents() const {
@@ -872,7 +869,7 @@ void GPUParticlesAttractorVectorField::_bind_methods() {
void GPUParticlesAttractorVectorField::set_extents(const Vector3 &p_extents) {
extents = p_extents;
RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents);
- update_gizmo();
+ update_gizmos();
}
Vector3 GPUParticlesAttractorVectorField::get_extents() const {
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/immediate_geometry_3d.cpp b/scene/3d/immediate_geometry_3d.cpp
deleted file mode 100644
index d64babaa9d..0000000000
--- a/scene/3d/immediate_geometry_3d.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/*************************************************************************/
-/* immediate_geometry_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 "immediate_geometry_3d.h"
-
-void ImmediateGeometry3D::begin(Mesh::PrimitiveType p_primitive, const Ref<Texture2D> &p_texture) {
- RS::get_singleton()->immediate_begin(im, (RS::PrimitiveType)p_primitive, p_texture.is_valid() ? p_texture->get_rid() : RID());
- if (p_texture.is_valid()) {
- cached_textures.push_back(p_texture);
- }
-}
-
-void ImmediateGeometry3D::set_normal(const Vector3 &p_normal) {
- RS::get_singleton()->immediate_normal(im, p_normal);
-}
-
-void ImmediateGeometry3D::set_tangent(const Plane &p_tangent) {
- RS::get_singleton()->immediate_tangent(im, p_tangent);
-}
-
-void ImmediateGeometry3D::set_color(const Color &p_color) {
- RS::get_singleton()->immediate_color(im, p_color);
-}
-
-void ImmediateGeometry3D::set_uv(const Vector2 &p_uv) {
- RS::get_singleton()->immediate_uv(im, p_uv);
-}
-
-void ImmediateGeometry3D::set_uv2(const Vector2 &p_uv2) {
- RS::get_singleton()->immediate_uv2(im, p_uv2);
-}
-
-void ImmediateGeometry3D::add_vertex(const Vector3 &p_vertex) {
- RS::get_singleton()->immediate_vertex(im, p_vertex);
- if (empty) {
- aabb.position = p_vertex;
- aabb.size = Vector3();
- empty = false;
- } else {
- aabb.expand_to(p_vertex);
- }
-}
-
-void ImmediateGeometry3D::end() {
- RS::get_singleton()->immediate_end(im);
-}
-
-void ImmediateGeometry3D::clear() {
- RS::get_singleton()->immediate_clear(im);
- empty = true;
- cached_textures.clear();
-}
-
-AABB ImmediateGeometry3D::get_aabb() const {
- return aabb;
-}
-
-Vector<Face3> ImmediateGeometry3D::get_faces(uint32_t p_usage_flags) const {
- return Vector<Face3>();
-}
-
-void ImmediateGeometry3D::add_sphere(int p_lats, int p_lons, float p_radius, bool p_add_uv) {
- const double lat_step = Math_TAU / p_lats;
- const double lon_step = Math_TAU / p_lons;
-
- for (int i = 1; i <= p_lats; i++) {
- double lat0 = lat_step * (i - 1) - Math_TAU / 4;
- double z0 = Math::sin(lat0);
- double zr0 = Math::cos(lat0);
-
- double lat1 = lat_step * i - Math_TAU / 4;
- double z1 = Math::sin(lat1);
- double zr1 = Math::cos(lat1);
-
- for (int j = p_lons; j >= 1; j--) {
- double lng0 = lon_step * (j - 1);
- double x0 = Math::cos(lng0);
- double y0 = Math::sin(lng0);
-
- double lng1 = lon_step * j;
- double x1 = Math::cos(lng1);
- double y1 = Math::sin(lng1);
-
- Vector3 v[4] = {
- Vector3(x1 * zr0, z0, y1 * zr0),
- Vector3(x1 * zr1, z1, y1 * zr1),
- Vector3(x0 * zr1, z1, y0 * zr1),
- Vector3(x0 * zr0, z0, y0 * zr0)
- };
-
-#define ADD_POINT(m_idx) \
- if (p_add_uv) { \
- set_uv(Vector2(Math::atan2(v[m_idx].x, v[m_idx].z) / Math_PI * 0.5 + 0.5, v[m_idx].y * 0.5 + 0.5)); \
- set_tangent(Plane(Vector3(-v[m_idx].z, v[m_idx].y, v[m_idx].x), 1)); \
- } \
- set_normal(v[m_idx]); \
- add_vertex(v[m_idx] * p_radius);
-
- ADD_POINT(0);
- ADD_POINT(1);
- ADD_POINT(2);
-
- ADD_POINT(2);
- ADD_POINT(3);
- ADD_POINT(0);
- }
- }
-}
-
-void ImmediateGeometry3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("begin", "primitive", "texture"), &ImmediateGeometry3D::begin, DEFVAL(Ref<Texture2D>()));
- ClassDB::bind_method(D_METHOD("set_normal", "normal"), &ImmediateGeometry3D::set_normal);
- ClassDB::bind_method(D_METHOD("set_tangent", "tangent"), &ImmediateGeometry3D::set_tangent);
- ClassDB::bind_method(D_METHOD("set_color", "color"), &ImmediateGeometry3D::set_color);
- ClassDB::bind_method(D_METHOD("set_uv", "uv"), &ImmediateGeometry3D::set_uv);
- ClassDB::bind_method(D_METHOD("set_uv2", "uv"), &ImmediateGeometry3D::set_uv2);
- ClassDB::bind_method(D_METHOD("add_vertex", "position"), &ImmediateGeometry3D::add_vertex);
- ClassDB::bind_method(D_METHOD("add_sphere", "lats", "lons", "radius", "add_uv"), &ImmediateGeometry3D::add_sphere, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("end"), &ImmediateGeometry3D::end);
- ClassDB::bind_method(D_METHOD("clear"), &ImmediateGeometry3D::clear);
-}
-
-ImmediateGeometry3D::ImmediateGeometry3D() {
- im = RenderingServer::get_singleton()->immediate_create();
- set_base(im);
-}
-
-ImmediateGeometry3D::~ImmediateGeometry3D() {
- RenderingServer::get_singleton()->free(im);
-}
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/immediate_geometry_3d.h b/scene/3d/importer_mesh_instance_3d.h
index ee4938d9f7..0cf7dbe86b 100644
--- a/scene/3d/immediate_geometry_3d.h
+++ b/scene/3d/importer_mesh_instance_3d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* immediate_geometry_3d.h */
+/* importer_mesh_instance_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,45 +28,37 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef IMMEDIATE_GEOMETRY_3D_H
-#define IMMEDIATE_GEOMETRY_3D_H
+#ifndef SCENE_IMPORTER_MESH_INSTANCE_3D_H
+#define SCENE_IMPORTER_MESH_INSTANCE_3D_H
-#include "scene/3d/visual_instance_3d.h"
-#include "scene/resources/mesh.h"
+#include "scene/3d/node_3d.h"
+#include "scene/resources/immediate_mesh.h"
+#include "scene/resources/skin.h"
-class ImmediateGeometry3D : public GeometryInstance3D {
- GDCLASS(ImmediateGeometry3D, GeometryInstance3D);
+class ImporterMesh;
- RID im;
- //a list of textures drawn need to be kept, to avoid references
- // in RenderingServer from becoming invalid if the texture is no longer used
- List<Ref<Texture2D>> cached_textures;
- bool empty = true;
- AABB aabb;
+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 begin(Mesh::PrimitiveType p_primitive, const Ref<Texture2D> &p_texture = Ref<Texture2D>());
- void set_normal(const Vector3 &p_normal);
- void set_tangent(const Plane &p_tangent);
- void set_color(const Color &p_color);
- void set_uv(const Vector2 &p_uv);
- void set_uv2(const Vector2 &p_uv2);
-
- void add_vertex(const Vector3 &p_vertex);
+ void set_mesh(const Ref<ImporterMesh> &p_mesh);
+ Ref<ImporterMesh> get_mesh() const;
- void end();
- void clear();
+ void set_skin(const Ref<Skin> &p_skin);
+ Ref<Skin> get_skin() const;
- void add_sphere(int p_lats, int p_lons, float p_radius, bool p_add_uv = true);
+ void set_surface_material(int p_idx, const Ref<Material> &p_material);
+ Ref<Material> get_surface_material(int p_idx) const;
- virtual AABB get_aabb() const override;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
-
- ImmediateGeometry3D();
- ~ImmediateGeometry3D();
+ void set_skeleton_path(const NodePath &p_path);
+ NodePath get_skeleton_path() const;
};
-
-#endif // IMMEDIATE_GEOMETRY_H
+#endif
diff --git a/scene/3d/physics_joint_3d.cpp b/scene/3d/joint_3d.cpp
index 01f10c171f..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;
}
@@ -348,7 +348,7 @@ void HingeJoint3D::set_param(Param p_param, real_t p_value) {
PhysicsServer3D::get_singleton()->hinge_joint_set_param(get_joint(), PhysicsServer3D::HingeJointParam(p_param), p_value);
}
- update_gizmo();
+ update_gizmos();
}
real_t HingeJoint3D::get_param(Param p_param) const {
@@ -363,7 +363,7 @@ void HingeJoint3D::set_flag(Flag p_flag, bool p_value) {
PhysicsServer3D::get_singleton()->hinge_joint_set_flag(get_joint(), PhysicsServer3D::HingeJointFlag(p_flag), p_value);
}
- update_gizmo();
+ update_gizmos();
}
bool HingeJoint3D::get_flag(Flag p_flag) const {
@@ -497,7 +497,7 @@ void SliderJoint3D::set_param(Param p_param, real_t p_value) {
if (is_configured()) {
PhysicsServer3D::get_singleton()->slider_joint_set_param(get_joint(), PhysicsServer3D::SliderJointParam(p_param), p_value);
}
- update_gizmo();
+ update_gizmos();
}
real_t SliderJoint3D::get_param(Param p_param) const {
@@ -602,7 +602,7 @@ void ConeTwistJoint3D::set_param(Param p_param, real_t p_value) {
PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(get_joint(), PhysicsServer3D::ConeTwistJointParam(p_param), p_value);
}
- update_gizmo();
+ update_gizmos();
}
real_t ConeTwistJoint3D::get_param(Param p_param) const {
@@ -857,7 +857,7 @@ void Generic6DOFJoint3D::set_param_x(Param p_param, real_t p_value) {
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
}
- update_gizmo();
+ update_gizmos();
}
real_t Generic6DOFJoint3D::get_param_x(Param p_param) const {
@@ -871,7 +871,7 @@ void Generic6DOFJoint3D::set_param_y(Param p_param, real_t p_value) {
if (is_configured()) {
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
}
- update_gizmo();
+ update_gizmos();
}
real_t Generic6DOFJoint3D::get_param_y(Param p_param) const {
@@ -885,7 +885,7 @@ void Generic6DOFJoint3D::set_param_z(Param p_param, real_t p_value) {
if (is_configured()) {
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
}
- update_gizmo();
+ update_gizmos();
}
real_t Generic6DOFJoint3D::get_param_z(Param p_param) const {
@@ -899,7 +899,7 @@ void Generic6DOFJoint3D::set_flag_x(Flag p_flag, bool p_enabled) {
if (is_configured()) {
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled);
}
- update_gizmo();
+ update_gizmos();
}
bool Generic6DOFJoint3D::get_flag_x(Flag p_flag) const {
@@ -913,7 +913,7 @@ void Generic6DOFJoint3D::set_flag_y(Flag p_flag, bool p_enabled) {
if (is_configured()) {
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled);
}
- update_gizmo();
+ update_gizmos();
}
bool Generic6DOFJoint3D::get_flag_y(Flag p_flag) const {
@@ -927,7 +927,7 @@ void Generic6DOFJoint3D::set_flag_z(Flag p_flag, bool p_enabled) {
if (is_configured()) {
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled);
}
- update_gizmo();
+ update_gizmos();
}
bool Generic6DOFJoint3D::get_flag_z(Flag p_flag) const {
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 d45749d36b..c787ba5087 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -30,22 +30,14 @@
#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;
RS::get_singleton()->light_set_param(light, RS::LightParam(p_param), p_value);
if (p_param == PARAM_SPOT_ANGLE || p_param == PARAM_RANGE) {
- update_gizmo();
+ update_gizmos();
if (p_param == PARAM_SPOT_ANGLE) {
update_configuration_warnings();
@@ -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];
}
@@ -95,7 +87,7 @@ void Light3D::set_color(const Color &p_color) {
color = p_color;
RS::get_singleton()->light_set_color(light, p_color);
// The gizmo color depends on the light color, so update it.
- update_gizmo();
+ update_gizmos();
}
Color Light3D::get_color() const {
@@ -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));
}
@@ -209,19 +201,19 @@ void Light3D::_validate_property(PropertyInfo &property) const {
}
if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_size") {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NONE;
}
if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_specular") {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NONE;
}
if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_projector") {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NONE;
}
if (get_light_type() != RS::LIGHT_DIRECTIONAL && property.name == "light_angular_distance") {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NONE;
}
}
@@ -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);
@@ -353,7 +345,7 @@ Light3D::Light3D(RenderingServer::LightType p_type) {
}
Light3D::Light3D() {
- ERR_PRINT("Light3D should not be instanced directly; use the DirectionalLight3D, OmniLight3D or SpotLight3D subtypes instead.");
+ ERR_PRINT("Light3D should not be instantiated directly; use the DirectionalLight3D, OmniLight3D or SpotLight3D subtypes instead.");
}
Light3D::~Light3D() {
@@ -375,15 +367,6 @@ DirectionalLight3D::ShadowMode DirectionalLight3D::get_shadow_mode() const {
return shadow_mode;
}
-void DirectionalLight3D::set_shadow_depth_range(ShadowDepthRange p_range) {
- shadow_depth_range = p_range;
- RS::get_singleton()->light_directional_set_shadow_depth_range_mode(light, RS::LightDirectionalShadowDepthRangeMode(p_range));
-}
-
-DirectionalLight3D::ShadowDepthRange DirectionalLight3D::get_shadow_depth_range() const {
- return shadow_depth_range;
-}
-
void DirectionalLight3D::set_blend_splits(bool p_enable) {
blend_splits = p_enable;
RS::get_singleton()->light_directional_set_blend_splits(light, p_enable);
@@ -406,9 +389,6 @@ void DirectionalLight3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shadow_mode", "mode"), &DirectionalLight3D::set_shadow_mode);
ClassDB::bind_method(D_METHOD("get_shadow_mode"), &DirectionalLight3D::get_shadow_mode);
- ClassDB::bind_method(D_METHOD("set_shadow_depth_range", "mode"), &DirectionalLight3D::set_shadow_depth_range);
- ClassDB::bind_method(D_METHOD("get_shadow_depth_range"), &DirectionalLight3D::get_shadow_depth_range);
-
ClassDB::bind_method(D_METHOD("set_blend_splits", "enabled"), &DirectionalLight3D::set_blend_splits);
ClassDB::bind_method(D_METHOD("is_blend_splits_enabled"), &DirectionalLight3D::is_blend_splits_enabled);
@@ -422,18 +402,14 @@ void DirectionalLight3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_split_3", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_3_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_fade_start", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_FADE_START);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "directional_shadow_blend_splits"), "set_blend_splits", "is_blend_splits_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_depth_range", PROPERTY_HINT_ENUM, "Stable,Optimized"), "set_shadow_depth_range", "get_shadow_depth_range");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_max_distance", PROPERTY_HINT_EXP_RANGE, "0,8192,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_pancake_size", PROPERTY_HINT_EXP_RANGE, "0,1024,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_PANCAKE_SIZE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_max_distance", PROPERTY_HINT_RANGE, "0,8192,0.1,or_greater,exp"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_pancake_size", PROPERTY_HINT_RANGE, "0,1024,0.1,or_greater,exp"), "set_param", "get_param", PARAM_SHADOW_PANCAKE_SIZE);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_in_sky_only"), "set_sky_only", "is_sky_only");
BIND_ENUM_CONSTANT(SHADOW_ORTHOGONAL);
BIND_ENUM_CONSTANT(SHADOW_PARALLEL_2_SPLITS);
BIND_ENUM_CONSTANT(SHADOW_PARALLEL_4_SPLITS);
-
- BIND_ENUM_CONSTANT(SHADOW_DEPTH_RANGE_STABLE);
- BIND_ENUM_CONSTANT(SHADOW_DEPTH_RANGE_OPTIMIZED);
}
DirectionalLight3D::DirectionalLight3D() :
@@ -441,10 +417,8 @@ 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);
- set_shadow_depth_range(SHADOW_DEPTH_RANGE_STABLE);
blend_splits = false;
}
@@ -472,7 +446,7 @@ void OmniLight3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_shadow_mode"), &OmniLight3D::get_shadow_mode);
ADD_GROUP("Omni", "omni_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "omni_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "omni_range", PROPERTY_HINT_RANGE, "0,4096,0.1,or_greater,exp"), "set_param", "get_param", PARAM_RANGE);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "omni_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION);
ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_mode", PROPERTY_HINT_ENUM, "Dual Paraboloid,Cube"), "set_shadow_mode", "get_shadow_mode");
@@ -484,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 {
@@ -504,8 +477,8 @@ TypedArray<String> SpotLight3D::get_configuration_warnings() const {
void SpotLight3D::_bind_methods() {
ADD_GROUP("Spot", "spot_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_range", PROPERTY_HINT_RANGE, "0,4096,0.1,or_greater,exp"), "set_param", "get_param", PARAM_RANGE);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_angle", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_param", "get_param", PARAM_SPOT_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_angle", PROPERTY_HINT_RANGE, "0,180,0.1,degrees"), "set_param", "get_param", PARAM_SPOT_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_angle_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_SPOT_ATTENUATION);
}
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index e145b08b74..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;
@@ -149,15 +145,9 @@ public:
SHADOW_PARALLEL_4_SPLITS,
};
- enum ShadowDepthRange {
- SHADOW_DEPTH_RANGE_STABLE = RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE,
- SHADOW_DEPTH_RANGE_OPTIMIZED = RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED,
- };
-
private:
bool blend_splits;
ShadowMode shadow_mode;
- ShadowDepthRange shadow_depth_range;
bool sky_only = false;
protected:
@@ -167,9 +157,6 @@ public:
void set_shadow_mode(ShadowMode p_mode);
ShadowMode get_shadow_mode() const;
- void set_shadow_depth_range(ShadowDepthRange p_range);
- ShadowDepthRange get_shadow_depth_range() const;
-
void set_blend_splits(bool p_enable);
bool is_blend_splits_enabled() const;
@@ -180,7 +167,6 @@ public:
};
VARIANT_ENUM_CAST(DirectionalLight3D::ShadowMode)
-VARIANT_ENUM_CAST(DirectionalLight3D::ShadowDepthRange)
class OmniLight3D : public Light3D {
GDCLASS(OmniLight3D, Light3D);
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index cc1177d541..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/resource_saver.h"
-#include "core/math/camera_matrix.h"
#include "core/math/delaunay_3d.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.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;
}
@@ -599,7 +594,7 @@ void LightmapGI::_gen_new_positions_from_octree(const GenProbesOctree *p_cell, f
const Vector3 *pp = probe_positions.ptr();
bool exists = false;
for (int j = 0; j < ppcount; j++) {
- if (pp[j].distance_to(real_pos) < CMP_EPSILON) {
+ if (pp[j].is_equal_approx(real_pos)) {
exists = true;
break;
}
@@ -717,7 +712,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
w_albedo[i + 3] = 255;
}
- md.albedo_on_uv2.instance();
+ md.albedo_on_uv2.instantiate();
md.albedo_on_uv2->create(lightmap_size.width, lightmap_size.height, false, Image::FORMAT_RGBA8, albedom);
}
@@ -940,7 +935,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
} break;
case ENVIRONMENT_MODE_CUSTOM_COLOR: {
- environment_image.instance();
+ environment_image.instantiate();
environment_image->create(128, 64, false, Image::FORMAT_RGBAF);
Color c = environment_custom_color;
c.r *= environment_custom_energy;
@@ -972,7 +967,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
}
//we assume they are all the same, so let's create a large one for saving
Ref<Image> large_image;
- large_image.instance();
+ large_image.instantiate();
large_image->create(images[0]->get_width(), images[0]->get_height() * images.size(), false, images[0]->get_format());
@@ -984,7 +979,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
Ref<ConfigFile> config;
- config.instance();
+ config.instantiate();
if (FileAccess::exists(base_path + ".import")) {
config->load(base_path + ".import");
}
@@ -1017,7 +1012,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
set_light_data(Ref<LightmapGIData>()); //clear
data->clear();
} else {
- data.instance();
+ data.instantiate();
}
data->set_light_texture(texture);
@@ -1250,7 +1245,7 @@ void LightmapGI::set_light_data(const Ref<LightmapGIData> &p_data) {
}
}
- update_gizmo();
+ update_gizmos();
}
Ref<LightmapGIData> LightmapGI::get_light_data() const {
@@ -1367,13 +1362,13 @@ LightmapGI::GenerateProbes LightmapGI::get_generate_probes() const {
void LightmapGI::_validate_property(PropertyInfo &property) const {
if (property.name == "environment_custom_sky" && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NONE;
}
if (property.name == "environment_custom_color" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR) {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NONE;
}
if (property.name == "environment_custom_energy" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NONE;
}
}
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 f63515f666..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)
@@ -44,8 +45,8 @@
#endif
-class LightmapDenoiser : public Reference {
- GDCLASS(LightmapDenoiser, Reference)
+class LightmapDenoiser : public RefCounted {
+ GDCLASS(LightmapDenoiser, RefCounted)
protected:
static LightmapDenoiser *(*create_function)();
@@ -54,8 +55,8 @@ public:
static Ref<LightmapDenoiser> create();
};
-class LightmapRaycaster : public Reference {
- GDCLASS(LightmapRaycaster, Reference)
+class LightmapRaycaster : public RefCounted {
+ GDCLASS(LightmapRaycaster, RefCounted)
protected:
static LightmapRaycaster *(*create_function)();
@@ -121,8 +122,8 @@ public:
static Ref<LightmapRaycaster> create();
};
-class Lightmapper : public Reference {
- GDCLASS(Lightmapper, Reference)
+class Lightmapper : public RefCounted {
+ GDCLASS(Lightmapper, RefCounted)
public:
enum GenerateProbes {
GENERATE_PROBES_DISABLED,
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index c495f68890..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,19 +86,19 @@ 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();
- for (List<String>::Element *E = ls.front(); E; E = E->next()) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, E->get(), PROPERTY_HINT_RANGE, "-1,1,0.00001"));
+ for (const String &E : ls) {
+ p_list->push_back(PropertyInfo(Variant::FLOAT, E, PROPERTY_HINT_RANGE, "-1,1,0.00001"));
}
if (mesh.is_valid()) {
for (int i = 0; i < mesh->get_surface_count(); i++) {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_material_override/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_material_override/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE));
}
}
}
@@ -133,7 +131,7 @@ void MeshInstance3D::set_mesh(const Ref<Mesh> &p_mesh) {
set_base(RID());
}
- update_gizmo();
+ update_gizmos();
notify_property_list_changed();
}
@@ -241,12 +239,12 @@ void MeshInstance3D::create_trimesh_collision() {
}
}
-Node *MeshInstance3D::create_convex_collision_node() {
+Node *MeshInstance3D::create_convex_collision_node(bool p_clean, bool p_simplify) {
if (mesh.is_null()) {
return nullptr;
}
- Ref<Shape3D> shape = mesh->create_convex_shape();
+ Ref<Shape3D> shape = mesh->create_convex_shape(p_clean, p_simplify);
if (shape.is_null()) {
return nullptr;
}
@@ -258,8 +256,8 @@ Node *MeshInstance3D::create_convex_collision_node() {
return static_body;
}
-void MeshInstance3D::create_convex_collision() {
- StaticBody3D *static_body = Object::cast_to<StaticBody3D>(create_convex_collision_node());
+void MeshInstance3D::create_convex_collision(bool p_clean, bool p_simplify) {
+ StaticBody3D *static_body = Object::cast_to<StaticBody3D>(create_convex_collision_node(p_clean, p_simplify));
ERR_FAIL_COND(!static_body);
static_body->set_name(String(get_name()) + "_col");
@@ -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;
}
@@ -356,7 +355,7 @@ Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
void MeshInstance3D::_mesh_changed() {
ERR_FAIL_COND(mesh.is_null());
surface_override_materials.resize(mesh->get_surface_count());
- update_gizmo();
+ update_gizmos();
}
void MeshInstance3D::create_debug_tangents() {
@@ -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) {
@@ -405,14 +406,14 @@ void MeshInstance3D::create_debug_tangents() {
if (lines.size()) {
Ref<StandardMaterial3D> sm;
- sm.instance();
+ sm.instantiate();
sm->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
sm->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
sm->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
Ref<ArrayMesh> am;
- am.instance();
+ am.instantiate();
Array a;
a.resize(Mesh::ARRAY_MAX);
a[Mesh::ARRAY_VERTEX] = lines;
@@ -451,7 +452,7 @@ void MeshInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_trimesh_collision"), &MeshInstance3D::create_trimesh_collision);
ClassDB::set_method_flags("MeshInstance3D", "create_trimesh_collision", METHOD_FLAGS_DEFAULT);
- ClassDB::bind_method(D_METHOD("create_convex_collision"), &MeshInstance3D::create_convex_collision);
+ ClassDB::bind_method(D_METHOD("create_convex_collision", "clean", "simplify"), &MeshInstance3D::create_convex_collision, DEFVAL(true), DEFVAL(false));
ClassDB::set_method_flags("MeshInstance3D", "create_convex_collision", METHOD_FLAGS_DEFAULT);
ClassDB::bind_method(D_METHOD("create_multiple_convex_collisions"), &MeshInstance3D::create_multiple_convex_collisions);
ClassDB::set_method_flags("MeshInstance3D", "create_multiple_convex_collisions", METHOD_FLAGS_DEFAULT);
diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h
index 9dea5804e0..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);
@@ -83,8 +83,8 @@ public:
Node *create_trimesh_collision_node();
void create_trimesh_collision();
- Node *create_convex_collision_node();
- void create_convex_collision();
+ Node *create_convex_collision_node(bool p_clean = true, bool p_simplify = false);
+ void create_convex_collision(bool p_clean = true, bool p_simplify = false);
Node *create_multiple_convex_collisions_node();
void create_multiple_convex_collisions();
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index 64cfe4dca7..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() {
@@ -242,7 +241,7 @@ void NavigationAgent3D::_avoidance_done(Vector3 p_new_velocity) {
}
velocity_submitted = false;
- emit_signal("velocity_computed", p_new_velocity);
+ emit_signal(SNAME("velocity_computed"), p_new_velocity);
}
TypedArray<String> NavigationAgent3D::get_configuration_warnings() const {
@@ -296,7 +295,7 @@ void NavigationAgent3D::update_navigation() {
navigation_path = NavigationServer3D::get_singleton()->map_get_path(agent_parent->get_world_3d()->get_navigation_map(), o, target_location, true);
navigation_finished = false;
nav_path_index = 0;
- emit_signal("path_changed");
+ emit_signal(SNAME("path_changed"));
}
if (navigation_path.size() == 0) {
@@ -312,7 +311,7 @@ void NavigationAgent3D::update_navigation() {
_check_distance_to_target();
nav_path_index -= 1;
navigation_finished = true;
- emit_signal("navigation_finished");
+ emit_signal(SNAME("navigation_finished"));
break;
}
}
@@ -322,7 +321,7 @@ void NavigationAgent3D::update_navigation() {
void NavigationAgent3D::_check_distance_to_target() {
if (!target_reached) {
if (distance_to_target() < target_desired_distance) {
- emit_signal("target_reached");
+ emit_signal(SNAME("target_reached"));
target_reached = true;
}
}
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 0afad62404..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"
@@ -59,7 +58,7 @@ void NavigationRegion3D::set_enabled(bool p_enabled) {
}
}
- update_gizmo();
+ update_gizmos();
}
bool NavigationRegion3D::is_enabled() const {
@@ -132,9 +131,9 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes
Object::cast_to<MeshInstance3D>(debug_view)->set_mesh(navmesh->get_debug_mesh());
}
- emit_signal("navigation_mesh_changed");
+ emit_signal(SNAME("navigation_mesh_changed"));
- update_gizmo();
+ update_gizmos();
update_configuration_warnings();
}
@@ -153,11 +152,11 @@ void _bake_navigation_mesh(void *p_user_data) {
Ref<NavigationMesh> nav_mesh = args->nav_region->get_navigation_mesh()->duplicate();
NavigationServer3D::get_singleton()->region_bake_navmesh(nav_mesh, args->nav_region);
- args->nav_region->call_deferred("_bake_finished", nav_mesh);
+ args->nav_region->call_deferred(SNAME("_bake_finished"), nav_mesh);
memdelete(args);
} else {
ERR_PRINT("Can't bake the navigation mesh if the `NavigationMesh` resource doesn't exist");
- args->nav_region->call_deferred("_bake_finished", Ref<NavigationMesh>());
+ args->nav_region->call_deferred(SNAME("_bake_finished"), Ref<NavigationMesh>());
memdelete(args);
}
}
@@ -174,7 +173,7 @@ void NavigationRegion3D::bake_navigation_mesh() {
void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) {
set_navigation_mesh(p_nav_mesh);
bake_thread.wait_to_finish();
- emit_signal("bake_finished");
+ emit_signal(SNAME("bake_finished"));
}
TypedArray<String> NavigationRegion3D::get_configuration_warnings() const {
@@ -211,7 +210,7 @@ void NavigationRegion3D::_bind_methods() {
}
void NavigationRegion3D::_navigation_changed() {
- update_gizmo();
+ update_gizmos();
update_configuration_warnings();
}
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 e96e4df55c..272a06bce4 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -30,10 +30,9 @@
#include "node_3d.h"
-#include "core/config/engine.h"
#include "core/object/message_queue.h"
-#include "scene/main/scene_tree.h"
-#include "scene/main/window.h"
+#include "scene/3d/visual_instance_3d.h"
+#include "scene/main/viewport.h"
#include "scene/scene_string_names.h"
/*
@@ -75,7 +74,7 @@ Node3DGizmo::Node3DGizmo() {
void Node3D::_notify_dirty() {
#ifdef TOOLS_ENABLED
- if ((data.gizmo.is_valid() || data.notify_transform) && !data.ignore_notification && !xform_change.in_list()) {
+ if ((!data.gizmos.is_empty() || data.notify_transform) && !data.ignore_notification && !xform_change.in_list()) {
#else
if (data.notify_transform && !data.ignore_notification && !xform_change.in_list()) {
@@ -102,14 +101,14 @@ void Node3D::_propagate_transform_changed(Node3D *p_origin) {
data.children_lock++;
- for (List<Node3D *>::Element *E = data.children.front(); E; E = E->next()) {
- if (E->get()->data.top_level_active) {
+ for (Node3D *&E : data.children) {
+ if (E->data.top_level_active) {
continue; //don't propagate to a top_level
}
- E->get()->_propagate_transform_changed(p_origin);
+ E->_propagate_transform_changed(p_origin);
}
#ifdef TOOLS_ENABLED
- if ((data.gizmo.is_valid() || data.notify_transform) && !data.ignore_notification && !xform_change.in_list()) {
+ if ((!data.gizmos.is_empty() || data.notify_transform) && !data.ignore_notification && !xform_change.in_list()) {
#else
if (data.notify_transform && !data.ignore_notification && !xform_change.in_list()) {
#endif
@@ -148,6 +147,7 @@ void Node3D::_notification(int p_what) {
_notify_dirty();
notification(NOTIFICATION_ENTER_WORLD);
+ _update_visibility_parent(true);
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -161,6 +161,7 @@ void Node3D::_notification(int p_what) {
data.parent = nullptr;
data.C = nullptr;
data.top_level_active = false;
+ _update_visibility_parent(true);
} break;
case NOTIFICATION_ENTER_WORLD: {
data.inside_world = true;
@@ -178,15 +179,14 @@ void Node3D::_notification(int p_what) {
}
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) {
- //get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this);
get_tree()->call_group_flags(0, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this);
- if (!data.gizmo_disabled) {
- if (data.gizmo.is_valid()) {
- data.gizmo->create();
+ if (!data.gizmos_disabled) {
+ for (int i = 0; i < data.gizmos.size(); i++) {
+ data.gizmos.write[i]->create();
if (is_visible_in_tree()) {
- data.gizmo->redraw();
+ data.gizmos.write[i]->redraw();
}
- data.gizmo->transform();
+ data.gizmos.write[i]->transform();
}
}
}
@@ -195,10 +195,7 @@ void Node3D::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_WORLD: {
#ifdef TOOLS_ENABLED
- if (data.gizmo.is_valid()) {
- data.gizmo->free();
- data.gizmo.unref();
- }
+ clear_gizmos();
#endif
if (get_script_instance()) {
@@ -212,8 +209,8 @@ void Node3D::_notification(int p_what) {
case NOTIFICATION_TRANSFORM_CHANGED: {
#ifdef TOOLS_ENABLED
- if (data.gizmo.is_valid()) {
- data.gizmo->transform();
+ for (int i = 0; i < data.gizmos.size(); i++) {
+ data.gizmos.write[i]->transform();
}
#endif
} break;
@@ -282,8 +279,12 @@ Transform3D Node3D::get_local_gizmo_transform() const {
}
#endif
-Node3D *Node3D::get_parent_spatial() const {
- return data.parent;
+Node3D *Node3D::get_parent_node_3d() const {
+ if (data.top_level) {
+ return nullptr;
+ }
+
+ return Object::cast_to<Node3D>(get_parent());
}
Transform3D Node3D::get_relative_transform(const Node *p_parent) const {
@@ -321,10 +322,6 @@ void Node3D::set_rotation(const Vector3 &p_euler_rad) {
}
}
-void Node3D::set_rotation_degrees(const Vector3 &p_euler_deg) {
- set_rotation(p_euler_deg * (Math_PI / 180.0));
-}
-
void Node3D::set_scale(const Vector3 &p_scale) {
if (data.dirty & DIRTY_VECTORS) {
data.rotation = data.local_transform.basis.get_rotation();
@@ -354,10 +351,6 @@ Vector3 Node3D::get_rotation() const {
return data.rotation;
}
-Vector3 Node3D::get_rotation_degrees() const {
- return get_rotation() * (180.0 / Math_PI);
-}
-
Vector3 Node3D::get_scale() const {
if (data.dirty & DIRTY_VECTORS) {
data.scale = data.local_transform.basis.get_scale();
@@ -369,80 +362,131 @@ Vector3 Node3D::get_scale() const {
return data.scale;
}
-void Node3D::update_gizmo() {
+void Node3D::update_gizmos() {
#ifdef TOOLS_ENABLED
if (!is_inside_world()) {
return;
}
- if (!data.gizmo.is_valid()) {
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this);
- }
- if (!data.gizmo.is_valid()) {
+
+ if (data.gizmos.is_empty()) {
return;
}
- if (data.gizmo_dirty) {
+ data.gizmos_dirty = true;
+ MessageQueue::get_singleton()->push_callable(callable_mp(this, &Node3D::_update_gizmos));
+#endif
+}
+
+void Node3D::set_subgizmo_selection(Ref<Node3DGizmo> p_gizmo, int p_id, Transform3D p_transform) {
+#ifdef TOOLS_ENABLED
+ if (!is_inside_world()) {
return;
}
- data.gizmo_dirty = true;
- MessageQueue::get_singleton()->push_call(this, "_update_gizmo");
+
+ if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) {
+ get_tree()->call_group_flags(0, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_set_subgizmo_selection, this, p_gizmo, p_id, p_transform);
+ }
#endif
}
-void Node3D::set_gizmo(const Ref<Node3DGizmo> &p_gizmo) {
+void Node3D::clear_subgizmo_selection() {
#ifdef TOOLS_ENABLED
+ if (!is_inside_world()) {
+ return;
+ }
- if (data.gizmo_disabled) {
+ if (data.gizmos.is_empty()) {
return;
}
- if (data.gizmo.is_valid() && is_inside_world()) {
- data.gizmo->free();
+
+ if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) {
+ get_tree()->call_group_flags(0, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_clear_subgizmo_selection, this);
+ }
+#endif
+}
+
+void Node3D::add_gizmo(Ref<Node3DGizmo> p_gizmo) {
+#ifdef TOOLS_ENABLED
+
+ if (data.gizmos_disabled || p_gizmo.is_null()) {
+ return;
}
- data.gizmo = p_gizmo;
- if (data.gizmo.is_valid() && is_inside_world()) {
- data.gizmo->create();
+ data.gizmos.push_back(p_gizmo);
+
+ if (p_gizmo.is_valid() && is_inside_world()) {
+ p_gizmo->create();
if (is_visible_in_tree()) {
- data.gizmo->redraw();
+ p_gizmo->redraw();
}
- data.gizmo->transform();
+ p_gizmo->transform();
+ }
+#endif
+}
+
+void Node3D::remove_gizmo(Ref<Node3DGizmo> p_gizmo) {
+#ifdef TOOLS_ENABLED
+
+ int idx = data.gizmos.find(p_gizmo);
+ if (idx != -1) {
+ p_gizmo->free();
+ data.gizmos.remove(idx);
}
+#endif
+}
+void Node3D::clear_gizmos() {
+#ifdef TOOLS_ENABLED
+ for (int i = 0; i < data.gizmos.size(); i++) {
+ data.gizmos.write[i]->free();
+ }
+ data.gizmos.clear();
#endif
}
-Ref<Node3DGizmo> Node3D::get_gizmo() const {
+Array Node3D::get_gizmos_bind() const {
+ Array ret;
+
#ifdef TOOLS_ENABLED
+ for (int i = 0; i < data.gizmos.size(); i++) {
+ ret.push_back(Variant(data.gizmos[i].ptr()));
+ }
+#endif
- return data.gizmo;
+ return ret;
+}
+
+Vector<Ref<Node3DGizmo>> Node3D::get_gizmos() const {
+#ifdef TOOLS_ENABLED
+
+ return data.gizmos;
#else
- return Ref<Node3DGizmo>();
+ return Vector<Ref<Node3DGizmo>>();
#endif
}
-void Node3D::_update_gizmo() {
+void Node3D::_update_gizmos() {
#ifdef TOOLS_ENABLED
- if (!is_inside_world()) {
+ if (data.gizmos_disabled || !is_inside_world() || !data.gizmos_dirty) {
return;
}
- data.gizmo_dirty = false;
- if (data.gizmo.is_valid()) {
+ data.gizmos_dirty = false;
+ for (int i = 0; i < data.gizmos.size(); i++) {
if (is_visible_in_tree()) {
- data.gizmo->redraw();
+ data.gizmos.write[i]->redraw();
} else {
- data.gizmo->clear();
+ data.gizmos.write[i]->clear();
}
}
#endif
}
#ifdef TOOLS_ENABLED
-void Node3D::set_disable_gizmo(bool p_enabled) {
- data.gizmo_disabled = p_enabled;
- if (!p_enabled && data.gizmo.is_valid()) {
- data.gizmo = Ref<Node3DGizmo>();
+void Node3D::set_disable_gizmos(bool p_enabled) {
+ data.gizmos_disabled = p_enabled;
+ if (!p_enabled) {
+ clear_gizmos();
}
}
-
#endif
void Node3D::set_disable_scale(bool p_enabled) {
@@ -487,13 +531,13 @@ void Node3D::_propagate_visibility_changed() {
notification(NOTIFICATION_VISIBILITY_CHANGED);
emit_signal(SceneStringNames::get_singleton()->visibility_changed);
#ifdef TOOLS_ENABLED
- if (data.gizmo.is_valid()) {
- _update_gizmo();
+ if (!data.gizmos.is_empty()) {
+ data.gizmos_dirty = true;
+ _update_gizmos();
}
#endif
- for (List<Node3D *>::Element *E = data.children.front(); E; E = E->next()) {
- Node3D *c = E->get();
+ for (Node3D *c : data.children) {
if (!c || !c->data.visible) {
continue;
}
@@ -554,31 +598,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);
@@ -610,7 +654,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);
@@ -639,19 +683,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.");
-
- Transform3D lookat;
- lookat.origin = p_pos;
+ 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.");
- 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);
}
@@ -690,6 +732,50 @@ void Node3D::force_update_transform() {
notification(NOTIFICATION_TRANSFORM_CHANGED);
}
+void Node3D::_update_visibility_parent(bool p_update_root) {
+ RID new_parent;
+
+ if (!visibility_parent_path.is_empty()) {
+ if (!p_update_root) {
+ return;
+ }
+ Node *parent = get_node_or_null(visibility_parent_path);
+ ERR_FAIL_COND_MSG(!parent, "Can't find visibility parent node at path: " + visibility_parent_path);
+ ERR_FAIL_COND_MSG(parent == this, "The visibility parent can't be the same node.");
+ GeometryInstance3D *gi = Object::cast_to<GeometryInstance3D>(parent);
+ ERR_FAIL_COND_MSG(!gi, "The visibility parent node must be a GeometryInstance3D, at path: " + visibility_parent_path);
+ new_parent = gi ? gi->get_instance() : RID();
+ } else if (data.parent) {
+ new_parent = data.parent->data.visibility_parent;
+ }
+
+ if (new_parent == data.visibility_parent) {
+ return;
+ }
+
+ data.visibility_parent = new_parent;
+
+ VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(this);
+ if (vi) {
+ RS::get_singleton()->instance_set_visibility_parent(vi->get_instance(), data.visibility_parent);
+ }
+
+ for (Node3D *c : data.children) {
+ c->_update_visibility_parent(false);
+ }
+}
+
+void Node3D::set_visibility_parent(const NodePath &p_path) {
+ visibility_parent_path = p_path;
+ if (is_inside_tree()) {
+ _update_visibility_parent(true);
+ }
+}
+
+NodePath Node3D::get_visibility_parent() const {
+ return visibility_parent_path;
+}
+
void Node3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_transform", "local"), &Node3D::set_transform);
ClassDB::bind_method(D_METHOD("get_transform"), &Node3D::get_transform);
@@ -697,13 +783,11 @@ void Node3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_position"), &Node3D::get_position);
ClassDB::bind_method(D_METHOD("set_rotation", "euler"), &Node3D::set_rotation);
ClassDB::bind_method(D_METHOD("get_rotation"), &Node3D::get_rotation);
- ClassDB::bind_method(D_METHOD("set_rotation_degrees", "euler_degrees"), &Node3D::set_rotation_degrees);
- ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &Node3D::get_rotation_degrees);
ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Node3D::set_scale);
ClassDB::bind_method(D_METHOD("get_scale"), &Node3D::get_scale);
ClassDB::bind_method(D_METHOD("set_global_transform", "global"), &Node3D::set_global_transform);
ClassDB::bind_method(D_METHOD("get_global_transform"), &Node3D::get_global_transform);
- ClassDB::bind_method(D_METHOD("get_parent_spatial"), &Node3D::get_parent_spatial);
+ ClassDB::bind_method(D_METHOD("get_parent_node_3d"), &Node3D::get_parent_node_3d);
ClassDB::bind_method(D_METHOD("set_ignore_transform_notification", "enabled"), &Node3D::set_ignore_transform_notification);
ClassDB::bind_method(D_METHOD("set_as_top_level", "enable"), &Node3D::set_as_top_level);
ClassDB::bind_method(D_METHOD("is_set_as_top_level"), &Node3D::is_set_as_top_level);
@@ -713,11 +797,15 @@ void Node3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("force_update_transform"), &Node3D::force_update_transform);
- ClassDB::bind_method(D_METHOD("_update_gizmo"), &Node3D::_update_gizmo);
+ ClassDB::bind_method(D_METHOD("set_visibility_parent", "path"), &Node3D::set_visibility_parent);
+ ClassDB::bind_method(D_METHOD("get_visibility_parent"), &Node3D::get_visibility_parent);
- ClassDB::bind_method(D_METHOD("update_gizmo"), &Node3D::update_gizmo);
- ClassDB::bind_method(D_METHOD("set_gizmo", "gizmo"), &Node3D::set_gizmo);
- ClassDB::bind_method(D_METHOD("get_gizmo"), &Node3D::get_gizmo);
+ ClassDB::bind_method(D_METHOD("update_gizmos"), &Node3D::update_gizmos);
+ ClassDB::bind_method(D_METHOD("add_gizmo", "gizmo"), &Node3D::add_gizmo);
+ ClassDB::bind_method(D_METHOD("get_gizmos"), &Node3D::get_gizmos_bind);
+ ClassDB::bind_method(D_METHOD("clear_gizmos"), &Node3D::clear_gizmos);
+ ClassDB::bind_method(D_METHOD("set_subgizmo_selection", "gizmo", "id", "transform"), &Node3D::set_subgizmo_selection);
+ ClassDB::bind_method(D_METHOD("clear_subgizmo_selection"), &Node3D::clear_subgizmo_selection);
ClassDB::bind_method(D_METHOD("set_visible", "visible"), &Node3D::set_visible);
ClassDB::bind_method(D_METHOD("is_visible"), &Node3D::is_visible);
@@ -758,17 +846,16 @@ void Node3D::_bind_methods() {
//ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM3D,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), "set_global_transform", "get_global_transform") ;
ADD_GROUP("Transform", "");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_position", "get_position");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_NONE, "", 0), "set_rotation", "get_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0,or_greater,or_lesser,noslider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level");
ADD_GROUP("Matrix", "");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform");
ADD_GROUP("Visibility", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "Node3DGizmo", 0), "set_gizmo", "get_gizmo");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "visibility_parent", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GeometryInstance3D"), "set_visibility_parent", "get_visibility_parent");
ADD_SIGNAL(MethodInfo("visibility_changed"));
}
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index 09a96bf8ca..d6dcdd96fe 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -32,10 +32,9 @@
#define NODE_3D_H
#include "scene/main/node.h"
-#include "scene/main/scene_tree.h"
-class Node3DGizmo : public Reference {
- GDCLASS(Node3DGizmo, Reference);
+class Node3DGizmo : public RefCounted {
+ GDCLASS(Node3DGizmo, RefCounted);
public:
virtual void create() = 0;
@@ -75,6 +74,8 @@ class Node3D : public Node {
bool top_level = false;
bool inside_world = false;
+ RID visibility_parent;
+
int children_lock = 0;
Node3D *parent = nullptr;
List<Node3D *> children;
@@ -88,19 +89,25 @@ class Node3D : public Node {
bool disable_scale = false;
#ifdef TOOLS_ENABLED
- Ref<Node3DGizmo> gizmo;
- bool gizmo_disabled = false;
- bool gizmo_dirty = false;
+ Vector<Ref<Node3DGizmo>> gizmos;
+ bool gizmos_disabled = false;
+ bool gizmos_dirty = false;
+ bool transform_gizmo_visible = true;
#endif
} data;
- void _update_gizmo();
+ NodePath visibility_parent_path;
+
+ void _update_gizmos();
void _notify_dirty();
void _propagate_transform_changed(Node3D *p_origin);
void _propagate_visibility_changed();
+ void _propagate_visibility_parent();
+ void _update_visibility_parent(bool p_update_root);
+
protected:
_FORCE_INLINE_ void set_ignore_transform_notification(bool p_ignore) { data.ignore_notification = p_ignore; }
@@ -118,18 +125,16 @@ public:
NOTIFICATION_LOCAL_TRANSFORM_CHANGED = 44,
};
- Node3D *get_parent_spatial() const;
+ Node3D *get_parent_node_3d() const;
Ref<World3D> get_world_3d() const;
void set_position(const Vector3 &p_position);
void set_rotation(const Vector3 &p_euler_rad);
- void set_rotation_degrees(const Vector3 &p_euler_deg);
void set_scale(const Vector3 &p_scale);
Vector3 get_position() const;
Vector3 get_rotation() const;
- Vector3 get_rotation_degrees() const;
Vector3 get_scale() const;
void set_transform(const Transform3D &p_transform);
@@ -141,6 +146,8 @@ public:
#ifdef TOOLS_ENABLED
virtual Transform3D get_global_gizmo_transform() const;
virtual Transform3D get_local_gizmo_transform() const;
+ virtual void set_transform_gizmo_visible(bool p_enabled) { data.transform_gizmo_visible = p_enabled; };
+ virtual bool is_transform_gizmo_visible() const { return data.transform_gizmo_visible; };
#endif
void set_as_top_level(bool p_enabled);
@@ -149,27 +156,32 @@ public:
void set_disable_scale(bool p_enabled);
bool is_scale_disabled() const;
- void set_disable_gizmo(bool p_enabled);
- void update_gizmo();
- void set_gizmo(const Ref<Node3DGizmo> &p_gizmo);
- Ref<Node3DGizmo> get_gizmo() const;
+ void set_disable_gizmos(bool p_enabled);
+ void update_gizmos();
+ void set_subgizmo_selection(Ref<Node3DGizmo> p_gizmo, int p_id, Transform3D p_transform = Transform3D());
+ void clear_subgizmo_selection();
+ Vector<Ref<Node3DGizmo>> get_gizmos() const;
+ Array get_gizmos_bind() const;
+ void add_gizmo(Ref<Node3DGizmo> p_gizmo);
+ void remove_gizmo(Ref<Node3DGizmo> p_gizmo);
+ void clear_gizmos();
_FORCE_INLINE_ bool is_inside_world() const { return data.inside_world; }
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);
@@ -196,6 +208,9 @@ public:
void force_update_transform();
+ void set_visibility_parent(const NodePath &p_path);
+ NodePath get_visibility_parent() const;
+
Node3D();
};
diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp
index 429e1d4b98..f3e174c01b 100644
--- a/scene/3d/occluder_instance_3d.cpp
+++ b/scene/3d/occluder_instance_3d.cpp
@@ -114,7 +114,7 @@ Ref<ArrayMesh> Occluder3D::get_debug_mesh() const {
arrays[Mesh::ARRAY_VERTEX] = vertices;
arrays[Mesh::ARRAY_INDEX] = indices;
- debug_mesh.instance();
+ debug_mesh.instantiate();
debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
return debug_mesh;
}
@@ -173,11 +173,13 @@ void OccluderInstance3D::set_occluder(const Ref<Occluder3D> &p_occluder) {
set_base(RID());
}
- update_gizmo();
+ update_gizmos();
+ update_configuration_warnings();
}
void OccluderInstance3D::_occluder_changed() {
- update_gizmo();
+ update_gizmos();
+ update_configuration_warnings();
}
Ref<Occluder3D> OccluderInstance3D::get_occluder() const {
@@ -186,24 +188,29 @@ Ref<Occluder3D> OccluderInstance3D::get_occluder() const {
void OccluderInstance3D::set_bake_mask(uint32_t p_mask) {
bake_mask = p_mask;
+ update_configuration_warnings();
}
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) {
@@ -303,7 +310,7 @@ OccluderInstance3D::BakeError OccluderInstance3D::bake(Node *p_from_node, String
if (get_occluder().is_valid()) {
occ = get_occluder();
} else {
- occ.instance();
+ occ.instantiate();
occ->set_path(p_occluder_path);
}
@@ -314,11 +321,36 @@ OccluderInstance3D::BakeError OccluderInstance3D::bake(Node *p_from_node, String
return BAKE_ERROR_OK;
}
+TypedArray<String> OccluderInstance3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
+ if (!bool(GLOBAL_GET("rendering/occlusion_culling/use_occlusion_culling"))) {
+ warnings.push_back(TTR("Occlusion culling is disabled in the Project Settings, which means occlusion culling won't be performed in the root viewport.\nTo resolve this, open the Project Settings and enable Rendering > Occlusion Culling > Use Occlusion Culling."));
+ }
+
+ if (bake_mask == 0) {
+ // NOTE: This warning will not be emitted if none of the 20 checkboxes
+ // exposed in the editor are checked. This is because there are
+ // currently 12 unexposed layers in the editor inspector.
+ warnings.push_back(TTR("The Bake Mask has no bits enabled, which means baking will not produce any occluder meshes for this OccluderInstance3D.\nTo resolve this, enable at least one bit in the Bake Mask property."));
+ }
+
+ if (occluder.is_null()) {
+ warnings.push_back(TTR("No occluder mesh is defined in the Occluder property, so no occlusion culling will be performed using this OccluderInstance3D.\nTo resolve this, select the OccluderInstance3D then use the Bake Occluders button at the top of the 3D editor viewport."));
+ } else if (occluder->get_vertices().size() < 3) {
+ // Using the "New Occluder" dropdown button won't result in a correct occluder,
+ // so warn the user about this.
+ warnings.push_back(TTR("The occluder mesh has less than 3 vertices, so no occlusion culling will be performed using this OccluderInstance3D.\nTo generate a proper occluder mesh, select the OccluderInstance3D then use the Bake Occluders button at the top of the 3D editor viewport."));
+ }
+
+ return warnings;
+}
+
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 4bb468274d..173614b80c 100644
--- a/scene/3d/occluder_instance_3d.h
+++ b/scene/3d/occluder_instance_3d.h
@@ -82,6 +82,8 @@ protected:
static void _bind_methods();
public:
+ virtual TypedArray<String> get_configuration_warnings() const override;
+
enum BakeError {
BAKE_ERROR_OK,
BAKE_ERROR_NO_SAVE_PATH,
@@ -97,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 de115b35e3..9ea37e4bfa 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -30,18 +30,15 @@
#include "path_3d.h"
-#include "core/config/engine.h"
-#include "scene/scene_string_names.h"
-
void Path3D::_notification(int p_what) {
}
void Path3D::_curve_changed() {
if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) {
- update_gizmo();
+ update_gizmos();
}
if (is_inside_tree()) {
- emit_signal("curve_changed");
+ emit_signal(SNAME("curve_changed"));
}
// update the configuration warnings of all children of type PathFollow
@@ -94,17 +91,24 @@ 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;
+ 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);
- } else if (rotation_mode == ROTATION_ORIENTED && o_next >= bl) {
- o_next = bl;
+ o_prev = Math::fposmod(o_prev, bl);
+ } else if (rotation_mode == ROTATION_ORIENTED) {
+ if (o_next >= bl) {
+ o_next = bl;
+ }
+ if (o_prev <= 0) {
+ o_prev = 0;
+ }
}
Vector3 pos = c->interpolate_baked(offset, cubic);
@@ -115,6 +119,11 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
if (rotation_mode == ROTATION_ORIENTED) {
Vector3 forward = c->interpolate_baked(o_next, cubic) - pos;
+ // Try with the previous position
+ if (forward.length_squared() < CMP_EPSILON2) {
+ forward = pos - c->interpolate_baked(o_prev, cubic);
+ }
+
if (forward.length_squared() < CMP_EPSILON2) {
forward = Vector3(0, 0, 1);
} else {
@@ -157,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) {
@@ -177,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)))) {
@@ -232,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();
}
@@ -295,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);
@@ -317,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 25c7c3d798..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);
@@ -65,7 +55,7 @@ void PhysicsBody3D::_bind_methods() {
PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) :
CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(), false) {
- PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), p_mode);
+ set_body_mode(p_mode);
}
PhysicsBody3D::~PhysicsBody3D() {
@@ -78,8 +68,7 @@ TypedArray<PhysicsBody3D> PhysicsBody3D::get_collision_exceptions() {
List<RID> exceptions;
PhysicsServer3D::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions);
Array ret;
- for (List<RID>::Element *E = exceptions.front(); E; E = E->next()) {
- RID body = E->get();
+ for (const RID &body : exceptions) {
ObjectID instance_id = PhysicsServer3D::get_singleton()->body_get_object_instance_id(body);
Object *obj = ObjectDB::get_instance(instance_id);
PhysicsBody3D *physics_body = Object::cast_to<PhysicsBody3D>(obj);
@@ -102,11 +91,18 @@ 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()) {
- motion_cache.instance();
+ 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;
}
@@ -118,25 +114,63 @@ 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) {
- 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_parameters.motion.length();
+ real_t precision = 0.001;
+
+ if (colliding) {
+ // Can't just use margin as a threshold because collision depth is calculated on unsafe motion,
+ // 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.collisions[0].depth > p_parameters.margin + precision) {
+ p_cancel_sliding = false;
+ }
+ }
+
+ if (p_cancel_sliding) {
+ // When motion is null, recovery is the resulting motion.
+ Vector3 motion_normal;
+ if (motion_length > CMP_EPSILON) {
+ motion_normal = p_parameters.motion / motion_length;
+ }
+
+ // Check depth of recovery.
+ 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 < p_parameters.margin + precision) {
+ // Apply adjustment to 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;
@@ -145,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) {
@@ -192,44 +231,16 @@ 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;
- }
-
- kinematic_motion = p_enabled;
-
- if (kinematic_motion) {
- PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC);
- } else {
- PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_STATIC);
- }
-
- _update_kinematic_motion();
-}
-
-bool StaticBody3D::is_kinematic_motion_enabled() const {
- return kinematic_motion;
-}
-
void StaticBody3D::set_constant_linear_velocity(const Vector3 &p_vel) {
constant_linear_velocity = p_vel;
- if (kinematic_motion) {
- _update_kinematic_motion();
- } else {
- PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity);
- }
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity);
}
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);
- }
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity);
}
Vector3 StaticBody3D::get_constant_linear_velocity() const {
@@ -240,79 +251,22 @@ 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) {
- if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
- return;
- }
-#endif
-
- ERR_FAIL_COND(!kinematic_motion);
-
- real_t delta_time = get_physics_process_delta_time();
-
- Transform3D new_transform = get_global_transform();
- 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);
-
- // Propagate transform change to node.
- set_ignore_transform_notification(true);
- set_global_transform(new_transform);
- set_ignore_transform_notification(false);
- _on_transform_changed();
- }
-}
-
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);
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");
}
-void StaticBody3D::_direct_state_changed(Object *p_state) {
-#ifdef DEBUG_ENABLED
- 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");
-#else
- PhysicsDirectBodyState3D *state = (PhysicsDirectBodyState3D *)p_state; //trust it
-#endif
-
- linear_velocity = state->get_linear_velocity();
- angular_velocity = state->get_angular_velocity();
-}
-
-StaticBody3D::StaticBody3D() :
- PhysicsBody3D(PhysicsServer3D::BODY_MODE_STATIC) {
+StaticBody3D::StaticBody3D(PhysicsServer3D::BodyMode p_mode) :
+ PhysicsBody3D(p_mode) {
}
void StaticBody3D::_reload_physics_characteristics() {
@@ -325,28 +279,104 @@ void StaticBody3D::_reload_physics_characteristics() {
}
}
-void StaticBody3D::_update_kinematic_motion() {
+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()) {
return;
}
#endif
- 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())) {
- set_physics_process_internal(true);
- return;
- }
+ if (sync_to_physics) {
+ set_only_update_transform_changes(true);
+ set_notify_local_transform(true);
} else {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
+ set_only_update_transform_changes(false);
+ set_notify_local_transform(false);
}
+}
+
+void AnimatableBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
+ AnimatableBody3D *body = (AnimatableBody3D *)p_instance;
+ body->_body_state_changed(p_state);
+}
+
+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 = p_state->get_transform();
+ set_notify_local_transform(false);
+ set_global_transform(last_valid_transform);
+ set_notify_local_transform(true);
+ _on_transform_changed();
+}
+
+void AnimatableBody3D::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ last_valid_transform = get_global_transform();
+ _update_kinematic_motion();
+ } break;
- set_physics_process_internal(false);
+ 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();
+
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_TRANSFORM, new_transform);
+
+ // ... but then revert changes.
+ set_notify_local_transform(false);
+ set_global_transform(last_valid_transform);
+ set_notify_local_transform(true);
+ _on_transform_changed();
+ } break;
+ }
}
-void RigidBody3D::_body_enter_tree(ObjectID p_id) {
+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::BOOL, "sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled");
+}
+
+AnimatableBody3D::AnimatableBody3D() :
+ StaticBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
+}
+
+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);
@@ -369,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);
@@ -390,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;
@@ -409,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);
}
@@ -436,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);
}
@@ -451,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();
@@ -486,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;
@@ -534,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++;
}
}
@@ -559,154 +590,224 @@ 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
- if (p_what == NOTIFICATION_ENTER_TREE) {
- if (Engine::get_singleton()->is_editor_hint()) {
- set_notify_local_transform(true); //used for warnings and only in editor
- }
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ set_notify_local_transform(true); //used for warnings and only in editor
+ }
+ } break;
+
+ case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ update_configuration_warnings();
+ }
+ } break;
}
+#endif
+}
- if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
- if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warnings();
+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);
}
+}
-#endif
+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();
}
-void RigidBody3D::set_mode(Mode p_mode) {
- mode = p_mode;
- switch (p_mode) {
- case MODE_DYNAMIC: {
- PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_DYNAMIC);
- } break;
- case MODE_STATIC: {
- PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_STATIC);
+bool RigidDynamicBody3D::is_lock_rotation_enabled() const {
+ return lock_rotation;
+}
- } break;
- case MODE_DYNAMIC_LOCKED: {
- PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED);
+void RigidDynamicBody3D::set_freeze_enabled(bool p_freeze) {
+ if (p_freeze == freeze) {
+ return;
+ }
- } break;
- case MODE_KINEMATIC: {
- PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC);
- } break;
+ freeze = p_freeze;
+ _apply_body_mode();
+}
+
+bool RigidDynamicBody3D::is_freeze_enabled() const {
+ return freeze;
+}
+
+void RigidDynamicBody3D::set_freeze_mode(FreezeMode p_freeze_mode) {
+ if (p_freeze_mode == freeze_mode) {
+ return;
}
- update_configuration_warnings();
+
+ freeze_mode = p_freeze_mode;
+ _apply_body_mode();
}
-RigidBody3D::Mode RigidBody3D::get_mode() const {
- return mode;
+RigidDynamicBody3D::FreezeMode RigidDynamicBody3D::get_freeze_mode() const {
+ return freeze_mode;
}
-void RigidBody3D::set_mass(real_t p_mass) {
+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;
}
@@ -715,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;
}
@@ -789,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));
}
}
@@ -808,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 {
@@ -830,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_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_mass", "mass"), &RigidBody3D::set_mass);
- ClassDB::bind_method(D_METHOD("get_mass"), &RigidBody3D::get_mass);
+ 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_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_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_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_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("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("get_inverse_inertia_tensor"), &RigidDynamicBody3D::get_inverse_inertia_tensor);
- ClassDB::bind_method(D_METHOD("get_inverse_inertia_tensor"), &RigidBody3D::get_inverse_inertia_tensor);
+ 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_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_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_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_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_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_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_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_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_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_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_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_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_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_axis_velocity", "axis_velocity"), &RigidDynamicBody3D::set_axis_velocity);
- ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody3D::set_axis_velocity);
+ 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("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("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("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("set_sleeping", "sleeping"), &RigidDynamicBody3D::set_sleeping);
+ ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidDynamicBody3D::is_sleeping);
- 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_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("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_lock_rotation_enabled", "lock_rotation"), &RigidDynamicBody3D::set_lock_rotation_enabled);
+ ClassDB::bind_method(D_METHOD("is_lock_rotation_enabled"), &RigidDynamicBody3D::is_lock_rotation_enabled);
- ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody3D::get_colliding_bodies);
+ 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);
- BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState3D")));
+ 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);
- 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_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass");
+ 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");
@@ -911,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");
@@ -924,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);
@@ -956,164 +1087,538 @@ 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;
}
}
- // 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());
+ 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();
+ }
+ }
- 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 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;
- int slide_count = max_slides;
- while (slide_count) {
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);
- 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);
- motion = result.remainder;
+ // 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 && result.motion.length() < 1) {
- Transform3D gt = get_global_transform();
- gt.origin -= result.motion.slide(up_direction);
- 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();
+ }
}
}
- motion = motion.slide(result.collision_normal);
- linear_velocity = linear_velocity.slide(result.collision_normal);
+ // 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);
- for (int j = 0; j < 3; j++) {
- if (locked_axis & (1 << j)) {
- linear_velocity[j] = 0.0;
+ 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 (slide_motion.dot(motion_velocity) > 0.0) {
+ motion = slide_motion;
+ } else {
+ motion = Vector3();
+ }
+
+ 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);
+ }
+ }
+ }
+ // 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;
}
- --slide_count;
+ 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)) {
- 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.
- result.motion = result.motion.project(up_direction);
+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;
+ }
+
+ // Snap by at least collision margin to keep floor state consistent.
+ real_t length = MAX(floor_snap_length, margin);
- Transform3D gt = get_global_transform();
+ 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);
}
}
+}
- gt.origin += recover;
- set_global_transform(gt);
+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;
+ }
- 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();
+ // Snap by at least collision margin to keep floor state consistent.
+ real_t length = MAX(floor_snap_length, margin);
- return true;
- } else {
- return false;
+ PhysicsServer3D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin);
+ parameters.max_collisions = 4;
+ parameters.collide_separation_ray = true;
+
+ 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) {
@@ -1124,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;
+}
+
+bool CharacterBody3D::is_on_ceiling_only() const {
+ return collision_state.ceiling && !collision_state.floor && !collision_state.wall;
}
-Vector3 CharacterBody3D::get_floor_normal() const {
+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;
+}
+
+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;
}
-int CharacterBody3D::get_slide_count() const {
+Vector3 CharacterBody3D::get_linear_velocity() const {
+ return get_real_velocity();
+}
+
+int CharacterBody3D::get_slide_collision_count() const {
return motion_results.size();
}
@@ -1167,8 +1709,9 @@ Ref<KinematicCollision3D> CharacterBody3D::_get_slide_collision(int p_bounce) {
slide_colliders.resize(p_bounce + 1);
}
- if (slide_colliders[p_bounce].is_null()) {
- slide_colliders.write[p_bounce].instance();
+ // 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;
}
@@ -1176,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_floor_stop_on_slope_enabled(bool p_enabled) {
+ floor_stop_on_slope = p_enabled;
+}
+
+bool CharacterBody3D::is_floor_constant_speed_enabled() const {
+ return floor_constant_speed;
+}
+
+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_stop_on_slope_enabled(bool p_enabled) {
- stop_on_slope = p_enabled;
+void CharacterBody3D::set_moving_platform_wall_layers(uint32_t p_exclude_layers) {
+ moving_platform_wall_layers = p_exclude_layers;
}
-bool CharacterBody3D::is_infinite_inertia_enabled() const {
- return infinite_inertia;
+void CharacterBody3D::set_motion_mode(MotionMode p_mode) {
+ motion_mode = p_mode;
}
-void CharacterBody3D::set_infinite_inertia_enabled(bool p_enabled) {
- infinite_inertia = p_enabled;
+
+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 {
@@ -1196,7 +1795,7 @@ int CharacterBody3D::get_max_slides() const {
}
void CharacterBody3D::set_max_slides(int p_max_slides) {
- ERR_FAIL_COND(p_max_slides > 0);
+ ERR_FAIL_COND(p_max_slides < 1);
max_slides = p_max_slides;
}
@@ -1208,20 +1807,21 @@ void CharacterBody3D::set_floor_max_angle(real_t p_radians) {
floor_max_angle = p_radians;
}
-real_t CharacterBody3D::get_floor_max_angle_degrees() const {
- return Math::rad2deg(floor_max_angle);
+real_t CharacterBody3D::get_floor_snap_length() {
+ return floor_snap_length;
}
-void CharacterBody3D::set_floor_max_angle_degrees(real_t p_degrees) {
- floor_max_angle = Math::deg2rad(p_degrees);
+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;
}
-const Vector3 &CharacterBody3D::get_snap() const {
- return snap;
+real_t CharacterBody3D::get_wall_min_slide_angle() const {
+ return wall_min_slide_angle;
}
-void CharacterBody3D::set_snap(const Vector3 &p_snap) {
- snap = p_snap;
+void CharacterBody3D::set_wall_min_slide_angle(real_t p_radians) {
+ wall_min_slide_angle = p_radians;
}
const Vector3 &CharacterBody3D::get_up_direction() const {
@@ -1229,62 +1829,110 @@ 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();
}
void CharacterBody3D::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- // Reset move_and_slide() data.
- on_floor = false;
- on_floor_body = RID();
- on_ceiling = false;
- on_wall = false;
- motion_results.clear();
- floor_velocity = Vector3();
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ // Reset move_and_slide() data.
+ collision_state.state = 0;
+ platform_rid = RID();
+ platform_object_id = ObjectID();
+ motion_results.clear();
+ platform_velocity = Vector3();
+ } break;
}
}
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_floor_max_angle_degrees"), &CharacterBody3D::get_floor_max_angle_degrees);
- ClassDB::bind_method(D_METHOD("set_floor_max_angle_degrees", "degrees"), &CharacterBody3D::set_floor_max_angle_degrees);
- 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"), "set_max_slides", "get_max_slides");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_floor_max_angle", "get_floor_max_angle");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle_degrees", PROPERTY_HINT_RANGE, "0,180,0.1", PROPERTY_USAGE_EDITOR), "set_floor_max_angle_degrees", "get_floor_max_angle_degrees");
- 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() :
@@ -1301,48 +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;
+}
+
+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() const {
+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;
}
-Object *KinematicCollision3D::get_collider_shape() const {
- Object *collider = get_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(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);
}
}
@@ -1350,42 +2018,30 @@ Object *KinematicCollision3D::get_collider_shape() const {
return nullptr;
}
-int KinematicCollision3D::get_collider_shape_index() const {
- return result.collider_shape;
-}
-
-Vector3 KinematicCollision3D::get_collider_velocity() const {
- return result.collider_velocity;
+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;
}
-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_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::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));
}
///////////////////////////////////////
@@ -2032,9 +2688,7 @@ bool PhysicalBone3D::_set(const StringName &p_name, const Variant &p_value) {
if (joint_data) {
if (joint_data->_set(p_name, p_value, joint)) {
#ifdef TOOLS_ENABLED
- if (get_gizmo().is_valid()) {
- get_gizmo()->redraw();
- }
+ update_gizmos();
#endif
return true;
}
@@ -2089,42 +2743,39 @@ void PhysicalBone3D::_notification(int p_what) {
_reload_joint();
}
break;
- case NOTIFICATION_EXIT_TREE:
+
+ case NOTIFICATION_EXIT_TREE: {
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;
}
}
parent_skeleton = nullptr;
PhysicsServer3D::get_singleton()->joint_clear(joint);
- break;
- case NOTIFICATION_TRANSFORM_CHANGED:
+ } break;
+
+ case NOTIFICATION_TRANSFORM_CHANGED: {
if (Engine::get_singleton()->is_editor_hint()) {
update_offset();
}
- break;
+ } break;
}
}
-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);
@@ -2150,8 +2801,6 @@ void PhysicalBone3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_joint_offset"), &PhysicalBone3D::get_joint_offset);
ClassDB::bind_method(D_METHOD("set_joint_rotation", "euler"), &PhysicalBone3D::set_joint_rotation);
ClassDB::bind_method(D_METHOD("get_joint_rotation"), &PhysicalBone3D::get_joint_rotation);
- ClassDB::bind_method(D_METHOD("set_joint_rotation_degrees", "euler_degrees"), &PhysicalBone3D::set_joint_rotation_degrees);
- ClassDB::bind_method(D_METHOD("get_joint_rotation_degrees"), &PhysicalBone3D::get_joint_rotation_degrees);
ClassDB::bind_method(D_METHOD("set_body_offset", "offset"), &PhysicalBone3D::set_body_offset);
ClassDB::bind_method(D_METHOD("get_body_offset"), &PhysicalBone3D::get_body_offset);
@@ -2186,12 +2835,11 @@ void PhysicalBone3D::_bind_methods() {
ADD_GROUP("Joint", "joint_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "joint_offset"), "set_joint_offset", "get_joint_offset");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_joint_rotation_degrees", "get_joint_rotation_degrees");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation", PROPERTY_HINT_NONE, "", 0), "set_joint_rotation", "get_joint_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation", PROPERTY_HINT_RANGE, "-360,360,0.01,or_lesser,or_greater,radians"), "set_joint_rotation", "get_joint_rotation");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "body_offset"), "set_body_offset", "get_body_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "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");
@@ -2223,9 +2871,7 @@ void PhysicalBone3D::_update_joint_offset() {
set_ignore_transform_notification(false);
#ifdef TOOLS_ENABLED
- if (get_gizmo().is_valid()) {
- get_gizmo()->redraw();
- }
+ update_gizmos();
#endif
}
@@ -2334,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();
}
@@ -2392,9 +3035,7 @@ void PhysicalBone3D::set_joint_type(JointType p_joint_type) {
#ifdef TOOLS_ENABLED
notify_property_list_changed();
- if (get_gizmo().is_valid()) {
- get_gizmo()->redraw();
- }
+ update_gizmos();
#endif
}
@@ -2422,14 +3063,6 @@ Vector3 PhysicalBone3D::get_joint_rotation() const {
return joint_offset.basis.get_rotation();
}
-void PhysicalBone3D::set_joint_rotation_degrees(const Vector3 &p_euler_deg) {
- set_joint_rotation(p_euler_deg * (Math_PI / 180.0));
-}
-
-Vector3 PhysicalBone3D::get_joint_rotation_degrees() const {
- return get_joint_rotation() * (180.0 / Math_PI);
-}
-
const Transform3D &PhysicalBone3D::get_body_offset() const {
return body_offset;
}
@@ -2564,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;
@@ -2599,10 +3231,10 @@ void PhysicalBone3D::_start_physics_simulation() {
return;
}
reset_to_rest_position();
- PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_DYNAMIC);
+ 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;
}
@@ -2612,16 +3244,16 @@ void PhysicalBone3D::_stop_physics_simulation() {
return;
}
if (parent_skeleton->get_animate_physical_bones()) {
- PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC);
+ set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC);
PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
} else {
- PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_STATIC);
+ set_body_mode(PhysicsServer3D::BODY_MODE_STATIC);
PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), 0);
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 a25cb06bc3..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 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,22 +73,15 @@ 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;
-
protected:
- void _notification(int p_what);
static void _bind_methods();
- void _direct_state_changed(Object *p_state);
-
public:
void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
Ref<PhysicsMaterial> get_physics_material_override() const;
@@ -99,37 +92,68 @@ public:
Vector3 get_constant_linear_velocity() const;
Vector3 get_constant_angular_velocity() const;
+ StaticBody3D(PhysicsServer3D::BodyMode p_mode = PhysicsServer3D::BODY_MODE_STATIC);
+
+private:
+ void _reload_physics_characteristics();
+};
+
+class AnimatableBody3D : public StaticBody3D {
+ GDCLASS(AnimatableBody3D, StaticBody3D);
+
+private:
+ Vector3 linear_velocity;
+ Vector3 angular_velocity;
+
+ 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();
+
+public:
virtual Vector3 get_linear_velocity() const override;
virtual Vector3 get_angular_velocity() const override;
- StaticBody3D();
+ AnimatableBody3D();
private:
- void _reload_physics_characteristics();
-
void _update_kinematic_motion();
- void set_kinematic_motion_enabled(bool p_enabled);
- bool is_kinematic_motion_enabled() const;
+ 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;
@@ -165,7 +189,7 @@ protected:
tagged = false;
}
};
- struct RigidBody3D_RemoveAction {
+ struct RigidDynamicBody3D_RemoveAction {
RID rid;
ObjectID body_id;
ShapePair pair;
@@ -187,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;
@@ -251,55 +299,124 @@ public:
void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3());
void apply_torque_impulse(const Vector3 &p_impulse);
- TypedArray<String> get_configuration_warnings() const override;
+ 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_infinite_inertia_enabled() const;
- void set_infinite_inertia_enabled(bool p_enabled);
+ bool is_floor_constant_speed_enabled() const;
+ void set_floor_constant_speed_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);
@@ -307,40 +424,47 @@ private:
real_t get_floor_max_angle() const;
void set_floor_max_angle(real_t p_radians);
- real_t get_floor_max_angle_degrees() const;
- void set_floor_max_angle_degrees(real_t p_degrees);
+ real_t get_floor_snap_length();
+ void set_floor_snap_length(real_t p_floor_snap_length);
- const Vector3 &get_snap() const;
- void set_snap(const Vector3 &p_snap);
+ real_t get_wall_min_slide_angle() const;
+ void set_wall_min_slide_angle(real_t p_radians);
- const Vector3 &get_up_direction() const;
- void set_up_direction(const Vector3 &p_up_direction);
+ uint32_t get_moving_platform_floor_layers() const;
+ void set_moving_platform_floor_layers(const uint32_t p_exclude_layer);
-protected:
- void _notification(int p_what);
- static void _bind_methods();
+ uint32_t get_moving_platform_wall_layers() const;
+ void set_moving_platform_wall_layers(const uint32_t p_exclude_layer);
-public:
- void move_and_slide();
+ void set_motion_mode(MotionMode p_mode);
+ MotionMode get_motion_mode() const;
- virtual Vector3 get_linear_velocity() const override;
- void set_linear_velocity(const Vector3 &p_velocity);
+ void set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_velocity);
+ MovingPlatformApplyVelocityOnLeave get_moving_platform_apply_velocity_on_leave() 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 _move_and_slide_free(double p_delta);
+ void _move_and_slide_grounded(double p_delta, bool p_was_on_floor);
- int get_slide_count() const;
- PhysicsServer3D::MotionResult get_slide_collision(int p_bounce) const;
+ 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);
- CharacterBody3D();
- ~CharacterBody3D();
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+ virtual void _validate_property(PropertyInfo &property) const override;
};
-class KinematicCollision3D : public Reference {
- GDCLASS(KinematicCollision3D, Reference);
+VARIANT_ENUM_CAST(CharacterBody3D::MotionMode);
+VARIANT_ENUM_CAST(CharacterBody3D::MovingPlatformApplyVelocityOnLeave);
+
+class KinematicCollision3D : public RefCounted {
+ GDCLASS(KinematicCollision3D, RefCounted);
PhysicsBody3D *owner = nullptr;
friend class PhysicsBody3D;
@@ -351,17 +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;
- 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 {
@@ -515,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();
@@ -528,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
@@ -550,9 +676,6 @@ public:
void set_joint_rotation(const Vector3 &p_euler_rad);
Vector3 get_joint_rotation() const;
- void set_joint_rotation_degrees(const Vector3 &p_euler_deg);
- Vector3 get_joint_rotation_degrees() const;
-
void set_body_offset(const Transform3D &p_offset);
const Transform3D &get_body_offset() const;
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.cpp b/scene/3d/proximity_group_3d.cpp
index 9d9fea68b0..23df00c1f6 100644
--- a/scene/3d/proximity_group_3d.cpp
+++ b/scene/3d/proximity_group_3d.cpp
@@ -34,9 +34,9 @@
void ProximityGroup3D::_clear_groups() {
Map<StringName, uint32_t>::Element *E;
+ const int size = 16;
- {
- const int size = 16;
+ do {
StringName remove_list[size];
E = groups.front();
int num = 0;
@@ -50,11 +50,7 @@ void ProximityGroup3D::_clear_groups() {
for (int i = 0; i < num; i++) {
groups.erase(remove_list[i]);
}
- }
-
- if (E) {
- _clear_groups(); // call until we go through the whole list
- }
+ } while (E);
}
void ProximityGroup3D::_update_groups() {
@@ -128,9 +124,10 @@ void ProximityGroup3D::broadcast(String p_method, Variant p_parameters) {
void ProximityGroup3D::_proximity_group_broadcast(String p_method, Variant p_parameters) {
if (dispatch_mode == MODE_PROXY) {
+ ERR_FAIL_COND(!is_inside_tree());
get_parent()->call(p_method, p_parameters);
} else {
- emit_signal("broadcast", p_method, p_parameters);
+ emit_signal(SNAME("broadcast"), p_method, p_parameters);
}
}
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 db841101e5..fd4c6e7416 100644
--- a/scene/3d/ray_cast_3d.cpp
+++ b/scene/3d/ray_cast_3d.cpp
@@ -31,13 +31,11 @@
#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;
- update_gizmo();
+ update_gizmos();
if (Engine::get_singleton()->is_editor_hint()) {
if (is_inside_tree()) {
@@ -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 {
@@ -102,7 +102,7 @@ Vector3 RayCast3D::get_collision_normal() const {
void RayCast3D::set_enabled(bool p_enabled) {
enabled = p_enabled;
- update_gizmo();
+ update_gizmos();
if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint()) {
set_physics_process_internal(p_enabled);
@@ -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);
@@ -366,7 +366,7 @@ void RayCast3D::_update_debug_shape_vertices() {
void RayCast3D::set_debug_shape_thickness(const float p_debug_shape_thickness) {
debug_shape_thickness = p_debug_shape_thickness;
- update_gizmo();
+ update_gizmos();
if (Engine::get_singleton()->is_editor_hint()) {
if (is_inside_tree()) {
@@ -419,6 +419,8 @@ void RayCast3D::_update_debug_shape_material(bool p_check_collision) {
debug_material = material;
material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ // Use double-sided rendering so that the RayCast can be seen if the camera is inside.
+ material->set_cull_mode(BaseMaterial3D::CULL_DISABLED);
material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA);
}
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.cpp b/scene/3d/reflection_probe.cpp
index 7762156b4a..719dbedd94 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -101,7 +101,7 @@ void ReflectionProbe::set_extents(const Vector3 &p_extents) {
RS::get_singleton()->reflection_probe_set_extents(probe, extents);
RS::get_singleton()->reflection_probe_set_origin_offset(probe, origin_offset);
- update_gizmo();
+ update_gizmos();
}
Vector3 ReflectionProbe::get_extents() const {
@@ -119,7 +119,7 @@ void ReflectionProbe::set_origin_offset(const Vector3 &p_extents) {
RS::get_singleton()->reflection_probe_set_extents(probe, extents);
RS::get_singleton()->reflection_probe_set_origin_offset(probe, origin_offset);
- update_gizmo();
+ update_gizmos();
}
Vector3 ReflectionProbe::get_origin_offset() const {
@@ -232,7 +232,7 @@ void ReflectionProbe::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Once (Fast),Always (Slow)"), "set_update_mode", "get_update_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "intensity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_intensity", "get_intensity");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,16384,0.1,or_greater"), "set_max_distance", "get_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,16384,0.1,or_greater,exp"), "set_max_distance", "get_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "origin_offset"), "set_origin_offset", "get_origin_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "box_projection"), "set_enable_box_projection", "is_box_projection_enabled");
diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h
index 15c2da3ae0..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);
@@ -55,7 +52,7 @@ private:
RID probe;
float intensity = 1.0;
float max_distance = 0.0;
- Vector3 extents = Vector3(1, 1, 1);
+ Vector3 extents = Vector3(10, 10, 10);
Vector3 origin_offset = Vector3(0, 0, 0);
bool box_projection = false;
bool enable_shadows = false;
diff --git a/scene/3d/remote_transform_3d.cpp b/scene/3d/remote_transform_3d.cpp
index a7b3a6f1ec..d5fb1fa6ab 100644
--- a/scene/3d/remote_transform_3d.cpp
+++ b/scene/3d/remote_transform_3d.cpp
@@ -34,7 +34,7 @@ void RemoteTransform3D::_update_cache() {
cache = ObjectID();
if (has_node(remote_node)) {
Node *node = get_node(remote_node);
- if (!node || this == node || node->is_a_parent_of(this) || this->is_a_parent_of(node)) {
+ if (!node || this == node || node->is_ancestor_of(this) || this->is_ancestor_of(node)) {
return;
}
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index f9d613a4bb..2b52f034b2 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -30,11 +30,11 @@
#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 "editor/plugins/skeleton_3d_editor_plugin.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 +72,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 +111,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 +153,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 +171,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
+ // 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,80 +207,14 @@ 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 (List<ObjectID>::Element *E = b.nodes_bound.front(); E; E = E->next()) {
- Object *obj = ObjectDB::get_instance(E->get());
- 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
+ // Update skins.
for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
const Skin *skin = E->get()->skin.operator->();
RID skeleton = E->get()->skeleton;
@@ -291,7 +232,7 @@ void Skeleton3D::_notification(int p_what) {
StringName bind_name = skin->get_bind_name(i);
if (bind_name != StringName()) {
- //bind name used, use this
+ // Bind name used, use this.
bool found = false;
for (int j = 0; j < len; j++) {
if (bonesptr[j].name == bind_name) {
@@ -329,32 +270,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 +328,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,14 +353,109 @@ 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;
}
-// skeleton creation api
+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);
@@ -404,7 +469,7 @@ void Skeleton3D::add_bone(const String &p_name) {
process_order_dirty = true;
version++;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
int Skeleton3D::find_bone(const String &p_name) const {
@@ -418,14 +483,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 +519,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 +530,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 +548,104 @@ 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;
}
+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;
+}
+
+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();
+}
+
+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::remove_bone_child(int p_bone, int p_child) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
+
+ 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();
+}
+
+Vector<int> Skeleton3D::get_parentless_bones() {
+ return parentless_bones;
+}
+
void Skeleton3D::set_bone_rest(int p_bone, const Transform3D &p_rest) {
- ERR_FAIL_INDEX(p_bone, bones.size());
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
bones.write[p_bone].rest = p_rest;
_make_dirty();
}
Transform3D Skeleton3D::get_bone_rest(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].rest;
}
void Skeleton3D::set_bone_enabled(int p_bone, bool p_enabled) {
- ERR_FAIL_INDEX(p_bone, bones.size());
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
bones.write[p_bone].enabled = p_enabled;
+ emit_signal(SceneStringNames::get_singleton()->bone_enabled_changed, p_bone);
_make_dirty();
}
bool Skeleton3D::is_bone_enabled(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].enabled;
}
-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();
-
- for (const List<ObjectID>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) {
- if (E->get() == id) {
- return; // already here
- }
- }
-
- bones.write[p_bone].nodes_bound.push_back(id);
-}
-
-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());
-
- ObjectID id = p_node->get_instance_id();
- bones.write[p_bone].nodes_bound.erase(id);
+void Skeleton3D::set_show_rest_only(bool p_enabled) {
+ show_rest_only = p_enabled;
+ emit_signal(SceneStringNames::get_singleton()->show_rest_only_changed);
+ _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 List<ObjectID>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) {
- Object *obj = ObjectDB::get_instance(E->get());
- ERR_CONTINUE(!obj);
- p_bound->push_back(Object::cast_to<Node>(obj));
- }
+bool Skeleton3D::is_show_rest_only() const {
+ return show_rest_only;
}
void Skeleton3D::clear_bones() {
@@ -558,10 +655,11 @@ void Skeleton3D::clear_bones() {
_make_dirty();
}
-// posing api
+// 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 +667,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 +684,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,30 +698,28 @@ 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]);
}
}
}
-void Skeleton3D::set_animate_physical_bones(bool p_animate) {
- animate_physical_bones = p_animate;
+void Skeleton3D::set_animate_physical_bones(bool p_enabled) {
+ animate_physical_bones = p_enabled;
if (Engine::get_singleton()->is_editor_hint() == false) {
bool sim = false;
@@ -632,7 +731,7 @@ void Skeleton3D::set_animate_physical_bones(bool p_animate) {
}
}
}
- set_physics_process_internal(sim == false && p_animate);
+ set_physics_process_internal(sim == false && p_enabled);
}
}
@@ -641,7 +740,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 +750,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 +776,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) {
@@ -740,7 +844,7 @@ void Skeleton3D::physical_bones_start_simulation_on(const TypedArray<StringName>
Vector<int> sim_bones;
if (p_bones.size() <= 0) {
- sim_bones.push_back(0); // if no bones is specified, activate ragdoll on full body
+ sim_bones.push_back(0); // If no bones is specified, activate ragdoll on full body.
} else {
sim_bones.resize(p_bones.size());
int c = 0;
@@ -793,31 +897,42 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
Ref<Skin> skin = p_skin;
if (skin.is_null()) {
- //need to create one from existing code, this is for compatibility only
- //when skeletons did not support skins. It is also used by gizmo
- //to display the skeleton.
+ // Need to create one from existing code, this is for compatibility only
+ // when skeletons did not support skins. It is also used by gizmo
+ // to display the skeleton.
- skin.instance();
+ skin.instantiate();
skin->set_bind_count(bones.size());
- _update_process_order(); //just in case
+ _update_process_order(); // Just in case.
- // pose changed, rebuild cache of inverses
+ // 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);
+ // Calculate global rests and invert them.
+ 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]);
}
}
for (int i = 0; i < len; i++) {
- //the inverse is what is actually required
+ // The inverse is what is actually required.
skin->set_bind_bone(i, i);
skin->set_bind_pose(i, skin->get_bind_pose(i).affine_inverse());
}
@@ -826,7 +941,7 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
ERR_FAIL_COND_V(skin.is_null(), Ref<SkinReference>());
Ref<SkinReference> skin_ref;
- skin_ref.instance();
+ skin_ref.instantiate();
skin_ref->skeleton_node = this;
skin_ref->bind_count = 0;
@@ -838,22 +953,214 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
skin->connect("changed", Callable(skin_ref.operator->(), "_skin_changed"));
- _make_dirty(); //skin needs to be updated, so update skeleton
+ _make_dirty(); // Skin needs to be updated, so update skeleton.
return skin_ref;
}
-// helper functions
-Transform3D Skeleton3D::bone_transform_to_world_transform(Transform3D p_bone_transform) {
- return get_global_transform() * p_bone_transform;
+void Skeleton3D::force_update_all_dirty_bones() {
+ if (dirty) {
+ const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON);
+ }
+}
+
+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]);
+ }
}
-Transform3D Skeleton3D::world_transform_to_bone_transform(Transform3D p_world_transform) {
+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];
+ bool bone_enabled = b.enabled && !show_rest_only;
+
+ if (b.disable_rest) {
+ if (bone_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 (bone_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::global_pose_to_world_transform(Transform3D p_global_pose) {
+ return get_global_transform() * p_global_pose;
+}
+
+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 +1173,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);
@@ -881,18 +1195,36 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton3D::get_bone_pose);
ClassDB::bind_method(D_METHOD("set_bone_pose", "bone_idx", "pose"), &Skeleton3D::set_bone_pose);
+ ClassDB::bind_method(D_METHOD("is_bone_enabled", "bone_idx"), &Skeleton3D::is_bone_enabled);
+ ClassDB::bind_method(D_METHOD("set_bone_enabled", "bone_idx", "enabled"), &Skeleton3D::set_bone_enabled, DEFVAL(true));
+
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("set_show_rest_only", "enabled"), &Skeleton3D::set_show_rest_only);
+ ClassDB::bind_method(D_METHOD("is_show_rest_only"), &Skeleton3D::is_show_rest_only);
+
+ ClassDB::bind_method(D_METHOD("set_animate_physical_bones", "enabled"), &Skeleton3D::set_animate_physical_bones);
ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton3D::get_animate_physical_bones);
ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton3D::physical_bones_stop_simulation);
@@ -900,12 +1232,24 @@ 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, "show_rest_only"), "set_show_rest_only", "is_show_rest_only");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "animate_physical_bones"), "set_animate_physical_bones", "get_animate_physical_bones");
+#endif // _3D_DISABLED
#ifdef TOOLS_ENABLED
ADD_SIGNAL(MethodInfo("pose_updated"));
#endif // TOOLS_ENABLED
+ ADD_SIGNAL(MethodInfo("bone_pose_changed", PropertyInfo(Variant::INT, "bone_idx")));
+ ADD_SIGNAL(MethodInfo("bone_enabled_changed", PropertyInfo(Variant::INT, "bone_idx")));
+ ADD_SIGNAL(MethodInfo("show_rest_only_changed"));
+
BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
}
@@ -913,7 +1257,7 @@ Skeleton3D::Skeleton3D() {
}
Skeleton3D::~Skeleton3D() {
- //some skins may remain bound
+ // Some skins may remain bound.
for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
E->get()->skeleton_node = nullptr;
}
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index 9be7dce5d2..9aa4fc823f 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;
@@ -40,8 +40,8 @@ typedef int BoneId;
class PhysicalBone3D;
class Skeleton3D;
-class SkinReference : public Reference {
- GDCLASS(SkinReference, Reference)
+class SkinReference : public RefCounted {
+ GDCLASS(SkinReference, RefCounted)
friend class Skeleton3D;
Skeleton3D *skeleton_node;
@@ -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,12 +130,15 @@ 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;
+ bool show_rest_only = false;
+
uint64_t version = 1;
void _update_process_order();
@@ -118,7 +150,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 +181,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 +197,11 @@ 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 set_show_rest_only(bool p_enabled);
+ bool is_show_rest_only() const;
void clear_bones();
// posing api
@@ -166,19 +212,45 @@ 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_dirty_bones();
+ 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
- void set_animate_physical_bones(bool p_animate);
+ void set_animate_physical_bones(bool p_enabled);
bool get_animate_physical_bones() const;
void bind_physical_bone_to_bone(int p_bone, PhysicalBone3D *p_physical_bone);
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 df5474d03e..9fceb21790 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() {
- RS::get_singleton()->mesh_surface_update_region(mesh, surface, 0, buffer);
+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()) {
@@ -266,12 +252,13 @@ void SoftBody3D::_notification(int p_what) {
PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, space);
prepare_physics_server();
} break;
+
case NOTIFICATION_READY: {
if (!parent_collision_ignore.is_empty()) {
add_collision_exception_with(get_node(parent_collision_ignore));
}
-
} break;
+
case NOTIFICATION_TRANSFORM_CHANGED: {
if (Engine::get_singleton()->is_editor_hint()) {
_reset_points_offsets();
@@ -285,71 +272,88 @@ void SoftBody3D::_notification(int p_what) {
set_as_top_level(true);
set_transform(Transform3D());
set_notify_transform(true);
-
} break;
+
case NOTIFICATION_VISIBILITY_CHANGED: {
_update_pickable();
-
} break;
+
case NOTIFICATION_EXIT_WORLD: {
PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, RID());
-
} break;
- }
-#ifdef TOOLS_ENABLED
+ case NOTIFICATION_DISABLED: {
+ if (is_inside_tree() && (disable_mode == DISABLE_MODE_REMOVE)) {
+ prepare_physics_server();
+ }
+ } break;
- if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
- if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warnings();
- }
- }
+ case NOTIFICATION_ENABLED: {
+ if (is_inside_tree() && (disable_mode == DISABLE_MODE_REMOVE)) {
+ prepare_physics_server();
+ }
+ } break;
+#ifdef TOOLS_ENABLED
+ case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ update_configuration_warnings();
+ }
+ } break;
#endif
+ }
}
-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"), &SoftDynamicBody3D::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftDynamicBody3D::get_collision_mask);
- 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_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_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_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_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_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_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_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_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_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");
@@ -364,9 +368,14 @@ void SoftBody3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "drag_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_coefficient", "get_drag_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ray_pickable"), "set_ray_pickable", "is_ray_pickable");
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "disable_mode", PROPERTY_HINT_ENUM, "Remove,KeepActive"), "set_disable_mode", "get_disable_mode");
+
+ BIND_ENUM_CONSTANT(DISABLE_MODE_REMOVE);
+ 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()) {
@@ -375,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;
}
@@ -397,18 +406,19 @@ void SoftBody3D::_update_physics_server() {
}
}
-void SoftBody3D::_draw_soft_mesh() {
+void SoftDynamicBody3D::_draw_soft_mesh() {
if (get_mesh().is_null()) {
return;
}
- if (!rendering_server_handler.is_ready()) {
- rendering_server_handler.prepare(get_mesh()->get_rid(), 0);
+ const RID mesh_rid = get_mesh()->get_rid();
+ if (!rendering_server_handler.is_ready(mesh_rid)) {
+ rendering_server_handler.prepare(mesh_rid, 0);
/// Necessary in order to render the mesh correctly (Soft body nodes are in global space)
simulation_started = true;
- call_deferred("set_as_top_level", true);
- call_deferred("set_transform", Transform3D());
+ call_deferred(SNAME("set_as_top_level"), true);
+ call_deferred(SNAME("set_transform"), Transform3D());
}
_update_physics_server();
@@ -420,30 +430,32 @@ 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;
}
+#endif
- if (get_mesh().is_valid()) {
+ 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;
}
@@ -456,7 +468,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);
@@ -465,7 +477,7 @@ void SoftBody3D::become_mesh_owner() {
surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;
Ref<ArrayMesh> soft_mesh;
- soft_mesh.instance();
+ soft_mesh.instantiate();
soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_lods, surface_format);
soft_mesh->surface_set_material(0, mesh->surface_get_material(0));
@@ -477,81 +489,106 @@ 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_parent_collision_ignore(const NodePath &p_parent_collision_ignore) {
+void SoftDynamicBody3D::set_disable_mode(DisableMode p_mode) {
+ if (disable_mode == p_mode) {
+ return;
+ }
+
+ bool inside_tree = is_inside_tree();
+
+ if (inside_tree && (disable_mode == DISABLE_MODE_REMOVE)) {
+ prepare_physics_server();
+ }
+
+ disable_mode = p_mode;
+
+ if (inside_tree && (disable_mode == DISABLE_MODE_REMOVE)) {
+ prepare_physics_server();
+ }
+}
+
+SoftDynamicBody3D::DisableMode SoftDynamicBody3D::get_disable_mode() const {
+ return disable_mode;
+}
+
+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;
- for (List<RID>::Element *E = exceptions.front(); E; E = E->next()) {
- RID body = E->get();
+ for (const RID &body : exceptions) {
ObjectID instance_id = PhysicsServer3D::get_singleton()->body_get_object_instance_id(body);
Object *obj = ObjectDB::get_instance(instance_id);
PhysicsBody3D *physics_body = Object::cast_to<PhysicsBody3D>(obj);
@@ -560,77 +597,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);
@@ -639,41 +676,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;
}
@@ -686,17 +715,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;
@@ -721,7 +750,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;
}
@@ -743,25 +772,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 0d0d39d48f..5e7fbfe29e 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,8 +49,8 @@ class SoftBodyRenderingServerHandler : public RenderingServerHandler {
uint8_t *write_buffer = nullptr;
private:
- SoftBodyRenderingServerHandler();
- bool is_ready() { return mesh.is_valid(); }
+ SoftDynamicBodyRenderingServerHandler();
+ bool is_ready(RID p_mesh_rid) const { return mesh.is_valid() && mesh == p_mesh_rid; }
void prepare(RID p_mesh_rid, int p_surface);
void clear();
void open();
@@ -63,10 +63,15 @@ 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 {
+ DISABLE_MODE_REMOVE,
+ DISABLE_MODE_KEEP_ACTIVE,
+ };
+
struct PinnedPoint {
int point_index = -1;
NodePath spatial_attachment_path;
@@ -79,10 +84,12 @@ public:
};
private:
- SoftBodyRenderingServerHandler rendering_server_handler;
+ SoftDynamicBodyRenderingServerHandler rendering_server_handler;
RID physics_rid;
+ DisableMode disable_mode = DISABLE_MODE_REMOVE;
+
bool mesh_owner = false;
uint32_t collision_mask = 1;
uint32_t collision_layer = 1;
@@ -99,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;
@@ -131,11 +136,14 @@ 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;
void set_parent_collision_ignore(const NodePath &p_parent_collision_ignore);
const NodePath &get_parent_collision_ignore() const;
@@ -174,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();
@@ -192,4 +198,6 @@ private:
int _has_pinned_point(int p_point_index) const;
};
-#endif // SOFT_PHYSICS_BODY_H
+VARIANT_ENUM_CAST(SoftDynamicBody3D::DisableMode);
+
+#endif // SOFT_DYNAMIC_BODY_H
diff --git a/scene/3d/spring_arm_3d.cpp b/scene/3d/spring_arm_3d.cpp
index 1911e14d54..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) {
@@ -84,7 +80,7 @@ real_t SpringArm3D::get_length() const {
void SpringArm3D::set_length(real_t p_length) {
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint())) {
- update_gizmo();
+ update_gizmos();
}
spring_length = p_length;
@@ -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 be474e82e0..349a534680 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -60,8 +60,8 @@ void SpriteBase3D::_propagate_color_changed() {
color_dirty = true;
_queue_update();
- for (List<SpriteBase3D *>::Element *E = children.front(); E; E = E->next()) {
- E->get()->_propagate_color_changed();
+ for (SpriteBase3D *&E : children) {
+ E->_propagate_color_changed();
}
}
@@ -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;
}
@@ -164,6 +164,8 @@ void SpriteBase3D::_im_update() {
_draw();
pending_update = false;
+
+ //texture->draw_rect_region(ci,dst_rect,src_rect,modulate);
}
void SpriteBase3D::_queue_update() {
@@ -172,7 +174,7 @@ void SpriteBase3D::_queue_update() {
}
triangle_mesh.unref();
- update_gizmo();
+ update_gizmos();
pending_update = true;
call_deferred(SceneStringNames::get_singleton()->_im_update);
@@ -201,9 +203,10 @@ 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] = {
+
(final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
(final_rect.position + final_rect.size) * pixel_size,
(final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
@@ -313,6 +316,9 @@ void SpriteBase3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_item_rect"), &SpriteBase3D::get_item_rect);
ClassDB::bind_method(D_METHOD("generate_triangle_mesh"), &SpriteBase3D::generate_triangle_mesh);
+ ClassDB::bind_method(D_METHOD("_queue_update"), &SpriteBase3D::_queue_update);
+ ClassDB::bind_method(D_METHOD("_im_update"), &SpriteBase3D::_im_update);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
@@ -343,21 +349,89 @@ SpriteBase3D::SpriteBase3D() {
flags[i] = i == FLAG_TRANSPARENT || i == FLAG_DOUBLE_SIDED;
}
- immediate = RenderingServer::get_singleton()->immediate_create();
- set_base(immediate);
+ material = RenderingServer::get_singleton()->material_create();
+ // Set defaults for material, names need to match up those in StandardMaterial3D
+ RS::get_singleton()->material_set_param(material, "albedo", Color(1, 1, 1, 1));
+ RS::get_singleton()->material_set_param(material, "specular", 0.5);
+ RS::get_singleton()->material_set_param(material, "metallic", 0.0);
+ RS::get_singleton()->material_set_param(material, "roughness", 1.0);
+ RS::get_singleton()->material_set_param(material, "uv1_offset", Vector3(0, 0, 0));
+ RS::get_singleton()->material_set_param(material, "uv1_scale", Vector3(1, 1, 1));
+ RS::get_singleton()->material_set_param(material, "uv2_offset", Vector3(0, 0, 0));
+ RS::get_singleton()->material_set_param(material, "uv2_scale", Vector3(1, 1, 1));
+ RS::get_singleton()->material_set_param(material, "alpha_scissor_threshold", 0.98);
+
+ mesh = RenderingServer::get_singleton()->mesh_create();
+
+ PackedVector3Array mesh_vertices;
+ PackedVector3Array mesh_normals;
+ PackedFloat32Array mesh_tangents;
+ PackedColorArray mesh_colors;
+ PackedVector2Array mesh_uvs;
+ PackedInt32Array indices;
+
+ mesh_vertices.resize(4);
+ mesh_normals.resize(4);
+ mesh_tangents.resize(16);
+ mesh_colors.resize(4);
+ mesh_uvs.resize(4);
+
+ // create basic mesh and store format information
+ for (int i = 0; i < 4; i++) {
+ mesh_normals.write[i] = Vector3(0.0, 0.0, 0.0);
+ mesh_tangents.write[i * 4 + 0] = 0.0;
+ mesh_tangents.write[i * 4 + 1] = 0.0;
+ mesh_tangents.write[i * 4 + 2] = 0.0;
+ mesh_tangents.write[i * 4 + 3] = 0.0;
+ mesh_colors.write[i] = Color(1.0, 1.0, 1.0, 1.0);
+ mesh_uvs.write[i] = Vector2(0.0, 0.0);
+ mesh_vertices.write[i] = Vector3(0.0, 0.0, 0.0);
+ }
+
+ indices.resize(6);
+ indices.write[0] = 0;
+ indices.write[1] = 1;
+ indices.write[2] = 2;
+ indices.write[3] = 0;
+ indices.write[4] = 2;
+ indices.write[5] = 3;
+
+ Array mesh_array;
+ mesh_array.resize(RS::ARRAY_MAX);
+ mesh_array[RS::ARRAY_VERTEX] = mesh_vertices;
+ mesh_array[RS::ARRAY_NORMAL] = mesh_normals;
+ mesh_array[RS::ARRAY_TANGENT] = mesh_tangents;
+ mesh_array[RS::ARRAY_COLOR] = mesh_colors;
+ mesh_array[RS::ARRAY_TEX_UV] = mesh_uvs;
+ mesh_array[RS::ARRAY_INDEX] = indices;
+
+ RS::SurfaceData sd;
+ RS::get_singleton()->mesh_create_surface_data_from_arrays(&sd, RS::PRIMITIVE_TRIANGLES, mesh_array);
+
+ mesh_surface_format = sd.format;
+ vertex_buffer = sd.vertex_data;
+ attribute_buffer = sd.attribute_data;
+
+ sd.material = material;
+
+ RS::get_singleton()->mesh_surface_make_offsets_from_format(sd.format, sd.vertex_count, sd.index_count, mesh_surface_offsets, vertex_stride, attrib_stride, skin_stride);
+ RS::get_singleton()->mesh_add_surface(mesh, sd);
+ set_base(mesh);
}
SpriteBase3D::~SpriteBase3D() {
- RenderingServer::get_singleton()->free(immediate);
+ RenderingServer::get_singleton()->free(mesh);
+ RenderingServer::get_singleton()->free(material);
}
///////////////////////////////////////////
void Sprite3D::_draw() {
- RID immediate = get_immediate();
-
- RS::get_singleton()->immediate_clear(immediate);
+ if (get_base() != get_mesh()) {
+ set_base(get_mesh());
+ }
if (!texture.is_valid()) {
+ set_base(RID());
return;
}
Vector2 tsize = texture->get_size();
@@ -366,7 +440,7 @@ void Sprite3D::_draw() {
}
Rect2 base_rect;
- if (region_enabled) {
+ if (region) {
base_rect = region_rect;
} else {
base_rect = Rect2(0, 0, texture->get_width(), texture->get_height());
@@ -396,9 +470,10 @@ 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] = {
+
(final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
(final_rect.position + final_rect.size) * pixel_size,
(final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
@@ -426,6 +501,7 @@ void Sprite3D::_draw() {
SWAP(uvs[0], uvs[1]);
SWAP(uvs[2], uvs[3]);
}
+
if (is_flipped_v()) {
SWAP(uvs[0], uvs[3]);
SWAP(uvs[1], uvs[2]);
@@ -442,11 +518,6 @@ void Sprite3D::_draw() {
tangent = Plane(1, 0, 0, 1);
}
- RID mat = StandardMaterial3D::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y);
- RS::get_singleton()->immediate_set_material(immediate, mat);
-
- RS::get_singleton()->immediate_begin(immediate, RS::PRIMITIVE_TRIANGLES, texture->get_rid());
-
int x_axis = ((axis + 1) % 3);
int y_axis = ((axis + 2) % 3);
@@ -466,31 +537,80 @@ void Sprite3D::_draw() {
AABB aabb;
- for (int i = 0; i < 6; i++) {
- static const int index[6] = { 0, 1, 2, 0, 2, 3 };
+ // Everything except position and UV is compressed
+ uint8_t *vertex_write_buffer = vertex_buffer.ptrw();
+ uint8_t *attribute_write_buffer = attribute_buffer.ptrw();
+
+ uint32_t v_normal;
+ {
+ Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
+
+ uint32_t value = 0;
+ value |= CLAMP(int(n.x * 1023.0), 0, 1023);
+ value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
+ value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
+
+ v_normal = value;
+ }
+ uint32_t v_tangent;
+ {
+ Plane t = tangent;
+ uint32_t value = 0;
+ value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023);
+ value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
+ value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
+ if (t.d > 0) {
+ value |= 3 << 30;
+ }
+ v_tangent = value;
+ }
- RS::get_singleton()->immediate_normal(immediate, normal);
- RS::get_singleton()->immediate_tangent(immediate, tangent);
- RS::get_singleton()->immediate_color(immediate, color);
- RS::get_singleton()->immediate_uv(immediate, uvs[index[i]]);
+ uint8_t v_color[4] = {
+ uint8_t(CLAMP(color.r * 255.0, 0.0, 255.0)),
+ uint8_t(CLAMP(color.g * 255.0, 0.0, 255.0)),
+ uint8_t(CLAMP(color.b * 255.0, 0.0, 255.0)),
+ uint8_t(CLAMP(color.a * 255.0, 0.0, 255.0))
+ };
+ for (int i = 0; i < 4; i++) {
Vector3 vtx;
- vtx[x_axis] = vertices[index[i]][0];
- vtx[y_axis] = vertices[index[i]][1];
- RS::get_singleton()->immediate_vertex(immediate, vtx);
+ vtx[x_axis] = vertices[i][0];
+ vtx[y_axis] = vertices[i][1];
if (i == 0) {
aabb.position = vtx;
aabb.size = Vector3();
} else {
aabb.expand_to(vtx);
}
+
+ float v_uv[2] = { (float)uvs[i].x, (float)uvs[i].y };
+ memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_TEX_UV]], v_uv, 8);
+
+ float v_vertex[3] = { (float)vtx.x, (float)vtx.y, (float)vtx.z };
+
+ memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3);
+ memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_NORMAL]], &v_normal, 4);
+ memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_TANGENT]], &v_tangent, 4);
+ memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_COLOR]], v_color, 4);
}
+
+ RID mesh = get_mesh();
+ RS::get_singleton()->mesh_surface_update_vertex_region(mesh, 0, 0, vertex_buffer);
+ RS::get_singleton()->mesh_surface_update_attribute_region(mesh, 0, 0, attribute_buffer);
+
+ RS::get_singleton()->mesh_set_custom_aabb(mesh, aabb);
set_aabb(aabb);
- RS::get_singleton()->immediate_end(immediate);
-}
-void Sprite3D::_texture_changed() {
- _queue_update();
+ RID shader_rid;
+ StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, &shader_rid);
+ if (last_shader != shader_rid) {
+ RS::get_singleton()->material_set_shader(get_material(), shader_rid);
+ last_shader = shader_rid;
+ }
+ if (last_texture != texture->get_rid()) {
+ RS::get_singleton()->material_set_param(get_material(), "texture_albedo", texture->get_rid());
+ last_texture = texture->get_rid();
+ }
}
void Sprite3D::set_texture(const Ref<Texture2D> &p_texture) {
@@ -498,11 +618,11 @@ void Sprite3D::set_texture(const Ref<Texture2D> &p_texture) {
return;
}
if (texture.is_valid()) {
- texture->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite3D::_texture_changed));
+ texture->disconnect(CoreStringNames::get_singleton()->changed, Callable(this, "_queue_update"));
}
texture = p_texture;
if (texture.is_valid()) {
- texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite3D::_texture_changed));
+ texture->connect(CoreStringNames::get_singleton()->changed, Callable(this, "_queue_update"));
}
_queue_update();
}
@@ -511,24 +631,23 @@ Ref<Texture2D> Sprite3D::get_texture() const {
return texture;
}
-void Sprite3D::set_region_enabled(bool p_region_enabled) {
- if (p_region_enabled == region_enabled) {
+void Sprite3D::set_region_enabled(bool p_region) {
+ if (p_region == region) {
return;
}
- region_enabled = p_region_enabled;
+ region = p_region;
_queue_update();
- notify_property_list_changed();
}
bool Sprite3D::is_region_enabled() const {
- return region_enabled;
+ return region;
}
void Sprite3D::set_region_rect(const Rect2 &p_region_rect) {
bool changed = region_rect != p_region_rect;
region_rect = p_region_rect;
- if (region_enabled && changed) {
+ if (region && changed) {
_queue_update();
}
}
@@ -593,9 +712,9 @@ Rect2 Sprite3D::get_item_rect() const {
return CanvasItem::get_item_rect();
*/
- Size2i s;
+ Size2 s;
- if (region_enabled) {
+ if (region) {
s = region_rect.size;
} else {
s = texture->get_size();
@@ -624,10 +743,6 @@ void Sprite3D::_validate_property(PropertyInfo &property) const {
if (property.name == "frame_coords") {
property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
-
- if (!region_enabled && property.name == "region_rect") {
- property.usage = PROPERTY_USAGE_NOEDITOR;
- }
}
void Sprite3D::_bind_methods() {
@@ -652,12 +767,12 @@ void Sprite3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_hframes", "hframes"), &Sprite3D::set_hframes);
ClassDB::bind_method(D_METHOD("get_hframes"), &Sprite3D::get_hframes);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
ADD_GROUP("Animation", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
ADD_GROUP("Region", "region_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region_enabled", "is_region_enabled");
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
@@ -666,17 +781,14 @@ void Sprite3D::_bind_methods() {
}
Sprite3D::Sprite3D() {
- region_enabled = false;
- frame = 0;
- vframes = 1;
- hframes = 1;
}
////////////////////////////////////////
void AnimatedSprite3D::_draw() {
- RID immediate = get_immediate();
- RS::get_singleton()->immediate_clear(immediate);
+ if (get_base() != get_mesh()) {
+ set_base(get_mesh());
+ }
if (frames.is_null()) {
return;
@@ -692,24 +804,23 @@ void AnimatedSprite3D::_draw() {
Ref<Texture2D> texture = frames->get_frame(animation, frame);
if (!texture.is_valid()) {
- return; //no texture no life
+ 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;
@@ -724,9 +835,10 @@ 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] = {
+
(final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
(final_rect.position + final_rect.size) * pixel_size,
(final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
@@ -770,12 +882,6 @@ void AnimatedSprite3D::_draw() {
tangent = Plane(1, 0, 0, -1);
}
- RID mat = StandardMaterial3D::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y);
-
- RS::get_singleton()->immediate_set_material(immediate, mat);
-
- RS::get_singleton()->immediate_begin(immediate, RS::PRIMITIVE_TRIANGLES, texture->get_rid());
-
int x_axis = ((axis + 1) % 3);
int y_axis = ((axis + 2) % 3);
@@ -795,30 +901,79 @@ void AnimatedSprite3D::_draw() {
AABB aabb;
- for (int i = 0; i < 6; i++) {
- static const int indices[6] = {
- 0, 1, 2,
- 0, 2, 3
- };
+ // Everything except position and UV is compressed
+ uint8_t *vertex_write_buffer = vertex_buffer.ptrw();
+ uint8_t *attribute_write_buffer = attribute_buffer.ptrw();
+
+ uint32_t v_normal;
+ {
+ Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
+
+ uint32_t value = 0;
+ value |= CLAMP(int(n.x * 1023.0), 0, 1023);
+ value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
+ value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
+
+ v_normal = value;
+ }
+ uint32_t v_tangent;
+ {
+ Plane t = tangent;
+ uint32_t value = 0;
+ value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023);
+ value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
+ value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
+ if (t.d > 0) {
+ value |= 3 << 30;
+ }
+ v_tangent = value;
+ }
- RS::get_singleton()->immediate_normal(immediate, normal);
- RS::get_singleton()->immediate_tangent(immediate, tangent);
- RS::get_singleton()->immediate_color(immediate, color);
- RS::get_singleton()->immediate_uv(immediate, uvs[indices[i]]);
+ uint8_t v_color[4] = {
+ uint8_t(CLAMP(color.r * 255.0, 0.0, 255.0)),
+ uint8_t(CLAMP(color.g * 255.0, 0.0, 255.0)),
+ uint8_t(CLAMP(color.b * 255.0, 0.0, 255.0)),
+ uint8_t(CLAMP(color.a * 255.0, 0.0, 255.0))
+ };
+ for (int i = 0; i < 4; i++) {
Vector3 vtx;
- vtx[x_axis] = vertices[indices[i]][0];
- vtx[y_axis] = vertices[indices[i]][1];
- RS::get_singleton()->immediate_vertex(immediate, vtx);
+ vtx[x_axis] = vertices[i][0];
+ vtx[y_axis] = vertices[i][1];
if (i == 0) {
aabb.position = vtx;
aabb.size = Vector3();
} else {
aabb.expand_to(vtx);
}
+
+ float v_uv[2] = { (float)uvs[i].x, (float)uvs[i].y };
+ memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_TEX_UV]], v_uv, 8);
+
+ float v_vertex[3] = { (float)vtx.x, (float)vtx.y, (float)vtx.z };
+ memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3);
+ memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_NORMAL]], &v_normal, 4);
+ memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_TANGENT]], &v_tangent, 4);
+ memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_COLOR]], v_color, 4);
}
+
+ RID mesh = get_mesh();
+ RS::get_singleton()->mesh_surface_update_vertex_region(mesh, 0, 0, vertex_buffer);
+ RS::get_singleton()->mesh_surface_update_attribute_region(mesh, 0, 0, attribute_buffer);
+
+ RS::get_singleton()->mesh_set_custom_aabb(mesh, aabb);
set_aabb(aabb);
- RS::get_singleton()->immediate_end(immediate);
+
+ RID shader_rid;
+ StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, &shader_rid);
+ if (last_shader != shader_rid) {
+ RS::get_singleton()->material_set_shader(get_material(), shader_rid);
+ last_shader = shader_rid;
+ }
+ if (last_texture != texture->get_rid()) {
+ RS::get_singleton()->material_set_param(get_material(), "texture_albedo", texture->get_rid());
+ last_texture = texture->get_rid();
+ }
}
void AnimatedSprite3D::_validate_property(PropertyInfo &property) const {
@@ -839,7 +994,7 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &property) const {
}
property.hint_string += String(E->get());
- if (animation == E->get()) {
+ if (animation == E) {
current_found = true;
}
}
@@ -880,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) {
@@ -902,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;
}
@@ -912,11 +1067,11 @@ void AnimatedSprite3D::_notification(int p_what) {
void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
if (frames.is_valid()) {
- frames->disconnect("changed", callable_mp(this, &AnimatedSprite3D::_res_changed));
+ frames->disconnect("changed", Callable(this, "_res_changed"));
}
frames = p_frames;
if (frames.is_valid()) {
- frames->connect("changed", callable_mp(this, &AnimatedSprite3D::_res_changed));
+ frames->connect("changed", Callable(this, "_res_changed"));
}
if (!frames.is_valid()) {
@@ -942,9 +1097,8 @@ void AnimatedSprite3D::set_frame(int p_frame) {
if (frames->has_animation(animation)) {
int limit = frames->get_frame_count(animation);
- if (p_frame >= limit) {
+ if (p_frame >= limit)
p_frame = limit - 1;
- }
}
if (p_frame < 0) {
@@ -958,7 +1112,6 @@ void AnimatedSprite3D::set_frame(int p_frame) {
frame = p_frame;
_reset_timeout();
_queue_update();
-
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -978,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) {
@@ -1022,7 +1175,7 @@ void AnimatedSprite3D::stop() {
}
bool AnimatedSprite3D::is_playing() const {
- return is_processing();
+ return playing;
}
void AnimatedSprite3D::_reset_timeout() {
@@ -1059,8 +1212,7 @@ StringName AnimatedSprite3D::get_animation() const {
}
TypedArray<String> AnimatedSprite3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
-
+ TypedArray<String> warnings = SpriteBase3D::get_configuration_warnings();
if (frames.is_null()) {
warnings.push_back(TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames."));
}
@@ -1085,11 +1237,13 @@ void AnimatedSprite3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_frame", "frame"), &AnimatedSprite3D::set_frame);
ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite3D::get_frame);
+ ClassDB::bind_method(D_METHOD("_res_changed"), &AnimatedSprite3D::_res_changed);
+
ADD_SIGNAL(MethodInfo("frame_changed"));
ADD_SIGNAL(MethodInfo("animation_finished"));
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames");
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "animation"), "set_animation", "get_animation");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation");
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing");
}
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index e3dd117804..90c2a309e1 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -72,12 +72,13 @@ 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 immediate;
+ RID mesh;
+ RID material;
- bool flags[FLAG_MAX];
+ bool flags[FLAG_MAX] = {};
AlphaCutMode alpha_cut = ALPHA_CUT_DISABLED;
StandardMaterial3D::BillboardMode billboard_mode = StandardMaterial3D::BILLBOARD_DISABLED;
bool pending_update = false;
@@ -91,7 +92,17 @@ protected:
static void _bind_methods();
virtual void _draw() = 0;
_FORCE_INLINE_ void set_aabb(const AABB &p_aabb) { aabb = p_aabb; }
- _FORCE_INLINE_ RID &get_immediate() { return immediate; }
+ _FORCE_INLINE_ RID &get_mesh() { return mesh; }
+ _FORCE_INLINE_ RID &get_material() { return material; }
+
+ uint32_t mesh_surface_offsets[RS::ARRAY_MAX];
+ PackedByteArray vertex_buffer;
+ PackedByteArray attribute_buffer;
+ uint32_t vertex_stride;
+ uint32_t attrib_stride;
+ uint32_t skin_stride;
+ uint32_t mesh_surface_format;
+
void _queue_update();
public:
@@ -107,7 +118,7 @@ public:
void set_flip_v(bool p_flip);
bool is_flipped_v() const;
- void set_region_enabled(bool p_region_enabled);
+ void set_region_enabled(bool p_region);
bool is_region_enabled() const;
void set_region_rect(const Rect2 &p_region_rect);
@@ -119,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;
@@ -147,15 +158,16 @@ class Sprite3D : public SpriteBase3D {
GDCLASS(Sprite3D, SpriteBase3D);
Ref<Texture2D> texture;
- bool region_enabled;
+ bool region = false;
Rect2 region_rect;
- int frame;
+ int frame = 0;
- int vframes;
- int hframes;
+ int vframes = 1;
+ int hframes = 1;
- void _texture_changed();
+ RID last_shader;
+ RID last_texture;
protected:
virtual void _draw() override;
@@ -167,7 +179,7 @@ public:
void set_texture(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_texture() const;
- void set_region_enabled(bool p_region_enabled);
+ void set_region_enabled(bool p_region);
bool is_region_enabled() const;
void set_region_rect(const Rect2 &p_region_rect);
@@ -199,14 +211,9 @@ class AnimatedSprite3D : public SpriteBase3D {
StringName animation = "default";
int frame = 0;
- bool centered = true;
-
- float timeout = 0.0;
-
- bool hflip = true;
- bool vflip = true;
+ bool centered = false;
- Color modulate;
+ double timeout = 0.0;
void _res_changed();
@@ -214,6 +221,9 @@ class AnimatedSprite3D : public SpriteBase3D {
void _set_playing(bool p_playing);
bool _is_playing() const;
+ RID last_shader;
+ RID last_texture;
+
protected:
virtual void _draw() override;
static void _bind_methods();
@@ -236,10 +246,11 @@ public:
virtual Rect2 get_item_rect() const override;
- TypedArray<String> get_configuration_warnings() const override;
+ virtual TypedArray<String> get_configuration_warnings() const override;
AnimatedSprite3D();
};
VARIANT_ENUM_CAST(SpriteBase3D::DrawFlags);
VARIANT_ENUM_CAST(SpriteBase3D::AlphaCutMode);
+
#endif // SPRITE_3D_H
diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp
index 0d88769b70..9a2aaa8be2 100644
--- a/scene/3d/vehicle_body_3d.cpp
+++ b/scene/3d/vehicle_body_3d.cpp
@@ -79,26 +79,29 @@ public:
};
void VehicleWheel3D::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent());
- if (!cb) {
- return;
- }
- body = cb;
- local_xform = get_transform();
- cb->wheels.push_back(this);
-
- m_chassisConnectionPointCS = get_transform().origin;
- m_wheelDirectionCS = -get_transform().basis.get_axis(Vector3::AXIS_Y).normalized();
- m_wheelAxleCS = get_transform().basis.get_axis(Vector3::AXIS_X).normalized();
- }
- if (p_what == NOTIFICATION_EXIT_TREE) {
- VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent());
- if (!cb) {
- return;
- }
- cb->wheels.erase(this);
- body = nullptr;
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent());
+ if (!cb) {
+ return;
+ }
+ body = cb;
+ local_xform = get_transform();
+ cb->wheels.push_back(this);
+
+ m_chassisConnectionPointCS = get_transform().origin;
+ m_wheelDirectionCS = -get_transform().basis.get_axis(Vector3::AXIS_Y).normalized();
+ m_wheelAxleCS = get_transform().basis.get_axis(Vector3::AXIS_X).normalized();
+ } break;
+
+ case NOTIFICATION_EXIT_TREE: {
+ VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent());
+ if (!cb) {
+ return;
+ }
+ cb->wheels.erase(this);
+ body = nullptr;
+ } break;
}
}
@@ -146,7 +149,7 @@ void VehicleWheel3D::_update(PhysicsDirectBodyState3D *s) {
void VehicleWheel3D::set_radius(real_t p_radius) {
m_wheelRadius = p_radius;
- update_gizmo();
+ update_gizmos();
}
real_t VehicleWheel3D::get_radius() const {
@@ -155,7 +158,7 @@ real_t VehicleWheel3D::get_radius() const {
void VehicleWheel3D::set_suspension_rest_length(real_t p_length) {
m_suspensionRestLength = p_length;
- update_gizmo();
+ update_gizmos();
}
real_t VehicleWheel3D::get_suspension_rest_length() const {
@@ -467,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];
@@ -555,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);
@@ -581,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;
@@ -799,24 +802,21 @@ void VehicleBody3D::_update_friction(PhysicsDirectBodyState3D *s) {
}
}
-void VehicleBody3D::_direct_state_changed(Object *p_state) {
- RigidBody3D::_direct_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");
+void VehicleBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
+ RigidDynamicBody3D::_body_state_changed(p_state);
- 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
@@ -828,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],
@@ -861,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) {
@@ -923,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/velocity_tracker_3d.h b/scene/3d/velocity_tracker_3d.h
index e971f4755a..827c3f5bd8 100644
--- a/scene/3d/velocity_tracker_3d.h
+++ b/scene/3d/velocity_tracker_3d.h
@@ -33,8 +33,8 @@
#include "scene/3d/node_3d.h"
-class VelocityTracker3D : public Reference {
- GDCLASS(VelocityTracker3D, Reference);
+class VelocityTracker3D : public RefCounted {
+ GDCLASS(VelocityTracker3D, RefCounted);
struct PositionHistory {
uint64_t frame = 0;
diff --git a/scene/3d/visibility_notifier_3d.cpp b/scene/3d/visibility_notifier_3d.cpp
deleted file mode 100644
index b230cb2fd7..0000000000
--- a/scene/3d/visibility_notifier_3d.cpp
+++ /dev/null
@@ -1,253 +0,0 @@
-/*************************************************************************/
-/* visibility_notifier_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 "visibility_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 VisibilityNotifier3D::_enter_camera(Camera3D *p_camera) {
- ERR_FAIL_COND(cameras.has(p_camera));
- cameras.insert(p_camera);
- if (cameras.size() == 1) {
- emit_signal(SceneStringNames::get_singleton()->screen_entered);
- _screen_enter();
- }
-
- emit_signal(SceneStringNames::get_singleton()->camera_entered, p_camera);
-}
-
-void VisibilityNotifier3D::_exit_camera(Camera3D *p_camera) {
- ERR_FAIL_COND(!cameras.has(p_camera));
- cameras.erase(p_camera);
-
- emit_signal(SceneStringNames::get_singleton()->camera_exited, p_camera);
- if (cameras.size() == 0) {
- emit_signal(SceneStringNames::get_singleton()->screen_exited);
-
- _screen_exit();
- }
-}
-
-void VisibilityNotifier3D::set_aabb(const AABB &p_aabb) {
- if (aabb == p_aabb) {
- return;
- }
- aabb = p_aabb;
-
- if (is_inside_world()) {
- get_world_3d()->_update_notifier(this, get_global_transform().xform(aabb));
- }
-
- update_gizmo();
-}
-
-AABB VisibilityNotifier3D::get_aabb() const {
- return aabb;
-}
-
-void VisibilityNotifier3D::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_WORLD: {
- world = get_world_3d();
- ERR_FAIL_COND(!world.is_valid());
- world->_register_notifier(this, get_global_transform().xform(aabb));
- } break;
- case NOTIFICATION_TRANSFORM_CHANGED: {
- world->_update_notifier(this, get_global_transform().xform(aabb));
- } break;
- case NOTIFICATION_EXIT_WORLD: {
- ERR_FAIL_COND(!world.is_valid());
- world->_remove_notifier(this);
- } break;
- }
-}
-
-bool VisibilityNotifier3D::is_on_screen() const {
- return cameras.size() != 0;
-}
-
-void VisibilityNotifier3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_aabb", "rect"), &VisibilityNotifier3D::set_aabb);
- ClassDB::bind_method(D_METHOD("get_aabb"), &VisibilityNotifier3D::get_aabb);
- ClassDB::bind_method(D_METHOD("is_on_screen"), &VisibilityNotifier3D::is_on_screen);
-
- ADD_PROPERTY(PropertyInfo(Variant::AABB, "aabb"), "set_aabb", "get_aabb");
-
- ADD_SIGNAL(MethodInfo("camera_entered", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D")));
- ADD_SIGNAL(MethodInfo("camera_exited", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D")));
- ADD_SIGNAL(MethodInfo("screen_entered"));
- ADD_SIGNAL(MethodInfo("screen_exited"));
-}
-
-VisibilityNotifier3D::VisibilityNotifier3D() {
- set_notify_transform(true);
-}
-
-//////////////////////////////////////
-
-void VisibilityEnabler3D::_screen_enter() {
- for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
- _change_node_state(E->key(), true);
- }
-
- visible = true;
-}
-
-void VisibilityEnabler3D::_screen_exit() {
- for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
- _change_node_state(E->key(), false);
- }
-
- visible = false;
-}
-
-void VisibilityEnabler3D::_find_nodes(Node *p_node) {
- bool add = false;
- Variant meta;
-
- {
- RigidBody3D *rb = Object::cast_to<RigidBody3D>(p_node);
- if (rb && ((rb->get_mode() == RigidBody3D::MODE_DYNAMIC || rb->get_mode() == RigidBody3D::MODE_DYNAMIC_LOCKED))) {
- add = true;
- meta = rb->get_mode();
- }
- }
-
- {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
- if (ap) {
- add = true;
- }
- }
-
- if (add) {
- p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler3D::_node_removed), varray(p_node), CONNECT_ONESHOT);
- nodes[p_node] = meta;
- _change_node_state(p_node, false);
- }
-
- for (int i = 0; i < p_node->get_child_count(); i++) {
- Node *c = p_node->get_child(i);
- if (c->get_filename() != String()) {
- continue; //skip, instance
- }
-
- _find_nodes(c);
- }
-}
-
-void VisibilityEnabler3D::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- if (Engine::get_singleton()->is_editor_hint()) {
- return;
- }
-
- Node *from = this;
- //find where current scene starts
- while (from->get_parent() && from->get_filename() == String()) {
- from = from->get_parent();
- }
-
- _find_nodes(from);
- }
-
- if (p_what == NOTIFICATION_EXIT_TREE) {
- if (Engine::get_singleton()->is_editor_hint()) {
- return;
- }
-
- for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
- if (!visible) {
- _change_node_state(E->key(), true);
- }
- E->key()->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler3D::_node_removed));
- }
-
- nodes.clear();
- }
-}
-
-void VisibilityEnabler3D::_change_node_state(Node *p_node, bool p_enabled) {
- ERR_FAIL_COND(!nodes.has(p_node));
-
- if (enabler[ENABLER_FREEZE_BODIES]) {
- RigidBody3D *rb = Object::cast_to<RigidBody3D>(p_node);
- if (rb) {
- rb->set_sleeping(!p_enabled);
- }
- }
-
- if (enabler[ENABLER_PAUSE_ANIMATIONS]) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
-
- if (ap) {
- ap->set_active(p_enabled);
- }
- }
-}
-
-void VisibilityEnabler3D::_node_removed(Node *p_node) {
- if (!visible) {
- _change_node_state(p_node, true);
- }
- nodes.erase(p_node);
-}
-
-void VisibilityEnabler3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_enabler", "enabler", "enabled"), &VisibilityEnabler3D::set_enabler);
- ClassDB::bind_method(D_METHOD("is_enabler_enabled", "enabler"), &VisibilityEnabler3D::is_enabler_enabled);
-
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_animations"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_ANIMATIONS);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "freeze_bodies"), "set_enabler", "is_enabler_enabled", ENABLER_FREEZE_BODIES);
-
- BIND_ENUM_CONSTANT(ENABLER_PAUSE_ANIMATIONS);
- BIND_ENUM_CONSTANT(ENABLER_FREEZE_BODIES);
- BIND_ENUM_CONSTANT(ENABLER_MAX);
-}
-
-void VisibilityEnabler3D::set_enabler(Enabler p_enabler, bool p_enable) {
- ERR_FAIL_INDEX(p_enabler, ENABLER_MAX);
- enabler[p_enabler] = p_enable;
-}
-
-bool VisibilityEnabler3D::is_enabler_enabled(Enabler p_enabler) const {
- ERR_FAIL_INDEX_V(p_enabler, ENABLER_MAX, false);
- return enabler[p_enabler];
-}
-
-VisibilityEnabler3D::VisibilityEnabler3D() {
- for (int i = 0; i < ENABLER_MAX; i++) {
- enabler[i] = true;
- }
-}
diff --git a/scene/3d/visible_on_screen_notifier_3d.cpp b/scene/3d/visible_on_screen_notifier_3d.cpp
new file mode 100644
index 0000000000..3d0bc3df9c
--- /dev/null
+++ b/scene/3d/visible_on_screen_notifier_3d.cpp
@@ -0,0 +1,199 @@
+/*************************************************************************/
+/* visible_on_screen_notifier_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 "visible_on_screen_notifier_3d.h"
+
+#include "scene/scene_string_names.h"
+
+void VisibleOnScreenNotifier3D::_visibility_enter() {
+ if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) {
+ return;
+ }
+
+ on_screen = true;
+ emit_signal(SceneStringNames::get_singleton()->screen_entered);
+ _screen_enter();
+}
+void VisibleOnScreenNotifier3D::_visibility_exit() {
+ if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) {
+ return;
+ }
+
+ on_screen = false;
+ emit_signal(SceneStringNames::get_singleton()->screen_exited);
+ _screen_exit();
+}
+
+void VisibleOnScreenNotifier3D::set_aabb(const AABB &p_aabb) {
+ if (aabb == p_aabb) {
+ return;
+ }
+ aabb = p_aabb;
+
+ RS::get_singleton()->visibility_notifier_set_aabb(get_base(), aabb);
+
+ update_gizmos();
+}
+
+AABB VisibleOnScreenNotifier3D::get_aabb() const {
+ return aabb;
+}
+
+bool VisibleOnScreenNotifier3D::is_on_screen() const {
+ return on_screen;
+}
+
+void VisibleOnScreenNotifier3D::_notification(int p_what) {
+ if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_EXIT_TREE) {
+ on_screen = false;
+ }
+}
+
+void VisibleOnScreenNotifier3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_aabb", "rect"), &VisibleOnScreenNotifier3D::set_aabb);
+ ClassDB::bind_method(D_METHOD("is_on_screen"), &VisibleOnScreenNotifier3D::is_on_screen);
+
+ ADD_PROPERTY(PropertyInfo(Variant::AABB, "aabb"), "set_aabb", "get_aabb");
+
+ ADD_SIGNAL(MethodInfo("screen_entered"));
+ ADD_SIGNAL(MethodInfo("screen_exited"));
+}
+
+Vector<Face3> VisibleOnScreenNotifier3D::get_faces(uint32_t p_usage_flags) const {
+ return Vector<Face3>();
+}
+
+VisibleOnScreenNotifier3D::VisibleOnScreenNotifier3D() {
+ RID notifier = RS::get_singleton()->visibility_notifier_create();
+ RS::get_singleton()->visibility_notifier_set_aabb(notifier, aabb);
+ RS::get_singleton()->visibility_notifier_set_callbacks(notifier, callable_mp(this, &VisibleOnScreenNotifier3D::_visibility_enter), callable_mp(this, &VisibleOnScreenNotifier3D::_visibility_exit));
+ set_base(notifier);
+}
+VisibleOnScreenNotifier3D::~VisibleOnScreenNotifier3D() {
+ RID base = get_base();
+ set_base(RID());
+ RS::get_singleton()->free(base);
+}
+
+//////////////////////////////////////
+
+void VisibleOnScreenEnabler3D::_screen_enter() {
+ _update_enable_mode(true);
+}
+
+void VisibleOnScreenEnabler3D::_screen_exit() {
+ _update_enable_mode(false);
+}
+
+void VisibleOnScreenEnabler3D::set_enable_mode(EnableMode p_mode) {
+ enable_mode = p_mode;
+ if (is_inside_tree()) {
+ _update_enable_mode(is_on_screen());
+ }
+}
+VisibleOnScreenEnabler3D::EnableMode VisibleOnScreenEnabler3D::get_enable_mode() {
+ return enable_mode;
+}
+
+void VisibleOnScreenEnabler3D::set_enable_node_path(NodePath p_path) {
+ if (enable_node_path == p_path) {
+ return;
+ }
+ enable_node_path = p_path;
+ if (is_inside_tree()) {
+ node_id = ObjectID();
+ Node *node = get_node(enable_node_path);
+ if (node) {
+ node_id = node->get_instance_id();
+ _update_enable_mode(is_on_screen());
+ }
+ }
+}
+NodePath VisibleOnScreenEnabler3D::get_enable_node_path() {
+ return enable_node_path;
+}
+
+void VisibleOnScreenEnabler3D::_update_enable_mode(bool p_enable) {
+ Node *node = static_cast<Node *>(ObjectDB::get_instance(node_id));
+ if (node) {
+ if (p_enable) {
+ switch (enable_mode) {
+ case ENABLE_MODE_INHERIT: {
+ node->set_process_mode(PROCESS_MODE_INHERIT);
+ } break;
+ case ENABLE_MODE_ALWAYS: {
+ node->set_process_mode(PROCESS_MODE_ALWAYS);
+ } break;
+ case ENABLE_MODE_WHEN_PAUSED: {
+ node->set_process_mode(PROCESS_MODE_WHEN_PAUSED);
+ } break;
+ }
+ } else {
+ node->set_process_mode(PROCESS_MODE_DISABLED);
+ }
+ }
+}
+void VisibleOnScreenEnabler3D::_notification(int p_what) {
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ return;
+ }
+
+ node_id = ObjectID();
+ Node *node = get_node(enable_node_path);
+ if (node) {
+ node_id = node->get_instance_id();
+ node->set_process_mode(PROCESS_MODE_DISABLED);
+ }
+ }
+
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+ node_id = ObjectID();
+ }
+}
+
+void VisibleOnScreenEnabler3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_enable_mode", "mode"), &VisibleOnScreenEnabler3D::set_enable_mode);
+ ClassDB::bind_method(D_METHOD("get_enable_mode"), &VisibleOnScreenEnabler3D::get_enable_mode);
+
+ ClassDB::bind_method(D_METHOD("set_enable_node_path", "path"), &VisibleOnScreenEnabler3D::set_enable_node_path);
+ ClassDB::bind_method(D_METHOD("get_enable_node_path"), &VisibleOnScreenEnabler3D::get_enable_node_path);
+
+ ADD_GROUP("Enabling", "enable_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "enable_mode", PROPERTY_HINT_ENUM, "Inherit,Always,WhenPaused"), "set_enable_mode", "get_enable_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "enable_node_path"), "set_enable_node_path", "get_enable_node_path");
+
+ BIND_ENUM_CONSTANT(ENABLE_MODE_INHERIT);
+ BIND_ENUM_CONSTANT(ENABLE_MODE_ALWAYS);
+ BIND_ENUM_CONSTANT(ENABLE_MODE_WHEN_PAUSED);
+}
+
+VisibleOnScreenEnabler3D::VisibleOnScreenEnabler3D() {
+}
diff --git a/scene/3d/visibility_notifier_3d.h b/scene/3d/visible_on_screen_notifier_3d.h
index 9f7705067f..fb7137c4f0 100644
--- a/scene/3d/visibility_notifier_3d.h
+++ b/scene/3d/visible_on_screen_notifier_3d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* visibility_notifier_3d.h */
+/* visible_on_screen_notifier_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,74 +28,74 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef VISIBILITY_NOTIFIER_H
-#define VISIBILITY_NOTIFIER_H
+#ifndef VISIBLE_ON_SCREEN_NOTIFIER_3D_H
+#define VISIBLE_ON_SCREEN_NOTIFIER_3D_H
-#include "scene/3d/node_3d.h"
+#include "scene/3d/visual_instance_3d.h"
class World3D;
class Camera3D;
-class VisibilityNotifier3D : public Node3D {
- GDCLASS(VisibilityNotifier3D, Node3D);
-
- Ref<World3D> world;
- Set<Camera3D *> cameras;
+class VisibleOnScreenNotifier3D : public VisualInstance3D {
+ GDCLASS(VisibleOnScreenNotifier3D, VisualInstance3D);
AABB aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
+private:
+ bool on_screen = false;
+ void _visibility_enter();
+ void _visibility_exit();
+
protected:
virtual void _screen_enter() {}
virtual void _screen_exit() {}
void _notification(int p_what);
static void _bind_methods();
- friend struct SpatialIndexer;
-
- void _enter_camera(Camera3D *p_camera);
- void _exit_camera(Camera3D *p_camera);
public:
void set_aabb(const AABB &p_aabb);
- AABB get_aabb() const;
+ virtual AABB get_aabb() const override;
bool is_on_screen() const;
- VisibilityNotifier3D();
+ virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
+
+ VisibleOnScreenNotifier3D();
+ ~VisibleOnScreenNotifier3D();
};
-class VisibilityEnabler3D : public VisibilityNotifier3D {
- GDCLASS(VisibilityEnabler3D, VisibilityNotifier3D);
+class VisibleOnScreenEnabler3D : public VisibleOnScreenNotifier3D {
+ GDCLASS(VisibleOnScreenEnabler3D, VisibleOnScreenNotifier3D);
public:
- enum Enabler {
- ENABLER_PAUSE_ANIMATIONS,
- ENABLER_FREEZE_BODIES,
- ENABLER_MAX
+ enum EnableMode {
+ ENABLE_MODE_INHERIT,
+ ENABLE_MODE_ALWAYS,
+ ENABLE_MODE_WHEN_PAUSED,
};
protected:
+ ObjectID node_id;
virtual void _screen_enter() override;
virtual void _screen_exit() override;
- bool visible = false;
-
- void _find_nodes(Node *p_node);
-
- Map<Node *, Variant> nodes;
- void _node_removed(Node *p_node);
- bool enabler[ENABLER_MAX];
-
- void _change_node_state(Node *p_node, bool p_enabled);
+ EnableMode enable_mode = ENABLE_MODE_INHERIT;
+ NodePath enable_node_path = NodePath("..");
void _notification(int p_what);
static void _bind_methods();
+ void _update_enable_mode(bool p_enable);
+
public:
- void set_enabler(Enabler p_enabler, bool p_enable);
- bool is_enabler_enabled(Enabler p_enabler) const;
+ void set_enable_mode(EnableMode p_mode);
+ EnableMode get_enable_mode();
+
+ void set_enable_node_path(NodePath p_path);
+ NodePath get_enable_node_path();
- VisibilityEnabler3D();
+ VisibleOnScreenEnabler3D();
};
-VARIANT_ENUM_CAST(VisibilityEnabler3D::Enabler);
+VARIANT_ENUM_CAST(VisibleOnScreenEnabler3D::EnableMode);
#endif // VISIBILITY_NOTIFIER_H
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index 6971c1ce2a..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);
@@ -150,40 +152,42 @@ Ref<Material> GeometryInstance3D::get_material_override() const {
return material_override;
}
-void GeometryInstance3D::set_lod_min_distance(float p_dist) {
- lod_min_distance = p_dist;
- RS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
+void GeometryInstance3D::set_visibility_range_begin(float p_dist) {
+ visibility_range_begin = p_dist;
+ RS::get_singleton()->instance_geometry_set_visibility_range(get_instance(), visibility_range_begin, visibility_range_end, visibility_range_begin_margin, visibility_range_end_margin);
+ update_configuration_warnings();
}
-float GeometryInstance3D::get_lod_min_distance() const {
- return lod_min_distance;
+float GeometryInstance3D::get_visibility_range_begin() const {
+ return visibility_range_begin;
}
-void GeometryInstance3D::set_lod_max_distance(float p_dist) {
- lod_max_distance = p_dist;
- RS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
+void GeometryInstance3D::set_visibility_range_end(float p_dist) {
+ visibility_range_end = p_dist;
+ RS::get_singleton()->instance_geometry_set_visibility_range(get_instance(), visibility_range_begin, visibility_range_end, visibility_range_begin_margin, visibility_range_end_margin);
+ update_configuration_warnings();
}
-float GeometryInstance3D::get_lod_max_distance() const {
- return lod_max_distance;
+float GeometryInstance3D::get_visibility_range_end() const {
+ return visibility_range_end;
}
-void GeometryInstance3D::set_lod_min_hysteresis(float p_dist) {
- lod_min_hysteresis = p_dist;
- RS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
+void GeometryInstance3D::set_visibility_range_begin_margin(float p_dist) {
+ visibility_range_begin_margin = p_dist;
+ RS::get_singleton()->instance_geometry_set_visibility_range(get_instance(), visibility_range_begin, visibility_range_end, visibility_range_begin_margin, visibility_range_end_margin);
}
-float GeometryInstance3D::get_lod_min_hysteresis() const {
- return lod_min_hysteresis;
+float GeometryInstance3D::get_visibility_range_begin_margin() const {
+ return visibility_range_begin_margin;
}
-void GeometryInstance3D::set_lod_max_hysteresis(float p_dist) {
- lod_max_hysteresis = p_dist;
- RS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
+void GeometryInstance3D::set_visibility_range_end_margin(float p_dist) {
+ visibility_range_end_margin = p_dist;
+ RS::get_singleton()->instance_geometry_set_visibility_range(get_instance(), visibility_range_begin, visibility_range_end, visibility_range_begin_margin, visibility_range_end_margin);
}
-float GeometryInstance3D::get_lod_max_hysteresis() const {
- return lod_max_hysteresis;
+float GeometryInstance3D::get_visibility_range_end_margin() const {
+ return visibility_range_end_margin;
}
void GeometryInstance3D::_notification(int p_what) {
@@ -238,17 +242,16 @@ bool GeometryInstance3D::_get(const StringName &p_name, Variant &r_ret) const {
void GeometryInstance3D::_get_property_list(List<PropertyInfo> *p_list) const {
List<PropertyInfo> pinfo;
RS::get_singleton()->instance_geometry_get_shader_parameter_list(get_instance(), &pinfo);
- for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
- PropertyInfo pi = E->get();
+ for (PropertyInfo &pi : pinfo) {
bool has_def_value = false;
Variant def_value = RS::get_singleton()->instance_geometry_get_shader_parameter_default_value(get_instance(), pi.name);
if (def_value.get_type() != Variant::NIL) {
has_def_value = true;
}
if (instance_uniforms.has(pi.name)) {
- pi.usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE | (has_def_value ? (PROPERTY_USAGE_CHECKABLE | PROPERTY_USAGE_CHECKED) : 0);
+ pi.usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE | (has_def_value ? (PROPERTY_USAGE_CHECKABLE | PROPERTY_USAGE_CHECKED) : PROPERTY_USAGE_NONE);
} else {
- pi.usage = PROPERTY_USAGE_EDITOR | (has_def_value ? PROPERTY_USAGE_CHECKABLE : 0); //do not save if not changed
+ pi.usage = PROPERTY_USAGE_EDITOR | (has_def_value ? PROPERTY_USAGE_CHECKABLE : PROPERTY_USAGE_NONE); //do not save if not changed
}
pi.name = "shader_params/" + pi.name;
@@ -293,7 +296,12 @@ void GeometryInstance3D::set_shader_instance_uniform(const StringName &p_uniform
instance_uniforms.erase(p_value);
} else {
instance_uniforms[p_uniform] = p_value;
- RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_uniform, p_value);
+ if (p_value.get_type() == Variant::OBJECT) {
+ RID tex_id = p_value;
+ RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_uniform, tex_id);
+ } else {
+ RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_uniform, p_value);
+ }
}
}
@@ -347,6 +355,16 @@ bool GeometryInstance3D::is_ignoring_occlusion_culling() {
return ignore_occlusion_culling;
}
+TypedArray<String> GeometryInstance3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
+ if (!Math::is_zero_approx(visibility_range_end) && visibility_range_end <= visibility_range_begin) {
+ warnings.push_back(TTR("The GeometryInstance3D visibility range's End distance is set to a non-zero value, but is lower than the Begin distance.\nThis means the GeometryInstance3D will never be visible.\nTo resolve this, set the End distance to 0 or to a value greater than the Begin distance."));
+ }
+
+ return warnings;
+}
+
void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_material_override", "material"), &GeometryInstance3D::set_material_override);
ClassDB::bind_method(D_METHOD("get_material_override"), &GeometryInstance3D::get_material_override);
@@ -357,17 +375,17 @@ void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_lod_bias", "bias"), &GeometryInstance3D::set_lod_bias);
ClassDB::bind_method(D_METHOD("get_lod_bias"), &GeometryInstance3D::get_lod_bias);
- ClassDB::bind_method(D_METHOD("set_lod_max_hysteresis", "mode"), &GeometryInstance3D::set_lod_max_hysteresis);
- ClassDB::bind_method(D_METHOD("get_lod_max_hysteresis"), &GeometryInstance3D::get_lod_max_hysteresis);
+ ClassDB::bind_method(D_METHOD("set_visibility_range_end_margin", "distance"), &GeometryInstance3D::set_visibility_range_end_margin);
+ ClassDB::bind_method(D_METHOD("get_visibility_range_end_margin"), &GeometryInstance3D::get_visibility_range_end_margin);
- ClassDB::bind_method(D_METHOD("set_lod_max_distance", "mode"), &GeometryInstance3D::set_lod_max_distance);
- ClassDB::bind_method(D_METHOD("get_lod_max_distance"), &GeometryInstance3D::get_lod_max_distance);
+ ClassDB::bind_method(D_METHOD("set_visibility_range_end", "distance"), &GeometryInstance3D::set_visibility_range_end);
+ ClassDB::bind_method(D_METHOD("get_visibility_range_end"), &GeometryInstance3D::get_visibility_range_end);
- ClassDB::bind_method(D_METHOD("set_lod_min_hysteresis", "mode"), &GeometryInstance3D::set_lod_min_hysteresis);
- ClassDB::bind_method(D_METHOD("get_lod_min_hysteresis"), &GeometryInstance3D::get_lod_min_hysteresis);
+ ClassDB::bind_method(D_METHOD("set_visibility_range_begin_margin", "distance"), &GeometryInstance3D::set_visibility_range_begin_margin);
+ ClassDB::bind_method(D_METHOD("get_visibility_range_begin_margin"), &GeometryInstance3D::get_visibility_range_begin_margin);
- ClassDB::bind_method(D_METHOD("set_lod_min_distance", "mode"), &GeometryInstance3D::set_lod_min_distance);
- ClassDB::bind_method(D_METHOD("get_lod_min_distance"), &GeometryInstance3D::get_lod_min_distance);
+ ClassDB::bind_method(D_METHOD("set_visibility_range_begin", "distance"), &GeometryInstance3D::set_visibility_range_begin);
+ ClassDB::bind_method(D_METHOD("get_visibility_range_begin"), &GeometryInstance3D::get_visibility_range_begin);
ClassDB::bind_method(D_METHOD("set_shader_instance_uniform", "uniform", "value"), &GeometryInstance3D::set_shader_instance_uniform);
ClassDB::bind_method(D_METHOD("get_shader_instance_uniform", "uniform"), &GeometryInstance3D::get_shader_instance_uniform);
@@ -389,20 +407,20 @@ void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_aabb"), &GeometryInstance3D::get_aabb);
ADD_GROUP("Geometry", "");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE), "set_material_override", "get_material_override");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE), "set_material_override", "get_material_override");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_bias", PROPERTY_HINT_RANGE, "0.001,128,0.001"), "set_lod_bias", "get_lod_bias");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_occlusion_culling"), "set_ignore_occlusion_culling", "is_ignoring_occlusion_culling");
ADD_GROUP("Global Illumination", "gi_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_mode", PROPERTY_HINT_ENUM, "Disabled,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("LOD", "lod_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_min_distance", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_min_distance", "get_lod_min_distance");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_min_hysteresis", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_min_hysteresis", "get_lod_min_hysteresis");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_max_distance", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_max_distance", "get_lod_max_distance");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_max_hysteresis", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_max_hysteresis", "get_lod_max_hysteresis");
+ 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");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_begin_margin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01"), "set_visibility_range_begin_margin", "get_visibility_range_begin_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_end", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01"), "set_visibility_range_end", "get_visibility_range_end");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_end_margin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01"), "set_visibility_range_end_margin", "get_visibility_range_end_margin");
//ADD_SIGNAL( MethodInfo("visibility_changed"));
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 68d29ef81e..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();
@@ -107,10 +104,13 @@ public:
private:
ShadowCastingSetting shadow_casting_setting = SHADOW_CASTING_SETTING_ON;
Ref<Material> material_override;
- float lod_min_distance = 0.0;
- float lod_max_distance = 0.0;
- float lod_min_hysteresis = 0.0;
- float lod_max_hysteresis = 0.0;
+
+ float visibility_range_begin = 0.0;
+ float visibility_range_end = 0.0;
+ float visibility_range_begin_margin = 0.0;
+ float visibility_range_end_margin = 0.0;
+
+ Vector<NodePath> visibility_range_children;
float lod_bias = 1.0;
@@ -136,17 +136,20 @@ public:
void set_cast_shadows_setting(ShadowCastingSetting p_shadow_casting_setting);
ShadowCastingSetting get_cast_shadows_setting() const;
- void set_lod_min_distance(float p_dist);
- float get_lod_min_distance() const;
+ void set_visibility_range_begin(float p_dist);
+ float get_visibility_range_begin() const;
+
+ void set_visibility_range_end(float p_dist);
+ float get_visibility_range_end() const;
- void set_lod_max_distance(float p_dist);
- float get_lod_max_distance() const;
+ void set_visibility_range_begin_margin(float p_dist);
+ float get_visibility_range_begin_margin() const;
- void set_lod_min_hysteresis(float p_dist);
- float get_lod_min_hysteresis() const;
+ void set_visibility_range_end_margin(float p_dist);
+ float get_visibility_range_end_margin() const;
- void set_lod_max_hysteresis(float p_dist);
- float get_lod_max_hysteresis() const;
+ void set_visibility_range_parent(const Node *p_parent);
+ void clear_visibility_range_parent();
void set_material_override(const Ref<Material> &p_material);
Ref<Material> get_material_override() const;
@@ -171,6 +174,7 @@ public:
void set_ignore_occlusion_culling(bool p_enabled);
bool is_ignoring_occlusion_culling();
+ TypedArray<String> get_configuration_warnings() const override;
GeometryInstance3D();
};
diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp
index e00be9204c..377abd5b38 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) {
@@ -55,7 +54,7 @@ void VoxelGIData::_set_data(const Dictionary &p_data) {
} else if (p_data.has("octree_df_png")) {
Vector<uint8_t> octree_df_png = p_data["octree_df_png"];
Ref<Image> img;
- img.instance();
+ img.instantiate();
Error err = img->load_png_from_buffer(octree_df_png);
ERR_FAIL_COND(err != OK);
ERR_FAIL_COND(img->get_format() != Image::FORMAT_L8);
@@ -76,7 +75,7 @@ Dictionary VoxelGIData::_get_data() const {
d["octree_data"] = get_data_cells();
if (otsize != Vector3i()) {
Ref<Image> img;
- img.instance();
+ img.instantiate();
img->create(otsize.x * otsize.y, otsize.z, false, Image::FORMAT_L8, get_distance_field());
Vector<uint8_t> df_png = img->save_png_to_buffer();
ERR_FAIL_COND_V(df_png.size() == 0, Dictionary());
@@ -143,15 +142,6 @@ float VoxelGIData::get_propagation() const {
return propagation;
}
-void VoxelGIData::set_anisotropy_strength(float p_anisotropy_strength) {
- RS::get_singleton()->voxel_gi_set_anisotropy_strength(probe, p_anisotropy_strength);
- anisotropy_strength = p_anisotropy_strength;
-}
-
-float VoxelGIData::get_anisotropy_strength() const {
- return anisotropy_strength;
-}
-
void VoxelGIData::set_energy(float p_energy) {
RS::get_singleton()->voxel_gi_set_energy(probe, p_energy);
energy = p_energy;
@@ -161,24 +151,6 @@ float VoxelGIData::get_energy() const {
return energy;
}
-void VoxelGIData::set_ao(float p_ao) {
- RS::get_singleton()->voxel_gi_set_ao(probe, p_ao);
- ao = p_ao;
-}
-
-float VoxelGIData::get_ao() const {
- return ao;
-}
-
-void VoxelGIData::set_ao_size(float p_ao_size) {
- RS::get_singleton()->voxel_gi_set_ao_size(probe, p_ao_size);
- ao_size = p_ao_size;
-}
-
-float VoxelGIData::get_ao_size() const {
- return ao_size;
-}
-
void VoxelGIData::set_bias(float p_bias) {
RS::get_singleton()->voxel_gi_set_bias(probe, p_bias);
bias = p_bias;
@@ -219,15 +191,6 @@ RID VoxelGIData::get_rid() const {
return probe;
}
-void VoxelGIData::_validate_property(PropertyInfo &property) const {
- if (property.name == "anisotropy_strength") {
- bool anisotropy_enabled = ProjectSettings::get_singleton()->get("rendering/global_illumination/voxel_gi/anisotropic");
- if (!anisotropy_enabled) {
- property.usage = PROPERTY_USAGE_NOEDITOR;
- }
- }
-}
-
void VoxelGIData::_bind_methods() {
ClassDB::bind_method(D_METHOD("allocate", "to_cell_xform", "aabb", "octree_size", "octree_cells", "data_cells", "distance_field", "level_counts"), &VoxelGIData::allocate);
@@ -253,15 +216,6 @@ void VoxelGIData::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_propagation", "propagation"), &VoxelGIData::set_propagation);
ClassDB::bind_method(D_METHOD("get_propagation"), &VoxelGIData::get_propagation);
- ClassDB::bind_method(D_METHOD("set_anisotropy_strength", "strength"), &VoxelGIData::set_anisotropy_strength);
- ClassDB::bind_method(D_METHOD("get_anisotropy_strength"), &VoxelGIData::get_anisotropy_strength);
-
- ClassDB::bind_method(D_METHOD("set_ao", "ao"), &VoxelGIData::set_ao);
- ClassDB::bind_method(D_METHOD("get_ao"), &VoxelGIData::get_ao);
-
- ClassDB::bind_method(D_METHOD("set_ao_size", "strength"), &VoxelGIData::set_ao_size);
- ClassDB::bind_method(D_METHOD("get_ao_size"), &VoxelGIData::get_ao_size);
-
ClassDB::bind_method(D_METHOD("set_interior", "interior"), &VoxelGIData::set_interior);
ClassDB::bind_method(D_METHOD("is_interior"), &VoxelGIData::is_interior);
@@ -278,9 +232,6 @@ void VoxelGIData::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0,8,0.01"), "set_bias", "get_bias");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "normal_bias", PROPERTY_HINT_RANGE, "0,8,0.01"), "set_normal_bias", "get_normal_bias");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "anisotropy_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_anisotropy_strength", "get_anisotropy_strength");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ao", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ao", "get_ao");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ao_size", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ao_size", "get_ao_size");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_two_bounces"), "set_use_two_bounces", "is_using_two_bounces");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior");
}
@@ -313,7 +264,7 @@ Ref<VoxelGIData> VoxelGI::get_probe_data() const {
void VoxelGI::set_subdiv(Subdiv p_subdiv) {
ERR_FAIL_INDEX(p_subdiv, SUBDIV_MAX);
subdiv = p_subdiv;
- update_gizmo();
+ update_gizmos();
}
VoxelGI::Subdiv VoxelGI::get_subdiv() const {
@@ -322,7 +273,7 @@ VoxelGI::Subdiv VoxelGI::get_subdiv() const {
void VoxelGI::set_extents(const Vector3 &p_extents) {
extents = p_extents;
- update_gizmo();
+ update_gizmos();
}
Vector3 VoxelGI::get_extents() const {
@@ -432,14 +383,14 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) {
int pmc = 0;
- for (List<PlotMesh>::Element *E = mesh_list.front(); E; E = E->next()) {
+ for (PlotMesh &E : mesh_list) {
if (bake_step_function) {
bake_step_function(pmc, RTR("Plotting Meshes") + " " + itos(pmc) + "/" + itos(mesh_list.size()));
}
pmc++;
- baker.plot_mesh(E->get().local_xform, E->get().mesh, E->get().instance_materials, E->get().override_material);
+ baker.plot_mesh(E.local_xform, E.mesh, E.instance_materials, E.override_material);
}
if (bake_step_function) {
bake_step_function(pmc++, RTR("Finishing Plot"));
@@ -447,7 +398,7 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) {
baker.end_bake();
- //create the data for visual server
+ //create the data for rendering server
if (p_create_visual_debug) {
MultiMeshInstance3D *mmi = memnew(MultiMeshInstance3D);
@@ -467,7 +418,7 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) {
Ref<VoxelGIData> probe_data = get_probe_data();
if (probe_data.is_null()) {
- probe_data.instance();
+ probe_data.instantiate();
}
if (bake_step_function) {
diff --git a/scene/3d/voxel_gi.h b/scene/3d/voxel_gi.h
index 5b9ee28b33..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 {
@@ -51,15 +50,11 @@ class VoxelGIData : public Resource {
float bias = 1.5;
float normal_bias = 0.0;
float propagation = 0.7;
- float anisotropy_strength = 0.5;
- float ao = 0.0;
- float ao_size = 0.5;
bool interior = false;
bool use_two_bounces = false;
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
public:
void allocate(const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts);
@@ -77,15 +72,6 @@ public:
void set_propagation(float p_propagation);
float get_propagation() const;
- void set_anisotropy_strength(float p_anisotropy_strength);
- float get_anisotropy_strength() const;
-
- void set_ao(float p_ao);
- float get_ao() const;
-
- void set_ao_size(float p_ao_size);
- float get_ao_size() const;
-
void set_energy(float p_energy);
float get_energy() const;
diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp
index ee0c3fe9b6..aa1236521d 100644
--- a/scene/3d/voxelizer.cpp
+++ b/scene/3d/voxelizer.cpp
@@ -29,24 +29,19 @@
/*************************************************************************/
#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.distance_squared_to(p_vtx[0]) < CMP_EPSILON2) {
+ if (p_pos.is_equal_approx(p_vtx[0])) {
r_uv = p_uv[0];
r_normal = p_normal[0];
return;
}
- if (p_pos.distance_squared_to(p_vtx[1]) < CMP_EPSILON2) {
+ if (p_pos.is_equal_approx(p_vtx[1])) {
r_uv = p_uv[1];
r_normal = p_normal[1];
return;
}
- if (p_pos.distance_squared_to(p_vtx[2]) < CMP_EPSILON2) {
+ if (p_pos.is_equal_approx(p_vtx[2])) {
r_uv = p_uv[2];
r_normal = p_normal[2];
return;
@@ -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
@@ -623,7 +618,6 @@ void Voxelizer::begin_bake(int p_subdiv, const AABB &p_bounds) {
bake_cells.resize(1);
material_cache.clear();
- print_line("subdiv: " + itos(p_subdiv));
//find out the actual real bounds, power of 2, which gets the highest subdivision
po2_bounds = p_bounds;
int longest_axis = po2_bounds.get_longest_axis_index();
@@ -636,7 +630,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]) {
@@ -666,7 +660,7 @@ void Voxelizer::end_bake() {
_fixup_plot(0, 0);
}
-//create the data for visual server
+//create the data for rendering server
int Voxelizer::get_voxel_gi_octree_depth() const {
return cell_subdiv;
@@ -890,7 +884,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);
@@ -931,14 +925,14 @@ void Voxelizer::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<Mult
Ref<MultiMesh> Voxelizer::create_debug_multimesh() {
Ref<MultiMesh> mm;
- mm.instance();
+ mm.instantiate();
mm->set_transform_format(MultiMesh::TRANSFORM_3D);
mm->set_use_colors(true);
mm->set_instance_count(leaf_voxel_count);
Ref<ArrayMesh> mesh;
- mesh.instance();
+ mesh.instantiate();
{
Array arr;
@@ -954,7 +948,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));
@@ -985,7 +979,7 @@ Ref<MultiMesh> Voxelizer::create_debug_multimesh() {
{
Ref<StandardMaterial3D> fsm;
- fsm.instance();
+ fsm.instantiate();
fsm->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
fsm->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
fsm->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
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 829ecc5ec2..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) {
@@ -145,7 +146,7 @@ TypedArray<String> WorldEnvironment::get_configuration_warnings() const {
}
if (camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() != camera_effects) {
- warnings.push_back(TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."));
+ warnings.push_back(TTR("Only one WorldEnvironment is allowed per scene (or set of instantiated scenes)."));
}
return warnings;
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 09662f3e7a..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"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -86,7 +85,8 @@ Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const {
Vector2 cpos = get_viewport()->get_camera_coords(p_pos);
Vector3 ray;
- CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_near(), get_far());
+ // Just use the first view, if multiple views are supported this function has no good result
+ CameraMatrix cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
Vector2 screen_he = cm.get_viewport_half_extents();
ray = Vector3(((cpos.x / viewport_size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (cpos.y / viewport_size.height)) * 2.0 - 1.0) * screen_he.y, -get_near()).normalized();
@@ -108,7 +108,8 @@ Point2 XRCamera3D::unproject_position(const Vector3 &p_pos) const {
Size2 viewport_size = get_viewport()->get_visible_rect().size;
- CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_near(), get_far());
+ // Just use the first view, if multiple views are supported this function has no good result
+ CameraMatrix cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
Plane p(get_camera_transform().xform_inv(p_pos), 1.0);
@@ -122,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());
@@ -137,7 +138,8 @@ Vector3 XRCamera3D::project_position(const Point2 &p_point, float p_z_depth) con
Size2 viewport_size = get_viewport()->get_visible_rect().size;
- CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_near(), get_far());
+ // Just use the first view, if multiple views are supported this function has no good result
+ CameraMatrix cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
Vector2 vp_he = cm.get_viewport_half_extents();
@@ -165,7 +167,8 @@ Vector<Plane> XRCamera3D::get_frustum() const {
ERR_FAIL_COND_V(!is_inside_world(), Vector<Plane>());
Size2 viewport_size = get_viewport()->get_visible_rect().size;
- CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_near(), get_far());
+ // TODO Just use the first view for now, this is mostly for debugging so we may look into using our combined projection here.
+ CameraMatrix cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
return cm.get_projection_planes(get_camera_transform());
};
@@ -200,13 +203,13 @@ void XRController3D::_notification(int p_what) {
// check button states
for (int i = 0; i < 16; i++) {
bool was_pressed = (button_states & mask) == mask;
- bool is_pressed = Input::get_singleton()->is_joy_button_pressed(joy_id, i);
+ bool is_pressed = Input::get_singleton()->is_joy_button_pressed(joy_id, (JoyButton)i);
if (!was_pressed && is_pressed) {
- emit_signal("button_pressed", i);
+ emit_signal(SNAME("button_pressed"), i);
button_states += mask;
} else if (was_pressed && !is_pressed) {
- emit_signal("button_released", i);
+ emit_signal(SNAME("button_released"), i);
button_states -= mask;
};
@@ -221,7 +224,7 @@ void XRController3D::_notification(int p_what) {
Ref<Mesh> trackerMesh = tracker->get_mesh();
if (mesh != trackerMesh) {
mesh = trackerMesh;
- emit_signal("mesh_updated", mesh);
+ emit_signal(SNAME("mesh_updated"), mesh);
}
};
}; break;
@@ -300,7 +303,7 @@ bool XRController3D::is_button_pressed(int p_button) const {
return false;
};
- return Input::get_singleton()->is_joy_button_pressed(joy_id, p_button);
+ return Input::get_singleton()->is_joy_button_pressed(joy_id, (JoyButton)p_button);
};
float XRController3D::get_joystick_axis(int p_axis) const {
@@ -309,7 +312,7 @@ float XRController3D::get_joystick_axis(int p_axis) const {
return 0.0;
};
- return Input::get_singleton()->get_joy_axis(joy_id, p_axis);
+ return Input::get_singleton()->get_joy_axis(joy_id, (JoyAxis)p_axis);
};
real_t XRController3D::get_rumble() const {
@@ -418,7 +421,7 @@ void XRAnchor3D::_notification(int p_what) {
Ref<Mesh> trackerMesh = tracker->get_mesh();
if (mesh != trackerMesh) {
mesh = trackerMesh;
- emit_signal("mesh_updated", mesh);
+ emit_signal(SNAME("mesh_updated"), mesh);
}
};
}; break;
@@ -516,6 +519,11 @@ TypedArray<String> XROrigin3D::get_configuration_warnings() const {
}
}
+ bool xr_enabled = GLOBAL_GET("rendering/xr/enabled");
+ if (!xr_enabled) {
+ warnings.push_back(TTR("XR is not enabled in rendering project settings. Stereoscopic output is not supported unless this is enabled."));
+ }
+
return warnings;
};
@@ -535,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);
@@ -543,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);
@@ -571,7 +579,7 @@ void XROrigin3D::_notification(int p_what) {
Ref<XRInterface> xr_interface = xr_server->get_primary_interface();
if (xr_interface.is_valid() && tracked_camera != nullptr) {
// get our positioning transform for our headset
- Transform3D t = xr_interface->get_transform_for_eye(XRInterface::EYE_MONO, Transform3D());
+ Transform3D t = xr_interface->get_camera_transform();
// now apply this to our camera
tracked_camera->set_transform(t);
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() {}