summaryrefslogtreecommitdiff
path: root/scene/3d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d')
-rw-r--r--scene/3d/SCsub1
-rw-r--r--scene/3d/area_3d.cpp103
-rw-r--r--scene/3d/area_3d.h16
-rw-r--r--scene/3d/audio_stream_player_3d.cpp9
-rw-r--r--scene/3d/audio_stream_player_3d.h2
-rw-r--r--scene/3d/camera_3d.cpp31
-rw-r--r--scene/3d/camera_3d.h5
-rw-r--r--scene/3d/collision_object_3d.cpp224
-rw-r--r--scene/3d/collision_object_3d.h36
-rw-r--r--scene/3d/collision_polygon_3d.cpp18
-rw-r--r--scene/3d/collision_polygon_3d.h2
-rw-r--r--scene/3d/collision_shape_3d.cpp37
-rw-r--r--scene/3d/collision_shape_3d.h4
-rw-r--r--scene/3d/cpu_particles_3d.cpp26
-rw-r--r--scene/3d/cpu_particles_3d.h6
-rw-r--r--scene/3d/gpu_particles_3d.cpp201
-rw-r--r--scene/3d/gpu_particles_3d.h38
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp14
-rw-r--r--scene/3d/gpu_particles_collision_3d.h2
-rw-r--r--scene/3d/light_3d.cpp33
-rw-r--r--scene/3d/light_3d.h4
-rw-r--r--scene/3d/lightmap_gi.cpp (renamed from scene/3d/baked_lightmap.cpp)242
-rw-r--r--scene/3d/lightmap_gi.h (renamed from scene/3d/baked_lightmap.h)38
-rw-r--r--scene/3d/lightmapper.cpp9
-rw-r--r--scene/3d/lightmapper.h85
-rw-r--r--scene/3d/listener_3d.cpp2
-rw-r--r--scene/3d/listener_3d.h2
-rw-r--r--scene/3d/mesh_instance_3d.cpp88
-rw-r--r--scene/3d/mesh_instance_3d.h11
-rw-r--r--scene/3d/navigation_agent_3d.cpp37
-rw-r--r--scene/3d/navigation_agent_3d.h3
-rw-r--r--scene/3d/navigation_obstacle_3d.cpp13
-rw-r--r--scene/3d/navigation_obstacle_3d.h2
-rw-r--r--scene/3d/navigation_region_3d.cpp21
-rw-r--r--scene/3d/navigation_region_3d.h2
-rw-r--r--scene/3d/node_3d.cpp138
-rw-r--r--scene/3d/node_3d.h38
-rw-r--r--scene/3d/occluder_instance_3d.cpp335
-rw-r--r--scene/3d/occluder_instance_3d.h108
-rw-r--r--scene/3d/path_3d.cpp34
-rw-r--r--scene/3d/path_3d.h2
-rw-r--r--scene/3d/physics_body_3d.cpp842
-rw-r--r--scene/3d/physics_body_3d.h186
-rw-r--r--scene/3d/physics_joint_3d.cpp89
-rw-r--r--scene/3d/physics_joint_3d.h2
-rw-r--r--scene/3d/ray_cast_3d.cpp6
-rw-r--r--scene/3d/reflection_probe.cpp4
-rw-r--r--scene/3d/remote_transform_3d.cpp21
-rw-r--r--scene/3d/remote_transform_3d.h2
-rw-r--r--scene/3d/skeleton_3d.cpp167
-rw-r--r--scene/3d/skeleton_3d.h55
-rw-r--r--scene/3d/skeleton_ik_3d.cpp104
-rw-r--r--scene/3d/skeleton_ik_3d.h26
-rw-r--r--scene/3d/soft_body_3d.cpp40
-rw-r--r--scene/3d/soft_body_3d.h2
-rw-r--r--scene/3d/spring_arm_3d.cpp2
-rw-r--r--scene/3d/sprite_3d.cpp29
-rw-r--r--scene/3d/sprite_3d.h6
-rw-r--r--scene/3d/vehicle_body_3d.cpp20
-rw-r--r--scene/3d/vehicle_body_3d.h6
-rw-r--r--scene/3d/velocity_tracker_3d.h4
-rw-r--r--scene/3d/visibility_notifier_3d.cpp229
-rw-r--r--scene/3d/visibility_notifier_3d.h53
-rw-r--r--scene/3d/visual_instance_3d.cpp89
-rw-r--r--scene/3d/visual_instance_3d.h34
-rw-r--r--scene/3d/voxel_gi.cpp (renamed from scene/3d/gi_probe.cpp)254
-rw-r--r--scene/3d/voxel_gi.h (renamed from scene/3d/gi_probe.h)44
-rw-r--r--scene/3d/voxelizer.cpp24
-rw-r--r--scene/3d/voxelizer.h18
-rw-r--r--scene/3d/world_environment.cpp31
-rw-r--r--scene/3d/world_environment.h2
-rw-r--r--scene/3d/xr_nodes.cpp129
-rw-r--r--scene/3d/xr_nodes.h8
73 files changed, 2664 insertions, 1886 deletions
diff --git a/scene/3d/SCsub b/scene/3d/SCsub
index ce69e8aa19..40bdaee47d 100644
--- a/scene/3d/SCsub
+++ b/scene/3d/SCsub
@@ -4,6 +4,5 @@ Import("env")
if env["disable_3d"]:
env.add_source_files(env.scene_sources, "node_3d.cpp")
- env.add_source_files(env.scene_sources, "skeleton_3d.cpp")
else:
env.add_source_files(env.scene_sources, "*.cpp")
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index 749cf4ff9d..44708cddff 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -118,7 +118,7 @@ void Area3D::_body_enter_tree(ObjectID p_id) {
E->get().in_tree = true;
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
for (int i = 0; i < E->get().shapes.size(); i++) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_id, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
}
}
@@ -132,7 +132,7 @@ void Area3D::_body_exit_tree(ObjectID p_id) {
E->get().in_tree = false;
emit_signal(SceneStringNames::get_singleton()->body_exited, node);
for (int i = 0; i < E->get().shapes.size(); i++) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_id, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
}
}
@@ -154,6 +154,7 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
if (body_in) {
if (!E) {
E = body_map.insert(objid, BodyState());
+ E->get().rid = p_body;
E->get().rc = 0;
E->get().in_tree = node && node->is_inside_tree();
if (node) {
@@ -170,7 +171,7 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
}
if (E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_entered, objid, node, p_body_shape, p_area_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_area_shape);
}
} else {
@@ -192,7 +193,7 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
}
}
if (node && in_tree) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, objid, obj, p_body_shape, p_area_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, obj, p_body_shape, p_area_shape);
}
}
@@ -224,7 +225,7 @@ void Area3D::_clear_monitoring() {
}
for (int i = 0; i < E->get().shapes.size(); i++) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->key(), node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
}
emit_signal(SceneStringNames::get_singleton()->body_exited, node);
@@ -253,7 +254,7 @@ void Area3D::_clear_monitoring() {
}
for (int i = 0; i < E->get().shapes.size(); i++) {
- emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E->key(), node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
+ emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E->get().rid, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
}
emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
@@ -298,7 +299,7 @@ void Area3D::_area_enter_tree(ObjectID p_id) {
E->get().in_tree = true;
emit_signal(SceneStringNames::get_singleton()->area_entered, node);
for (int i = 0; i < E->get().shapes.size(); i++) {
- emit_signal(SceneStringNames::get_singleton()->area_shape_entered, p_id, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
+ emit_signal(SceneStringNames::get_singleton()->area_shape_entered, E->get().rid, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
}
}
@@ -312,7 +313,7 @@ void Area3D::_area_exit_tree(ObjectID p_id) {
E->get().in_tree = false;
emit_signal(SceneStringNames::get_singleton()->area_exited, node);
for (int i = 0; i < E->get().shapes.size(); i++) {
- emit_signal(SceneStringNames::get_singleton()->area_shape_exited, p_id, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
+ emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E->get().rid, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
}
}
@@ -334,6 +335,7 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
if (area_in) {
if (!E) {
E = area_map.insert(objid, AreaState());
+ E->get().rid = p_area;
E->get().rc = 0;
E->get().in_tree = node && node->is_inside_tree();
if (node) {
@@ -350,7 +352,7 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
}
if (!node || E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->area_shape_entered, objid, node, p_area_shape, p_self_shape);
+ emit_signal(SceneStringNames::get_singleton()->area_shape_entered, p_area, node, p_area_shape, p_self_shape);
}
} else {
@@ -372,7 +374,7 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
}
}
if (!node || in_tree) {
- emit_signal(SceneStringNames::get_singleton()->area_shape_exited, objid, obj, p_area_shape, p_self_shape);
+ emit_signal(SceneStringNames::get_singleton()->area_shape_exited, p_area, obj, p_area_shape, p_self_shape);
}
}
@@ -451,52 +453,6 @@ bool Area3D::overlaps_body(Node *p_body) const {
return E->get().in_tree;
}
-void Area3D::set_collision_mask(uint32_t p_mask) {
- collision_mask = p_mask;
- PhysicsServer3D::get_singleton()->area_set_collision_mask(get_rid(), p_mask);
-}
-
-uint32_t Area3D::get_collision_mask() const {
- return collision_mask;
-}
-
-void Area3D::set_collision_layer(uint32_t p_layer) {
- collision_layer = p_layer;
- PhysicsServer3D::get_singleton()->area_set_collision_layer(get_rid(), p_layer);
-}
-
-uint32_t Area3D::get_collision_layer() const {
- return collision_layer;
-}
-
-void Area3D::set_collision_mask_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_mask();
- if (p_value) {
- mask |= 1 << p_bit;
- } else {
- mask &= ~(1 << p_bit);
- }
- set_collision_mask(mask);
-}
-
-bool Area3D::get_collision_mask_bit(int p_bit) const {
- return get_collision_mask() & (1 << p_bit);
-}
-
-void Area3D::set_collision_layer_bit(int p_bit, bool p_value) {
- uint32_t layer = get_collision_layer();
- if (p_value) {
- layer |= 1 << p_bit;
- } else {
- layer &= ~(1 << p_bit);
- }
- set_collision_layer(layer);
-}
-
-bool Area3D::get_collision_layer_bit(int p_bit) const {
- return get_collision_layer() & (1 << p_bit);
-}
-
void Area3D::set_audio_bus_override(bool p_override) {
audio_bus_override = p_override;
}
@@ -595,18 +551,6 @@ 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_collision_mask", "collision_mask"), &Area3D::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &Area3D::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &Area3D::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &Area3D::get_collision_layer);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &Area3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &Area3D::get_collision_mask_bit);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &Area3D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &Area3D::get_collision_layer_bit);
-
ClassDB::bind_method(D_METHOD("set_monitorable", "enable"), &Area3D::set_monitorable);
ClassDB::bind_method(D_METHOD("is_monitorable"), &Area3D::is_monitorable);
@@ -640,32 +584,33 @@ void Area3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_reverb_uniformity", "amount"), &Area3D::set_reverb_uniformity);
ClassDB::bind_method(D_METHOD("get_reverb_uniformity"), &Area3D::get_reverb_uniformity);
- ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
- ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D")));
ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D")));
- ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape")));
- ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape")));
ADD_SIGNAL(MethodInfo("area_entered", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D")));
ADD_SIGNAL(MethodInfo("area_exited", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D")));
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority");
+
+ 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::VECTOR3, "gravity_vec"), "set_gravity_vector", "get_gravity_vector");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_gravity", "get_gravity");
+ 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::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable");
- 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");
+
ADD_GROUP("Audio Bus", "audio_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_bus_override"), "set_audio_bus_override", "is_overriding_audio_bus");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus_name", "get_audio_bus_name");
+
ADD_GROUP("Reverb Bus", "reverb_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reverb_bus_enable"), "set_use_reverb_bus", "is_using_reverb_bus");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "reverb_bus_name", PROPERTY_HINT_ENUM, ""), "set_reverb_bus", "get_reverb_bus");
diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h
index 6d976115f7..5b8d612717 100644
--- a/scene/3d/area_3d.h
+++ b/scene/3d/area_3d.h
@@ -54,8 +54,6 @@ private:
real_t gravity_distance_scale = 0.0;
real_t angular_damp = 0.1;
real_t linear_damp = 0.1;
- uint32_t collision_mask = 1;
- uint32_t collision_layer = 1;
int priority = 0;
bool monitoring = false;
bool monitorable = false;
@@ -85,6 +83,7 @@ private:
};
struct BodyState {
+ RID rid;
int rc = 0;
bool in_tree = false;
VSet<ShapePair> shapes;
@@ -116,6 +115,7 @@ private:
};
struct AreaState {
+ RID rid;
int rc = 0;
bool in_tree = false;
VSet<AreaShapePair> shapes;
@@ -169,18 +169,6 @@ public:
void set_monitorable(bool p_enable);
bool is_monitorable() const;
- void set_collision_mask(uint32_t p_mask);
- uint32_t get_collision_mask() const;
-
- 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_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
-
TypedArray<Node3D> get_overlapping_bodies() const;
TypedArray<Area3D> get_overlapping_areas() const; //function for script
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 72392be5bd..9640043031 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -404,10 +404,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
break;
}
- List<Camera3D *> cameras;
- world_3d->get_camera_list(&cameras);
-
- for (List<Camera3D *>::Element *E = cameras.front(); E; E = E->next()) {
+ for (const Set<Camera3D *>::Element *E = world_3d->get_cameras().front(); E; E = E->next()) {
Camera3D *camera = E->get();
Viewport *vp = camera->get_viewport();
if (!vp->is_audio_listener()) {
@@ -962,9 +959,9 @@ void AudioStreamPlayer3D::_bind_methods() {
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");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "attenuation_model", PROPERTY_HINT_ENUM, "Inverse,InverseSquare,Log,Disabled"), "set_attenuation_model", "get_attenuation_model");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "attenuation_model", PROPERTY_HINT_ENUM, "Inverse,Inverse Square,Log,Disabled"), "set_attenuation_model", "get_attenuation_model");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_db", PROPERTY_HINT_RANGE, "-80,80"), "set_unit_db", "get_unit_db");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_size", PROPERTY_HINT_RANGE, "0.1,100,0.1"), "set_unit_size", "get_unit_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_size", PROPERTY_HINT_RANGE, "0.1,100,0.01,or_greater"), "set_unit_size", "get_unit_size");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_db", PROPERTY_HINT_RANGE, "-24,6"), "set_max_db", "get_max_db");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,4,0.01,or_greater"), "set_pitch_scale", "get_pitch_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing");
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index 70c535bd89..8aec493602 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -98,7 +98,7 @@ private:
AttenuationModel attenuation_model = ATTENUATION_INVERSE_DISTANCE;
float unit_db = 0.0;
- float unit_size = 1.0;
+ float unit_size = 10.0;
float max_db = 3.0;
float pitch_scale = 1.0;
bool autoplay = false;
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index cd8d02233b..62bbebe6e7 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -93,10 +93,6 @@ void Camera3D::_update_camera() {
}
get_viewport()->_camera_transform_changed_notify();
-
- if (get_world_3d().is_valid()) {
- get_world_3d()->_update_camera(this);
- }
}
void Camera3D::_notification(int p_what) {
@@ -150,8 +146,8 @@ void Camera3D::_notification(int p_what) {
}
}
-Transform Camera3D::get_camera_transform() const {
- Transform tr = get_global_transform().orthonormalized();
+Transform3D Camera3D::get_camera_transform() const {
+ Transform3D tr = get_global_transform().orthonormalized();
tr.origin += tr.basis.get_axis(1) * v_offset;
tr.origin += tr.basis.get_axis(0) * h_offset;
return tr;
@@ -318,7 +314,7 @@ Vector3 Camera3D::project_ray_origin(const Point2 &p_pos) const {
};
bool Camera3D::is_position_behind(const Vector3 &p_pos) const {
- Transform t = get_global_transform();
+ Transform3D t = get_global_transform();
Vector3 eyedir = -t.basis.get_axis(2).normalized();
return eyedir.dot(p_pos - t.origin) < near;
}
@@ -337,7 +333,7 @@ Vector<Vector3> Camera3D::get_near_plane_points() const {
}
Vector3 endpoints[8];
- cm.get_endpoints(Transform(), endpoints);
+ cm.get_endpoints(Transform3D(), endpoints);
Vector<Vector3> points;
points.push_back(Vector3());
@@ -500,6 +496,7 @@ 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("set_cull_mask_bit", "layer", "enable"), &Camera3D::set_cull_mask_bit);
@@ -623,6 +620,16 @@ Vector<Plane> Camera3D::get_frustum() const {
return cm.get_projection_planes(get_camera_transform());
}
+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(float p_offset) {
v_offset = p_offset;
_update_camera();
@@ -686,8 +693,8 @@ ClippedCamera3D::ClipProcessCallback ClippedCamera3D::get_process_callback() con
return process_callback;
}
-Transform ClippedCamera3D::get_camera_transform() const {
- Transform t = Camera3D::get_camera_transform();
+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;
}
@@ -735,7 +742,7 @@ void ClippedCamera3D::_notification(int p_what) {
}
}
- Transform xf = get_global_transform();
+ Transform3D xf = get_global_transform();
xf.origin = ray_from;
xf.orthonormalize();
@@ -761,6 +768,7 @@ uint32_t ClippedCamera3D::get_collision_mask() const {
}
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;
@@ -771,6 +779,7 @@ void ClippedCamera3D::set_collision_mask_bit(int p_bit, bool p_value) {
}
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);
}
diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h
index cea61e4db8..c6efc8f9a9 100644
--- a/scene/3d/camera_3d.h
+++ b/scene/3d/camera_3d.h
@@ -134,7 +134,7 @@ public:
void set_near(float p_near);
void set_frustum_offset(Vector2 p_offset);
- virtual Transform get_camera_transform() const;
+ virtual Transform3D get_camera_transform() const;
virtual Vector3 project_ray_normal(const Point2 &p_pos) const;
virtual Vector3 project_ray_origin(const Point2 &p_pos) const;
@@ -153,6 +153,7 @@ public:
bool get_cull_mask_bit(int p_layer) 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;
@@ -207,7 +208,7 @@ private:
protected:
void _notification(int p_what);
static void _bind_methods();
- virtual Transform get_camera_transform() const override;
+ virtual Transform3D get_camera_transform() const override;
public:
void set_clip_to_areas(bool p_clip);
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index 39880db29c..a04667e53b 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -31,12 +31,27 @@
#include "collision_object_3d.h"
#include "core/config/engine.h"
-#include "mesh_instance_3d.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());
+ }
+ _update_debug_shapes();
+ }
+ } break;
+
+ case NOTIFICATION_EXIT_TREE: {
+ if (debug_shapes_count > 0) {
+ _clear_debug_shapes();
+ }
+ } break;
+
case NOTIFICATION_ENTER_WORLD: {
if (area) {
PhysicsServer3D::get_singleton()->area_set_transform(rid, get_global_transform());
@@ -62,6 +77,8 @@ void CollisionObject3D::_notification(int p_what) {
PhysicsServer3D::get_singleton()->body_set_state(rid, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
}
+ _on_transform_changed();
+
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
_update_pickable();
@@ -78,6 +95,64 @@ void CollisionObject3D::_notification(int p_what) {
}
}
+void CollisionObject3D::set_collision_layer(uint32_t p_layer) {
+ collision_layer = p_layer;
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_collision_layer(get_rid(), p_layer);
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), p_layer);
+ }
+}
+
+uint32_t CollisionObject3D::get_collision_layer() const {
+ return collision_layer;
+}
+
+void CollisionObject3D::set_collision_mask(uint32_t p_mask) {
+ collision_mask = p_mask;
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_collision_mask(get_rid(), p_mask);
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), p_mask);
+ }
+}
+
+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.");
+ uint32_t collision_layer = get_collision_layer();
+ if (p_value) {
+ collision_layer |= 1 << p_bit;
+ } else {
+ collision_layer &= ~(1 << p_bit);
+ }
+ 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);
+}
+
+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.");
+ uint32_t mask = get_collision_mask();
+ if (p_value) {
+ mask |= 1 << p_bit;
+ } else {
+ mask &= ~(1 << p_bit);
+ }
+ 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);
+}
+
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);
@@ -112,39 +187,103 @@ void CollisionObject3D::_update_pickable() {
}
}
+bool CollisionObject3D::_are_collision_shapes_visible() {
+ return is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !Engine::get_singleton()->is_editor_hint();
+}
+
+void CollisionObject3D::_update_shape_data(uint32_t p_owner) {
+ if (_are_collision_shapes_visible()) {
+ if (debug_shapes_to_update.is_empty()) {
+ callable_mp(this, &CollisionObject3D::_update_debug_shapes).call_deferred({}, 0);
+ }
+ debug_shapes_to_update.insert(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();
+ ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
+ for (int i = 0; i < shapedata.shapes.size(); i++) {
+ ShapeData::ShapeBase &s = shapes[i];
+ if (s.shape == p_shape && s.debug_shape.is_valid()) {
+ Ref<Mesh> mesh = s.shape->get_debug_mesh();
+ RS::get_singleton()->instance_set_base(s.debug_shape, mesh->get_rid());
+ }
+ }
+ }
+}
+
void CollisionObject3D::_update_debug_shapes() {
+ if (!is_inside_tree()) {
+ debug_shapes_to_update.clear();
+ return;
+ }
+
for (Set<uint32_t>::Element *shapedata_idx = debug_shapes_to_update.front(); shapedata_idx; shapedata_idx = shapedata_idx->next()) {
if (shapes.has(shapedata_idx->get())) {
ShapeData &shapedata = shapes[shapedata_idx->get()];
+ ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
for (int i = 0; i < shapedata.shapes.size(); i++) {
- ShapeData::ShapeBase &s = shapedata.shapes.write[i];
- if (s.debug_shape) {
- s.debug_shape->queue_delete();
- s.debug_shape = nullptr;
- }
+ ShapeData::ShapeBase &s = shapes[i];
if (s.shape.is_null() || shapedata.disabled) {
+ if (s.debug_shape.is_valid()) {
+ RS::get_singleton()->free(s.debug_shape);
+ s.debug_shape = RID();
+ --debug_shapes_count;
+ }
continue;
}
+ if (s.debug_shape.is_null()) {
+ s.debug_shape = RS::get_singleton()->instance_create();
+ RS::get_singleton()->instance_set_scenario(s.debug_shape, get_world_3d()->get_scenario());
+
+ if (!s.shape->is_connected("changed", callable_mp(this, &CollisionObject3D::_shape_changed))) {
+ s.shape->connect("changed", callable_mp(this, &CollisionObject3D::_shape_changed),
+ varray(s.shape), CONNECT_DEFERRED);
+ }
+
+ ++debug_shapes_count;
+ }
+
Ref<Mesh> mesh = s.shape->get_debug_mesh();
- MeshInstance3D *mi = memnew(MeshInstance3D);
- mi->set_transform(shapedata.xform);
- mi->set_mesh(mesh);
- add_child(mi);
- mi->force_update_transform();
- s.debug_shape = mi;
+ RS::get_singleton()->instance_set_base(s.debug_shape, mesh->get_rid());
+ RS::get_singleton()->instance_set_transform(s.debug_shape, get_global_transform() * shapedata.xform);
}
}
}
debug_shapes_to_update.clear();
}
-void CollisionObject3D::_update_shape_data(uint32_t p_owner) {
- if (is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !Engine::get_singleton()->is_editor_hint()) {
- if (debug_shapes_to_update.is_empty()) {
- call_deferred("_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();
+ ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
+ for (int i = 0; i < shapedata.shapes.size(); i++) {
+ ShapeData::ShapeBase &s = shapes[i];
+ if (s.debug_shape.is_valid()) {
+ RS::get_singleton()->free(s.debug_shape);
+ s.debug_shape = RID();
+ if (s.shape.is_valid() && s.shape->is_connected("changed", callable_mp(this, &CollisionObject3D::_update_shape_data))) {
+ s.shape->disconnect("changed", callable_mp(this, &CollisionObject3D::_update_shape_data));
+ }
+ }
+ }
+ }
+ debug_shapes_count = 0;
+}
+
+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();
+ 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);
+ }
}
- debug_shapes_to_update.insert(p_owner);
}
}
@@ -158,6 +297,14 @@ bool CollisionObject3D::is_ray_pickable() const {
}
void CollisionObject3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &CollisionObject3D::set_collision_layer);
+ 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_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);
@@ -179,14 +326,17 @@ 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);
- ClassDB::bind_method(D_METHOD("_update_debug_shapes"), &CollisionObject3D::_update_debug_shapes);
-
- BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx")));
+ 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")));
- 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, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "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_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");
+
+ 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");
}
@@ -220,7 +370,11 @@ void CollisionObject3D::shape_owner_set_disabled(uint32_t p_owner, bool p_disabl
ERR_FAIL_COND(!shapes.has(p_owner));
ShapeData &sd = shapes[p_owner];
+ if (sd.disabled == p_disabled) {
+ return;
+ }
sd.disabled = p_disabled;
+
for (int i = 0; i < sd.shapes.size(); i++) {
if (area) {
PhysicsServer3D::get_singleton()->area_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
@@ -252,7 +406,7 @@ Array CollisionObject3D::_get_shape_owners() {
return ret;
}
-void CollisionObject3D::shape_owner_set_transform(uint32_t p_owner, const Transform &p_transform) {
+void CollisionObject3D::shape_owner_set_transform(uint32_t p_owner, const Transform3D &p_transform) {
ERR_FAIL_COND(!shapes.has(p_owner));
ShapeData &sd = shapes[p_owner];
@@ -267,9 +421,8 @@ void CollisionObject3D::shape_owner_set_transform(uint32_t p_owner, const Transf
_update_shape_data(p_owner);
}
-
-Transform CollisionObject3D::shape_owner_get_transform(uint32_t p_owner) const {
- ERR_FAIL_COND_V(!shapes.has(p_owner), Transform());
+Transform3D CollisionObject3D::shape_owner_get_transform(uint32_t p_owner) const {
+ ERR_FAIL_COND_V(!shapes.has(p_owner), Transform3D());
return shapes[p_owner].xform;
}
@@ -325,7 +478,7 @@ void CollisionObject3D::shape_owner_remove_shape(uint32_t p_owner, int p_shape)
ERR_FAIL_COND(!shapes.has(p_owner));
ERR_FAIL_INDEX(p_shape, shapes[p_owner].shapes.size());
- const ShapeData::ShapeBase &s = shapes[p_owner].shapes[p_shape];
+ ShapeData::ShapeBase &s = shapes[p_owner].shapes.write[p_shape];
int index_to_remove = s.index;
if (area) {
@@ -334,8 +487,12 @@ void CollisionObject3D::shape_owner_remove_shape(uint32_t p_owner, int p_shape)
PhysicsServer3D::get_singleton()->body_remove_shape(rid, index_to_remove);
}
- if (s.debug_shape) {
- s.debug_shape->queue_delete();
+ if (s.debug_shape.is_valid()) {
+ RS::get_singleton()->free(s.debug_shape);
+ if (s.shape.is_valid() && s.shape->is_connected("changed", callable_mp(this, &CollisionObject3D::_shape_changed))) {
+ s.shape->disconnect("changed", callable_mp(this, &CollisionObject3D::_shape_changed));
+ }
+ --debug_shapes_count;
}
shapes[p_owner].shapes.remove(p_shape);
@@ -395,17 +552,14 @@ bool CollisionObject3D::get_capture_input_on_drag() const {
return capture_input_on_drag;
}
-String CollisionObject3D::get_configuration_warning() const {
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> CollisionObject3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (shapes.is_empty()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape.");
+ warnings.push_back(TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape."));
}
- return warning;
+ return warnings;
}
CollisionObject3D::CollisionObject3D() {
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
index fe20176984..50a9b4fcd0 100644
--- a/scene/3d/collision_object_3d.h
+++ b/scene/3d/collision_object_3d.h
@@ -37,15 +37,18 @@
class CollisionObject3D : public Node3D {
GDCLASS(CollisionObject3D, Node3D);
+ uint32_t collision_layer = 1;
+ uint32_t collision_mask = 1;
+
bool area = false;
RID rid;
struct ShapeData {
Object *owner = nullptr;
- Transform xform;
+ Transform3D xform;
struct ShapeBase {
- Node *debug_shape = nullptr;
+ RID debug_shape;
Ref<Shape3D> shape;
int index = 0;
};
@@ -62,31 +65,50 @@ class CollisionObject3D : public Node3D {
bool ray_pickable = true;
Set<uint32_t> debug_shapes_to_update;
+ int debug_shapes_count = 0;
+ Transform3D debug_shape_old_transform;
void _update_pickable();
+ bool _are_collision_shapes_visible();
void _update_shape_data(uint32_t p_owner);
+ void _shape_changed(const Ref<Shape3D> &p_shape);
+ void _update_debug_shapes();
+ void _clear_debug_shapes();
protected:
CollisionObject3D(RID p_rid, bool p_area);
void _notification(int p_what);
static void _bind_methods();
+
+ 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 _mouse_enter();
virtual void _mouse_exit();
- void _update_debug_shapes();
-
public:
+ void set_collision_layer(uint32_t p_layer);
+ uint32_t get_collision_layer() const;
+
+ 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_mask_bit(int p_bit, bool p_value);
+ bool get_collision_mask_bit(int p_bit) const;
+
uint32_t create_shape_owner(Object *p_owner);
void remove_shape_owner(uint32_t owner);
void get_shape_owners(List<uint32_t> *r_owners);
Array _get_shape_owners();
- void shape_owner_set_transform(uint32_t p_owner, const Transform &p_transform);
- Transform shape_owner_get_transform(uint32_t p_owner) const;
+ void shape_owner_set_transform(uint32_t p_owner, const Transform3D &p_transform);
+ Transform3D shape_owner_get_transform(uint32_t p_owner) const;
Object *shape_owner_get_owner(uint32_t p_owner) const;
void shape_owner_set_disabled(uint32_t p_owner, bool p_disabled);
@@ -110,7 +132,7 @@ public:
_FORCE_INLINE_ RID get_rid() const { return rid; }
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
CollisionObject3D();
~CollisionObject3D();
diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp
index e3e2eb4669..8a4f8b639b 100644
--- a/scene/3d/collision_polygon_3d.cpp
+++ b/scene/3d/collision_polygon_3d.cpp
@@ -121,7 +121,7 @@ void CollisionPolygon3D::set_polygon(const Vector<Point2> &p_polygon) {
if (parent) {
_build_polygon();
}
- update_configuration_warning();
+ update_configuration_warnings();
update_gizmo();
}
@@ -167,24 +167,18 @@ void CollisionPolygon3D::set_margin(real_t p_margin) {
}
}
-String CollisionPolygon3D::get_configuration_warning() const {
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> CollisionPolygon3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += 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, KinematicBody3D, 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, RigidBody3D, CharacterBody3D, etc. to give them a shape."));
}
if (polygon.is_empty()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("An empty CollisionPolygon3D has no effect on collision.");
+ warnings.push_back(TTR("An empty CollisionPolygon3D has no effect on collision."));
}
- return warning;
+ return warnings;
}
bool CollisionPolygon3D::_is_editable_3d_polygon() const {
diff --git a/scene/3d/collision_polygon_3d.h b/scene/3d/collision_polygon_3d.h
index 750751b509..73b8a8e0e3 100644
--- a/scene/3d/collision_polygon_3d.h
+++ b/scene/3d/collision_polygon_3d.h
@@ -74,7 +74,7 @@ public:
real_t get_margin() const;
void set_margin(real_t p_margin);
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
CollisionPolygon3D();
};
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
index 242d82ab4c..be3fde8013 100644
--- a/scene/3d/collision_shape_3d.cpp
+++ b/scene/3d/collision_shape_3d.cpp
@@ -120,34 +120,25 @@ void CollisionShape3D::resource_changed(RES res) {
update_gizmo();
}
-String CollisionShape3D::get_configuration_warning() const {
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> CollisionShape3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += 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, KinematicBody3D, 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, RigidBody3D, CharacterBody3D, etc. to give them a shape."));
}
if (!shape.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it.");
+ warnings.push_back(TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it."));
}
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) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static.");
+ warnings.push_back(TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static."));
}
- return warning;
+ return warnings;
}
void CollisionShape3D::_bind_methods() {
@@ -170,12 +161,10 @@ void CollisionShape3D::set_shape(const Ref<Shape3D> &p_shape) {
}
if (!shape.is_null()) {
shape->unregister_owner(this);
- shape->disconnect("changed", callable_mp(this, &CollisionShape3D::_shape_changed));
}
shape = p_shape;
if (!shape.is_null()) {
shape->register_owner(this);
- shape->connect("changed", callable_mp(this, &CollisionShape3D::_shape_changed));
}
update_gizmo();
if (parent) {
@@ -185,10 +174,11 @@ void CollisionShape3D::set_shape(const Ref<Shape3D> &p_shape) {
}
}
- if (is_inside_tree()) {
- _shape_changed();
+ if (is_inside_tree() && parent) {
+ // If this is a heightfield shape our center may have changed
+ _update_in_shape_owner(true);
}
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<Shape3D> CollisionShape3D::get_shape() const {
@@ -218,10 +208,3 @@ CollisionShape3D::~CollisionShape3D() {
}
//RenderingServer::get_singleton()->free(indicator);
}
-
-void CollisionShape3D::_shape_changed() {
- // If this is a heightfield shape our center may have changed
- if (parent) {
- _update_in_shape_owner(true);
- }
-}
diff --git a/scene/3d/collision_shape_3d.h b/scene/3d/collision_shape_3d.h
index 5512417f75..f69c1e38eb 100644
--- a/scene/3d/collision_shape_3d.h
+++ b/scene/3d/collision_shape_3d.h
@@ -47,8 +47,6 @@ class CollisionShape3D : public Node3D {
bool disabled = false;
protected:
- void _shape_changed();
-
void _update_in_shape_owner(bool p_xform_only = false);
protected:
@@ -64,7 +62,7 @@ public:
void set_disabled(bool p_disabled);
bool is_disabled() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
CollisionShape3D();
~CollisionShape3D();
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index d22d7ff3ab..2301fef651 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -189,8 +189,8 @@ bool CPUParticles3D::get_fractional_delta() const {
return fractional_delta;
}
-String CPUParticles3D::get_configuration_warning() const {
- String warnings = GeometryInstance3D::get_configuration_warning();
+TypedArray<String> CPUParticles3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
bool mesh_found = false;
bool anim_material_found = false;
@@ -209,18 +209,12 @@ String CPUParticles3D::get_configuration_warning() const {
anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
if (!mesh_found) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("Nothing is visible because no mesh has been assigned.");
+ 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 ||
get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid())) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("CPUParticles3D animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\".");
+ warnings.push_back(TTR("CPUParticles3D animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
}
return warnings;
@@ -580,7 +574,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
}
}
- Transform emission_xform;
+ Transform3D emission_xform;
Basis velocity_xform;
if (!local_coords) {
emission_xform = get_global_transform();
@@ -699,7 +693,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
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.transform = Transform();
+ p.transform = Transform3D();
p.time = 0;
p.lifetime = lifetime * (1.0 - Math::randf() * lifetime_randomness);
p.base_color = Color(1, 1, 1, 1);
@@ -1036,7 +1030,7 @@ void CPUParticles3D::_update_particle_data_buffer() {
for (int i = 0; i < pc; i++) {
int idx = order ? order[i] : i;
- Transform t = r[idx].transform;
+ Transform3D t = r[idx].transform;
if (!local_coords) {
t = inv_emission_transform * t;
@@ -1056,7 +1050,7 @@ void CPUParticles3D::_update_particle_data_buffer() {
ptr[10] = t.basis.elements[2][2];
ptr[11] = t.origin.z;
} else {
- zeromem(ptr, sizeof(float) * 12);
+ memset(ptr, 0, sizeof(float) * 12);
}
Color c = r[idx].color;
@@ -1145,7 +1139,7 @@ void CPUParticles3D::_notification(int p_what) {
float *ptr = w;
for (int i = 0; i < pc; i++) {
- Transform t = inv_emission_transform * r[i].transform;
+ Transform3D t = inv_emission_transform * r[i].transform;
if (r[i].active) {
ptr[0] = t.basis.elements[0][0];
@@ -1161,7 +1155,7 @@ void CPUParticles3D::_notification(int p_what) {
ptr[10] = t.basis.elements[2][2];
ptr[11] = t.origin.z;
} else {
- zeromem(ptr, sizeof(float) * 12);
+ memset(ptr, 0, sizeof(float) * 12);
}
ptr += 20;
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index 10ac32622d..b35e659757 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -83,7 +83,7 @@ private:
bool emitting = false;
struct Particle {
- Transform transform;
+ Transform3D transform;
Color color;
float custom[4] = {};
Vector3 velocity;
@@ -141,7 +141,7 @@ private:
int fixed_fps = 0;
bool fractional_delta = true;
- Transform inv_emission_transform;
+ Transform3D inv_emission_transform;
SafeFlag can_update;
@@ -280,7 +280,7 @@ public:
void set_gravity(const Vector3 &p_gravity);
Vector3 get_gravity() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void restart();
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index e2cfc2ed87..d7f4bfeb4e 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -115,7 +115,7 @@ void GPUParticles3D::set_process_material(const Ref<Material> &p_material) {
}
RS::get_singleton()->particles_set_process_material(particles, material_rid);
- update_configuration_warning();
+ update_configuration_warnings();
}
void GPUParticles3D::set_speed_scale(float p_scale) {
@@ -181,12 +181,33 @@ void GPUParticles3D::set_draw_order(DrawOrder p_order) {
RS::get_singleton()->particles_set_draw_order(particles, RS::ParticlesDrawOrder(p_order));
}
+void GPUParticles3D::set_trail_enabled(bool p_enabled) {
+ trail_enabled = p_enabled;
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+ update_configuration_warnings();
+}
+void GPUParticles3D::set_trail_length(float p_seconds) {
+ ERR_FAIL_COND(p_seconds < 0.001);
+ trail_length = p_seconds;
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+}
+
+bool GPUParticles3D::is_trail_enabled() const {
+ return trail_enabled;
+}
+float GPUParticles3D::get_trail_length() const {
+ return trail_length;
+}
+
GPUParticles3D::DrawOrder GPUParticles3D::get_draw_order() const {
return draw_order;
}
void GPUParticles3D::set_draw_passes(int p_count) {
ERR_FAIL_COND(p_count < 1);
+ for (int i = p_count; i < draw_passes.size(); i++) {
+ set_draw_pass_mesh(i, Ref<Mesh>());
+ }
draw_passes.resize(p_count);
RS::get_singleton()->particles_set_draw_passes(particles, p_count);
notify_property_list_changed();
@@ -199,8 +220,16 @@ int GPUParticles3D::get_draw_passes() const {
void GPUParticles3D::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {
ERR_FAIL_INDEX(p_pass, draw_passes.size());
+ if (Engine::get_singleton()->is_editor_hint() && draw_passes.write[p_pass].is_valid()) {
+ draw_passes.write[p_pass]->disconnect("changed", callable_mp((Node *)this, &Node::update_configuration_warnings));
+ }
+
draw_passes.write[p_pass] = p_mesh;
+ if (Engine::get_singleton()->is_editor_hint() && draw_passes.write[p_pass].is_valid()) {
+ draw_passes.write[p_pass]->connect("changed", callable_mp((Node *)this, &Node::update_configuration_warnings), varray(), CONNECT_DEFERRED);
+ }
+
RID mesh_rid;
if (p_mesh.is_valid()) {
mesh_rid = p_mesh->get_rid();
@@ -208,7 +237,8 @@ void GPUParticles3D::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {
RS::get_singleton()->particles_set_draw_pass_mesh(particles, p_pass, mesh_rid);
- update_configuration_warning();
+ _skinning_changed();
+ update_configuration_warnings();
}
Ref<Mesh> GPUParticles3D::get_draw_pass_mesh(int p_pass) const {
@@ -235,13 +265,22 @@ bool GPUParticles3D::get_fractional_delta() const {
return fractional_delta;
}
-String GPUParticles3D::get_configuration_warning() const {
+void GPUParticles3D::set_interpolate(bool p_enable) {
+ interpolate = p_enable;
+ RS::get_singleton()->particles_set_interpolate(particles, p_enable);
+}
+
+bool GPUParticles3D::get_interpolate() const {
+ return interpolate;
+}
+
+TypedArray<String> GPUParticles3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
if (RenderingServer::get_singleton()->is_low_end()) {
- return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles3D node instead. You can use the \"Convert to CPUParticles3D\" option for this purpose.");
+ warnings.push_back(TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles3D node instead. You can use the \"Convert to CPUParticles3D\" option for this purpose."));
}
- String warnings = GeometryInstance3D::get_configuration_warning();
-
bool meshes_found = false;
bool anim_material_found = false;
@@ -250,7 +289,7 @@ String GPUParticles3D::get_configuration_warning() const {
meshes_found = true;
for (int j = 0; j < draw_passes[i]->get_surface_count(); j++) {
anim_material_found = Object::cast_to<ShaderMaterial>(draw_passes[i]->surface_get_material(j).ptr()) != nullptr;
- StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(draw_passes[i]->surface_get_material(j).ptr());
+ BaseMaterial3D *spat = Object::cast_to<BaseMaterial3D>(draw_passes[i]->surface_get_material(j).ptr());
anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
}
if (anim_material_found) {
@@ -260,30 +299,73 @@ String GPUParticles3D::get_configuration_warning() const {
}
anim_material_found = anim_material_found || Object::cast_to<ShaderMaterial>(get_material_override().ptr()) != nullptr;
- StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(get_material_override().ptr());
- anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
+ {
+ BaseMaterial3D *spat = Object::cast_to<BaseMaterial3D>(get_material_override().ptr());
+ anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == BaseMaterial3D::BILLBOARD_PARTICLES);
+ }
if (!meshes_found) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("Nothing is visible because meshes have not been assigned to draw passes.");
+ warnings.push_back(TTR("Nothing is visible because meshes have not been assigned to draw passes."));
}
if (process_material.is_null()) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted.");
+ warnings.push_back(TTR("A material to process the particles is not assigned, so no behavior is imprinted."));
} 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_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
- if (warnings != String()) {
- warnings += "\n";
+ warnings.push_back(TTR("Particles animation requires the usage of a BaseMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
+ }
+ }
+
+ if (trail_enabled) {
+ int dp_count = 0;
+ bool missing_trails = false;
+ bool no_materials = false;
+
+ for (int i = 0; i < draw_passes.size(); i++) {
+ Ref<Mesh> draw_pass = draw_passes[i];
+ if (draw_pass.is_valid() && draw_pass->get_builtin_bind_pose_count() > 0) {
+ dp_count++;
+ }
+
+ if (draw_pass.is_valid()) {
+ int mats_found = 0;
+ for (int j = 0; j < draw_passes[i]->get_surface_count(); j++) {
+ BaseMaterial3D *spat = Object::cast_to<BaseMaterial3D>(draw_passes[i]->surface_get_material(j).ptr());
+ if (spat) {
+ mats_found++;
+ }
+ if (spat && !spat->get_flag(BaseMaterial3D::FLAG_PARTICLE_TRAILS_MODE)) {
+ missing_trails = true;
+ }
+ }
+
+ if (mats_found != draw_passes[i]->get_surface_count()) {
+ no_materials = true;
+ }
}
- warnings += "- " + TTR("Particles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\".");
+ }
+
+ BaseMaterial3D *spat = Object::cast_to<BaseMaterial3D>(get_material_override().ptr());
+ if (spat) {
+ no_materials = false;
+ }
+ if (spat && !spat->get_flag(BaseMaterial3D::FLAG_PARTICLE_TRAILS_MODE)) {
+ missing_trails = true;
+ }
+
+ if (dp_count && skin.is_valid()) {
+ warnings.push_back(TTR("Using Trail meshes with a skin causes Skin to override Trail poses. Suggest removing the Skin."));
+ } else if (dp_count == 0 && skin.is_null()) {
+ warnings.push_back(TTR("Trails active, but neither Trail meshes or a Skin were found."));
+ } else if (dp_count > 1) {
+ warnings.push_back(TTR("Only one Trail mesh is supported. If you want to use more than a single mesh, a Skin is needed (see documentation)."));
+ }
+
+ if ((dp_count || !skin.is_null()) && (missing_trails || no_materials)) {
+ warnings.push_back(TTR("Trails enabled, but one or more mesh materials are either missing or not set for trails rendering."));
}
}
@@ -309,7 +391,7 @@ void GPUParticles3D::_validate_property(PropertyInfo &property) const {
}
}
-void GPUParticles3D::emit_particle(const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
+void GPUParticles3D::emit_particle(const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
RS::get_singleton()->particles_emit(particles, p_transform, p_velocity, p_color, p_custom, p_emit_flags);
}
@@ -375,6 +457,47 @@ void GPUParticles3D::_notification(int p_what) {
}
}
+void GPUParticles3D::_skinning_changed() {
+ Vector<Transform3D> xforms;
+ if (skin.is_valid()) {
+ xforms.resize(skin->get_bind_count());
+ for (int i = 0; i < skin->get_bind_count(); i++) {
+ xforms.write[i] = skin->get_bind_pose(i);
+ }
+ } else {
+ for (int i = 0; i < draw_passes.size(); i++) {
+ Ref<Mesh> draw_pass = draw_passes[i];
+ 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);
+ }
+ break;
+ }
+ }
+ }
+
+ RS::get_singleton()->particles_set_trail_bind_poses(particles, xforms);
+ update_configuration_warnings();
+}
+
+void GPUParticles3D::set_skin(const Ref<Skin> &p_skin) {
+ skin = p_skin;
+ _skinning_changed();
+}
+Ref<Skin> GPUParticles3D::get_skin() const {
+ return skin;
+}
+
+void GPUParticles3D::set_transform_align(TransformAlign p_align) {
+ ERR_FAIL_INDEX(uint32_t(p_align), 4);
+ transform_align = p_align;
+ RS::get_singleton()->particles_set_transform_align(particles, RS::ParticlesTransformAlign(transform_align));
+}
+GPUParticles3D::TransformAlign GPUParticles3D::get_transform_align() const {
+ return transform_align;
+}
+
void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &GPUParticles3D::set_emitting);
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &GPUParticles3D::set_amount);
@@ -387,6 +510,7 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &GPUParticles3D::set_use_local_coordinates);
ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &GPUParticles3D::set_fixed_fps);
ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &GPUParticles3D::set_fractional_delta);
+ ClassDB::bind_method(D_METHOD("set_interpolate", "enable"), &GPUParticles3D::set_interpolate);
ClassDB::bind_method(D_METHOD("set_process_material", "material"), &GPUParticles3D::set_process_material);
ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &GPUParticles3D::set_speed_scale);
ClassDB::bind_method(D_METHOD("set_collision_base_size", "size"), &GPUParticles3D::set_collision_base_size);
@@ -402,6 +526,7 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &GPUParticles3D::get_use_local_coordinates);
ClassDB::bind_method(D_METHOD("get_fixed_fps"), &GPUParticles3D::get_fixed_fps);
ClassDB::bind_method(D_METHOD("get_fractional_delta"), &GPUParticles3D::get_fractional_delta);
+ ClassDB::bind_method(D_METHOD("get_interpolate"), &GPUParticles3D::get_interpolate);
ClassDB::bind_method(D_METHOD("get_process_material"), &GPUParticles3D::get_process_material);
ClassDB::bind_method(D_METHOD("get_speed_scale"), &GPUParticles3D::get_speed_scale);
ClassDB::bind_method(D_METHOD("get_collision_base_size"), &GPUParticles3D::get_collision_base_size);
@@ -416,6 +541,9 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_draw_passes"), &GPUParticles3D::get_draw_passes);
ClassDB::bind_method(D_METHOD("get_draw_pass_mesh", "pass"), &GPUParticles3D::get_draw_pass_mesh);
+ ClassDB::bind_method(D_METHOD("set_skin", "skin"), &GPUParticles3D::set_skin);
+ ClassDB::bind_method(D_METHOD("get_skin"), &GPUParticles3D::get_skin);
+
ClassDB::bind_method(D_METHOD("restart"), &GPUParticles3D::restart);
ClassDB::bind_method(D_METHOD("capture_aabb"), &GPUParticles3D::capture_aabb);
@@ -424,6 +552,15 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("emit_particle", "xform", "velocity", "color", "custom", "flags"), &GPUParticles3D::emit_particle);
+ ClassDB::bind_method(D_METHOD("set_trail_enabled", "enabled"), &GPUParticles3D::set_trail_enabled);
+ ClassDB::bind_method(D_METHOD("set_trail_length", "secs"), &GPUParticles3D::set_trail_length);
+
+ ClassDB::bind_method(D_METHOD("is_trail_enabled"), &GPUParticles3D::is_trail_enabled);
+ ClassDB::bind_method(D_METHOD("get_trail_length"), &GPUParticles3D::get_trail_length);
+
+ ClassDB::bind_method(D_METHOD("set_transform_align", "align"), &GPUParticles3D::set_transform_align);
+ 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::NODE_PATH, "sub_emitter", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GPUParticles3D"), "set_sub_emitter", "get_sub_emitter");
@@ -435,13 +572,18 @@ void GPUParticles3D::_bind_methods() {
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");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interpolate"), "set_interpolate", "get_interpolate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_base_size", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_collision_base_size", "get_collision_base_size");
ADD_GROUP("Drawing", "");
ADD_PROPERTY(PropertyInfo(Variant::AABB, "visibility_aabb"), "set_visibility_aabb", "get_visibility_aabb");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,Reverse Lifetime,View Depth"), "set_draw_order", "get_draw_order");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_align", PROPERTY_HINT_ENUM, "Disabled,ZBillboard,YToVelocity,ZBillboardYToVelocity"), "set_transform_align", "get_transform_align");
+ ADD_GROUP("Trails", "trail_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_trail_enabled", "is_trail_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_trail_length", "get_trail_length");
ADD_GROUP("Process Material", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
ADD_GROUP("Draw Passes", "draw_");
@@ -449,9 +591,11 @@ void GPUParticles3D::_bind_methods() {
for (int i = 0; i < MAX_DRAW_PASSES; i++) {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "draw_pass_" + itos(i + 1), PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_draw_pass_mesh", "get_draw_pass_mesh", i);
}
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "draw_skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin");
BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
+ BIND_ENUM_CONSTANT(DRAW_ORDER_REVERSE_LIFETIME);
BIND_ENUM_CONSTANT(DRAW_ORDER_VIEW_DEPTH);
BIND_ENUM_CONSTANT(EMIT_FLAG_POSITION);
@@ -461,27 +605,36 @@ void GPUParticles3D::_bind_methods() {
BIND_ENUM_CONSTANT(EMIT_FLAG_CUSTOM);
BIND_CONSTANT(MAX_DRAW_PASSES);
+
+ BIND_ENUM_CONSTANT(TRANSFORM_ALIGN_DISABLED);
+ BIND_ENUM_CONSTANT(TRANSFORM_ALIGN_Z_BILLBOARD);
+ BIND_ENUM_CONSTANT(TRANSFORM_ALIGN_Y_TO_VELOCITY);
+ BIND_ENUM_CONSTANT(TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY);
}
GPUParticles3D::GPUParticles3D() {
particles = RS::get_singleton()->particles_create();
+ RS::get_singleton()->particles_set_mode(particles, RS::PARTICLES_MODE_3D);
set_base(particles);
one_shot = false; // Needed so that set_emitting doesn't access uninitialized values
set_emitting(true);
set_one_shot(false);
set_amount(8);
set_lifetime(1);
- set_fixed_fps(0);
+ set_fixed_fps(30);
set_fractional_delta(true);
+ set_interpolate(true);
set_pre_process_time(0);
set_explosiveness_ratio(0);
set_randomness_ratio(0);
+ set_trail_length(0.3);
set_visibility_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8)));
set_use_local_coordinates(true);
set_draw_passes(1);
set_draw_order(DRAW_ORDER_INDEX);
set_speed_scale(1);
- set_collision_base_size(0.01);
+ set_collision_base_size(collision_base_size);
+ set_transform_align(TRANSFORM_ALIGN_DISABLED);
}
GPUParticles3D::~GPUParticles3D() {
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index 0c1a1a510c..7b21cf03f1 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -34,6 +34,7 @@
#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 {
private:
@@ -43,9 +44,17 @@ public:
enum DrawOrder {
DRAW_ORDER_INDEX,
DRAW_ORDER_LIFETIME,
+ DRAW_ORDER_REVERSE_LIFETIME,
DRAW_ORDER_VIEW_DEPTH,
};
+ enum TransformAlign {
+ TRANSFORM_ALIGN_DISABLED,
+ TRANSFORM_ALIGN_Z_BILLBOARD,
+ TRANSFORM_ALIGN_Y_TO_VELOCITY,
+ TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY
+ };
+
enum {
MAX_DRAW_PASSES = 4
};
@@ -64,17 +73,26 @@ private:
bool local_coords;
int fixed_fps;
bool fractional_delta;
+ bool interpolate = true;
NodePath sub_emitter;
- float collision_base_size;
+ float collision_base_size = 0.01;
+
+ bool trail_enabled = false;
+ float trail_length = 0.3;
+
+ TransformAlign transform_align = TRANSFORM_ALIGN_DISABLED;
Ref<Material> process_material;
DrawOrder draw_order;
Vector<Ref<Mesh>> draw_passes;
+ Ref<Skin> skin;
void _attach_sub_emitter();
+ void _skinning_changed();
+
protected:
static void _bind_methods();
void _notification(int p_what);
@@ -96,6 +114,8 @@ public:
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_trail_enabled(bool p_enabled);
+ void set_trail_length(float p_seconds);
bool is_emitting() const;
int get_amount() const;
@@ -109,6 +129,8 @@ public:
Ref<Material> get_process_material() const;
float get_speed_scale() const;
float get_collision_base_size() const;
+ bool is_trail_enabled() const;
+ float get_trail_length() const;
void set_fixed_fps(int p_count);
int get_fixed_fps() const;
@@ -116,6 +138,9 @@ public:
void set_fractional_delta(bool p_enable);
bool get_fractional_delta() const;
+ void set_interpolate(bool p_enable);
+ bool get_interpolate() const;
+
void set_draw_order(DrawOrder p_order);
DrawOrder get_draw_order() const;
@@ -125,11 +150,17 @@ public:
void set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh);
Ref<Mesh> get_draw_pass_mesh(int p_pass) const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void set_sub_emitter(const NodePath &p_path);
NodePath get_sub_emitter() const;
+ void set_skin(const Ref<Skin> &p_skin);
+ Ref<Skin> get_skin() const;
+
+ void set_transform_align(TransformAlign p_align);
+ TransformAlign get_transform_align() const;
+
void restart();
enum EmitFlags {
@@ -140,7 +171,7 @@ public:
EMIT_FLAG_CUSTOM = RS::PARTICLES_EMIT_FLAG_CUSTOM
};
- void emit_particle(const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags);
+ void emit_particle(const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags);
AABB capture_aabb() const;
GPUParticles3D();
@@ -148,6 +179,7 @@ public:
};
VARIANT_ENUM_CAST(GPUParticles3D::DrawOrder)
+VARIANT_ENUM_CAST(GPUParticles3D::TransformAlign)
VARIANT_ENUM_CAST(GPUParticles3D::EmitFlags)
#endif // PARTICLES_H
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index 97241be60f..322bc60fce 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -131,7 +131,7 @@ void GPUParticlesCollisionSDF::_find_meshes(const AABB &p_aabb, Node *p_at_node,
if (mesh.is_valid()) {
AABB aabb = mesh->get_aabb();
- Transform xf = get_global_transform().affine_inverse() * mi->get_global_transform();
+ Transform3D xf = get_global_transform().affine_inverse() * mi->get_global_transform();
if (p_aabb.intersects(xf.xform(aabb))) {
PlotMesh pm;
@@ -147,7 +147,7 @@ void GPUParticlesCollisionSDF::_find_meshes(const AABB &p_aabb, Node *p_at_node,
if (s->is_visible_in_tree()) {
Array meshes = p_at_node->call("get_meshes");
for (int i = 0; i < meshes.size(); i += 2) {
- Transform mxf = meshes[i];
+ Transform3D mxf = meshes[i];
Ref<Mesh> mesh = meshes[i + 1];
if (!mesh.is_valid()) {
continue;
@@ -155,7 +155,7 @@ void GPUParticlesCollisionSDF::_find_meshes(const AABB &p_aabb, Node *p_at_node,
AABB aabb = mesh->get_aabb();
- Transform xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf);
+ Transform3D xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf);
if (p_aabb.intersects(xf.xform(aabb))) {
PlotMesh pm;
@@ -346,7 +346,7 @@ void GPUParticlesCollisionSDF::_compute_sdf(ComputeSDFParams *params) {
ThreadWorkPool work_pool;
work_pool.init();
work_pool.begin_work(params->size.z, this, &GPUParticlesCollisionSDF::_compute_sdf_z, params);
- while (work_pool.get_work_index() < (uint32_t)params->size.z) {
+ while (!work_pool.is_done_dispatching()) {
OS::get_singleton()->delay_usec(10000);
bake_step_function(work_pool.get_work_index() * 100 / params->size.z, "Baking SDF");
}
@@ -598,14 +598,14 @@ void GPUParticlesCollisionHeightField::_notification(int p_what) {
if (follow_camera_mode && get_viewport()) {
Camera3D *cam = get_viewport()->get_camera();
if (cam) {
- Transform xform = get_global_transform();
+ Transform3D xform = get_global_transform();
Vector3 x_axis = xform.basis.get_axis(Vector3::AXIS_X).normalized();
Vector3 z_axis = xform.basis.get_axis(Vector3::AXIS_Z).normalized();
float x_len = xform.basis.get_scale().x;
float z_len = xform.basis.get_scale().z;
Vector3 cam_pos = cam->get_global_transform().origin;
- Transform new_xform = xform;
+ Transform3D new_xform = xform;
while (x_axis.dot(cam_pos - new_xform.origin) > x_len) {
new_xform.origin += x_axis * x_len;
@@ -653,7 +653,7 @@ void GPUParticlesCollisionHeightField::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_extents", "get_extents");
ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "256,512,1024,2048,4096,8192"), "set_resolution", "get_resolution");
ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "WhenMoved,Always"), "set_update_mode", "get_update_mode");
- ADD_GROUP("Folow Camera", "follow_camera_");
+ ADD_GROUP("Follow Camera", "follow_camera_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_camera_enabled"), "set_follow_camera_mode", "is_follow_camera_mode_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "follow_camera_push_ratio", PROPERTY_HINT_RANGE, "0.01,1,0.01"), "set_follow_camera_push_ratio", "get_follow_camera_push_ratio");
diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h
index 81c33663f3..c55463378d 100644
--- a/scene/3d/gpu_particles_collision_3d.h
+++ b/scene/3d/gpu_particles_collision_3d.h
@@ -119,7 +119,7 @@ private:
struct PlotMesh {
Ref<Mesh> mesh;
- Transform local_xform;
+ Transform3D local_xform;
};
void _find_meshes(const AABB &p_aabb, Node *p_at_node, List<PlotMesh> &plot_meshes);
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index f109640aef..d45749d36b 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -48,7 +48,7 @@ void Light3D::set_param(Param p_param, float p_value) {
update_gizmo();
if (p_param == PARAM_SPOT_ANGLE) {
- update_configuration_warning();
+ update_configuration_warnings();
}
}
}
@@ -63,7 +63,7 @@ void Light3D::set_shadow(bool p_enable) {
RS::get_singleton()->light_set_shadow(light, p_enable);
if (type == RenderingServer::LIGHT_SPOT || type == RenderingServer::LIGHT_OMNI) {
- update_configuration_warning();
+ update_configuration_warnings();
}
notify_property_list_changed();
@@ -153,7 +153,7 @@ void Light3D::set_projector(const Ref<Texture2D> &p_texture) {
projector = p_texture;
RID tex_id = projector.is_valid() ? projector->get_rid() : RID();
RS::get_singleton()->light_set_projector(light, tex_id);
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<Texture2D> Light3D::get_projector() const {
@@ -457,17 +457,14 @@ OmniLight3D::ShadowMode OmniLight3D::get_shadow_mode() const {
return shadow_mode;
}
-String OmniLight3D::get_configuration_warning() const {
- String warning = Light3D::get_configuration_warning();
+TypedArray<String> OmniLight3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!has_shadow() && get_projector().is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Projector texture only works with shadows active.");
+ warnings.push_back(TTR("Projector texture only works with shadows active."));
}
- return warning;
+ return warnings;
}
void OmniLight3D::_bind_methods() {
@@ -491,24 +488,18 @@ OmniLight3D::OmniLight3D() :
set_param(PARAM_SHADOW_NORMAL_BIAS, 2.0);
}
-String SpotLight3D::get_configuration_warning() const {
- String warning = Light3D::get_configuration_warning();
+TypedArray<String> SpotLight3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows.");
+ warnings.push_back(TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows."));
}
if (!has_shadow() && get_projector().is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Projector texture only works with shadows active.");
+ warnings.push_back(TTR("Projector texture only works with shadows active."));
}
- return warning;
+ return warnings;
}
void SpotLight3D::_bind_methods() {
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index 311db54bce..e145b08b74 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -202,7 +202,7 @@ public:
void set_shadow_mode(ShadowMode p_mode);
ShadowMode get_shadow_mode() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
OmniLight3D();
};
@@ -216,7 +216,7 @@ protected:
static void _bind_methods();
public:
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
SpotLight3D() :
Light3D(RenderingServer::LIGHT_SPOT) {}
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/lightmap_gi.cpp
index 95ffbe48c1..a3f681e53c 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* baked_lightmap.cpp */
+/* lightmap_gi.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,19 +28,19 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "baked_lightmap.h"
+#include "lightmap_gi.h"
#include "core/io/config_file.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/resource_saver.h"
#include "core/math/camera_matrix.h"
#include "core/math/delaunay_3d.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/templates/sort_array.h"
#include "lightmap_probe.h"
-void BakedLightmapData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance) {
+void LightmapGIData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance) {
User user;
user.path = p_path;
user.uv_scale = p_uv_scale;
@@ -49,35 +49,35 @@ void BakedLightmapData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale
users.push_back(user);
}
-int BakedLightmapData::get_user_count() const {
+int LightmapGIData::get_user_count() const {
return users.size();
}
-NodePath BakedLightmapData::get_user_path(int p_user) const {
+NodePath LightmapGIData::get_user_path(int p_user) const {
ERR_FAIL_INDEX_V(p_user, users.size(), NodePath());
return users[p_user].path;
}
-int32_t BakedLightmapData::get_user_sub_instance(int p_user) const {
+int32_t LightmapGIData::get_user_sub_instance(int p_user) const {
ERR_FAIL_INDEX_V(p_user, users.size(), -1);
return users[p_user].sub_instance;
}
-Rect2 BakedLightmapData::get_user_lightmap_uv_scale(int p_user) const {
+Rect2 LightmapGIData::get_user_lightmap_uv_scale(int p_user) const {
ERR_FAIL_INDEX_V(p_user, users.size(), Rect2());
return users[p_user].uv_scale;
}
-int BakedLightmapData::get_user_lightmap_slice_index(int p_user) const {
+int LightmapGIData::get_user_lightmap_slice_index(int p_user) const {
ERR_FAIL_INDEX_V(p_user, users.size(), -1);
return users[p_user].slice_index;
}
-void BakedLightmapData::clear_users() {
+void LightmapGIData::clear_users() {
users.clear();
}
-void BakedLightmapData::_set_user_data(const Array &p_data) {
+void LightmapGIData::_set_user_data(const Array &p_data) {
ERR_FAIL_COND(p_data.size() <= 0);
ERR_FAIL_COND((p_data.size() % 4) != 0);
@@ -86,7 +86,7 @@ void BakedLightmapData::_set_user_data(const Array &p_data) {
}
}
-Array BakedLightmapData::_get_user_data() const {
+Array LightmapGIData::_get_user_data() const {
Array ret;
for (int i = 0; i < users.size(); i++) {
ret.push_back(users[i].path);
@@ -97,33 +97,33 @@ Array BakedLightmapData::_get_user_data() const {
return ret;
}
-RID BakedLightmapData::get_rid() const {
+RID LightmapGIData::get_rid() const {
return lightmap;
}
-void BakedLightmapData::clear() {
+void LightmapGIData::clear() {
users.clear();
}
-void BakedLightmapData::set_light_texture(const Ref<TextureLayered> &p_light_texture) {
+void LightmapGIData::set_light_texture(const Ref<TextureLayered> &p_light_texture) {
light_texture = p_light_texture;
RS::get_singleton()->lightmap_set_textures(lightmap, light_texture.is_valid() ? light_texture->get_rid() : RID(), uses_spherical_harmonics);
}
-Ref<TextureLayered> BakedLightmapData::get_light_texture() const {
+Ref<TextureLayered> LightmapGIData::get_light_texture() const {
return light_texture;
}
-void BakedLightmapData::set_uses_spherical_harmonics(bool p_enable) {
+void LightmapGIData::set_uses_spherical_harmonics(bool p_enable) {
uses_spherical_harmonics = p_enable;
RS::get_singleton()->lightmap_set_textures(lightmap, light_texture.is_valid() ? light_texture->get_rid() : RID(), uses_spherical_harmonics);
}
-bool BakedLightmapData::is_using_spherical_harmonics() const {
+bool LightmapGIData::is_using_spherical_harmonics() const {
return uses_spherical_harmonics;
}
-void BakedLightmapData::set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) {
+void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) {
if (p_points.size()) {
int pc = p_points.size();
ERR_FAIL_COND(pc * 9 != p_point_sh.size());
@@ -141,31 +141,31 @@ void BakedLightmapData::set_capture_data(const AABB &p_bounds, bool p_interior,
bounds = p_bounds;
}
-PackedVector3Array BakedLightmapData::get_capture_points() const {
+PackedVector3Array LightmapGIData::get_capture_points() const {
return RS::get_singleton()->lightmap_get_probe_capture_points(lightmap);
}
-PackedColorArray BakedLightmapData::get_capture_sh() const {
+PackedColorArray LightmapGIData::get_capture_sh() const {
return RS::get_singleton()->lightmap_get_probe_capture_sh(lightmap);
}
-PackedInt32Array BakedLightmapData::get_capture_tetrahedra() const {
+PackedInt32Array LightmapGIData::get_capture_tetrahedra() const {
return RS::get_singleton()->lightmap_get_probe_capture_tetrahedra(lightmap);
}
-PackedInt32Array BakedLightmapData::get_capture_bsp_tree() const {
+PackedInt32Array LightmapGIData::get_capture_bsp_tree() const {
return RS::get_singleton()->lightmap_get_probe_capture_bsp_tree(lightmap);
}
-AABB BakedLightmapData::get_capture_bounds() const {
+AABB LightmapGIData::get_capture_bounds() const {
return bounds;
}
-bool BakedLightmapData::is_interior() const {
+bool LightmapGIData::is_interior() const {
return interior;
}
-void BakedLightmapData::_set_probe_data(const Dictionary &p_data) {
+void LightmapGIData::_set_probe_data(const Dictionary &p_data) {
ERR_FAIL_COND(!p_data.has("bounds"));
ERR_FAIL_COND(!p_data.has("points"));
ERR_FAIL_COND(!p_data.has("tetrahedra"));
@@ -175,7 +175,7 @@ void BakedLightmapData::_set_probe_data(const Dictionary &p_data) {
set_capture_data(p_data["bounds"], p_data["interior"], p_data["points"], p_data["sh"], p_data["tetrahedra"], p_data["bsp"]);
}
-Dictionary BakedLightmapData::_get_probe_data() const {
+Dictionary LightmapGIData::_get_probe_data() const {
Dictionary d;
d["bounds"] = get_capture_bounds();
d["points"] = get_capture_points();
@@ -186,23 +186,23 @@ Dictionary BakedLightmapData::_get_probe_data() const {
return d;
}
-void BakedLightmapData::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_set_user_data", "data"), &BakedLightmapData::_set_user_data);
- ClassDB::bind_method(D_METHOD("_get_user_data"), &BakedLightmapData::_get_user_data);
+void LightmapGIData::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_set_user_data", "data"), &LightmapGIData::_set_user_data);
+ ClassDB::bind_method(D_METHOD("_get_user_data"), &LightmapGIData::_get_user_data);
- ClassDB::bind_method(D_METHOD("set_light_texture", "light_texture"), &BakedLightmapData::set_light_texture);
- ClassDB::bind_method(D_METHOD("get_light_texture"), &BakedLightmapData::get_light_texture);
+ ClassDB::bind_method(D_METHOD("set_light_texture", "light_texture"), &LightmapGIData::set_light_texture);
+ ClassDB::bind_method(D_METHOD("get_light_texture"), &LightmapGIData::get_light_texture);
- ClassDB::bind_method(D_METHOD("set_uses_spherical_harmonics", "uses_spherical_harmonics"), &BakedLightmapData::set_uses_spherical_harmonics);
- ClassDB::bind_method(D_METHOD("is_using_spherical_harmonics"), &BakedLightmapData::is_using_spherical_harmonics);
+ ClassDB::bind_method(D_METHOD("set_uses_spherical_harmonics", "uses_spherical_harmonics"), &LightmapGIData::set_uses_spherical_harmonics);
+ ClassDB::bind_method(D_METHOD("is_using_spherical_harmonics"), &LightmapGIData::is_using_spherical_harmonics);
- ClassDB::bind_method(D_METHOD("add_user", "path", "uv_scale", "slice_index", "sub_instance"), &BakedLightmapData::add_user);
- ClassDB::bind_method(D_METHOD("get_user_count"), &BakedLightmapData::get_user_count);
- ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &BakedLightmapData::get_user_path);
- ClassDB::bind_method(D_METHOD("clear_users"), &BakedLightmapData::clear_users);
+ ClassDB::bind_method(D_METHOD("add_user", "path", "uv_scale", "slice_index", "sub_instance"), &LightmapGIData::add_user);
+ ClassDB::bind_method(D_METHOD("get_user_count"), &LightmapGIData::get_user_count);
+ ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &LightmapGIData::get_user_path);
+ ClassDB::bind_method(D_METHOD("clear_users"), &LightmapGIData::clear_users);
- ClassDB::bind_method(D_METHOD("_set_probe_data", "data"), &BakedLightmapData::_set_probe_data);
- ClassDB::bind_method(D_METHOD("_get_probe_data"), &BakedLightmapData::_get_probe_data);
+ ClassDB::bind_method(D_METHOD("_set_probe_data", "data"), &LightmapGIData::_set_probe_data);
+ ClassDB::bind_method(D_METHOD("_get_probe_data"), &LightmapGIData::_get_probe_data);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered"), "set_light_texture", "get_light_texture");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uses_spherical_harmonics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_uses_spherical_harmonics", "is_using_spherical_harmonics");
@@ -210,17 +210,17 @@ void BakedLightmapData::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "probe_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_probe_data", "_get_probe_data");
}
-BakedLightmapData::BakedLightmapData() {
+LightmapGIData::LightmapGIData() {
lightmap = RS::get_singleton()->lightmap_create();
}
-BakedLightmapData::~BakedLightmapData() {
+LightmapGIData::~LightmapGIData() {
RS::get_singleton()->free(lightmap);
}
///////////////////////////
-void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> &meshes, Vector<LightsFound> &lights, Vector<Vector3> &probes) {
+void LightmapGI::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> &meshes, Vector<LightsFound> &lights, Vector<Vector3> &probes) {
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node);
if (mi && mi->get_gi_mode() == GeometryInstance3D::GI_MODE_BAKED && mi->is_visible_in_tree()) {
Ref<Mesh> mesh = mi->get_mesh();
@@ -259,7 +259,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound>
if (all_override.is_valid()) {
mf.overrides.push_back(all_override);
} else {
- mf.overrides.push_back(mi->get_surface_material(i));
+ mf.overrides.push_back(mi->get_surface_override_material(i));
}
}
@@ -273,7 +273,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound>
if (!mi && s) {
Array bmeshes = p_at_node->call("get_bake_bmeshes");
if (bmeshes.size() && (bmeshes.size() & 1) == 0) {
- Transform xf = get_global_transform().affine_inverse() * s->get_global_transform();
+ Transform3D xf = get_global_transform().affine_inverse() * s->get_global_transform();
for (int i = 0; i < bmeshes.size(); i += 2) {
Ref<Mesh> mesh = bmeshes[i];
if (!mesh.is_valid()) {
@@ -282,7 +282,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound>
MeshesFound mf;
- Transform mesh_xf = bmeshes[i + 1];
+ Transform3D mesh_xf = bmeshes[i + 1];
mf.xform = xf * mesh_xf;
mf.node_path = get_path_to(s);
mf.subindex = i / 2;
@@ -306,7 +306,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound>
LightmapProbe *probe = Object::cast_to<LightmapProbe>(p_at_node);
if (probe) {
- Transform xf = get_global_transform().affine_inverse() * probe->get_global_transform();
+ Transform3D xf = get_global_transform().affine_inverse() * probe->get_global_transform();
probes.push_back(xf.origin);
}
@@ -320,7 +320,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound>
}
}
-int BakedLightmap::_bsp_get_simplex_side(const Vector<Vector3> &p_points, const LocalVector<BSPSimplex> &p_simplices, const Plane &p_plane, uint32_t p_simplex) const {
+int LightmapGI::_bsp_get_simplex_side(const Vector<Vector3> &p_points, const LocalVector<BSPSimplex> &p_simplices, const Plane &p_plane, uint32_t p_simplex) const {
int over = 0;
int under = 0;
int coplanar = 0;
@@ -348,7 +348,7 @@ int BakedLightmap::_bsp_get_simplex_side(const Vector<Vector3> &p_points, const
//#define DEBUG_BSP
-int32_t BakedLightmap::_compute_bsp_tree(const Vector<Vector3> &p_points, const LocalVector<Plane> &p_planes, LocalVector<int32_t> &planes_tested, const LocalVector<BSPSimplex> &p_simplices, const LocalVector<int32_t> &p_simplex_indices, LocalVector<BSPNode> &bsp_nodes) {
+int32_t LightmapGI::_compute_bsp_tree(const Vector<Vector3> &p_points, const LocalVector<Plane> &p_planes, LocalVector<int32_t> &planes_tested, const LocalVector<BSPSimplex> &p_simplices, const LocalVector<int32_t> &p_simplex_indices, LocalVector<BSPNode> &bsp_nodes) {
//if we reach here, it means there is more than one simplex
int32_t node_index = (int32_t)bsp_nodes.size();
bsp_nodes.push_back(BSPNode());
@@ -533,7 +533,7 @@ int32_t BakedLightmap::_compute_bsp_tree(const Vector<Vector3> &p_points, const
return node_index;
}
-bool BakedLightmap::_lightmap_bake_step_function(float p_completion, const String &p_text, void *ud, bool p_refresh) {
+bool LightmapGI::_lightmap_bake_step_function(float p_completion, const String &p_text, void *ud, bool p_refresh) {
BakeStepUD *bsud = (BakeStepUD *)ud;
bool ret = false;
if (bsud->func) {
@@ -542,7 +542,7 @@ bool BakedLightmap::_lightmap_bake_step_function(float p_completion, const Strin
return ret;
}
-void BakedLightmap::_plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cell_size, const Vector3 *p_triangle) {
+void LightmapGI::_plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cell_size, const Vector3 *p_triangle) {
for (int i = 0; i < 8; i++) {
Vector3i pos = p_cell->offset;
uint32_t half_size = p_cell->size / 2;
@@ -578,7 +578,7 @@ void BakedLightmap::_plot_triangle_into_octree(GenProbesOctree *p_cell, float p_
}
}
-void BakedLightmap::_gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool, Vector3iHash> &positions_used, const AABB &p_bounds) {
+void LightmapGI::_gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool, Vector3iHash> &positions_used, const AABB &p_bounds) {
for (int i = 0; i < 8; i++) {
Vector3i pos = p_cell->offset;
if (i & 1) {
@@ -618,11 +618,7 @@ void BakedLightmap::_gen_new_positions_from_octree(const GenProbesOctree *p_cell
}
}
-BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_data_path, Lightmapper::BakeStepFunc p_bake_step, void *p_bake_userdata) {
- if (p_image_data_path == "" && (get_light_data().is_null() || !get_light_data()->get_path().is_resource_file())) {
- return BAKE_ERROR_NO_SAVE_PATH;
- }
-
+LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_path, Lightmapper::BakeStepFunc p_bake_step, void *p_bake_userdata) {
if (p_image_data_path == "") {
if (get_light_data().is_null()) {
return BAKE_ERROR_NO_SAVE_PATH;
@@ -891,7 +887,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d
}
for (int i = 0; i < lights_found.size(); i++) {
Light3D *light = lights_found[i].light;
- Transform xf = lights_found[i].xform;
+ Transform3D xf = lights_found[i].xform;
if (Object::cast_to<DirectionalLight3D>(light)) {
DirectionalLight3D *l = Object::cast_to<DirectionalLight3D>(light);
@@ -1015,10 +1011,10 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d
/* POSTBAKE: Save Light Data */
- Ref<BakedLightmapData> data;
+ Ref<LightmapGIData> data;
if (get_light_data().is_valid()) {
data = get_light_data();
- set_light_data(Ref<BakedLightmapData>()); //clear
+ set_light_data(Ref<LightmapGIData>()); //clear
data->clear();
} else {
data.instance();
@@ -1187,7 +1183,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d
return BAKE_ERROR_OK;
}
-void BakedLightmap::_notification(int p_what) {
+void LightmapGI::_notification(int p_what) {
if (p_what == NOTIFICATION_POST_ENTER_TREE) {
if (light_data.is_valid()) {
_assign_lightmaps();
@@ -1201,7 +1197,7 @@ void BakedLightmap::_notification(int p_what) {
}
}
-void BakedLightmap::_assign_lightmaps() {
+void LightmapGI::_assign_lightmaps() {
ERR_FAIL_COND(!light_data.is_valid());
for (int i = 0; i < light_data->get_user_count(); i++) {
@@ -1220,7 +1216,7 @@ void BakedLightmap::_assign_lightmaps() {
}
}
-void BakedLightmap::_clear_lightmaps() {
+void LightmapGI::_clear_lightmaps() {
ERR_FAIL_COND(!light_data.is_valid());
for (int i = 0; i < light_data->get_user_count(); i++) {
Node *node = get_node(light_data->get_user_path(i));
@@ -1238,7 +1234,7 @@ void BakedLightmap::_clear_lightmaps() {
}
}
-void BakedLightmap::set_light_data(const Ref<BakedLightmapData> &p_data) {
+void LightmapGI::set_light_data(const Ref<LightmapGIData> &p_data) {
if (light_data.is_valid()) {
if (is_inside_tree()) {
_clear_lightmaps();
@@ -1257,119 +1253,119 @@ void BakedLightmap::set_light_data(const Ref<BakedLightmapData> &p_data) {
update_gizmo();
}
-Ref<BakedLightmapData> BakedLightmap::get_light_data() const {
+Ref<LightmapGIData> LightmapGI::get_light_data() const {
return light_data;
}
-void BakedLightmap::set_bake_quality(BakeQuality p_quality) {
+void LightmapGI::set_bake_quality(BakeQuality p_quality) {
bake_quality = p_quality;
}
-BakedLightmap::BakeQuality BakedLightmap::get_bake_quality() const {
+LightmapGI::BakeQuality LightmapGI::get_bake_quality() const {
return bake_quality;
}
-AABB BakedLightmap::get_aabb() const {
+AABB LightmapGI::get_aabb() const {
return AABB();
}
-Vector<Face3> BakedLightmap::get_faces(uint32_t p_usage_flags) const {
+Vector<Face3> LightmapGI::get_faces(uint32_t p_usage_flags) const {
return Vector<Face3>();
}
-void BakedLightmap::set_use_denoiser(bool p_enable) {
+void LightmapGI::set_use_denoiser(bool p_enable) {
use_denoiser = p_enable;
}
-bool BakedLightmap::is_using_denoiser() const {
+bool LightmapGI::is_using_denoiser() const {
return use_denoiser;
}
-void BakedLightmap::set_directional(bool p_enable) {
+void LightmapGI::set_directional(bool p_enable) {
directional = p_enable;
}
-bool BakedLightmap::is_directional() const {
+bool LightmapGI::is_directional() const {
return directional;
}
-void BakedLightmap::set_interior(bool p_enable) {
+void LightmapGI::set_interior(bool p_enable) {
interior = p_enable;
}
-bool BakedLightmap::is_interior() const {
+bool LightmapGI::is_interior() const {
return interior;
}
-void BakedLightmap::set_environment_mode(EnvironmentMode p_mode) {
+void LightmapGI::set_environment_mode(EnvironmentMode p_mode) {
environment_mode = p_mode;
notify_property_list_changed();
}
-BakedLightmap::EnvironmentMode BakedLightmap::get_environment_mode() const {
+LightmapGI::EnvironmentMode LightmapGI::get_environment_mode() const {
return environment_mode;
}
-void BakedLightmap::set_environment_custom_sky(const Ref<Sky> &p_sky) {
+void LightmapGI::set_environment_custom_sky(const Ref<Sky> &p_sky) {
environment_custom_sky = p_sky;
}
-Ref<Sky> BakedLightmap::get_environment_custom_sky() const {
+Ref<Sky> LightmapGI::get_environment_custom_sky() const {
return environment_custom_sky;
}
-void BakedLightmap::set_environment_custom_color(const Color &p_color) {
+void LightmapGI::set_environment_custom_color(const Color &p_color) {
environment_custom_color = p_color;
}
-Color BakedLightmap::get_environment_custom_color() const {
+Color LightmapGI::get_environment_custom_color() const {
return environment_custom_color;
}
-void BakedLightmap::set_environment_custom_energy(float p_energy) {
+void LightmapGI::set_environment_custom_energy(float p_energy) {
environment_custom_energy = p_energy;
}
-float BakedLightmap::get_environment_custom_energy() const {
+float LightmapGI::get_environment_custom_energy() const {
return environment_custom_energy;
}
-void BakedLightmap::set_bounces(int p_bounces) {
+void LightmapGI::set_bounces(int p_bounces) {
ERR_FAIL_COND(p_bounces < 0 || p_bounces > 16);
bounces = p_bounces;
}
-int BakedLightmap::get_bounces() const {
+int LightmapGI::get_bounces() const {
return bounces;
}
-void BakedLightmap::set_bias(float p_bias) {
+void LightmapGI::set_bias(float p_bias) {
ERR_FAIL_COND(p_bias < 0.00001);
bias = p_bias;
}
-float BakedLightmap::get_bias() const {
+float LightmapGI::get_bias() const {
return bias;
}
-void BakedLightmap::set_max_texture_size(int p_size) {
+void LightmapGI::set_max_texture_size(int p_size) {
ERR_FAIL_COND(p_size < 2048);
max_texture_size = p_size;
}
-int BakedLightmap::get_max_texture_size() const {
+int LightmapGI::get_max_texture_size() const {
return max_texture_size;
}
-void BakedLightmap::set_generate_probes(GenerateProbes p_generate_probes) {
+void LightmapGI::set_generate_probes(GenerateProbes p_generate_probes) {
gen_probes = p_generate_probes;
}
-BakedLightmap::GenerateProbes BakedLightmap::get_generate_probes() const {
+LightmapGI::GenerateProbes LightmapGI::get_generate_probes() const {
return gen_probes;
}
-void BakedLightmap::_validate_property(PropertyInfo &property) const {
+void LightmapGI::_validate_property(PropertyInfo &property) const {
if (property.name == "environment_custom_sky" && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) {
property.usage = 0;
}
@@ -1381,47 +1377,47 @@ void BakedLightmap::_validate_property(PropertyInfo &property) const {
}
}
-void BakedLightmap::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_light_data", "data"), &BakedLightmap::set_light_data);
- ClassDB::bind_method(D_METHOD("get_light_data"), &BakedLightmap::get_light_data);
+void LightmapGI::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_light_data", "data"), &LightmapGI::set_light_data);
+ ClassDB::bind_method(D_METHOD("get_light_data"), &LightmapGI::get_light_data);
- ClassDB::bind_method(D_METHOD("set_bake_quality", "bake_quality"), &BakedLightmap::set_bake_quality);
- ClassDB::bind_method(D_METHOD("get_bake_quality"), &BakedLightmap::get_bake_quality);
+ ClassDB::bind_method(D_METHOD("set_bake_quality", "bake_quality"), &LightmapGI::set_bake_quality);
+ ClassDB::bind_method(D_METHOD("get_bake_quality"), &LightmapGI::get_bake_quality);
- ClassDB::bind_method(D_METHOD("set_bounces", "bounces"), &BakedLightmap::set_bounces);
- ClassDB::bind_method(D_METHOD("get_bounces"), &BakedLightmap::get_bounces);
+ ClassDB::bind_method(D_METHOD("set_bounces", "bounces"), &LightmapGI::set_bounces);
+ ClassDB::bind_method(D_METHOD("get_bounces"), &LightmapGI::get_bounces);
- ClassDB::bind_method(D_METHOD("set_generate_probes", "subdivision"), &BakedLightmap::set_generate_probes);
- ClassDB::bind_method(D_METHOD("get_generate_probes"), &BakedLightmap::get_generate_probes);
+ ClassDB::bind_method(D_METHOD("set_generate_probes", "subdivision"), &LightmapGI::set_generate_probes);
+ ClassDB::bind_method(D_METHOD("get_generate_probes"), &LightmapGI::get_generate_probes);
- ClassDB::bind_method(D_METHOD("set_bias", "bias"), &BakedLightmap::set_bias);
- ClassDB::bind_method(D_METHOD("get_bias"), &BakedLightmap::get_bias);
+ ClassDB::bind_method(D_METHOD("set_bias", "bias"), &LightmapGI::set_bias);
+ ClassDB::bind_method(D_METHOD("get_bias"), &LightmapGI::get_bias);
- ClassDB::bind_method(D_METHOD("set_environment_mode", "mode"), &BakedLightmap::set_environment_mode);
- ClassDB::bind_method(D_METHOD("get_environment_mode"), &BakedLightmap::get_environment_mode);
+ ClassDB::bind_method(D_METHOD("set_environment_mode", "mode"), &LightmapGI::set_environment_mode);
+ ClassDB::bind_method(D_METHOD("get_environment_mode"), &LightmapGI::get_environment_mode);
- ClassDB::bind_method(D_METHOD("set_environment_custom_sky", "sky"), &BakedLightmap::set_environment_custom_sky);
- ClassDB::bind_method(D_METHOD("get_environment_custom_sky"), &BakedLightmap::get_environment_custom_sky);
+ ClassDB::bind_method(D_METHOD("set_environment_custom_sky", "sky"), &LightmapGI::set_environment_custom_sky);
+ ClassDB::bind_method(D_METHOD("get_environment_custom_sky"), &LightmapGI::get_environment_custom_sky);
- ClassDB::bind_method(D_METHOD("set_environment_custom_color", "color"), &BakedLightmap::set_environment_custom_color);
- ClassDB::bind_method(D_METHOD("get_environment_custom_color"), &BakedLightmap::get_environment_custom_color);
+ ClassDB::bind_method(D_METHOD("set_environment_custom_color", "color"), &LightmapGI::set_environment_custom_color);
+ ClassDB::bind_method(D_METHOD("get_environment_custom_color"), &LightmapGI::get_environment_custom_color);
- ClassDB::bind_method(D_METHOD("set_environment_custom_energy", "energy"), &BakedLightmap::set_environment_custom_energy);
- ClassDB::bind_method(D_METHOD("get_environment_custom_energy"), &BakedLightmap::get_environment_custom_energy);
+ ClassDB::bind_method(D_METHOD("set_environment_custom_energy", "energy"), &LightmapGI::set_environment_custom_energy);
+ ClassDB::bind_method(D_METHOD("get_environment_custom_energy"), &LightmapGI::get_environment_custom_energy);
- ClassDB::bind_method(D_METHOD("set_max_texture_size", "max_texture_size"), &BakedLightmap::set_max_texture_size);
- ClassDB::bind_method(D_METHOD("get_max_texture_size"), &BakedLightmap::get_max_texture_size);
+ ClassDB::bind_method(D_METHOD("set_max_texture_size", "max_texture_size"), &LightmapGI::set_max_texture_size);
+ ClassDB::bind_method(D_METHOD("get_max_texture_size"), &LightmapGI::get_max_texture_size);
- ClassDB::bind_method(D_METHOD("set_use_denoiser", "use_denoiser"), &BakedLightmap::set_use_denoiser);
- ClassDB::bind_method(D_METHOD("is_using_denoiser"), &BakedLightmap::is_using_denoiser);
+ ClassDB::bind_method(D_METHOD("set_use_denoiser", "use_denoiser"), &LightmapGI::set_use_denoiser);
+ ClassDB::bind_method(D_METHOD("is_using_denoiser"), &LightmapGI::is_using_denoiser);
- ClassDB::bind_method(D_METHOD("set_interior", "enable"), &BakedLightmap::set_interior);
- ClassDB::bind_method(D_METHOD("is_interior"), &BakedLightmap::is_interior);
+ ClassDB::bind_method(D_METHOD("set_interior", "enable"), &LightmapGI::set_interior);
+ ClassDB::bind_method(D_METHOD("is_interior"), &LightmapGI::is_interior);
- ClassDB::bind_method(D_METHOD("set_directional", "directional"), &BakedLightmap::set_directional);
- ClassDB::bind_method(D_METHOD("is_directional"), &BakedLightmap::is_directional);
+ ClassDB::bind_method(D_METHOD("set_directional", "directional"), &LightmapGI::set_directional);
+ ClassDB::bind_method(D_METHOD("is_directional"), &LightmapGI::is_directional);
- // ClassDB::bind_method(D_METHOD("bake", "from_node"), &BakedLightmap::bake, DEFVAL(Variant()));
+ // ClassDB::bind_method(D_METHOD("bake", "from_node"), &LightmapGI::bake, DEFVAL(Variant()));
ADD_GROUP("Tweaks", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "quality", PROPERTY_HINT_ENUM, "Low,Medium,High,Ultra"), "set_bake_quality", "get_bake_quality");
@@ -1439,7 +1435,7 @@ void BakedLightmap::_bind_methods() {
ADD_GROUP("Gen Probes", "generate_probes_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "generate_probes_subdiv", PROPERTY_HINT_ENUM, "Disabled,4,8,16,32"), "set_generate_probes", "get_generate_probes");
ADD_GROUP("Data", "");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_data", PROPERTY_HINT_RESOURCE_TYPE, "BakedLightmapData"), "set_light_data", "get_light_data");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_data", PROPERTY_HINT_RESOURCE_TYPE, "LightmapGIData"), "set_light_data", "get_light_data");
BIND_ENUM_CONSTANT(BAKE_QUALITY_LOW);
BIND_ENUM_CONSTANT(BAKE_QUALITY_MEDIUM);
@@ -1466,5 +1462,5 @@ void BakedLightmap::_bind_methods() {
BIND_ENUM_CONSTANT(ENVIRONMENT_MODE_CUSTOM_COLOR);
}
-BakedLightmap::BakedLightmap() {
+LightmapGI::LightmapGI() {
}
diff --git a/scene/3d/baked_lightmap.h b/scene/3d/lightmap_gi.h
index e2d89ab2d0..8a54512383 100644
--- a/scene/3d/baked_lightmap.h
+++ b/scene/3d/lightmap_gi.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* baked_lightmap.h */
+/* lightmap_gi.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef BAKED_LIGHTMAP_H
-#define BAKED_LIGHTMAP_H
+#ifndef LIGHTMAP_GI_H
+#define LIGHTMAP_GI_H
#include "core/templates/local_vector.h"
#include "scene/3d/light_3d.h"
@@ -39,8 +39,8 @@
#include "scene/3d/visual_instance_3d.h"
#include "scene/resources/sky.h"
-class BakedLightmapData : public Resource {
- GDCLASS(BakedLightmapData, Resource);
+class LightmapGIData : public Resource {
+ GDCLASS(LightmapGIData, Resource);
RES_BASE_EXTENSION("lmbake")
Ref<TextureLayered> light_texture;
@@ -95,12 +95,12 @@ public:
void clear();
virtual RID get_rid() const override;
- BakedLightmapData();
- ~BakedLightmapData();
+ LightmapGIData();
+ ~LightmapGIData();
};
-class BakedLightmap : public VisualInstance3D {
- GDCLASS(BakedLightmap, VisualInstance3D);
+class LightmapGI : public VisualInstance3D {
+ GDCLASS(LightmapGI, VisualInstance3D);
public:
enum BakeQuality {
@@ -149,15 +149,15 @@ private:
bool directional = false;
GenerateProbes gen_probes = GENERATE_PROBES_DISABLED;
- Ref<BakedLightmapData> light_data;
+ Ref<LightmapGIData> light_data;
struct LightsFound {
- Transform xform;
+ Transform3D xform;
Light3D *light = nullptr;
};
struct MeshesFound {
- Transform xform;
+ Transform3D xform;
NodePath node_path;
int32_t subindex = 0;
Ref<Mesh> mesh;
@@ -230,8 +230,8 @@ protected:
void _notification(int p_what);
public:
- void set_light_data(const Ref<BakedLightmapData> &p_data);
- Ref<BakedLightmapData> get_light_data() const;
+ void set_light_data(const Ref<LightmapGIData> &p_data);
+ Ref<LightmapGIData> get_light_data() const;
void set_bake_quality(BakeQuality p_quality);
BakeQuality get_bake_quality() const;
@@ -273,12 +273,12 @@ public:
Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
BakeError bake(Node *p_from_node, String p_image_data_path = "", Lightmapper::BakeStepFunc p_bake_step = nullptr, void *p_bake_userdata = nullptr);
- BakedLightmap();
+ LightmapGI();
};
-VARIANT_ENUM_CAST(BakedLightmap::BakeQuality);
-VARIANT_ENUM_CAST(BakedLightmap::GenerateProbes);
-VARIANT_ENUM_CAST(BakedLightmap::BakeError);
-VARIANT_ENUM_CAST(BakedLightmap::EnvironmentMode);
+VARIANT_ENUM_CAST(LightmapGI::BakeQuality);
+VARIANT_ENUM_CAST(LightmapGI::GenerateProbes);
+VARIANT_ENUM_CAST(LightmapGI::BakeError);
+VARIANT_ENUM_CAST(LightmapGI::EnvironmentMode);
#endif // BAKED_LIGHTMAP_H
diff --git a/scene/3d/lightmapper.cpp b/scene/3d/lightmapper.cpp
index c17ac52aa2..9e5078ba95 100644
--- a/scene/3d/lightmapper.cpp
+++ b/scene/3d/lightmapper.cpp
@@ -39,6 +39,15 @@ Ref<LightmapDenoiser> LightmapDenoiser::create() {
return Ref<LightmapDenoiser>();
}
+LightmapRaycaster *(*LightmapRaycaster::create_function)() = nullptr;
+
+Ref<LightmapRaycaster> LightmapRaycaster::create() {
+ if (create_function) {
+ return Ref<LightmapRaycaster>(create_function());
+ }
+ return Ref<LightmapRaycaster>();
+}
+
Lightmapper::CreateFunc Lightmapper::create_custom = nullptr;
Lightmapper::CreateFunc Lightmapper::create_gpu = nullptr;
Lightmapper::CreateFunc Lightmapper::create_cpu = nullptr;
diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h
index a07a964c01..3a6a88d435 100644
--- a/scene/3d/lightmapper.h
+++ b/scene/3d/lightmapper.h
@@ -34,8 +34,18 @@
#include "scene/resources/mesh.h"
#include "servers/rendering/rendering_device.h"
-class LightmapDenoiser : public Reference {
- GDCLASS(LightmapDenoiser, Reference)
+#if !defined(__aligned)
+
+#if defined(_WIN32) && defined(_MSC_VER)
+#define __aligned(...) __declspec(align(__VA_ARGS__))
+#else
+#define __aligned(...) __attribute__((aligned(__VA_ARGS__)))
+#endif
+
+#endif
+
+class LightmapDenoiser : public RefCounted {
+ GDCLASS(LightmapDenoiser, RefCounted)
protected:
static LightmapDenoiser *(*create_function)();
@@ -44,8 +54,75 @@ public:
static Ref<LightmapDenoiser> create();
};
-class Lightmapper : public Reference {
- GDCLASS(Lightmapper, Reference)
+class LightmapRaycaster : public RefCounted {
+ GDCLASS(LightmapRaycaster, RefCounted)
+protected:
+ static LightmapRaycaster *(*create_function)();
+
+public:
+ // compatible with embree3 rays
+ struct __aligned(16) Ray {
+ const static unsigned int INVALID_GEOMETRY_ID = ((unsigned int)-1); // from rtcore_common.h
+
+ /*! Default construction does nothing. */
+ _FORCE_INLINE_ Ray() :
+ geomID(INVALID_GEOMETRY_ID) {}
+
+ /*! Constructs a ray from origin, direction, and ray segment. Near
+ * has to be smaller than far. */
+ _FORCE_INLINE_ Ray(const Vector3 &org,
+ const Vector3 &dir,
+ float tnear = 0.0f,
+ float tfar = INFINITY) :
+ org(org),
+ tnear(tnear),
+ dir(dir),
+ time(0.0f),
+ tfar(tfar),
+ mask(-1),
+ u(0.0),
+ v(0.0),
+ primID(INVALID_GEOMETRY_ID),
+ geomID(INVALID_GEOMETRY_ID),
+ instID(INVALID_GEOMETRY_ID) {}
+
+ /*! Tests if we hit something. */
+ _FORCE_INLINE_ explicit operator bool() const { return geomID != INVALID_GEOMETRY_ID; }
+
+ public:
+ Vector3 org; //!< Ray origin + tnear
+ float tnear; //!< Start of ray segment
+ Vector3 dir; //!< Ray direction + tfar
+ float time; //!< Time of this ray for motion blur.
+ float tfar; //!< End of ray segment
+ unsigned int mask; //!< used to mask out objects during traversal
+ unsigned int id; //!< ray ID
+ unsigned int flags; //!< ray flags
+
+ Vector3 normal; //!< Not normalized geometry normal
+ float u; //!< Barycentric u coordinate of hit
+ float v; //!< Barycentric v coordinate of hit
+ unsigned int primID; //!< primitive ID
+ unsigned int geomID; //!< geometry ID
+ unsigned int instID; //!< instance ID
+ };
+
+ virtual bool intersect(Ray &p_ray) = 0;
+
+ virtual void intersect(Vector<Ray> &r_rays) = 0;
+
+ virtual void add_mesh(const Vector<Vector3> &p_vertices, const Vector<Vector3> &p_normals, const Vector<Vector2> &p_uv2s, unsigned int p_id) = 0;
+ virtual void set_mesh_alpha_texture(Ref<Image> p_alpha_texture, unsigned int p_id) = 0;
+ virtual void commit() = 0;
+
+ virtual void set_mesh_filter(const Set<int> &p_mesh_ids) = 0;
+ virtual void clear_mesh_filter() = 0;
+
+ static Ref<LightmapRaycaster> create();
+};
+
+class Lightmapper : public RefCounted {
+ GDCLASS(Lightmapper, RefCounted)
public:
enum GenerateProbes {
GENERATE_PROBES_DISABLED,
diff --git a/scene/3d/listener_3d.cpp b/scene/3d/listener_3d.cpp
index 9842f152d7..636be083ab 100644
--- a/scene/3d/listener_3d.cpp
+++ b/scene/3d/listener_3d.cpp
@@ -105,7 +105,7 @@ void Listener3D::_notification(int p_what) {
}
}
-Transform Listener3D::get_listener_transform() const {
+Transform3D Listener3D::get_listener_transform() const {
return get_global_transform().orthonormalized();
}
diff --git a/scene/3d/listener_3d.h b/scene/3d/listener_3d.h
index 85657a8e53..bcc66f167c 100644
--- a/scene/3d/listener_3d.h
+++ b/scene/3d/listener_3d.h
@@ -65,7 +65,7 @@ public:
void clear_current();
bool is_current() const;
- virtual Transform get_listener_transform() const;
+ virtual Transform3D get_listener_transform() const;
void set_visible_layers(uint32_t p_layers);
uint32_t get_visible_layers() const;
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index b997c64b29..c495f68890 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -51,13 +51,13 @@ bool MeshInstance3D::_set(const StringName &p_name, const Variant &p_value) {
return true;
}
- if (p_name.operator String().begins_with("material/")) {
+ if (p_name.operator String().begins_with("surface_material_override/")) {
int idx = p_name.operator String().get_slicec('/', 1).to_int();
- if (idx >= materials.size() || idx < 0) {
+ if (idx >= surface_override_materials.size() || idx < 0) {
return false;
}
- set_surface_material(idx, p_value);
+ set_surface_override_material(idx, p_value);
return true;
}
@@ -75,12 +75,12 @@ bool MeshInstance3D::_get(const StringName &p_name, Variant &r_ret) const {
return true;
}
- if (p_name.operator String().begins_with("material/")) {
+ if (p_name.operator String().begins_with("surface_material_override/")) {
int idx = p_name.operator String().get_slicec('/', 1).to_int();
- if (idx >= materials.size() || idx < 0) {
+ if (idx >= surface_override_materials.size() || idx < 0) {
return false;
}
- r_ret = materials[idx];
+ r_ret = surface_override_materials[idx];
return true;
}
return false;
@@ -100,7 +100,7 @@ void MeshInstance3D::_get_property_list(List<PropertyInfo> *p_list) const {
if (mesh.is_valid()) {
for (int i = 0; i < mesh->get_surface_count(); i++) {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "material/" + 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, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE));
}
}
}
@@ -126,7 +126,7 @@ void MeshInstance3D::set_mesh(const Ref<Mesh> &p_mesh) {
}
mesh->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &MeshInstance3D::_mesh_changed));
- materials.resize(mesh->get_surface_count());
+ surface_override_materials.resize(mesh->get_surface_count());
set_base(mesh->get_rid());
} else {
@@ -271,32 +271,67 @@ void MeshInstance3D::create_convex_collision() {
}
}
+Node *MeshInstance3D::create_multiple_convex_collisions_node() {
+ if (mesh.is_null()) {
+ return nullptr;
+ }
+
+ Vector<Ref<Shape3D>> shapes = mesh->convex_decompose();
+ if (!shapes.size()) {
+ return nullptr;
+ }
+
+ StaticBody3D *static_body = memnew(StaticBody3D);
+ for (int i = 0; i < shapes.size(); i++) {
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
+ cshape->set_shape(shapes[i]);
+ static_body->add_child(cshape);
+ }
+ return static_body;
+}
+
+void MeshInstance3D::create_multiple_convex_collisions() {
+ StaticBody3D *static_body = Object::cast_to<StaticBody3D>(create_multiple_convex_collisions_node());
+ ERR_FAIL_COND(!static_body);
+ static_body->set_name(String(get_name()) + "_col");
+
+ add_child(static_body);
+ if (get_owner()) {
+ static_body->set_owner(get_owner());
+ int count = static_body->get_child_count();
+ for (int i = 0; i < count; i++) {
+ CollisionShape3D *cshape = Object::cast_to<CollisionShape3D>(static_body->get_child(i));
+ cshape->set_owner(get_owner());
+ }
+ }
+}
+
void MeshInstance3D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
_resolve_skeleton_path();
}
}
-int MeshInstance3D::get_surface_material_count() const {
- return materials.size();
+int MeshInstance3D::get_surface_override_material_count() const {
+ return surface_override_materials.size();
}
-void MeshInstance3D::set_surface_material(int p_surface, const Ref<Material> &p_material) {
- ERR_FAIL_INDEX(p_surface, materials.size());
+void MeshInstance3D::set_surface_override_material(int p_surface, const Ref<Material> &p_material) {
+ ERR_FAIL_INDEX(p_surface, surface_override_materials.size());
- materials.write[p_surface] = p_material;
+ surface_override_materials.write[p_surface] = p_material;
- if (materials[p_surface].is_valid()) {
- RS::get_singleton()->instance_set_surface_material(get_instance(), p_surface, materials[p_surface]->get_rid());
+ if (surface_override_materials[p_surface].is_valid()) {
+ RS::get_singleton()->instance_set_surface_override_material(get_instance(), p_surface, surface_override_materials[p_surface]->get_rid());
} else {
- RS::get_singleton()->instance_set_surface_material(get_instance(), p_surface, RID());
+ RS::get_singleton()->instance_set_surface_override_material(get_instance(), p_surface, RID());
}
}
-Ref<Material> MeshInstance3D::get_surface_material(int p_surface) const {
- ERR_FAIL_INDEX_V(p_surface, materials.size(), Ref<Material>());
+Ref<Material> MeshInstance3D::get_surface_override_material(int p_surface) const {
+ ERR_FAIL_INDEX_V(p_surface, surface_override_materials.size(), Ref<Material>());
- return materials[p_surface];
+ return surface_override_materials[p_surface];
}
Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
@@ -305,7 +340,7 @@ Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
return material_override;
}
- Ref<Material> surface_material = get_surface_material(p_surface);
+ Ref<Material> surface_material = get_surface_override_material(p_surface);
if (surface_material.is_valid()) {
return surface_material;
}
@@ -320,7 +355,8 @@ Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
void MeshInstance3D::_mesh_changed() {
ERR_FAIL_COND(mesh.is_null());
- materials.resize(mesh->get_surface_count());
+ surface_override_materials.resize(mesh->get_surface_count());
+ update_gizmo();
}
void MeshInstance3D::create_debug_tangents() {
@@ -391,7 +427,7 @@ void MeshInstance3D::create_debug_tangents() {
add_child(mi);
#ifdef TOOLS_ENABLED
- if (this == get_tree()->get_edited_scene_root()) {
+ if (is_inside_tree() && this == get_tree()->get_edited_scene_root()) {
mi->set_owner(this);
} else {
mi->set_owner(get_owner());
@@ -408,15 +444,17 @@ void MeshInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_skin", "skin"), &MeshInstance3D::set_skin);
ClassDB::bind_method(D_METHOD("get_skin"), &MeshInstance3D::get_skin);
- ClassDB::bind_method(D_METHOD("get_surface_material_count"), &MeshInstance3D::get_surface_material_count);
- ClassDB::bind_method(D_METHOD("set_surface_material", "surface", "material"), &MeshInstance3D::set_surface_material);
- ClassDB::bind_method(D_METHOD("get_surface_material", "surface"), &MeshInstance3D::get_surface_material);
+ ClassDB::bind_method(D_METHOD("get_surface_override_material_count"), &MeshInstance3D::get_surface_override_material_count);
+ ClassDB::bind_method(D_METHOD("set_surface_override_material", "surface", "material"), &MeshInstance3D::set_surface_override_material);
+ ClassDB::bind_method(D_METHOD("get_surface_override_material", "surface"), &MeshInstance3D::get_surface_override_material);
ClassDB::bind_method(D_METHOD("get_active_material", "surface"), &MeshInstance3D::get_active_material);
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::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);
ClassDB::bind_method(D_METHOD("create_debug_tangents"), &MeshInstance3D::create_debug_tangents);
ClassDB::set_method_flags("MeshInstance3D", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h
index eb300784b1..9dea5804e0 100644
--- a/scene/3d/mesh_instance_3d.h
+++ b/scene/3d/mesh_instance_3d.h
@@ -52,7 +52,7 @@ protected:
};
Map<StringName, BlendShapeTrack> blend_shape_tracks;
- Vector<Ref<Material>> materials;
+ Vector<Ref<Material>> surface_override_materials;
void _mesh_changed();
void _resolve_skeleton_path();
@@ -75,9 +75,9 @@ public:
void set_skeleton_path(const NodePath &p_skeleton);
NodePath get_skeleton_path();
- int get_surface_material_count() const;
- void set_surface_material(int p_surface, const Ref<Material> &p_material);
- Ref<Material> get_surface_material(int p_surface) const;
+ int get_surface_override_material_count() const;
+ void set_surface_override_material(int p_surface, const Ref<Material> &p_material);
+ Ref<Material> get_surface_override_material(int p_surface) const;
Ref<Material> get_active_material(int p_surface) const;
Node *create_trimesh_collision_node();
@@ -86,6 +86,9 @@ public:
Node *create_convex_collision_node();
void create_convex_collision();
+ Node *create_multiple_convex_collisions_node();
+ void create_multiple_convex_collisions();
+
void create_debug_tangents();
virtual AABB get_aabb() const override;
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index 21ca3d70dd..64cfe4dca7 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -34,6 +34,8 @@
#include "servers/navigation_server_3d.h"
void NavigationAgent3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_rid"), &NavigationAgent3D::get_rid);
+
ClassDB::bind_method(D_METHOD("set_target_desired_distance", "desired_distance"), &NavigationAgent3D::set_target_desired_distance);
ClassDB::bind_method(D_METHOD("get_target_desired_distance"), &NavigationAgent3D::get_target_desired_distance);
@@ -95,8 +97,11 @@ void NavigationAgent3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
agent_parent = Object::cast_to<Node3D>(get_parent());
-
- NavigationServer3D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
+ if (agent_parent != nullptr) {
+ // place agent on navigation map first or else the RVO agent callback creation fails silently later
+ NavigationServer3D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_3d()->get_navigation_map());
+ NavigationServer3D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
+ }
set_physics_process_internal(true);
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -106,12 +111,7 @@ void NavigationAgent3D::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (agent_parent) {
NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin);
- if (!target_reached) {
- if (distance_to_target() < target_desired_distance) {
- emit_signal("target_reached");
- target_reached = true;
- }
- }
+ _check_distance_to_target();
}
} break;
}
@@ -245,17 +245,14 @@ void NavigationAgent3D::_avoidance_done(Vector3 p_new_velocity) {
emit_signal("velocity_computed", p_new_velocity);
}
-String NavigationAgent3D::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> NavigationAgent3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node3D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The NavigationAgent3D can be used only under a spatial node.");
+ warnings.push_back(TTR("The NavigationAgent3D can be used only under a spatial node."));
}
- return warning;
+ return warnings;
}
void NavigationAgent3D::update_navigation() {
@@ -312,6 +309,7 @@ void NavigationAgent3D::update_navigation() {
while (o.distance_to(navigation_path[nav_path_index] - Vector3(0, navigation_height_offset, 0)) < target_desired_distance) {
nav_path_index += 1;
if (nav_path_index == navigation_path.size()) {
+ _check_distance_to_target();
nav_path_index -= 1;
navigation_finished = true;
emit_signal("navigation_finished");
@@ -320,3 +318,12 @@ void NavigationAgent3D::update_navigation() {
}
}
}
+
+void NavigationAgent3D::_check_distance_to_target() {
+ if (!target_reached) {
+ if (distance_to_target() < target_desired_distance) {
+ emit_signal("target_reached");
+ target_reached = true;
+ }
+ }
+}
diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h
index 22db889618..56da2d1acf 100644
--- a/scene/3d/navigation_agent_3d.h
+++ b/scene/3d/navigation_agent_3d.h
@@ -143,10 +143,11 @@ public:
void set_velocity(Vector3 p_velocity);
void _avoidance_done(Vector3 p_new_velocity);
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
private:
void update_navigation();
+ void _check_distance_to_target();
};
#endif
diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp
index df03bca4fd..20ffc3b00e 100644
--- a/scene/3d/navigation_obstacle_3d.cpp
+++ b/scene/3d/navigation_obstacle_3d.cpp
@@ -76,17 +76,14 @@ NavigationObstacle3D::~NavigationObstacle3D() {
agent = RID(); // Pointless
}
-String NavigationObstacle3D::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> NavigationObstacle3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- if (!parent_node3d) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object.");
+ if (!Object::cast_to<Node3D>(get_parent())) {
+ warnings.push_back(TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object."));
}
- return warning;
+ return warnings;
}
void NavigationObstacle3D::update_agent_shape() {
diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h
index b1bb53724a..2f78f624a4 100644
--- a/scene/3d/navigation_obstacle_3d.h
+++ b/scene/3d/navigation_obstacle_3d.h
@@ -52,7 +52,7 @@ public:
return agent;
}
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
private:
void update_agent_shape();
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 3ca704e4b8..0afad62404 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -135,7 +135,7 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes
emit_signal("navigation_mesh_changed");
update_gizmo();
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<NavigationMesh> NavigationRegion3D::get_navigation_mesh() const {
@@ -177,21 +177,16 @@ void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) {
emit_signal("bake_finished");
}
-String NavigationRegion3D::get_configuration_warning() const {
- if (!is_visible_in_tree() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> NavigationRegion3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- if (!navmesh.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible_in_tree() && is_inside_tree()) {
+ if (!navmesh.is_valid()) {
+ warnings.push_back(TTR("A NavigationMesh resource must be set or created for this node to work."));
}
- warning += TTR("A NavigationMesh resource must be set or created for this node to work.");
}
- return warning;
+ return warnings;
}
void NavigationRegion3D::_bind_methods() {
@@ -217,7 +212,7 @@ void NavigationRegion3D::_bind_methods() {
void NavigationRegion3D::_navigation_changed() {
update_gizmo();
- update_configuration_warning();
+ update_configuration_warnings();
}
NavigationRegion3D::NavigationRegion3D() {
diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h
index 52fa2d6159..c2045215b1 100644
--- a/scene/3d/navigation_region_3d.h
+++ b/scene/3d/navigation_region_3d.h
@@ -66,7 +66,7 @@ public:
void bake_navigation_mesh();
void _bake_finished(Ref<NavigationMesh> p_nav_mesh);
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
NavigationRegion3D();
~NavigationRegion3D();
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index ba0f8cc870..e96b8ee1f9 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -32,6 +32,7 @@
#include "core/config/engine.h"
#include "core/object/message_queue.h"
+#include "scene/3d/visual_instance_3d.h"
#include "scene/main/scene_tree.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
@@ -148,6 +149,7 @@ void Node3D::_notification(int p_what) {
_notify_dirty();
notification(NOTIFICATION_ENTER_WORLD);
+ _update_visibility_parent(true);
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -161,6 +163,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;
@@ -223,7 +226,7 @@ void Node3D::_notification(int p_what) {
}
}
-void Node3D::set_transform(const Transform &p_transform) {
+void Node3D::set_transform(const Transform3D &p_transform) {
data.local_transform = p_transform;
data.dirty |= DIRTY_VECTORS;
_propagate_transform_changed(this);
@@ -232,8 +235,8 @@ void Node3D::set_transform(const Transform &p_transform) {
}
}
-void Node3D::set_global_transform(const Transform &p_transform) {
- Transform xform =
+void Node3D::set_global_transform(const Transform3D &p_transform) {
+ Transform3D xform =
(data.parent && !data.top_level_active) ?
data.parent->get_global_transform().affine_inverse() * p_transform :
p_transform;
@@ -241,16 +244,15 @@ void Node3D::set_global_transform(const Transform &p_transform) {
set_transform(xform);
}
-Transform Node3D::get_transform() const {
+Transform3D Node3D::get_transform() const {
if (data.dirty & DIRTY_LOCAL) {
_update_local_transform();
}
return data.local_transform;
}
-
-Transform Node3D::get_global_transform() const {
- ERR_FAIL_COND_V(!is_inside_tree(), Transform());
+Transform3D Node3D::get_global_transform() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), Transform3D());
if (data.dirty & DIRTY_GLOBAL) {
if (data.dirty & DIRTY_LOCAL) {
@@ -274,25 +276,28 @@ Transform Node3D::get_global_transform() const {
}
#ifdef TOOLS_ENABLED
-Transform Node3D::get_global_gizmo_transform() const {
+Transform3D Node3D::get_global_gizmo_transform() const {
return get_global_transform();
}
-Transform Node3D::get_local_gizmo_transform() const {
+Transform3D Node3D::get_local_gizmo_transform() const {
return get_transform();
}
#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());
}
-Transform Node3D::get_relative_transform(const Node *p_parent) const {
- if (p_parent == this) {
- return Transform();
- }
+Transform3D Node3D::get_relative_transform(const Node *p_parent) const {
+ if (p_parent == this)
+ return Transform3D();
- ERR_FAIL_COND_V(!data.parent, Transform());
+ ERR_FAIL_COND_V(!data.parent, Transform3D());
if (p_parent == data.parent) {
return get_transform();
@@ -301,8 +306,8 @@ Transform Node3D::get_relative_transform(const Node *p_parent) const {
}
}
-void Node3D::set_translation(const Vector3 &p_translation) {
- data.local_transform.origin = p_translation;
+void Node3D::set_position(const Vector3 &p_position) {
+ data.local_transform.origin = p_position;
_propagate_transform_changed(this);
if (data.notify_local_transform) {
notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
@@ -341,7 +346,7 @@ void Node3D::set_scale(const Vector3 &p_scale) {
}
}
-Vector3 Node3D::get_translation() const {
+Vector3 Node3D::get_position() const {
return data.local_transform.origin;
}
@@ -557,87 +562,87 @@ bool Node3D::is_visible() const {
}
void Node3D::rotate_object_local(const Vector3 &p_axis, float p_angle) {
- Transform t = get_transform();
+ 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) {
- Transform t = get_transform();
+ Transform3D t = get_transform();
t.basis.rotate(p_axis, p_angle);
set_transform(t);
}
void Node3D::rotate_x(float p_angle) {
- Transform t = get_transform();
+ Transform3D t = get_transform();
t.basis.rotate(Vector3(1, 0, 0), p_angle);
set_transform(t);
}
void Node3D::rotate_y(float p_angle) {
- Transform t = get_transform();
+ Transform3D t = get_transform();
t.basis.rotate(Vector3(0, 1, 0), p_angle);
set_transform(t);
}
void Node3D::rotate_z(float p_angle) {
- Transform t = get_transform();
+ Transform3D t = get_transform();
t.basis.rotate(Vector3(0, 0, 1), p_angle);
set_transform(t);
}
void Node3D::translate(const Vector3 &p_offset) {
- Transform t = get_transform();
+ Transform3D t = get_transform();
t.translate(p_offset);
set_transform(t);
}
void Node3D::translate_object_local(const Vector3 &p_offset) {
- Transform t = get_transform();
+ Transform3D t = get_transform();
- Transform s;
+ Transform3D s;
s.translate(p_offset);
set_transform(t * s);
}
void Node3D::scale(const Vector3 &p_ratio) {
- Transform t = get_transform();
+ Transform3D t = get_transform();
t.basis.scale(p_ratio);
set_transform(t);
}
void Node3D::scale_object_local(const Vector3 &p_scale) {
- Transform t = get_transform();
+ Transform3D t = get_transform();
t.basis.scale_local(p_scale);
set_transform(t);
}
void Node3D::global_rotate(const Vector3 &p_axis, float p_angle) {
- Transform t = get_global_transform();
+ Transform3D t = get_global_transform();
t.basis.rotate(p_axis, p_angle);
set_global_transform(t);
}
void Node3D::global_scale(const Vector3 &p_scale) {
- Transform t = get_global_transform();
+ Transform3D t = get_global_transform();
t.basis.scale(p_scale);
set_global_transform(t);
}
void Node3D::global_translate(const Vector3 &p_offset) {
- Transform t = get_global_transform();
+ Transform3D t = get_global_transform();
t.origin += p_offset;
set_global_transform(t);
}
void Node3D::orthonormalize() {
- Transform t = get_transform();
+ Transform3D t = get_transform();
t.orthonormalize();
set_transform(t);
}
void Node3D::set_identity() {
- set_transform(Transform());
+ set_transform(Transform3D());
}
void Node3D::look_at(const Vector3 &p_target, const Vector3 &p_up) {
@@ -649,7 +654,7 @@ void Node3D::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target
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.");
- Transform lookat;
+ Transform3D lookat;
lookat.origin = p_pos;
Vector3 original_scale(get_scale());
@@ -692,11 +697,56 @@ 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 (List<Node3D *>::Element *E = data.children.front(); E; E = E->next()) {
+ Node3D *c = E->get();
+ 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);
- ClassDB::bind_method(D_METHOD("set_translation", "translation"), &Node3D::set_translation);
- ClassDB::bind_method(D_METHOD("get_translation"), &Node3D::get_translation);
+ ClassDB::bind_method(D_METHOD("set_position", "position"), &Node3D::set_position);
+ 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);
@@ -705,7 +755,7 @@ void Node3D::_bind_methods() {
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);
@@ -715,6 +765,9 @@ void Node3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("force_update_transform"), &Node3D::force_update_transform);
+ 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("update_gizmo"), &Node3D::update_gizmo);
@@ -758,18 +811,19 @@ void Node3D::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_EXIT_WORLD);
BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
- //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), "set_global_transform", "get_global_transform") ;
+ //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::TRANSFORM, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_translation", "get_translation");
+ 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::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::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform");
+ 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::NODE_PATH, "visibility_parent", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GeometryInstance3D"), "set_visibility_parent", "get_visibility_parent");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "Node3DGizmo", 0), "set_gizmo", "get_gizmo");
ADD_SIGNAL(MethodInfo("visibility_changed"));
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index a62c7b31a8..c7e36cf2ec 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -34,8 +34,8 @@
#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;
@@ -62,8 +62,8 @@ class Node3D : public Node {
mutable SelfList<Node> xform_change;
struct Data {
- mutable Transform global_transform;
- mutable Transform local_transform;
+ mutable Transform3D global_transform;
+ mutable Transform3D local_transform;
mutable Vector3 rotation;
mutable Vector3 scale = Vector3(1, 1, 1);
@@ -75,6 +75,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;
@@ -95,12 +97,17 @@ class Node3D : public Node {
} data;
+ NodePath visibility_parent_path;
+
void _update_gizmo();
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,29 +125,29 @@ 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_translation(const Vector3 &p_translation);
+ 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_translation() const;
+ Vector3 get_position() const;
Vector3 get_rotation() const;
Vector3 get_rotation_degrees() const;
Vector3 get_scale() const;
- void set_transform(const Transform &p_transform);
- void set_global_transform(const Transform &p_transform);
+ void set_transform(const Transform3D &p_transform);
+ void set_global_transform(const Transform3D &p_transform);
- Transform get_transform() const;
- Transform get_global_transform() const;
+ Transform3D get_transform() const;
+ Transform3D get_global_transform() const;
#ifdef TOOLS_ENABLED
- virtual Transform get_global_gizmo_transform() const;
- virtual Transform get_local_gizmo_transform() const;
+ virtual Transform3D get_global_gizmo_transform() const;
+ virtual Transform3D get_local_gizmo_transform() const;
#endif
void set_as_top_level(bool p_enabled);
@@ -156,7 +163,7 @@ public:
_FORCE_INLINE_ bool is_inside_world() const { return data.inside_world; }
- Transform get_relative_transform(const Node *p_parent) const;
+ Transform3D get_relative_transform(const Node *p_parent) const;
void rotate(const Vector3 &p_axis, float p_angle);
void rotate_x(float p_angle);
@@ -196,6 +203,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
new file mode 100644
index 0000000000..429e1d4b98
--- /dev/null
+++ b/scene/3d/occluder_instance_3d.cpp
@@ -0,0 +1,335 @@
+/*************************************************************************/
+/* occluder_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 "occluder_instance_3d.h"
+#include "core/core_string_names.h"
+#include "scene/3d/mesh_instance_3d.h"
+
+RID Occluder3D::get_rid() const {
+ if (!occluder.is_valid()) {
+ occluder = RS::get_singleton()->occluder_create();
+ RS::get_singleton()->occluder_set_mesh(occluder, vertices, indices);
+ }
+ return occluder;
+}
+
+void Occluder3D::set_vertices(PackedVector3Array p_vertices) {
+ vertices = p_vertices;
+ if (occluder.is_valid()) {
+ RS::get_singleton()->occluder_set_mesh(occluder, vertices, indices);
+ }
+ _update_changes();
+}
+
+PackedVector3Array Occluder3D::get_vertices() const {
+ return vertices;
+}
+
+void Occluder3D::set_indices(PackedInt32Array p_indices) {
+ indices = p_indices;
+ if (occluder.is_valid()) {
+ RS::get_singleton()->occluder_set_mesh(occluder, vertices, indices);
+ }
+ _update_changes();
+}
+
+PackedInt32Array Occluder3D::get_indices() const {
+ return indices;
+}
+
+void Occluder3D::_update_changes() {
+ aabb = AABB();
+
+ const Vector3 *ptr = vertices.ptr();
+ for (int i = 0; i < vertices.size(); i++) {
+ aabb.expand_to(ptr[i]);
+ }
+
+ debug_lines.clear();
+ debug_mesh.unref();
+
+ emit_changed();
+}
+
+Vector<Vector3> Occluder3D::get_debug_lines() const {
+ if (!debug_lines.is_empty()) {
+ return debug_lines;
+ }
+
+ if (indices.size() % 3 != 0) {
+ return Vector<Vector3>();
+ }
+
+ for (int i = 0; i < indices.size() / 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ int a = indices[i * 3 + j];
+ int b = indices[i * 3 + (j + 1) % 3];
+ ERR_FAIL_INDEX_V_MSG(a, vertices.size(), Vector<Vector3>(), "Occluder indices are out of range.");
+ ERR_FAIL_INDEX_V_MSG(b, vertices.size(), Vector<Vector3>(), "Occluder indices are out of range.");
+ debug_lines.push_back(vertices[a]);
+ debug_lines.push_back(vertices[b]);
+ }
+ }
+ return debug_lines;
+}
+
+Ref<ArrayMesh> Occluder3D::get_debug_mesh() const {
+ if (debug_mesh.is_valid()) {
+ return debug_mesh;
+ }
+
+ if (indices.size() % 3 != 0) {
+ return debug_mesh;
+ }
+
+ Array arrays;
+ arrays.resize(Mesh::ARRAY_MAX);
+ arrays[Mesh::ARRAY_VERTEX] = vertices;
+ arrays[Mesh::ARRAY_INDEX] = indices;
+
+ debug_mesh.instance();
+ debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
+ return debug_mesh;
+}
+
+AABB Occluder3D::get_aabb() const {
+ return aabb;
+}
+
+void Occluder3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &Occluder3D::set_vertices);
+ ClassDB::bind_method(D_METHOD("get_vertices"), &Occluder3D::get_vertices);
+
+ ClassDB::bind_method(D_METHOD("set_indices", "indices"), &Occluder3D::set_indices);
+ ClassDB::bind_method(D_METHOD("get_indices"), &Occluder3D::get_indices);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_vertices", "get_vertices");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "indices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_indices", "get_indices");
+}
+
+Occluder3D::Occluder3D() {
+}
+
+Occluder3D::~Occluder3D() {
+ if (occluder.is_valid()) {
+ RS::get_singleton()->free(occluder);
+ }
+}
+/////////////////////////////////////////////////
+
+AABB OccluderInstance3D::get_aabb() const {
+ if (occluder.is_valid()) {
+ return occluder->get_aabb();
+ }
+ return AABB();
+}
+
+Vector<Face3> OccluderInstance3D::get_faces(uint32_t p_usage_flags) const {
+ return Vector<Face3>();
+}
+
+void OccluderInstance3D::set_occluder(const Ref<Occluder3D> &p_occluder) {
+ if (occluder == p_occluder) {
+ return;
+ }
+
+ if (occluder.is_valid()) {
+ occluder->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &OccluderInstance3D::_occluder_changed));
+ }
+
+ occluder = p_occluder;
+
+ if (occluder.is_valid()) {
+ set_base(occluder->get_rid());
+ occluder->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &OccluderInstance3D::_occluder_changed));
+ } else {
+ set_base(RID());
+ }
+
+ update_gizmo();
+}
+
+void OccluderInstance3D::_occluder_changed() {
+ update_gizmo();
+}
+
+Ref<Occluder3D> OccluderInstance3D::get_occluder() const {
+ return occluder;
+}
+
+void OccluderInstance3D::set_bake_mask(uint32_t p_mask) {
+ bake_mask = p_mask;
+}
+
+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));
+ } else {
+ set_bake_mask(bake_mask & (~(1 << p_layer)));
+ }
+}
+
+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::_bake_material_check(Ref<Material> p_material) {
+ StandardMaterial3D *standard_mat = Object::cast_to<StandardMaterial3D>(p_material.ptr());
+ if (standard_mat && standard_mat->get_transparency() != StandardMaterial3D::TRANSPARENCY_DISABLED) {
+ return false;
+ }
+ return true;
+}
+
+void OccluderInstance3D::_bake_node(Node *p_node, PackedVector3Array &r_vertices, PackedInt32Array &r_indices) {
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
+ if (mi && mi->is_visible_in_tree()) {
+ Ref<Mesh> mesh = mi->get_mesh();
+ bool valid = true;
+
+ if (mesh.is_null()) {
+ valid = false;
+ }
+
+ if (valid && !_bake_material_check(mi->get_material_override())) {
+ valid = false;
+ }
+
+ if ((mi->get_layer_mask() & bake_mask) == 0) {
+ valid = false;
+ }
+
+ if (valid) {
+ Transform3D global_to_local = get_global_transform().affine_inverse() * mi->get_global_transform();
+
+ for (int i = 0; i < mesh->get_surface_count(); i++) {
+ if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
+ continue;
+ }
+
+ if (mi->get_surface_override_material(i).is_valid()) {
+ if (!_bake_material_check(mi->get_surface_override_material(i))) {
+ continue;
+ }
+ } else {
+ if (!_bake_material_check(mesh->surface_get_material(i))) {
+ continue;
+ }
+ }
+
+ Array arrays = mesh->surface_get_arrays(i);
+
+ int vertex_offset = r_vertices.size();
+ PackedVector3Array vertices = arrays[Mesh::ARRAY_VERTEX];
+ r_vertices.resize(r_vertices.size() + vertices.size());
+
+ Vector3 *vtx_ptr = r_vertices.ptrw();
+ for (int j = 0; j < vertices.size(); j++) {
+ vtx_ptr[vertex_offset + j] = global_to_local.xform(vertices[j]);
+ }
+
+ int index_offset = r_indices.size();
+ PackedInt32Array indices = arrays[Mesh::ARRAY_INDEX];
+ r_indices.resize(r_indices.size() + indices.size());
+
+ int *idx_ptr = r_indices.ptrw();
+ for (int j = 0; j < indices.size(); j++) {
+ idx_ptr[index_offset + j] = vertex_offset + indices[j];
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ Node *child = p_node->get_child(i);
+ if (!child->get_owner()) {
+ continue; //maybe a helper
+ }
+
+ _bake_node(child, r_vertices, r_indices);
+ }
+}
+
+OccluderInstance3D::BakeError OccluderInstance3D::bake(Node *p_from_node, String p_occluder_path) {
+ if (p_occluder_path == "") {
+ if (get_occluder().is_null()) {
+ return BAKE_ERROR_NO_SAVE_PATH;
+ }
+ }
+
+ PackedVector3Array vertices;
+ PackedInt32Array indices;
+
+ _bake_node(p_from_node, vertices, indices);
+
+ if (vertices.is_empty() || indices.is_empty()) {
+ return BAKE_ERROR_NO_MESHES;
+ }
+
+ Ref<Occluder3D> occ;
+ if (get_occluder().is_valid()) {
+ occ = get_occluder();
+ } else {
+ occ.instance();
+ occ->set_path(p_occluder_path);
+ }
+
+ occ->set_vertices(vertices);
+ occ->set_indices(indices);
+ set_occluder(occ);
+
+ return BAKE_ERROR_OK;
+}
+
+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_occluder", "occluder"), &OccluderInstance3D::set_occluder);
+ ClassDB::bind_method(D_METHOD("get_occluder"), &OccluderInstance3D::get_occluder);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "occluder", PROPERTY_HINT_RESOURCE_TYPE, "Occluder3D"), "set_occluder", "get_occluder");
+ ADD_GROUP("Bake", "bake_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_bake_mask", "get_bake_mask");
+}
+
+OccluderInstance3D::OccluderInstance3D() {
+}
+
+OccluderInstance3D::~OccluderInstance3D() {
+}
diff --git a/scene/3d/occluder_instance_3d.h b/scene/3d/occluder_instance_3d.h
new file mode 100644
index 0000000000..4bb468274d
--- /dev/null
+++ b/scene/3d/occluder_instance_3d.h
@@ -0,0 +1,108 @@
+/*************************************************************************/
+/* occluder_instance_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef OCCLUDER_INSTANCE_3D_H
+#define OCCLUDER_INSTANCE_3D_H
+
+#include "scene/3d/visual_instance_3d.h"
+
+class Occluder3D : public Resource {
+ GDCLASS(Occluder3D, Resource);
+ RES_BASE_EXTENSION("occ");
+
+ mutable RID occluder;
+ mutable Ref<ArrayMesh> debug_mesh;
+ mutable Vector<Vector3> debug_lines;
+ AABB aabb;
+
+ PackedVector3Array vertices;
+ PackedInt32Array indices;
+
+ void _update_changes();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_vertices(PackedVector3Array p_vertices);
+ PackedVector3Array get_vertices() const;
+
+ void set_indices(PackedInt32Array p_indices);
+ PackedInt32Array get_indices() const;
+
+ Vector<Vector3> get_debug_lines() const;
+ Ref<ArrayMesh> get_debug_mesh() const;
+ AABB get_aabb() const;
+
+ virtual RID get_rid() const override;
+ Occluder3D();
+ ~Occluder3D();
+};
+
+class OccluderInstance3D : public VisualInstance3D {
+ GDCLASS(OccluderInstance3D, Node3D);
+
+private:
+ Ref<Occluder3D> occluder;
+ uint32_t bake_mask = 0xFFFFFFFF;
+
+ void _occluder_changed();
+
+ bool _bake_material_check(Ref<Material> p_material);
+ void _bake_node(Node *p_node, PackedVector3Array &r_vertices, PackedInt32Array &r_indices);
+
+protected:
+ static void _bind_methods();
+
+public:
+ enum BakeError {
+ BAKE_ERROR_OK,
+ BAKE_ERROR_NO_SAVE_PATH,
+ BAKE_ERROR_NO_MESHES,
+ };
+
+ void set_occluder(const Ref<Occluder3D> &p_occluder);
+ Ref<Occluder3D> get_occluder() const;
+
+ virtual AABB get_aabb() const override;
+ virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
+
+ 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;
+ BakeError bake(Node *p_from_node, String p_occluder_path = "");
+
+ OccluderInstance3D();
+ ~OccluderInstance3D();
+};
+
+#endif
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index 7e2601902b..de115b35e3 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -50,7 +50,7 @@ void Path3D::_curve_changed() {
for (int i = 0; i < get_child_count(); i++) {
PathFollow3D *child = Object::cast_to<PathFollow3D>(get_child(i));
if (child) {
- child->update_configuration_warning();
+ child->update_configuration_warnings();
}
}
}
@@ -108,7 +108,7 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
}
Vector3 pos = c->interpolate_baked(offset, cubic);
- Transform t = get_transform();
+ Transform3D t = get_transform();
// Vector3 pos_offset = Vector3(h_offset, v_offset, 0); not used in all cases
// will be replaced by "Vector3(h_offset, v_offset, 0)" where it was formerly used
@@ -241,29 +241,21 @@ void PathFollow3D::_validate_property(PropertyInfo &property) const {
}
}
-String PathFollow3D::get_configuration_warning() const {
- if (!is_visible_in_tree() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> PathFollow3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- if (!Object::cast_to<Path3D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("PathFollow3D only works when set as a child of a Path3D node.");
- } else {
- Path3D *path = Object::cast_to<Path3D>(get_parent());
- if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible_in_tree() && is_inside_tree()) {
+ if (!Object::cast_to<Path3D>(get_parent())) {
+ warnings.push_back(TTR("PathFollow3D only works when set as a child of a Path3D node."));
+ } else {
+ Path3D *path = Object::cast_to<Path3D>(get_parent());
+ if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) {
+ warnings.push_back(TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource."));
}
- warning += TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource.");
}
}
- return warning;
+ return warnings;
}
void PathFollow3D::_bind_methods() {
@@ -368,7 +360,7 @@ float PathFollow3D::get_unit_offset() const {
void PathFollow3D::set_rotation_mode(RotationMode p_rotation_mode) {
rotation_mode = p_rotation_mode;
- update_configuration_warning();
+ update_configuration_warnings();
_update_transform();
}
diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h
index 17ee47593e..8545370a4a 100644
--- a/scene/3d/path_3d.h
+++ b/scene/3d/path_3d.h
@@ -104,7 +104,7 @@ public:
void set_cubic_interpolation(bool p_enable);
bool get_cubic_interpolation() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
PathFollow3D() {}
};
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index e225c1f22d..25c7c3d798 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -43,62 +43,35 @@
#include "editor/plugins/node_3d_editor_plugin.h"
#endif
-Vector3 PhysicsBody3D::get_linear_velocity() const {
- return Vector3();
-}
-
-Vector3 PhysicsBody3D::get_angular_velocity() const {
- return Vector3();
-}
-
-real_t PhysicsBody3D::get_inverse_mass() const {
- return 0;
-}
-
-void PhysicsBody3D::set_collision_layer(uint32_t p_layer) {
- collision_layer = p_layer;
- PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), p_layer);
-}
-
-uint32_t PhysicsBody3D::get_collision_layer() const {
- return collision_layer;
-}
+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));
-void PhysicsBody3D::set_collision_mask(uint32_t p_mask) {
- collision_mask = p_mask;
- PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), p_mask);
-}
+ 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);
-uint32_t PhysicsBody3D::get_collision_mask() const {
- return collision_mask;
-}
+ ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody3D::get_collision_exceptions);
+ ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody3D::add_collision_exception_with);
+ ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody3D::remove_collision_exception_with);
-void PhysicsBody3D::set_collision_mask_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_mask();
- if (p_value) {
- mask |= 1 << p_bit;
- } else {
- mask &= ~(1 << p_bit);
- }
- set_collision_mask(mask);
+ ADD_GROUP("Axis Lock", "axis_lock_");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_X);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Y);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Z);
}
-bool PhysicsBody3D::get_collision_mask_bit(int p_bit) const {
- return get_collision_mask() & (1 << p_bit);
+PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) :
+ CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(), false) {
+ PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), p_mode);
}
-void PhysicsBody3D::set_collision_layer_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_layer();
- if (p_value) {
- mask |= 1 << p_bit;
- } else {
- mask &= ~(1 << p_bit);
+PhysicsBody3D::~PhysicsBody3D() {
+ if (motion_cache.is_valid()) {
+ motion_cache->owner = nullptr;
}
- set_collision_layer(mask);
-}
-
-bool PhysicsBody3D::get_collision_layer_bit(int p_bit) const {
- return get_collision_layer() & (1 << p_bit);
}
TypedArray<PhysicsBody3D> PhysicsBody3D::get_collision_exceptions() {
@@ -129,29 +102,75 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) {
PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid());
}
-void PhysicsBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &PhysicsBody3D::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &PhysicsBody3D::get_collision_layer);
+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) {
+ 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();
+ motion_cache->owner = this;
+ }
- ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &PhysicsBody3D::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &PhysicsBody3D::get_collision_mask);
+ motion_cache->result = result;
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &PhysicsBody3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &PhysicsBody3D::get_collision_mask_bit);
+ return motion_cache;
+ }
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &PhysicsBody3D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &PhysicsBody3D::get_collision_layer_bit);
+ 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);
- 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");
+ for (int i = 0; i < 3; i++) {
+ if (locked_axis & (1 << i)) {
+ r_result.motion[i] = 0;
+ }
+ }
+
+ if (!p_test_only) {
+ gt.origin += r_result.motion;
+ set_global_transform(gt);
+ }
+
+ return colliding;
}
-PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) :
- CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(), false) {
- PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), p_mode);
- collision_layer = 1;
- collision_mask = 1;
+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) {
+ ERR_FAIL_COND_V(!is_inside_tree(), false);
+
+ PhysicsServer3D::MotionResult *r = nullptr;
+ if (r_collision.is_valid()) {
+ // Needs const_cast because method bindings don't support non-const Ref.
+ 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);
+}
+
+void PhysicsBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) {
+ if (p_lock) {
+ locked_axis |= p_axis;
+ } else {
+ locked_axis &= (~p_axis);
+ }
+ PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock);
+}
+
+bool PhysicsBody3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const {
+ return (locked_axis & p_axis);
+}
+
+Vector3 PhysicsBody3D::get_linear_velocity() const {
+ return Vector3();
+}
+
+Vector3 PhysicsBody3D::get_angular_velocity() const {
+ return Vector3();
+}
+
+real_t PhysicsBody3D::get_inverse_mass() const {
+ return 0;
}
void StaticBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
@@ -173,14 +192,44 @@ 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;
- PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity);
+
+ if (kinematic_motion) {
+ _update_kinematic_motion();
+ } else {
+ 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;
- PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity);
+
+ if (kinematic_motion) {
+ _update_kinematic_motion();
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity);
+ }
}
Vector3 StaticBody3D::get_constant_linear_velocity() const {
@@ -191,30 +240,81 @@ 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);
- ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody3D::get_collision_exceptions);
- ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody3D::add_collision_exception_with);
- ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody3D::remove_collision_exception_with);
-
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() {}
-
void StaticBody3D::_reload_physics_characteristics() {
if (physics_material_override.is_null()) {
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, 0);
@@ -225,6 +325,27 @@ void StaticBody3D::_reload_physics_characteristics() {
}
}
+void StaticBody3D::_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;
+ }
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
+ }
+
+ set_physics_process_internal(false);
+}
+
void RigidBody3D::_body_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
@@ -242,7 +363,7 @@ void RigidBody3D::_body_enter_tree(ObjectID p_id) {
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
for (int i = 0; i < E->get().shapes.size(); i++) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_id, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape);
}
contact_monitor->locked = false;
@@ -263,13 +384,13 @@ void RigidBody3D::_body_exit_tree(ObjectID p_id) {
emit_signal(SceneStringNames::get_singleton()->body_exited, node);
for (int i = 0; i < E->get().shapes.size(); i++) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_id, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape);
}
contact_monitor->locked = false;
}
-void RigidBody3D::_body_inout(int p_status, ObjectID p_instance, int p_body_shape, int p_local_shape) {
+void RigidBody3D::_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;
@@ -284,6 +405,7 @@ void RigidBody3D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
if (body_in) {
if (!E) {
E = contact_monitor->body_map.insert(objid, BodyState());
+ E->get().rid = p_body;
//E->get().rc=0;
E->get().in_tree = node && node->is_inside_tree();
if (node) {
@@ -300,7 +422,7 @@ void RigidBody3D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
}
if (E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_entered, objid, node, p_body_shape, p_local_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_local_shape);
}
} else {
@@ -324,12 +446,13 @@ void RigidBody3D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
contact_monitor->body_map.erase(E);
}
if (node && in_tree) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, objid, obj, p_body_shape, p_local_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, obj, p_body_shape, p_local_shape);
}
}
}
struct _RigidBodyInOut {
+ RID rid;
ObjectID id;
int shape = 0;
int local_shape = 0;
@@ -338,6 +461,7 @@ struct _RigidBodyInOut {
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
@@ -355,6 +479,7 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
get_script_instance()->call("_integrate_forces", state);
}
set_ignore_transform_notification(false);
+ _on_transform_changed();
if (contact_monitor) {
contact_monitor->locked = true;
@@ -376,6 +501,7 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
//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);
@@ -384,6 +510,7 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(obj);
if (!E) {
+ toadd[toadd_count].rid = rid;
toadd[toadd_count].local_shape = local_shape;
toadd[toadd_count].id = obj;
toadd[toadd_count].shape = shape;
@@ -394,6 +521,7 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
ShapePair sp(shape, local_shape);
int idx = E->get().shapes.find(sp);
if (idx == -1) {
+ toadd[toadd_count].rid = rid;
toadd[toadd_count].local_shape = local_shape;
toadd[toadd_count].id = obj;
toadd[toadd_count].shape = shape;
@@ -409,6 +537,7 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
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];
toremove_count++;
@@ -419,13 +548,13 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
//process removals
for (int i = 0; i < toremove_count; i++) {
- _body_inout(0, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape);
+ _body_inout(0, toremove[i].rid, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape);
}
//process additions
for (int i = 0; i < toadd_count; i++) {
- _body_inout(1, toadd[i].id, toadd[i].shape, toadd[i].local_shape);
+ _body_inout(1, toremove[i].rid, toadd[i].id, toadd[i].shape, toadd[i].local_shape);
}
contact_monitor->locked = false;
@@ -444,7 +573,7 @@ void RigidBody3D::_notification(int p_what) {
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warning();
+ update_configuration_warnings();
}
}
@@ -454,22 +583,22 @@ void RigidBody3D::_notification(int p_what) {
void RigidBody3D::set_mode(Mode p_mode) {
mode = p_mode;
switch (p_mode) {
- case MODE_RIGID: {
- PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_RIGID);
+ 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);
} break;
- case MODE_CHARACTER: {
- PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_CHARACTER);
+ case MODE_DYNAMIC_LOCKED: {
+ PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED);
} break;
case MODE_KINEMATIC: {
PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC);
} break;
}
- update_configuration_warning();
+ update_configuration_warnings();
}
RigidBody3D::Mode RigidBody3D::get_mode() const {
@@ -573,7 +702,7 @@ Vector3 RigidBody3D::get_angular_velocity() const {
return angular_velocity;
}
-Basis RigidBody3D::get_inverse_inertia_tensor() {
+Basis RigidBody3D::get_inverse_inertia_tensor() const {
return inverse_inertia_tensor;
}
@@ -683,14 +812,6 @@ bool RigidBody3D::is_contact_monitor_enabled() const {
return contact_monitor != nullptr;
}
-void RigidBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) {
- PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock);
-}
-
-bool RigidBody3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const {
- return PhysicsServer3D::get_singleton()->body_is_axis_locked(get_rid(), p_axis);
-}
-
Array RigidBody3D::get_colliding_bodies() const {
ERR_FAIL_COND_V(!contact_monitor, Array());
@@ -709,19 +830,16 @@ Array RigidBody3D::get_colliding_bodies() const {
return ret;
}
-String RigidBody3D::get_configuration_warning() const {
- Transform t = get_transform();
+TypedArray<String> RigidBody3D::get_configuration_warnings() const {
+ Transform3D t = get_transform();
- String warning = CollisionObject3D::get_configuration_warning();
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Size changes to RigidBody3D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.");
+ 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."));
}
- return warning;
+ return warnings;
}
void RigidBody3D::_bind_methods() {
@@ -779,16 +897,11 @@ void RigidBody3D::_bind_methods() {
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("_direct_state_changed"), &RigidBody3D::_direct_state_changed);
-
- ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &RigidBody3D::set_axis_lock);
- ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &RigidBody3D::get_axis_lock);
-
ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody3D::get_colliding_bodies);
BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState3D")));
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Rigid,Static,Character,Kinematic"), "set_mode", "get_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");
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");
@@ -798,13 +911,6 @@ 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_GROUP("Axis Lock", "axis_lock_");
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_X);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Z);
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");
@@ -812,21 +918,21 @@ void RigidBody3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity"), "set_angular_velocity", "get_angular_velocity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp");
- ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
- ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("sleeping_state_changed"));
- BIND_ENUM_CONSTANT(MODE_RIGID);
+ BIND_ENUM_CONSTANT(MODE_DYNAMIC);
BIND_ENUM_CONSTANT(MODE_STATIC);
- BIND_ENUM_CONSTANT(MODE_CHARACTER);
+ BIND_ENUM_CONSTANT(MODE_DYNAMIC_LOCKED);
BIND_ENUM_CONSTANT(MODE_KINEMATIC);
}
RigidBody3D::RigidBody3D() :
- PhysicsBody3D(PhysicsServer3D::BODY_MODE_RIGID) {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsBody3D(PhysicsServer3D::BODY_MODE_DYNAMIC) {
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &RigidBody3D::_direct_state_changed));
}
RigidBody3D::~RigidBody3D() {
@@ -845,147 +951,92 @@ void RigidBody3D::_reload_physics_characteristics() {
}
}
-//////////////////////////////////////////////////////
-//////////////////////////
-
-Ref<KinematicCollision3D> KinematicBody3D::_move(const Vector3 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only) {
- Collision col;
- if (move_and_collide(p_motion, p_infinite_inertia, col, p_exclude_raycast_shapes, p_test_only)) {
- if (motion_cache.is_null()) {
- motion_cache.instance();
- motion_cache->owner = this;
- }
-
- motion_cache->collision = col;
-
- return motion_cache;
- }
-
- return Ref<KinematicCollision3D>();
-}
-
-Vector3 KinematicBody3D::get_linear_velocity() const {
- return linear_velocity;
-}
-
-Vector3 KinematicBody3D::get_angular_velocity() const {
- return angular_velocity;
-}
-
-bool KinematicBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only) {
- Transform gt = get_global_transform();
- PhysicsServer3D::MotionResult result;
- bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, &result, p_exclude_raycast_shapes);
-
- if (colliding) {
- r_collision.collider_metadata = result.collider_metadata;
- r_collision.collider_shape = result.collider_shape;
- r_collision.collider_vel = result.collider_velocity;
- r_collision.collision = result.collision_point;
- r_collision.normal = result.collision_normal;
- r_collision.collider = result.collider_id;
- r_collision.collider_rid = result.collider;
- r_collision.travel = result.motion;
- r_collision.remainder = result.remainder;
- r_collision.local_shape = result.collision_local_shape;
- }
-
- for (int i = 0; i < 3; i++) {
- if (locked_axis & (1 << i)) {
- result.motion[i] = 0;
- }
- }
-
- if (!p_test_only) {
- gt.origin += result.motion;
- set_global_transform(gt);
- }
-
- return colliding;
-}
+///////////////////////////////////////
//so, if you pass 45 as limit, avoid numerical precision errors when angle is 45.
#define FLOOR_ANGLE_THRESHOLD 0.01
-Vector3 KinematicBody3D::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_up_direction, bool p_stop_on_slope, int p_max_slides, real_t p_floor_max_angle, bool p_infinite_inertia) {
- Vector3 body_velocity = p_linear_velocity;
- Vector3 body_velocity_normal = body_velocity.normalized();
- Vector3 up_direction = p_up_direction.normalized();
+void CharacterBody3D::move_and_slide() {
+ Vector3 body_velocity_normal = linear_velocity.normalized();
+
+ bool was_on_floor = on_floor;
for (int i = 0; i < 3; i++) {
if (locked_axis & (1 << i)) {
- body_velocity[i] = 0;
+ linear_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 + body_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time());
+ Vector3 motion = (floor_velocity + linear_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time());
on_floor = false;
on_floor_body = RID();
on_ceiling = false;
on_wall = false;
- colliders.clear();
+ motion_results.clear();
floor_normal = Vector3();
floor_velocity = Vector3();
- while (p_max_slides) {
- Collision collision;
+ 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, p_infinite_inertia, collision);
+ collided = move_and_collide(motion, infinite_inertia, result, margin);
if (!collided) {
motion = Vector3(); //clear because no collision happened and motion completed
}
} else { //separate raycasts (if any)
- collided = separate_raycast_shapes(p_infinite_inertia, collision);
+ collided = separate_raycast_shapes(result);
if (collided) {
- collision.remainder = motion; //keep
- collision.travel = Vector3();
+ result.remainder = motion; //keep
+ result.motion = Vector3();
}
}
if (collided) {
found_collision = true;
- colliders.push_back(collision);
- motion = collision.remainder;
+ motion_results.push_back(result);
+ motion = result.remainder;
if (up_direction == Vector3()) {
//all is a wall
on_wall = true;
} else {
- if (Math::acos(collision.normal.dot(up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
+ if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
on_floor = true;
- floor_normal = collision.normal;
- on_floor_body = collision.collider_rid;
- floor_velocity = collision.collider_vel;
-
- if (p_stop_on_slope) {
- if ((body_velocity_normal + up_direction).length() < 0.01 && collision.travel.length() < 1) {
- Transform gt = get_global_transform();
- gt.origin -= collision.travel.slide(up_direction);
+ 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);
- return Vector3();
+ linear_velocity = Vector3();
+ return;
}
}
- } else if (Math::acos(collision.normal.dot(-up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
+ } else if (Math::acos(result.collision_normal.dot(-up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
on_ceiling = true;
} else {
on_wall = true;
}
}
- motion = motion.slide(collision.normal);
- body_velocity = body_velocity.slide(collision.normal);
+ motion = motion.slide(result.collision_normal);
+ linear_velocity = linear_velocity.slide(result.collision_normal);
for (int j = 0; j < 3; j++) {
if (locked_axis & (1 << j)) {
- body_velocity[j] = 0;
+ linear_velocity[j] = 0.0;
}
}
}
@@ -995,83 +1046,47 @@ Vector3 KinematicBody3D::move_and_slide(const Vector3 &p_linear_velocity, const
break;
}
- --p_max_slides;
+ --slide_count;
}
- return body_velocity;
-}
-
-Vector3 KinematicBody3D::move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction, bool p_stop_on_slope, int p_max_slides, real_t p_floor_max_angle, bool p_infinite_inertia) {
- Vector3 up_direction = p_up_direction.normalized();
- bool was_on_floor = on_floor;
-
- Vector3 ret = move_and_slide(p_linear_velocity, up_direction, p_stop_on_slope, p_max_slides, p_floor_max_angle, p_infinite_inertia);
- if (!was_on_floor || p_snap == Vector3()) {
- return ret;
+ if (!was_on_floor || snap == Vector3()) {
+ return;
}
- Collision col;
- Transform gt = get_global_transform();
-
- if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) {
+ // 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(col.normal.dot(up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
+ if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
on_floor = true;
- floor_normal = col.normal;
- on_floor_body = col.collider_rid;
- floor_velocity = col.collider_vel;
- if (p_stop_on_slope) {
+ 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.
- col.travel = col.travel.project(up_direction);
+ result.motion = result.motion.project(up_direction);
}
} else {
apply = false; //snapped with floor direction, but did not snap to a floor, do not snap.
}
}
if (apply) {
- gt.origin += col.travel;
+ gt.origin += result.motion;
set_global_transform(gt);
}
}
-
- return ret;
-}
-
-bool KinematicBody3D::is_on_floor() const {
- return on_floor;
-}
-
-bool KinematicBody3D::is_on_wall() const {
- return on_wall;
-}
-
-bool KinematicBody3D::is_on_ceiling() const {
- return on_ceiling;
-}
-
-Vector3 KinematicBody3D::get_floor_normal() const {
- return floor_normal;
-}
-
-Vector3 KinematicBody3D::get_floor_velocity() const {
- return floor_velocity;
-}
-
-bool KinematicBody3D::test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia) {
- ERR_FAIL_COND_V(!is_inside_tree(), false);
-
- return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia);
}
-bool KinematicBody3D::separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision) {
+bool CharacterBody3D::separate_raycast_shapes(PhysicsServer3D::MotionResult &r_result) {
PhysicsServer3D::SeparationResult sep_res[8]; //max 8 rays
- Transform gt = get_global_transform();
+ Transform3D gt = get_global_transform();
Vector3 recover;
- int hits = PhysicsServer3D::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin);
+ 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++) {
@@ -1085,15 +1100,15 @@ bool KinematicBody3D::separate_raycast_shapes(bool p_infinite_inertia, Collision
set_global_transform(gt);
if (deepest != -1) {
- r_collision.collider = sep_res[deepest].collider_id;
- r_collision.collider_metadata = sep_res[deepest].collider_metadata;
- r_collision.collider_shape = sep_res[deepest].collider_shape;
- r_collision.collider_vel = sep_res[deepest].collider_velocity;
- r_collision.collision = sep_res[deepest].collision_point;
- r_collision.normal = sep_res[deepest].collision_normal;
- r_collision.local_shape = sep_res[deepest].collision_local_shape;
- r_collision.travel = recover;
- r_collision.remainder = Vector3();
+ 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();
return true;
} else {
@@ -1101,39 +1116,53 @@ bool KinematicBody3D::separate_raycast_shapes(bool p_infinite_inertia, Collision
}
}
-void KinematicBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) {
- if (p_lock) {
- locked_axis |= p_axis;
- } else {
- locked_axis &= (~p_axis);
- }
- PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock);
+void CharacterBody3D::set_safe_margin(real_t p_margin) {
+ margin = p_margin;
}
-bool KinematicBody3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const {
- return PhysicsServer3D::get_singleton()->body_is_axis_locked(get_rid(), p_axis);
+real_t CharacterBody3D::get_safe_margin() const {
+ return margin;
}
-void KinematicBody3D::set_safe_margin(real_t p_margin) {
- margin = p_margin;
- PhysicsServer3D::get_singleton()->body_set_kinematic_safe_margin(get_rid(), margin);
+Vector3 CharacterBody3D::get_linear_velocity() const {
+ return linear_velocity;
}
-real_t KinematicBody3D::get_safe_margin() const {
- return margin;
+void CharacterBody3D::set_linear_velocity(const Vector3 &p_velocity) {
+ linear_velocity = p_velocity;
}
-int KinematicBody3D::get_slide_count() const {
- return colliders.size();
+bool CharacterBody3D::is_on_floor() const {
+ return on_floor;
}
-KinematicBody3D::Collision KinematicBody3D::get_slide_collision(int p_bounce) const {
- ERR_FAIL_INDEX_V(p_bounce, colliders.size(), Collision());
- return colliders[p_bounce];
+bool CharacterBody3D::is_on_wall() const {
+ return on_wall;
+}
+
+bool CharacterBody3D::is_on_ceiling() const {
+ return on_ceiling;
+}
+
+Vector3 CharacterBody3D::get_floor_normal() const {
+ return floor_normal;
}
-Ref<KinematicCollision3D> KinematicBody3D::_get_slide_collision(int p_bounce) {
- ERR_FAIL_INDEX_V(p_bounce, colliders.size(), Ref<KinematicCollision3D>());
+Vector3 CharacterBody3D::get_floor_velocity() const {
+ return floor_velocity;
+}
+
+int CharacterBody3D::get_slide_count() const {
+ return motion_results.size();
+}
+
+PhysicsServer3D::MotionResult CharacterBody3D::get_slide_collision(int p_bounce) const {
+ ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), PhysicsServer3D::MotionResult());
+ return motion_results[p_bounce];
+}
+
+Ref<KinematicCollision3D> CharacterBody3D::_get_slide_collision(int p_bounce) {
+ ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), Ref<KinematicCollision3D>());
if (p_bounce >= slide_colliders.size()) {
slide_colliders.resize(p_bounce + 1);
}
@@ -1143,76 +1172,126 @@ Ref<KinematicCollision3D> KinematicBody3D::_get_slide_collision(int p_bounce) {
slide_colliders.write[p_bounce]->owner = this;
}
- slide_colliders.write[p_bounce]->collision = colliders[p_bounce];
+ slide_colliders.write[p_bounce]->result = motion_results[p_bounce];
return slide_colliders[p_bounce];
}
-void KinematicBody3D::_notification(int p_what) {
+bool CharacterBody3D::is_stop_on_slope_enabled() const {
+ return stop_on_slope;
+}
+
+void CharacterBody3D::set_stop_on_slope_enabled(bool p_enabled) {
+ stop_on_slope = p_enabled;
+}
+
+bool CharacterBody3D::is_infinite_inertia_enabled() const {
+ return infinite_inertia;
+}
+void CharacterBody3D::set_infinite_inertia_enabled(bool p_enabled) {
+ infinite_inertia = p_enabled;
+}
+
+int CharacterBody3D::get_max_slides() const {
+ return max_slides;
+}
+
+void CharacterBody3D::set_max_slides(int p_max_slides) {
+ ERR_FAIL_COND(p_max_slides > 0);
+ max_slides = p_max_slides;
+}
+
+real_t CharacterBody3D::get_floor_max_angle() const {
+ return floor_max_angle;
+}
+
+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);
+}
+
+void CharacterBody3D::set_floor_max_angle_degrees(real_t p_degrees) {
+ floor_max_angle = Math::deg2rad(p_degrees);
+}
+
+const Vector3 &CharacterBody3D::get_snap() const {
+ return snap;
+}
+
+void CharacterBody3D::set_snap(const Vector3 &p_snap) {
+ snap = p_snap;
+}
+
+const Vector3 &CharacterBody3D::get_up_direction() const {
+ return up_direction;
+}
+
+void CharacterBody3D::set_up_direction(const Vector3 &p_up_direction) {
+ 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;
- colliders.clear();
+ motion_results.clear();
floor_velocity = Vector3();
}
}
-void KinematicBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &KinematicBody3D::_direct_state_changed);
-
- ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody3D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody3D::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true));
- ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody3D::move_and_slide_with_snap, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true));
+void CharacterBody3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody3D::move_and_slide);
- ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody3D::test_move, DEFVAL(true));
+ 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("is_on_floor"), &KinematicBody3D::is_on_floor);
- ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody3D::is_on_ceiling);
- ClassDB::bind_method(D_METHOD("is_on_wall"), &KinematicBody3D::is_on_wall);
- ClassDB::bind_method(D_METHOD("get_floor_normal"), &KinematicBody3D::get_floor_normal);
- ClassDB::bind_method(D_METHOD("get_floor_velocity"), &KinematicBody3D::get_floor_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("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_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_axis_lock", "axis", "lock"), &KinematicBody3D::set_axis_lock);
- ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &KinematicBody3D::get_axis_lock);
+ ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody3D::is_on_floor);
+ ClassDB::bind_method(D_METHOD("is_on_ceiling"), &CharacterBody3D::is_on_ceiling);
+ ClassDB::bind_method(D_METHOD("is_on_wall"), &CharacterBody3D::is_on_wall);
+ 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("set_safe_margin", "pixels"), &KinematicBody3D::set_safe_margin);
- ClassDB::bind_method(D_METHOD("get_safe_margin"), &KinematicBody3D::get_safe_margin);
-
- ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody3D::get_slide_count);
- ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody3D::_get_slide_collision);
-
- ADD_GROUP("Axis Lock", "axis_lock_");
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_motion_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_motion_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_motion_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z);
+ ClassDB::bind_method(D_METHOD("get_slide_count"), &CharacterBody3D::get_slide_count);
+ ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody3D::_get_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::VECTOR3, "up_direction"), "set_up_direction", "get_up_direction");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
}
-void KinematicBody3D::_direct_state_changed(Object *p_state) {
-#ifdef DEBUG_ENABLED
- PhysicsDirectBodyState3D *state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
-#else
- PhysicsDirectBodyState3D *state = (PhysicsDirectBodyState3D *)p_state; //trust it
-#endif
-
- linear_velocity = state->get_linear_velocity();
- angular_velocity = state->get_angular_velocity();
-}
-
-KinematicBody3D::KinematicBody3D() :
+CharacterBody3D::CharacterBody3D() :
PhysicsBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) {
- set_safe_margin(0.001);
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
}
-KinematicBody3D::~KinematicBody3D() {
- if (motion_cache.is_valid()) {
- motion_cache->owner = nullptr;
- }
-
+CharacterBody3D::~CharacterBody3D() {
for (int i = 0; i < slide_colliders.size(); i++) {
if (slide_colliders[i].is_valid()) {
slide_colliders.write[i]->owner = nullptr;
@@ -1223,39 +1302,39 @@ KinematicBody3D::~KinematicBody3D() {
///////////////////////////////////////
Vector3 KinematicCollision3D::get_position() const {
- return collision.collision;
+ return result.collision_point;
}
Vector3 KinematicCollision3D::get_normal() const {
- return collision.normal;
+ return result.collision_normal;
}
Vector3 KinematicCollision3D::get_travel() const {
- return collision.travel;
+ return result.motion;
}
Vector3 KinematicCollision3D::get_remainder() const {
- return collision.remainder;
+ return result.remainder;
}
Object *KinematicCollision3D::get_local_shape() const {
if (!owner) {
return nullptr;
}
- uint32_t ownerid = owner->shape_find_owner(collision.local_shape);
+ uint32_t ownerid = owner->shape_find_owner(result.collision_local_shape);
return owner->shape_owner_get_owner(ownerid);
}
Object *KinematicCollision3D::get_collider() const {
- if (collision.collider.is_valid()) {
- return ObjectDB::get_instance(collision.collider);
+ if (result.collider_id.is_valid()) {
+ return ObjectDB::get_instance(result.collider_id);
}
return nullptr;
}
ObjectID KinematicCollision3D::get_collider_id() const {
- return collision.collider;
+ return result.collider_id;
}
Object *KinematicCollision3D::get_collider_shape() const {
@@ -1263,7 +1342,7 @@ Object *KinematicCollision3D::get_collider_shape() const {
if (collider) {
CollisionObject3D *obj2d = Object::cast_to<CollisionObject3D>(collider);
if (obj2d) {
- uint32_t ownerid = obj2d->shape_find_owner(collision.collider_shape);
+ uint32_t ownerid = obj2d->shape_find_owner(result.collider_shape);
return obj2d->shape_owner_get_owner(ownerid);
}
}
@@ -1272,11 +1351,11 @@ Object *KinematicCollision3D::get_collider_shape() const {
}
int KinematicCollision3D::get_collider_shape_index() const {
- return collision.collider_shape;
+ return result.collider_shape;
}
Vector3 KinematicCollision3D::get_collider_velocity() const {
- return collision.collider_vel;
+ return result.collider_velocity;
}
Variant KinematicCollision3D::get_collider_metadata() const {
@@ -1309,12 +1388,6 @@ void KinematicCollision3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::NIL, "collider_metadata", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "", "get_collider_metadata");
}
-KinematicCollision3D::KinematicCollision3D() {
- collision.collider_shape = 0;
- collision.local_shape = 0;
- owner = nullptr;
-}
-
///////////////////////////////////////
bool PhysicalBone3D::JointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
@@ -2020,6 +2093,8 @@ void PhysicalBone3D::_notification(int p_what) {
if (parent_skeleton) {
if (-1 != bone_id) {
parent_skeleton->unbind_physical_bone_from_bone(bone_id);
+ parent_skeleton->unbind_child_node_from_bone(bone_id, this);
+ bone_id = -1;
}
}
parent_skeleton = nullptr;
@@ -2044,15 +2119,17 @@ void PhysicalBone3D::_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
- Transform global_transform(state->get_transform());
+ Transform3D global_transform(state->get_transform());
set_ignore_transform_notification(true);
set_global_transform(global_transform);
set_ignore_transform_notification(false);
+ _on_transform_changed();
// Update skeleton
if (parent_skeleton) {
@@ -2066,8 +2143,6 @@ void PhysicalBone3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &PhysicalBone3D::apply_central_impulse);
ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &PhysicalBone3D::apply_impulse, Vector3());
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &PhysicalBone3D::_direct_state_changed);
-
ClassDB::bind_method(D_METHOD("set_joint_type", "joint_type"), &PhysicalBone3D::set_joint_type);
ClassDB::bind_method(D_METHOD("get_joint_type"), &PhysicalBone3D::get_joint_type);
@@ -2108,16 +2183,13 @@ void PhysicalBone3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &PhysicalBone3D::set_can_sleep);
ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &PhysicalBone3D::is_able_to_sleep);
- ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicalBone3D::set_axis_lock);
- ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicalBone3D::get_axis_lock);
-
ADD_GROUP("Joint", "joint_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "joint_offset"), "set_joint_offset", "get_joint_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::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::TRANSFORM, "body_offset"), "set_body_offset", "get_body_offset");
+ 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, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
@@ -2127,14 +2199,6 @@ void PhysicalBone3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep");
- ADD_GROUP("Axis Lock", "axis_lock_");
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_X);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Z);
-
BIND_ENUM_CONSTANT(JOINT_TYPE_NONE);
BIND_ENUM_CONSTANT(JOINT_TYPE_PIN);
BIND_ENUM_CONSTANT(JOINT_TYPE_CONE);
@@ -2184,8 +2248,8 @@ void PhysicalBone3D::_reload_joint() {
return;
}
- Transform joint_transf = get_global_transform() * joint_offset;
- Transform local_a = body_a->get_global_transform().affine_inverse() * joint_transf;
+ Transform3D joint_transf = get_global_transform() * joint_offset;
+ Transform3D local_a = body_a->get_global_transform().affine_inverse() * joint_transf;
local_a.orthonormalize();
switch (get_joint_type()) {
@@ -2278,11 +2342,11 @@ void PhysicalBone3D::_set_gizmo_move_joint(bool p_move_joint) {
}
#ifdef TOOLS_ENABLED
-Transform PhysicalBone3D::get_global_gizmo_transform() const {
+Transform3D PhysicalBone3D::get_global_gizmo_transform() const {
return gizmo_move_joint ? get_global_transform() * joint_offset : get_global_transform();
}
-Transform PhysicalBone3D::get_local_gizmo_transform() const {
+Transform3D PhysicalBone3D::get_local_gizmo_transform() const {
return gizmo_move_joint ? get_transform() * joint_offset : get_transform();
}
#endif
@@ -2338,13 +2402,13 @@ PhysicalBone3D::JointType PhysicalBone3D::get_joint_type() const {
return joint_data ? joint_data->get_joint_type() : JOINT_TYPE_NONE;
}
-void PhysicalBone3D::set_joint_offset(const Transform &p_offset) {
+void PhysicalBone3D::set_joint_offset(const Transform3D &p_offset) {
joint_offset = p_offset;
_update_joint_offset();
}
-const Transform &PhysicalBone3D::get_joint_offset() const {
+const Transform3D &PhysicalBone3D::get_joint_offset() const {
return joint_offset;
}
@@ -2366,11 +2430,11 @@ Vector3 PhysicalBone3D::get_joint_rotation_degrees() const {
return get_joint_rotation() * (180.0 / Math_PI);
}
-const Transform &PhysicalBone3D::get_body_offset() const {
+const Transform3D &PhysicalBone3D::get_body_offset() const {
return body_offset;
}
-void PhysicalBone3D::set_body_offset(const Transform &p_offset) {
+void PhysicalBone3D::set_body_offset(const Transform3D &p_offset) {
body_offset = p_offset;
body_offset_inverse = body_offset.affine_inverse();
@@ -2476,14 +2540,6 @@ bool PhysicalBone3D::is_able_to_sleep() const {
return can_sleep;
}
-void PhysicalBone3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) {
- PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock);
-}
-
-bool PhysicalBone3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const {
- return PhysicsServer3D::get_singleton()->body_is_axis_locked(get_rid(), p_axis);
-}
-
PhysicalBone3D::PhysicalBone3D() :
PhysicsBody3D(PhysicsServer3D::BODY_MODE_STATIC) {
joint = PhysicsServer3D::get_singleton()->joint_create();
@@ -2523,7 +2579,7 @@ void PhysicalBone3D::update_bone_id() {
void PhysicalBone3D::update_offset() {
#ifdef TOOLS_ENABLED
if (parent_skeleton) {
- Transform bone_transform(parent_skeleton->get_global_transform());
+ Transform3D bone_transform(parent_skeleton->get_global_transform());
if (-1 != bone_id) {
bone_transform *= parent_skeleton->get_bone_global_pose(bone_id);
}
@@ -2543,10 +2599,10 @@ void PhysicalBone3D::_start_physics_simulation() {
return;
}
reset_to_rest_position();
- PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_RIGID);
+ PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), 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(), this, "_direct_state_changed");
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &PhysicalBone3D::_direct_state_changed));
set_as_top_level(true);
_internal_simulate_physics = true;
}
@@ -2565,8 +2621,8 @@ void PhysicalBone3D::_stop_physics_simulation() {
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0);
}
if (_internal_simulate_physics) {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), nullptr, "");
- parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false);
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
+ 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 1450fce6a6..8df3635be0 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -37,38 +37,37 @@
#include "servers/physics_server_3d.h"
#include "skeleton_3d.h"
+class KinematicCollision3D;
+
class PhysicsBody3D : public CollisionObject3D {
GDCLASS(PhysicsBody3D, CollisionObject3D);
- uint32_t collision_layer;
- uint32_t collision_mask;
-
protected:
static void _bind_methods();
PhysicsBody3D(PhysicsServer3D::BodyMode p_mode);
-public:
- virtual Vector3 get_linear_velocity() const;
- virtual Vector3 get_angular_velocity() const;
- virtual real_t get_inverse_mass() const;
+ Ref<KinematicCollision3D> motion_cache;
+
+ uint16_t locked_axis = 0;
- void set_collision_layer(uint32_t p_layer);
- uint32_t get_collision_layer() const;
+ 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);
- void set_collision_mask(uint32_t p_mask);
- uint32_t get_collision_mask() const;
+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);
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
+ void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
+ bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ virtual Vector3 get_linear_velocity() const;
+ virtual Vector3 get_angular_velocity() const;
+ virtual real_t get_inverse_mass() const;
TypedArray<PhysicsBody3D> get_collision_exceptions();
void add_collision_exception_with(Node *p_node); //must be physicsbody
void remove_collision_exception_with(Node *p_node);
- PhysicsBody3D();
+ virtual ~PhysicsBody3D();
};
class StaticBody3D : public PhysicsBody3D {
@@ -77,11 +76,19 @@ class StaticBody3D : public PhysicsBody3D {
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;
@@ -92,11 +99,18 @@ public:
Vector3 get_constant_linear_velocity() const;
Vector3 get_constant_angular_velocity() const;
+ virtual Vector3 get_linear_velocity() const override;
+ virtual Vector3 get_angular_velocity() const override;
+
StaticBody3D();
- ~StaticBody3D();
private:
void _reload_physics_characteristics();
+
+ void _update_kinematic_motion();
+
+ void set_kinematic_motion_enabled(bool p_enabled);
+ bool is_kinematic_motion_enabled() const;
};
class RigidBody3D : public PhysicsBody3D {
@@ -104,16 +118,16 @@ class RigidBody3D : public PhysicsBody3D {
public:
enum Mode {
- MODE_RIGID,
+ MODE_DYNAMIC,
MODE_STATIC,
- MODE_CHARACTER,
+ MODE_DYNAMIC_LOCKED,
MODE_KINEMATIC,
};
protected:
bool can_sleep = true;
PhysicsDirectBodyState3D *state = nullptr;
- Mode mode = MODE_RIGID;
+ Mode mode = MODE_DYNAMIC;
real_t mass = 1.0;
Ref<PhysicsMaterial> physics_material_override;
@@ -152,10 +166,12 @@ protected:
}
};
struct RigidBody3D_RemoveAction {
+ RID rid;
ObjectID body_id;
ShapePair pair;
};
struct BodyState {
+ RID rid;
//int rc;
bool in_tree = false;
VSet<ShapePair> shapes;
@@ -170,7 +186,7 @@ protected:
void _body_enter_tree(ObjectID p_id);
void _body_exit_tree(ObjectID p_id);
- void _body_inout(int p_status, ObjectID p_instance, int p_body_shape, int p_local_shape);
+ 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);
void _notification(int p_what);
@@ -196,7 +212,7 @@ public:
void set_angular_velocity(const Vector3 &p_velocity);
Vector3 get_angular_velocity() const override;
- Basis get_inverse_inertia_tensor();
+ Basis get_inverse_inertia_tensor() const;
void set_gravity_scale(real_t p_gravity_scale);
real_t get_gravity_scale() const;
@@ -225,9 +241,6 @@ public:
void set_use_continuous_collision_detection(bool p_enable);
bool is_using_continuous_collision_detection() const;
- void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
- bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const;
-
Array get_colliding_bodies() const;
void add_central_force(const Vector3 &p_force);
@@ -238,7 +251,7 @@ public:
void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3());
void apply_torque_impulse(const Vector3 &p_impulse);
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
RigidBody3D();
~RigidBody3D();
@@ -251,30 +264,20 @@ VARIANT_ENUM_CAST(RigidBody3D::Mode);
class KinematicCollision3D;
-class KinematicBody3D : public PhysicsBody3D {
- GDCLASS(KinematicBody3D, PhysicsBody3D);
-
-public:
- struct Collision {
- Vector3 collision;
- Vector3 normal;
- Vector3 collider_vel;
- ObjectID collider;
- RID collider_rid;
- int collider_shape = 0;
- Variant collider_metadata;
- Vector3 remainder;
- Vector3 travel;
- int local_shape = 0;
- };
+class CharacterBody3D : public PhysicsBody3D {
+ GDCLASS(CharacterBody3D, PhysicsBody3D);
private:
- Vector3 linear_velocity;
- Vector3 angular_velocity;
+ real_t margin = 0.001;
- uint16_t locked_axis = 0;
+ 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);
- real_t margin;
+ Vector3 linear_velocity;
Vector3 floor_normal;
Vector3 floor_velocity;
@@ -282,38 +285,47 @@ private:
bool on_floor = false;
bool on_ceiling = false;
bool on_wall = false;
- Vector<Collision> colliders;
+ Vector<PhysicsServer3D::MotionResult> motion_results;
Vector<Ref<KinematicCollision3D>> slide_colliders;
- Ref<KinematicCollision3D> motion_cache;
- _FORCE_INLINE_ bool _ignores_mode(PhysicsServer3D::BodyMode) const;
-
- Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
Ref<KinematicCollision3D> _get_slide_collision(int p_bounce);
-protected:
- void _notification(int p_what);
- static void _bind_methods();
+ bool separate_raycast_shapes(PhysicsServer3D::MotionResult &r_result);
- virtual void _direct_state_changed(Object *p_state);
+ void set_safe_margin(real_t p_margin);
+ real_t get_safe_margin() const;
-public:
- virtual Vector3 get_linear_velocity() const override;
- virtual Vector3 get_angular_velocity() const override;
+ bool is_stop_on_slope_enabled() const;
+ void set_stop_on_slope_enabled(bool p_enabled);
- bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
- bool test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia);
+ bool is_infinite_inertia_enabled() const;
+ void set_infinite_inertia_enabled(bool p_enabled);
- bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision);
+ int get_max_slides() const;
+ void set_max_slides(int p_max_slides);
- void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
- bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const;
+ real_t get_floor_max_angle() const;
+ void set_floor_max_angle(real_t p_radians);
- void set_safe_margin(real_t p_margin);
- real_t get_safe_margin() const;
+ real_t get_floor_max_angle_degrees() const;
+ void set_floor_max_angle_degrees(real_t p_degrees);
+
+ const Vector3 &get_snap() const;
+ void set_snap(const Vector3 &p_snap);
+
+ const Vector3 &get_up_direction() const;
+ void set_up_direction(const Vector3 &p_up_direction);
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void move_and_slide();
+
+ virtual Vector3 get_linear_velocity() const override;
+ void set_linear_velocity(const Vector3 &p_velocity);
- Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, real_t p_floor_max_angle = Math::deg2rad((real_t)45.0), bool p_infinite_inertia = true);
- Vector3 move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, real_t p_floor_max_angle = Math::deg2rad((real_t)45.0), bool p_infinite_inertia = true);
bool is_on_floor() const;
bool is_on_wall() const;
bool is_on_ceiling() const;
@@ -321,18 +333,19 @@ public:
Vector3 get_floor_velocity() const;
int get_slide_count() const;
- Collision get_slide_collision(int p_bounce) const;
+ PhysicsServer3D::MotionResult get_slide_collision(int p_bounce) const;
- KinematicBody3D();
- ~KinematicBody3D();
+ CharacterBody3D();
+ ~CharacterBody3D();
};
-class KinematicCollision3D : public Reference {
- GDCLASS(KinematicCollision3D, Reference);
+class KinematicCollision3D : public RefCounted {
+ GDCLASS(KinematicCollision3D, RefCounted);
- KinematicBody3D *owner;
- friend class KinematicBody3D;
- KinematicBody3D::Collision collision;
+ PhysicsBody3D *owner = nullptr;
+ friend class PhysicsBody3D;
+ friend class CharacterBody3D;
+ PhysicsServer3D::MotionResult result;
protected:
static void _bind_methods();
@@ -349,8 +362,6 @@ public:
int get_collider_shape_index() const;
Vector3 get_collider_velocity() const;
Variant get_collider_metadata() const;
-
- KinematicCollision3D();
};
class PhysicalBone3D : public PhysicsBody3D {
@@ -480,12 +491,12 @@ private:
#endif
JointData *joint_data = nullptr;
- Transform joint_offset;
+ Transform3D joint_offset;
RID joint;
Skeleton3D *parent_skeleton = nullptr;
- Transform body_offset;
- Transform body_offset_inverse;
+ Transform3D body_offset;
+ Transform3D body_offset_inverse;
bool simulate_physics = false;
bool _internal_simulate_physics = false;
int bone_id = -1;
@@ -521,8 +532,8 @@ public:
public:
#ifdef TOOLS_ENABLED
- virtual Transform get_global_gizmo_transform() const override;
- virtual Transform get_local_gizmo_transform() const override;
+ virtual Transform3D get_global_gizmo_transform() const override;
+ virtual Transform3D get_local_gizmo_transform() const override;
#endif
const JointData *get_joint_data() const;
@@ -533,8 +544,8 @@ public:
void set_joint_type(JointType p_joint_type);
JointType get_joint_type() const;
- void set_joint_offset(const Transform &p_offset);
- const Transform &get_joint_offset() const;
+ void set_joint_offset(const Transform3D &p_offset);
+ const Transform3D &get_joint_offset() const;
void set_joint_rotation(const Vector3 &p_euler_rad);
Vector3 get_joint_rotation() const;
@@ -542,8 +553,8 @@ public:
void set_joint_rotation_degrees(const Vector3 &p_euler_deg);
Vector3 get_joint_rotation_degrees() const;
- void set_body_offset(const Transform &p_offset);
- const Transform &get_body_offset() const;
+ void set_body_offset(const Transform3D &p_offset);
+ const Transform3D &get_body_offset() const;
void set_simulate_physics(bool p_simulate);
bool get_simulate_physics();
@@ -573,9 +584,6 @@ public:
void set_can_sleep(bool p_active);
bool is_able_to_sleep() const;
- void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
- bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const;
-
void apply_central_impulse(const Vector3 &p_impulse);
void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3());
diff --git a/scene/3d/physics_joint_3d.cpp b/scene/3d/physics_joint_3d.cpp
index de9c75621b..01f10c171f 100644
--- a/scene/3d/physics_joint_3d.cpp
+++ b/scene/3d/physics_joint_3d.cpp
@@ -65,6 +65,7 @@ void Joint3D::_update_joint(bool p_only_free) {
if (p_only_free || !is_inside_tree()) {
PhysicsServer3D::get_singleton()->joint_clear(joint);
warning = String();
+ update_configuration_warnings();
return;
}
@@ -75,43 +76,26 @@ void Joint3D::_update_joint(bool p_only_free) {
PhysicsBody3D *body_b = Object::cast_to<PhysicsBody3D>(node_b);
if (node_a && !body_a && node_b && !body_b) {
- PhysicsServer3D::get_singleton()->joint_clear(joint);
warning = TTR("Node A and Node B must be PhysicsBody3Ds");
- update_configuration_warning();
- return;
- }
-
- if (node_a && !body_a) {
- PhysicsServer3D::get_singleton()->joint_clear(joint);
+ } else if (node_a && !body_a) {
warning = TTR("Node A must be a PhysicsBody3D");
- update_configuration_warning();
- return;
- }
-
- if (node_b && !body_b) {
- PhysicsServer3D::get_singleton()->joint_clear(joint);
+ } else if (node_b && !body_b) {
warning = TTR("Node B must be a PhysicsBody3D");
- update_configuration_warning();
- return;
- }
-
- if (!body_a && !body_b) {
- PhysicsServer3D::get_singleton()->joint_clear(joint);
+ } else if (!body_a && !body_b) {
warning = TTR("Joint is not connected to any PhysicsBody3Ds");
- update_configuration_warning();
- return;
+ } else if (body_a == body_b) {
+ warning = TTR("Node A and Node B must be different PhysicsBody3Ds");
+ } else {
+ warning = String();
}
- if (body_a == body_b) {
+ update_configuration_warnings();
+
+ if (!warning.is_empty()) {
PhysicsServer3D::get_singleton()->joint_clear(joint);
- warning = TTR("Node A and Node B must be different PhysicsBody3Ds");
- update_configuration_warning();
return;
}
- warning = String();
- update_configuration_warning();
-
configured = true;
if (body_a) {
@@ -206,17 +190,14 @@ bool Joint3D::get_exclude_nodes_from_collision() const {
return exclude_from_collision;
}
-String Joint3D::get_configuration_warning() const {
- String node_warning = Node3D::get_configuration_warning();
+TypedArray<String> Joint3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node3D::get_configuration_warnings();
if (!warning.is_empty()) {
- if (!node_warning.is_empty()) {
- node_warning += "\n\n";
- }
- node_warning += warning;
+ warnings.push_back(warning);
}
- return node_warning;
+ return warnings;
}
void Joint3D::_bind_methods() {
@@ -391,15 +372,15 @@ bool HingeJoint3D::get_flag(Flag p_flag) const {
}
void HingeJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
- Transform gt = get_global_transform();
- Transform ainv = body_a->get_global_transform().affine_inverse();
+ Transform3D gt = get_global_transform();
+ Transform3D ainv = body_a->get_global_transform().affine_inverse();
- Transform local_a = ainv * gt;
+ Transform3D local_a = ainv * gt;
local_a.orthonormalize();
- Transform local_b = gt;
+ Transform3D local_b = gt;
if (body_b) {
- Transform binv = body_b->get_global_transform().affine_inverse();
+ Transform3D binv = body_b->get_global_transform().affine_inverse();
local_b = binv * gt;
}
@@ -525,15 +506,15 @@ real_t SliderJoint3D::get_param(Param p_param) const {
}
void SliderJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
- Transform gt = get_global_transform();
- Transform ainv = body_a->get_global_transform().affine_inverse();
+ Transform3D gt = get_global_transform();
+ Transform3D ainv = body_a->get_global_transform().affine_inverse();
- Transform local_a = ainv * gt;
+ Transform3D local_a = ainv * gt;
local_a.orthonormalize();
- Transform local_b = gt;
+ Transform3D local_b = gt;
if (body_b) {
- Transform binv = body_b->get_global_transform().affine_inverse();
+ Transform3D binv = body_b->get_global_transform().affine_inverse();
local_b = binv * gt;
}
@@ -630,18 +611,18 @@ real_t ConeTwistJoint3D::get_param(Param p_param) const {
}
void ConeTwistJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
- Transform gt = get_global_transform();
+ Transform3D gt = get_global_transform();
//Vector3 cone_twistpos = gt.origin;
//Vector3 cone_twistdir = gt.basis.get_axis(2);
- Transform ainv = body_a->get_global_transform().affine_inverse();
+ Transform3D ainv = body_a->get_global_transform().affine_inverse();
- Transform local_a = ainv * gt;
+ Transform3D local_a = ainv * gt;
local_a.orthonormalize();
- Transform local_b = gt;
+ Transform3D local_b = gt;
if (body_b) {
- Transform binv = body_b->get_global_transform().affine_inverse();
+ Transform3D binv = body_b->get_global_transform().affine_inverse();
local_b = binv * gt;
}
@@ -955,18 +936,18 @@ bool Generic6DOFJoint3D::get_flag_z(Flag p_flag) const {
}
void Generic6DOFJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
- Transform gt = get_global_transform();
+ Transform3D gt = get_global_transform();
//Vector3 cone_twistpos = gt.origin;
//Vector3 cone_twistdir = gt.basis.get_axis(2);
- Transform ainv = body_a->get_global_transform().affine_inverse();
+ Transform3D ainv = body_a->get_global_transform().affine_inverse();
- Transform local_a = ainv * gt;
+ Transform3D local_a = ainv * gt;
local_a.orthonormalize();
- Transform local_b = gt;
+ Transform3D local_b = gt;
if (body_b) {
- Transform binv = body_b->get_global_transform().affine_inverse();
+ Transform3D binv = body_b->get_global_transform().affine_inverse();
local_b = binv * gt;
}
diff --git a/scene/3d/physics_joint_3d.h b/scene/3d/physics_joint_3d.h
index f624ba602b..3e0ea38a5c 100644
--- a/scene/3d/physics_joint_3d.h
+++ b/scene/3d/physics_joint_3d.h
@@ -63,7 +63,7 @@ protected:
_FORCE_INLINE_ bool is_configured() const { return configured; }
public:
- virtual String get_configuration_warning() const override;
+ virtual TypedArray<String> get_configuration_warnings() const override;
void set_node_a(const NodePath &p_node_a);
NodePath get_node_a() const;
diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp
index 66f3e539a2..db841101e5 100644
--- a/scene/3d/ray_cast_3d.cpp
+++ b/scene/3d/ray_cast_3d.cpp
@@ -61,6 +61,7 @@ uint32_t RayCast3D::get_collision_mask() const {
}
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.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -71,6 +72,7 @@ void RayCast3D::set_collision_mask_bit(int p_bit, bool p_value) {
}
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);
}
@@ -203,7 +205,7 @@ void RayCast3D::_update_raycast_state() {
PhysicsDirectSpaceState3D *dss = PhysicsServer3D::get_singleton()->space_get_direct_state(w3d->get_space());
ERR_FAIL_COND(!dss);
- Transform gt = get_global_transform();
+ Transform3D gt = get_global_transform();
Vector3 to = target_position;
if (to == Vector3()) {
@@ -426,7 +428,7 @@ void RayCast3D::_update_debug_shape_material(bool p_check_collision) {
color = get_tree()->get_debug_collisions_color();
}
- if (p_check_collision) {
+ if (p_check_collision && collided) {
if ((color.get_h() < 0.055 || color.get_h() > 0.945) && color.get_s() > 0.5 && color.get_v() > 0.5) {
// If base color is already quite reddish, highlight collision with green color
color = Color(0.0, 1.0, 0.0, color.a);
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index ad24f39bce..7762156b4a 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -230,7 +230,7 @@ void ReflectionProbe::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_update_mode", "mode"), &ReflectionProbe::set_update_mode);
ClassDB::bind_method(D_METHOD("get_update_mode"), &ReflectionProbe::get_update_mode);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Once,Always"), "set_update_mode", "get_update_mode");
+ 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::VECTOR3, "extents"), "set_extents", "get_extents");
@@ -242,7 +242,7 @@ void ReflectionProbe::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_threshold", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_lod_threshold", "get_lod_threshold");
ADD_GROUP("Ambient", "ambient_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "ambient_mode", PROPERTY_HINT_ENUM, "Disabled,Environment,ConstantColor"), "set_ambient_mode", "get_ambient_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "ambient_mode", PROPERTY_HINT_ENUM, "Disabled,Environment,Constant Color"), "set_ambient_mode", "get_ambient_mode");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ambient_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ambient_color", "get_ambient_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ambient_color_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_ambient_color_energy", "get_ambient_color_energy");
diff --git a/scene/3d/remote_transform_3d.cpp b/scene/3d/remote_transform_3d.cpp
index 83ac813c53..a7b3a6f1ec 100644
--- a/scene/3d/remote_transform_3d.cpp
+++ b/scene/3d/remote_transform_3d.cpp
@@ -65,7 +65,7 @@ void RemoteTransform3D::_update_remote() {
if (update_remote_position && update_remote_rotation && update_remote_scale) {
n->set_global_transform(get_global_transform());
} else {
- Transform our_trans = get_global_transform();
+ Transform3D our_trans = get_global_transform();
if (update_remote_rotation) {
n->set_rotation(our_trans.basis.get_rotation());
@@ -76,7 +76,7 @@ void RemoteTransform3D::_update_remote() {
}
if (update_remote_position) {
- Transform n_trans = n->get_global_transform();
+ Transform3D n_trans = n->get_global_transform();
n_trans.set_origin(our_trans.get_origin());
n->set_global_transform(n_trans);
@@ -87,7 +87,7 @@ void RemoteTransform3D::_update_remote() {
if (update_remote_position && update_remote_rotation && update_remote_scale) {
n->set_transform(get_transform());
} else {
- Transform our_trans = get_transform();
+ Transform3D our_trans = get_transform();
if (update_remote_rotation) {
n->set_rotation(our_trans.basis.get_rotation());
@@ -98,7 +98,7 @@ void RemoteTransform3D::_update_remote() {
}
if (update_remote_position) {
- Transform n_trans = n->get_transform();
+ Transform3D n_trans = n->get_transform();
n_trans.set_origin(our_trans.get_origin());
n->set_transform(n_trans);
@@ -133,7 +133,7 @@ void RemoteTransform3D::set_remote_node(const NodePath &p_remote_node) {
_update_remote();
}
- update_configuration_warning();
+ update_configuration_warnings();
}
NodePath RemoteTransform3D::get_remote_node() const {
@@ -179,17 +179,14 @@ void RemoteTransform3D::force_update_cache() {
_update_cache();
}
-String RemoteTransform3D::get_configuration_warning() const {
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> RemoteTransform3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!has_node(remote_node) || !Object::cast_to<Node3D>(get_node(remote_node))) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work.");
+ warnings.push_back(TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work."));
}
- return warning;
+ return warnings;
}
void RemoteTransform3D::_bind_methods() {
diff --git a/scene/3d/remote_transform_3d.h b/scene/3d/remote_transform_3d.h
index 21005d92d1..321bd3b51e 100644
--- a/scene/3d/remote_transform_3d.h
+++ b/scene/3d/remote_transform_3d.h
@@ -70,7 +70,7 @@ public:
void force_update_cache();
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
RemoteTransform3D();
};
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index db5fc7593e..f9d613a4bb 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -94,20 +94,6 @@ bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) {
set_bone_enabled(which, p_value);
} else if (what == "pose") {
set_bone_pose(which, p_value);
- } else if (what == "bound_children") {
- Array children = p_value;
-
- if (is_inside_tree()) {
- bones.write[which].nodes_bound.clear();
-
- for (int i = 0; i < children.size(); i++) {
- NodePath npath = children[i];
- ERR_CONTINUE(npath.operator String() == "");
- Node *node = get_node(npath);
- ERR_CONTINUE(!node);
- bind_child_node_to_bone(which, node);
- }
- }
} else {
return false;
}
@@ -137,19 +123,6 @@ bool Skeleton3D::_get(const StringName &p_path, Variant &r_ret) const {
r_ret = is_bone_enabled(which);
} else if (what == "pose") {
r_ret = get_bone_pose(which);
- } else if (what == "bound_children") {
- Array children;
-
- for (const List<ObjectID>::Element *E = bones[which].nodes_bound.front(); E; E = E->next()) {
- Object *obj = ObjectDB::get_instance(E->get());
- ERR_CONTINUE(!obj);
- Node *node = Object::cast_to<Node>(obj);
- ERR_CONTINUE(!node);
- NodePath npath = get_path_to(node);
- children.push_back(npath);
- }
-
- r_ret = children;
} else {
return false;
}
@@ -162,10 +135,9 @@ void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const {
String prep = "bones/" + itos(i) + "/";
p_list->push_back(PropertyInfo(Variant::STRING, prep + "name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prep + "rest", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::ARRAY, prep + "bound_children", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
}
@@ -237,53 +209,57 @@ void Skeleton3D::_notification(int p_what) {
for (int i = 0; i < len; i++) {
Bone &b = bonesptr[order[i]];
- if (b.global_pose_override_amount >= 0.999) {
- b.pose_global = b.global_pose_override;
- } else {
- if (b.disable_rest) {
- if (b.enabled) {
- Transform 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;
- } else {
- b.pose_global = pose;
- }
+ 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 {
- if (b.parent >= 0) {
- b.pose_global = bonesptr[b.parent].pose_global;
- } else {
- b.pose_global = Transform();
- }
+ b.pose_global = pose;
+ b.pose_global_no_override = pose;
}
-
} else {
- if (b.enabled) {
- Transform 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);
- } else {
- b.pose_global = b.rest * pose;
- }
+ if (b.parent >= 0) {
+ b.pose_global = bonesptr[b.parent].pose_global;
+ b.pose_global_no_override = bonesptr[b.parent].pose_global;
} else {
- if (b.parent >= 0) {
- b.pose_global = bonesptr[b.parent].pose_global * b.rest;
- } else {
- b.pose_global = b.rest;
- }
+ b.pose_global = Transform3D();
+ b.pose_global_no_override = Transform3D();
}
}
- 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);
+ } 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;
}
@@ -361,7 +337,6 @@ void Skeleton3D::_notification(int p_what) {
} 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.
@@ -380,18 +355,18 @@ void Skeleton3D::_notification(int p_what) {
set_physics_process_internal(true);
}
} break;
-#endif
}
}
void Skeleton3D::clear_bones_global_pose_override() {
for (int i = 0; i < bones.size(); i += 1) {
bones.write[i].global_pose_override_amount = 0;
+ bones.write[i].global_pose_override_reset = true;
}
_make_dirty();
}
-void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform &p_pose, float p_amount, bool p_persistent) {
+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());
bones.write[p_bone].global_pose_override_amount = p_amount;
bones.write[p_bone].global_pose_override = p_pose;
@@ -399,14 +374,22 @@ void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform &p_po
_make_dirty();
}
-Transform Skeleton3D::get_bone_global_pose(int p_bone) const {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
+Transform3D Skeleton3D::get_bone_global_pose(int p_bone) const {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D());
if (dirty) {
const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON);
}
return bones[p_bone].pose_global;
}
+Transform3D Skeleton3D::get_bone_global_pose_no_override(int p_bone) const {
+ ERR_FAIL_INDEX_V(p_bone, bones.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::add_bone(const String &p_name) {
ERR_FAIL_COND(p_name == "" || p_name.find(":") != -1 || p_name.find("/") != -1);
@@ -511,15 +494,14 @@ int Skeleton3D::get_bone_parent(int p_bone) const {
return bones[p_bone].parent;
}
-void Skeleton3D::set_bone_rest(int p_bone, const Transform &p_rest) {
+void Skeleton3D::set_bone_rest(int p_bone, const Transform3D &p_rest) {
ERR_FAIL_INDEX(p_bone, bones.size());
bones.write[p_bone].rest = p_rest;
_make_dirty();
}
-
-Transform Skeleton3D::get_bone_rest(int p_bone) const {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
+Transform3D Skeleton3D::get_bone_rest(int p_bone) const {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D());
return bones[p_bone].rest;
}
@@ -578,7 +560,7 @@ void Skeleton3D::clear_bones() {
// posing api
-void Skeleton3D::set_bone_pose(int p_bone, const Transform &p_pose) {
+void Skeleton3D::set_bone_pose(int p_bone, const Transform3D &p_pose) {
ERR_FAIL_INDEX(p_bone, bones.size());
bones.write[p_bone].pose = p_pose;
@@ -586,24 +568,23 @@ void Skeleton3D::set_bone_pose(int p_bone, const Transform &p_pose) {
_make_dirty();
}
}
-
-Transform Skeleton3D::get_bone_pose(int p_bone) const {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
+Transform3D Skeleton3D::get_bone_pose(int p_bone) const {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D());
return bones[p_bone].pose;
}
-void Skeleton3D::set_bone_custom_pose(int p_bone, const Transform &p_custom_pose) {
+void Skeleton3D::set_bone_custom_pose(int p_bone, const Transform3D &p_custom_pose) {
ERR_FAIL_INDEX(p_bone, bones.size());
//ERR_FAIL_COND( !is_inside_scene() );
- bones.write[p_bone].custom_pose_enable = (p_custom_pose != Transform());
+ bones.write[p_bone].custom_pose_enable = (p_custom_pose != Transform3D());
bones.write[p_bone].custom_pose = p_custom_pose;
_make_dirty();
}
-Transform Skeleton3D::get_bone_custom_pose(int p_bone) const {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
+Transform3D Skeleton3D::get_bone_custom_pose(int p_bone) const {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D());
return bones[p_bone].custom_pose;
}
@@ -638,8 +619,6 @@ void Skeleton3D::localize_rests() {
}
}
-#ifndef _3D_DISABLED
-
void Skeleton3D::set_animate_physical_bones(bool p_animate) {
animate_physical_bones = p_animate;
@@ -713,7 +692,7 @@ void Skeleton3D::_rebuild_physical_bones_cache() {
const int b_size = bones.size();
for (int i = 0; i < b_size; ++i) {
PhysicalBone3D *parent_pb = _get_physical_bone_parent(i);
- if (parent_pb != bones[i].physical_bone) {
+ if (parent_pb != bones[i].cache_parent_physical_bone) {
bones.write[i].cache_parent_physical_bone = parent_pb;
if (bones[i].physical_bone) {
bones[i].physical_bone->_on_bone_parent_changed();
@@ -800,8 +779,6 @@ void Skeleton3D::physical_bones_remove_collision_exception(RID p_exception) {
_physical_bones_add_remove_collision_exception(false, this, p_exception);
}
-#endif // _3D_DISABLED
-
void Skeleton3D::_skin_changed() {
_make_dirty();
}
@@ -867,11 +844,11 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
}
// helper functions
-Transform Skeleton3D::bone_transform_to_world_transform(Transform p_bone_transform) {
+Transform3D Skeleton3D::bone_transform_to_world_transform(Transform3D p_bone_transform) {
return get_global_transform() * p_bone_transform;
}
-Transform Skeleton3D::world_transform_to_bone_transform(Transform p_world_transform) {
+Transform3D Skeleton3D::world_transform_to_bone_transform(Transform3D p_world_transform) {
return get_global_transform().affine_inverse() * p_world_transform;
}
@@ -899,10 +876,6 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bone_disable_rest", "bone_idx", "disable"), &Skeleton3D::set_bone_disable_rest);
ClassDB::bind_method(D_METHOD("is_bone_rest_disabled", "bone_idx"), &Skeleton3D::is_bone_rest_disabled);
- ClassDB::bind_method(D_METHOD("bind_child_node_to_bone", "bone_idx", "node"), &Skeleton3D::bind_child_node_to_bone);
- ClassDB::bind_method(D_METHOD("unbind_child_node_from_bone", "bone_idx", "node"), &Skeleton3D::unbind_child_node_from_bone);
- ClassDB::bind_method(D_METHOD("get_bound_child_nodes_to_bone", "bone_idx"), &Skeleton3D::_get_bound_child_nodes_to_bone);
-
ClassDB::bind_method(D_METHOD("clear_bones"), &Skeleton3D::clear_bones);
ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton3D::get_bone_pose);
@@ -911,6 +884,7 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_bones_global_pose_override"), &Skeleton3D::clear_bones_global_pose_override);
ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton3D::set_bone_global_pose_override, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_bone_global_pose", "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("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);
@@ -918,8 +892,6 @@ void Skeleton3D::_bind_methods() {
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);
-#ifndef _3D_DISABLED
-
ClassDB::bind_method(D_METHOD("set_animate_physical_bones"), &Skeleton3D::set_animate_physical_bones);
ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton3D::get_animate_physical_bones);
@@ -929,7 +901,6 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton3D::physical_bones_remove_collision_exception);
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"));
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index 2941ac2c45..2f6e416c8c 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -35,16 +35,13 @@
#include "scene/3d/node_3d.h"
#include "scene/resources/skin.h"
-#ifndef _3D_DISABLED
typedef int BoneId;
class PhysicalBone3D;
-#endif // _3D_DISABLED
-
class Skeleton3D;
-class SkinReference : public Reference {
- GDCLASS(SkinReference, Reference)
+class SkinReference : public RefCounted {
+ GDCLASS(SkinReference, RefCounted)
friend class Skeleton3D;
Skeleton3D *skeleton_node;
@@ -79,22 +76,21 @@ private:
int sort_index = 0; //used for re-sorting process order
bool disable_rest = false;
- Transform rest;
+ Transform3D rest;
- Transform pose;
- Transform pose_global;
+ Transform3D pose;
+ Transform3D pose_global;
+ Transform3D pose_global_no_override;
bool custom_pose_enable = false;
- Transform custom_pose;
+ Transform3D custom_pose;
float global_pose_override_amount = 0.0;
bool global_pose_override_reset = false;
- Transform global_pose_override;
+ Transform3D global_pose_override;
-#ifndef _3D_DISABLED
PhysicalBone3D *physical_bone = nullptr;
PhysicalBone3D *cache_parent_physical_bone = nullptr;
-#endif // _3D_DISABLED
List<ObjectID> nodes_bound;
};
@@ -113,18 +109,6 @@ private:
uint64_t version = 1;
- // bind helpers
- Array _get_bound_child_nodes_to_bone(int p_bone) const {
- Array bound;
- List<Node *> children;
- get_bound_child_nodes_to_bone(p_bone, &children);
-
- for (int i = 0; i < children.size(); i++) {
- bound.push_back(children[i]);
- }
- return bound;
- }
-
void _update_process_order();
protected:
@@ -157,12 +141,13 @@ public:
int get_bone_count() const;
- void set_bone_rest(int p_bone, const Transform &p_rest);
- Transform get_bone_rest(int p_bone) const;
- Transform get_bone_global_pose(int p_bone) const;
+ void set_bone_rest(int p_bone, const Transform3D &p_rest);
+ Transform3D get_bone_rest(int p_bone) const;
+ 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 Transform &p_pose, float p_amount, bool p_persistent = false);
+ 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;
@@ -175,11 +160,11 @@ public:
// posing api
- void set_bone_pose(int p_bone, const Transform &p_pose);
- Transform get_bone_pose(int p_bone) const;
+ void set_bone_pose(int p_bone, const Transform3D &p_pose);
+ Transform3D get_bone_pose(int p_bone) const;
- void set_bone_custom_pose(int p_bone, const Transform &p_custom_pose);
- Transform get_bone_custom_pose(int p_bone) const;
+ void set_bone_custom_pose(int p_bone, const Transform3D &p_custom_pose);
+ Transform3D get_bone_custom_pose(int p_bone) const;
void localize_rests(); // used for loaders and tools
int get_process_order(int p_idx);
@@ -188,10 +173,9 @@ public:
Ref<SkinReference> register_skin(const Ref<Skin> &p_skin);
// Helper functions
- Transform bone_transform_to_world_transform(Transform p_transform);
- Transform world_transform_to_bone_transform(Transform p_transform);
+ Transform3D bone_transform_to_world_transform(Transform3D p_transform);
+ Transform3D world_transform_to_bone_transform(Transform3D p_transform);
-#ifndef _3D_DISABLED
// Physical bone API
void set_animate_physical_bones(bool p_animate);
@@ -213,7 +197,6 @@ public:
void physical_bones_start_simulation_on(const TypedArray<StringName> &p_bones);
void physical_bones_add_collision_exception(RID p_exception);
void physical_bones_remove_collision_exception(RID p_exception);
-#endif // _3D_DISABLED
public:
Skeleton3D();
diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp
index 6cde6a9b17..1005d51e63 100644
--- a/scene/3d/skeleton_ik_3d.cpp
+++ b/scene/3d/skeleton_ik_3d.cpp
@@ -129,7 +129,7 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain
return true;
}
-void FabrikInverseKinematic::solve_simple(Task *p_task, bool p_solve_magnet) {
+void FabrikInverseKinematic::solve_simple(Task *p_task, bool p_solve_magnet, Vector3 p_origin_pos) {
real_t distance_to_goal(1e4);
real_t previous_distance_to_goal(0);
int can_solve(p_task->max_iterations);
@@ -138,7 +138,7 @@ void FabrikInverseKinematic::solve_simple(Task *p_task, bool p_solve_magnet) {
--can_solve;
solve_simple_backwards(p_task->chain, p_solve_magnet);
- solve_simple_forwards(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();
}
@@ -176,13 +176,13 @@ void FabrikInverseKinematic::solve_simple_backwards(Chain &r_chain, bool p_solve
}
}
-void FabrikInverseKinematic::solve_simple_forwards(Chain &r_chain, bool p_solve_magnet) {
+void FabrikInverseKinematic::solve_simple_forwards(Chain &r_chain, bool p_solve_magnet, Vector3 p_origin_pos) {
if (p_solve_magnet && !r_chain.middle_chain_item) {
return;
}
ChainItem *sub_chain_root(&r_chain.chain_root);
- Vector3 origin(r_chain.chain_root.initial_transform.origin);
+ Vector3 origin = p_origin_pos;
while (sub_chain_root) { // Reach the tip
sub_chain_root->current_pos = origin;
@@ -212,7 +212,7 @@ void FabrikInverseKinematic::solve_simple_forwards(Chain &r_chain, bool p_solve_
}
}
-FabrikInverseKinematic::Task *FabrikInverseKinematic::create_simple_task(Skeleton3D *p_sk, BoneId root_bone, BoneId tip_bone, const Transform &goal_transform) {
+FabrikInverseKinematic::Task *FabrikInverseKinematic::create_simple_task(Skeleton3D *p_sk, BoneId root_bone, BoneId tip_bone, const Transform3D &goal_transform) {
FabrikInverseKinematic::EndEffector ee;
ee.tip_bone = tip_bone;
@@ -236,17 +236,17 @@ void FabrikInverseKinematic::free_task(Task *p_task) {
}
}
-void FabrikInverseKinematic::set_goal(Task *p_task, const Transform &p_goal) {
+void FabrikInverseKinematic::set_goal(Task *p_task, const Transform3D &p_goal) {
p_task->goal_global_transform = p_goal;
}
-void FabrikInverseKinematic::make_goal(Task *p_task, const Transform &p_inverse_transf, real_t blending_delta) {
+void FabrikInverseKinematic::make_goal(Task *p_task, const Transform3D &p_inverse_transf, real_t blending_delta) {
if (blending_delta >= 0.99f) {
// Update the end_effector (local transform) without blending
p_task->end_effectors.write[0].goal_transform = p_inverse_transf * p_task->goal_global_transform;
} else {
// End effector in local transform
- const Transform end_effector_pose(p_task->skeleton->get_bone_global_pose(p_task->end_effectors[0].tip_bone));
+ const Transform3D end_effector_pose(p_task->skeleton->get_bone_global_pose_no_override(p_task->end_effectors[0].tip_bone));
// Update the end_effector (local transform) by blending with current pose
p_task->end_effectors.write[0].goal_transform = end_effector_pose.interpolate_with(p_inverse_transf * p_task->goal_global_transform, blending_delta);
@@ -270,77 +270,42 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove
return; // Skip solving
}
- // This line below is part of the problem - removing it fixes the issue with BoneAttachment nodes...
- p_task->skeleton->set_bone_global_pose_override(p_task->chain.chain_root.bone, Transform(), 0.0, true);
-
- if (p_task->chain.middle_chain_item) {
- p_task->skeleton->set_bone_global_pose_override(p_task->chain.middle_chain_item->bone, Transform(), 0.0, true);
- }
-
- for (int i = 0; i < p_task->chain.tips.size(); i += 1) {
- p_task->skeleton->set_bone_global_pose_override(p_task->chain.tips[i].chain_item->bone, Transform(), 0.0, true);
- }
-
- // Update the transforms to their global poses
- // (Needed to sync IK with animation)
+ // Update the initial root transform so its synced with any animation changes
_update_chain(p_task->skeleton, &p_task->chain.chain_root);
+ p_task->skeleton->set_bone_global_pose_override(p_task->chain.chain_root.bone, Transform3D(), 0.0, false);
+ Vector3 origin_pos = p_task->skeleton->get_bone_global_pose(p_task->chain.chain_root.bone).origin;
+
make_goal(p_task, p_task->skeleton->get_global_transform().affine_inverse(), blending_delta);
if (p_use_magnet && p_task->chain.middle_chain_item) {
p_task->chain.magnet_position = p_task->chain.middle_chain_item->initial_transform.origin.lerp(p_magnet_position, blending_delta);
- solve_simple(p_task, true);
+ solve_simple(p_task, true, origin_pos);
}
- solve_simple(p_task, false);
+ solve_simple(p_task, false, origin_pos);
// Assign new bone position.
ChainItem *ci(&p_task->chain.chain_root);
while (ci) {
- Transform new_bone_pose(ci->initial_transform);
+ Transform3D new_bone_pose(ci->initial_transform);
new_bone_pose.origin = ci->current_pos;
- // The root bone needs to be rotated differently so it isn't frozen in place.
- if (ci == &p_task->chain.chain_root && !ci->children.is_empty()) {
- new_bone_pose = new_bone_pose.looking_at(ci->children[0].current_pos);
- const Vector3 bone_rest_dir = p_task->skeleton->get_bone_rest(ci->children[0].bone).origin.normalized().abs();
- const Vector3 bone_rest_dir_abs = bone_rest_dir.abs();
- if (bone_rest_dir_abs.x > bone_rest_dir_abs.y && bone_rest_dir_abs.x > bone_rest_dir_abs.z) {
- if (bone_rest_dir.x < 0) {
- new_bone_pose.basis.rotate_local(Vector3(0, 1, 0), -Math_PI / 2.0f);
- } else {
- new_bone_pose.basis.rotate_local(Vector3(0, 1, 0), Math_PI / 2.0f);
- }
- } else if (bone_rest_dir_abs.y > bone_rest_dir_abs.x && bone_rest_dir_abs.y > bone_rest_dir_abs.z) {
- if (bone_rest_dir.y < 0) {
- new_bone_pose.basis.rotate_local(Vector3(1, 0, 0), Math_PI / 2.0f);
- } else {
- new_bone_pose.basis.rotate_local(Vector3(1, 0, 0), -Math_PI / 2.0f);
- }
- } else {
- if (bone_rest_dir.z < 0) {
- // Do nothing!
- } else {
- new_bone_pose.basis.rotate_local(Vector3(0, 0, 1), Math_PI);
- }
- }
- } else {
- 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 (!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);
- }
+ 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);
+ }
+ } else {
+ // Set target orientation to tip
+ if (override_tip_basis) {
+ new_bone_pose.basis = p_task->chain.tips[0].end_effector->goal_transform.basis;
} else {
- // Set target orientation to tip
- if (override_tip_basis) {
- new_bone_pose.basis = p_task->chain.tips[0].end_effector->goal_transform.basis;
- } else {
- new_bone_pose.basis = new_bone_pose.basis * p_task->chain.tips[0].end_effector->goal_transform.basis;
- }
+ new_bone_pose.basis = new_bone_pose.basis * p_task->chain.tips[0].end_effector->goal_transform.basis;
}
}
@@ -363,7 +328,7 @@ void FabrikInverseKinematic::_update_chain(const Skeleton3D *p_sk, ChainItem *p_
return;
}
- p_chain_item->initial_transform = p_sk->get_bone_global_pose(p_chain_item->bone);
+ p_chain_item->initial_transform = p_sk->get_bone_global_pose_no_override(p_chain_item->bone);
p_chain_item->current_pos = p_chain_item->initial_transform.origin;
ChainItem *items = p_chain_item->children.ptrw();
@@ -432,7 +397,7 @@ void SkeletonIK3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "root_bone"), "set_root_bone", "get_root_bone");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "tip_bone"), "set_tip_bone", "get_tip_bone");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "interpolation", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_interpolation", "get_interpolation");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "target"), "set_target_transform", "get_target_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "target"), "set_target_transform", "get_target_transform");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_tip_basis"), "set_override_tip_basis", "is_override_tip_basis");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_magnet"), "set_use_magnet", "is_using_magnet");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "magnet"), "set_magnet_position", "get_magnet_position");
@@ -496,12 +461,12 @@ real_t SkeletonIK3D::get_interpolation() const {
return interpolation;
}
-void SkeletonIK3D::set_target_transform(const Transform &p_target) {
+void SkeletonIK3D::set_target_transform(const Transform3D &p_target) {
target = p_target;
reload_goal();
}
-const Transform &SkeletonIK3D::get_target_transform() const {
+const Transform3D &SkeletonIK3D::get_target_transform() const {
return target;
}
@@ -567,9 +532,12 @@ void SkeletonIK3D::start(bool p_one_time) {
void SkeletonIK3D::stop() {
set_process_internal(false);
+ if (skeleton) {
+ skeleton->clear_bones_global_pose_override();
+ }
}
-Transform SkeletonIK3D::_get_target_transform() {
+Transform3D SkeletonIK3D::_get_target_transform() {
if (!target_node_override && !target_node_path_override.is_empty()) {
target_node_override = Object::cast_to<Node3D>(get_node(target_node_path_override));
}
diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h
index 9255e18b72..81dfe675c3 100644
--- a/scene/3d/skeleton_ik_3d.h
+++ b/scene/3d/skeleton_ik_3d.h
@@ -37,13 +37,13 @@
* @author AndreaCatania
*/
-#include "core/math/transform.h"
+#include "core/math/transform_3d.h"
#include "scene/3d/skeleton_3d.h"
class FabrikInverseKinematic {
struct EndEffector {
BoneId tip_bone;
- Transform goal_transform;
+ Transform3D goal_transform;
};
struct ChainItem {
@@ -55,7 +55,7 @@ class FabrikInverseKinematic {
real_t length = 0.0;
/// Positions relative to root bone
- Transform initial_transform;
+ Transform3D initial_transform;
Vector3 current_pos;
// Direction from this bone to child
Vector3 current_ori;
@@ -97,7 +97,7 @@ public:
BoneId root_bone = -1;
Vector<EndEffector> end_effectors;
- Transform goal_global_transform;
+ Transform3D goal_global_transform;
Task() {}
};
@@ -106,17 +106,17 @@ private:
/// Init a chain that starts from the root to tip
static bool build_chain(Task *p_task, bool p_force_simple_chain = true);
- static void solve_simple(Task *p_task, bool p_solve_magnet);
+ static void solve_simple(Task *p_task, bool p_solve_magnet, Vector3 p_origin_pos);
/// Special solvers that solve only chains with one end effector
static void solve_simple_backwards(Chain &r_chain, bool p_solve_magnet);
- static void solve_simple_forwards(Chain &r_chain, bool p_solve_magnet);
+ static void solve_simple_forwards(Chain &r_chain, bool p_solve_magnet, Vector3 p_origin_pos);
public:
- static Task *create_simple_task(Skeleton3D *p_sk, BoneId root_bone, BoneId tip_bone, const Transform &goal_transform);
+ static Task *create_simple_task(Skeleton3D *p_sk, BoneId root_bone, BoneId tip_bone, const Transform3D &goal_transform);
static void free_task(Task *p_task);
// The goal of chain should be always in local space
- static void set_goal(Task *p_task, const Transform &p_goal);
- static void make_goal(Task *p_task, const Transform &p_inverse_transf, real_t blending_delta);
+ static void set_goal(Task *p_task, const Transform3D &p_goal);
+ static void make_goal(Task *p_task, const Transform3D &p_inverse_transf, real_t blending_delta);
static void solve(Task *p_task, real_t blending_delta, bool override_tip_basis, bool p_use_magnet, const Vector3 &p_magnet_position);
static void _update_chain(const Skeleton3D *p_skeleton, ChainItem *p_chain_item);
@@ -128,7 +128,7 @@ class SkeletonIK3D : public Node {
StringName root_bone;
StringName tip_bone;
real_t interpolation = 1.0;
- Transform target;
+ Transform3D target;
NodePath target_node_path_override;
bool override_tip_basis = true;
bool use_magnet = false;
@@ -161,8 +161,8 @@ public:
void set_interpolation(real_t p_interpolation);
real_t get_interpolation() const;
- void set_target_transform(const Transform &p_target);
- const Transform &get_target_transform() const;
+ void set_target_transform(const Transform3D &p_target);
+ const Transform3D &get_target_transform() const;
void set_target_node(const NodePath &p_node);
NodePath get_target_node();
@@ -190,7 +190,7 @@ public:
void stop();
private:
- Transform _get_target_transform();
+ Transform3D _get_target_transform();
void reload_chain();
void reload_goal();
void _solve_chain();
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index 3fde4d6ef3..df5474d03e 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -85,11 +85,11 @@ void SoftBodyRenderingServerHandler::commit_changes() {
}
void SoftBodyRenderingServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
- copymem(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3);
+ 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) {
- copymem(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3);
+ memcpy(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3);
}
void SoftBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
@@ -249,7 +249,7 @@ void SoftBody3D::_softbody_changed() {
prepare_physics_server();
_reset_points_offsets();
#ifdef TOOLS_ENABLED
- update_configuration_warning();
+ update_configuration_warnings();
#endif
}
@@ -283,7 +283,7 @@ void SoftBody3D::_notification(int p_what) {
set_notify_transform(false);
// Required to be top level with Transform at center of world in order to modify RenderingServer only to support custom Transform
set_as_top_level(true);
- set_transform(Transform());
+ set_transform(Transform3D());
set_notify_transform(true);
} break;
@@ -301,7 +301,7 @@ void SoftBody3D::_notification(int p_what) {
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warning();
+ update_configuration_warnings();
}
}
@@ -366,27 +366,19 @@ void SoftBody3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ray_pickable"), "set_ray_pickable", "is_ray_pickable");
}
-String SoftBody3D::get_configuration_warning() const {
- String warning = MeshInstance3D::get_configuration_warning();
+TypedArray<String> SoftBody3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (get_mesh().is_null()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
-
- warning += TTR("This body will be ignored until you set a mesh.");
+ warnings.push_back(TTR("This body will be ignored until you set a mesh."));
}
- Transform t = get_transform();
+ 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)) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
-
- warning += 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 SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
- return warning;
+ return warnings;
}
void SoftBody3D::_update_physics_server() {
@@ -416,7 +408,7 @@ void SoftBody3D::_draw_soft_mesh() {
/// 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", Transform());
+ call_deferred("set_transform", Transform3D());
}
_update_physics_server();
@@ -460,7 +452,7 @@ void SoftBody3D::become_mesh_owner() {
mesh_owner = true;
Vector<Ref<Material>> copy_materials;
- copy_materials.append_array(materials);
+ copy_materials.append_array(surface_override_materials);
ERR_FAIL_COND(!mesh->get_surface_count());
@@ -480,7 +472,7 @@ void SoftBody3D::become_mesh_owner() {
set_mesh(soft_mesh);
for (int i = copy_materials.size() - 1; 0 <= i; --i) {
- set_surface_material(i, copy_materials[i]);
+ set_surface_override_material(i, copy_materials[i]);
}
}
}
@@ -504,6 +496,7 @@ uint32_t SoftBody3D::get_collision_layer() const {
}
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();
if (p_value) {
mask |= 1 << p_bit;
@@ -514,10 +507,12 @@ void SoftBody3D::set_collision_mask_bit(int p_bit, bool p_value) {
}
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);
}
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();
if (p_value) {
layer |= 1 << p_bit;
@@ -528,6 +523,7 @@ void SoftBody3D::set_collision_layer_bit(int p_bit, bool p_value) {
}
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);
}
diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h
index f98df39209..0d0d39d48f 100644
--- a/scene/3d/soft_body_3d.h
+++ b/scene/3d/soft_body_3d.h
@@ -113,7 +113,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
protected:
void _update_physics_server();
diff --git a/scene/3d/spring_arm_3d.cpp b/scene/3d/spring_arm_3d.cpp
index 9518b47696..1911e14d54 100644
--- a/scene/3d/spring_arm_3d.cpp
+++ b/scene/3d/spring_arm_3d.cpp
@@ -153,7 +153,7 @@ void SpringArm3D::process_spring() {
}
current_spring_length = spring_length * motion_delta;
- Transform childs_transform;
+ Transform3D childs_transform;
childs_transform.origin = get_global_transform().origin + cast_direction * (spring_length * motion_delta);
for (int i = get_child_count() - 1; 0 <= i; --i) {
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 0be54e7243..9ec461d973 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -505,6 +505,7 @@ void Sprite3D::set_texture(const Ref<Texture2D> &p_texture) {
texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite3D::_texture_changed));
}
_queue_update();
+ emit_signal(SceneStringNames::get_singleton()->texture_changed);
}
Ref<Texture2D> Sprite3D::get_texture() const {
@@ -551,15 +552,15 @@ int Sprite3D::get_frame() const {
return frame;
}
-void Sprite3D::set_frame_coords(const Vector2 &p_coord) {
- ERR_FAIL_INDEX(int(p_coord.x), hframes);
- ERR_FAIL_INDEX(int(p_coord.y), vframes);
+void Sprite3D::set_frame_coords(const Vector2i &p_coord) {
+ ERR_FAIL_INDEX(p_coord.x, hframes);
+ ERR_FAIL_INDEX(p_coord.y, vframes);
- set_frame(int(p_coord.y) * hframes + int(p_coord.x));
+ set_frame(p_coord.y * hframes + p_coord.x);
}
-Vector2 Sprite3D::get_frame_coords() const {
- return Vector2(frame % hframes, frame / hframes);
+Vector2i Sprite3D::get_frame_coords() const {
+ return Vector2i(frame % hframes, frame / hframes);
}
void Sprite3D::set_vframes(int p_amount) {
@@ -657,12 +658,13 @@ void Sprite3D::_bind_methods() {
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::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "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");
ADD_SIGNAL(MethodInfo("frame_changed"));
+ ADD_SIGNAL(MethodInfo("texture_changed"));
}
Sprite3D::Sprite3D() {
@@ -928,7 +930,7 @@ void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
notify_property_list_changed();
_reset_timeout();
_queue_update();
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<SpriteFrames> AnimatedSprite3D::get_sprite_frames() const {
@@ -1058,17 +1060,14 @@ StringName AnimatedSprite3D::get_animation() const {
return animation;
}
-String AnimatedSprite3D::get_configuration_warning() const {
- String warning = SpriteBase3D::get_configuration_warning();
+TypedArray<String> AnimatedSprite3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (frames.is_null()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames.");
+ warnings.push_back(TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames."));
}
- return warning;
+ return warnings;
}
void AnimatedSprite3D::_bind_methods() {
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index d1bc8dc737..e3dd117804 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -176,8 +176,8 @@ public:
void set_frame(int p_frame);
int get_frame() const;
- void set_frame_coords(const Vector2 &p_coord);
- Vector2 get_frame_coords() const;
+ void set_frame_coords(const Vector2i &p_coord);
+ Vector2i get_frame_coords() const;
void set_vframes(int p_amount);
int get_vframes() const;
@@ -236,7 +236,7 @@ public:
virtual Rect2 get_item_rect() const override;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
AnimatedSprite3D();
};
diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp
index 5b0b3b89d3..0d88769b70 100644
--- a/scene/3d/vehicle_body_3d.cpp
+++ b/scene/3d/vehicle_body_3d.cpp
@@ -102,17 +102,14 @@ void VehicleWheel3D::_notification(int p_what) {
}
}
-String VehicleWheel3D::get_configuration_warning() const {
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> VehicleWheel3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<VehicleBody3D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D.");
+ warnings.push_back(TTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D."));
}
- return warning;
+ return warnings;
}
void VehicleWheel3D::_update(PhysicsDirectBodyState3D *s) {
@@ -349,7 +346,7 @@ VehicleWheel3D::VehicleWheel3D() {
void VehicleBody3D::_update_wheel_transform(VehicleWheel3D &wheel, PhysicsDirectBodyState3D *s) {
wheel.m_raycastInfo.m_isInContact = false;
- Transform chassisTrans = s->get_transform();
+ Transform3D chassisTrans = s->get_transform();
/*
if (interpolatedTransform && (getRigidBody()->getMotionState())) {
getRigidBody()->getMotionState()->getWorldTransform(chassisTrans);
@@ -787,7 +784,7 @@ void VehicleBody3D::_update_friction(PhysicsDirectBodyState3D *s) {
Vector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel];
#if defined ROLLING_INFLUENCE_FIX // fix. It only worked if car's up was along Y - VT.
- Vector3 vChassisWorldUp = s->get_transform().basis.transposed()[1]; //getRigidBody()->getCenterOfMassTransform().getBasis().getColumn(m_indexUpAxis);
+ Vector3 vChassisWorldUp = s->get_transform().basis.transposed()[1]; //getRigidBody()->getCenterOfMassTransform3D().getBasis().getColumn(m_indexUpAxis);
rel_pos -= vChassisWorldUp * (vChassisWorldUp.dot(rel_pos) * (1.f - wheelInfo.m_rollInfluence));
#else
rel_pos[1] *= wheelInfo.m_rollInfluence; //?
@@ -806,6 +803,7 @@ 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");
real_t step = state->get_step();
@@ -843,7 +841,7 @@ void VehicleBody3D::_direct_state_changed(Object *p_state) {
Vector3 vel = state->get_linear_velocity() + (state->get_angular_velocity()).cross(relpos); // * mPos);
if (wheel.m_raycastInfo.m_isInContact) {
- const Transform &chassisWorldTransform = state->get_transform();
+ const Transform3D &chassisWorldTransform = state->get_transform();
Vector3 fwd(
chassisWorldTransform.basis[0][Vector3::AXIS_Z],
@@ -925,7 +923,7 @@ void VehicleBody3D::_bind_methods() {
VehicleBody3D::VehicleBody3D() {
exclude.insert(get_rid());
- //PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ //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 860fa7e3b7..2c10205ea3 100644
--- a/scene/3d/vehicle_body_3d.h
+++ b/scene/3d/vehicle_body_3d.h
@@ -40,8 +40,8 @@ class VehicleWheel3D : public Node3D {
friend class VehicleBody3D;
- Transform m_worldTransform;
- Transform local_xform;
+ Transform3D m_worldTransform;
+ Transform3D local_xform;
bool engine_traction = false;
bool steers = false;
@@ -145,7 +145,7 @@ public:
void set_steering(real_t p_steering);
real_t get_steering() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
VehicleWheel3D();
};
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
index 471838b9d1..39b17d195b 100644
--- a/scene/3d/visibility_notifier_3d.cpp
+++ b/scene/3d/visibility_notifier_3d.cpp
@@ -36,27 +36,23 @@
#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();
+void VisibilityNotifier3D::_visibility_enter() {
+ if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) {
+ return;
}
- emit_signal(SceneStringNames::get_singleton()->camera_entered, p_camera);
+ on_screen = true;
+ emit_signal(SceneStringNames::get_singleton()->screen_entered);
+ _screen_enter();
}
-
-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::_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 VisibilityNotifier3D::set_aabb(const AABB &p_aabb) {
@@ -65,9 +61,7 @@ void VisibilityNotifier3D::set_aabb(const AABB &p_aabb) {
}
aabb = p_aabb;
- if (is_inside_world()) {
- get_world_3d()->_update_notifier(this, get_global_transform().xform(aabb));
- }
+ RS::get_singleton()->visibility_notifier_set_aabb(get_base(), aabb);
update_gizmo();
}
@@ -76,178 +70,129 @@ 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 on_screen;
}
-bool VisibilityNotifier3D::is_on_screen() const {
- return cameras.size() != 0;
+void VisibilityNotifier3D::_notification(int p_what) {
+ if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_EXIT_TREE) {
+ on_screen = false;
+ }
}
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"));
}
+Vector<Face3> VisibilityNotifier3D::get_faces(uint32_t p_usage_flags) const {
+ return Vector<Face3>();
+}
+
VisibilityNotifier3D::VisibilityNotifier3D() {
- set_notify_transform(true);
+ 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, &VisibilityNotifier3D::_visibility_enter), callable_mp(this, &VisibilityNotifier3D::_visibility_exit));
+ set_base(notifier);
}
//////////////////////////////////////
void VisibilityEnabler3D::_screen_enter() {
- for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
- _change_node_state(E->key(), true);
- }
-
- visible = true;
+ _update_enable_mode(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;
+ _update_enable_mode(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_CHARACTER || rb->get_mode() == RigidBody3D::MODE_RIGID))) {
- add = true;
- meta = rb->get_mode();
- }
+void VisibilityEnabler3D::set_enable_mode(EnableMode p_mode) {
+ enable_mode = p_mode;
+ if (is_inside_tree()) {
+ _update_enable_mode(is_on_screen());
}
+}
+VisibilityEnabler3D::EnableMode VisibilityEnabler3D::get_enable_mode() {
+ return enable_mode;
+}
- {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
- if (ap) {
- add = true;
- }
+void VisibilityEnabler3D::set_enable_node_path(NodePath p_path) {
+ if (enable_node_path == p_path) {
+ return;
}
-
- 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);
+ 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());
+ }
}
-
- 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
+}
+NodePath VisibilityEnabler3D::get_enable_node_path() {
+ return enable_node_path;
+}
+
+void VisibilityEnabler3D::_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);
}
-
- _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();
+ 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);
}
-
- _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);
- }
+ node_id = ObjectID();
}
}
-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);
+ ClassDB::bind_method(D_METHOD("set_enable_mode", "mode"), &VisibilityEnabler3D::set_enable_mode);
+ ClassDB::bind_method(D_METHOD("get_enable_mode"), &VisibilityEnabler3D::get_enable_mode);
- 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);
+ ClassDB::bind_method(D_METHOD("set_enable_node_path", "path"), &VisibilityEnabler3D::set_enable_node_path);
+ ClassDB::bind_method(D_METHOD("get_enable_node_path"), &VisibilityEnabler3D::get_enable_node_path);
- BIND_ENUM_CONSTANT(ENABLER_PAUSE_ANIMATIONS);
- BIND_ENUM_CONSTANT(ENABLER_FREEZE_BODIES);
- BIND_ENUM_CONSTANT(ENABLER_MAX);
-}
+ 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");
-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];
+ BIND_ENUM_CONSTANT(ENABLE_MODE_INHERIT);
+ BIND_ENUM_CONSTANT(ENABLE_MODE_ALWAYS);
+ BIND_ENUM_CONSTANT(ENABLE_MODE_WHEN_PAUSED);
}
VisibilityEnabler3D::VisibilityEnabler3D() {
- for (int i = 0; i < ENABLER_MAX; i++) {
- enabler[i] = true;
- }
}
diff --git a/scene/3d/visibility_notifier_3d.h b/scene/3d/visibility_notifier_3d.h
index 9f7705067f..878c97e35e 100644
--- a/scene/3d/visibility_notifier_3d.h
+++ b/scene/3d/visibility_notifier_3d.h
@@ -31,34 +31,34 @@
#ifndef VISIBILITY_NOTIFIER_H
#define VISIBILITY_NOTIFIER_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 VisibilityNotifier3D : public VisualInstance3D {
+ GDCLASS(VisibilityNotifier3D, 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;
+ virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
+
VisibilityNotifier3D();
};
@@ -66,36 +66,35 @@ class VisibilityEnabler3D : public VisibilityNotifier3D {
GDCLASS(VisibilityEnabler3D, VisibilityNotifier3D);
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();
};
-VARIANT_ENUM_CAST(VisibilityEnabler3D::Enabler);
+VARIANT_ENUM_CAST(VisibilityEnabler3D::EnableMode);
#endif // VISIBILITY_NOTIFIER_H
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index 394c67e873..c16e3c2d78 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -61,7 +61,7 @@ void VisualInstance3D::_notification(int p_what) {
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
- Transform gt = get_global_transform();
+ Transform3D gt = get_global_transform();
RenderingServer::get_singleton()->instance_set_transform(instance, gt);
} break;
case NOTIFICATION_EXIT_WORLD: {
@@ -150,40 +150,40 @@ 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);
}
-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);
}
-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) {
@@ -338,6 +338,15 @@ GeometryInstance3D::GIMode GeometryInstance3D::get_gi_mode() const {
return gi_mode;
}
+void GeometryInstance3D::set_ignore_occlusion_culling(bool p_enabled) {
+ ignore_occlusion_culling = p_enabled;
+ RS::get_singleton()->instance_geometry_set_flag(get_instance(), RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, ignore_occlusion_culling);
+}
+
+bool GeometryInstance3D::is_ignoring_occlusion_culling() {
+ return ignore_occlusion_culling;
+}
+
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);
@@ -345,20 +354,23 @@ void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cast_shadows_setting", "shadow_casting_setting"), &GeometryInstance3D::set_cast_shadows_setting);
ClassDB::bind_method(D_METHOD("get_cast_shadows_setting"), &GeometryInstance3D::get_cast_shadows_setting);
- 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_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_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_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_shader_instance_uniform", "uniform", "value"), &GeometryInstance3D::set_shader_instance_uniform);
- ClassDB::bind_method(D_METHOD("get_shader_instance_uniform", "uniform"), &GeometryInstance3D::get_shader_instance_uniform);
+ ClassDB::bind_method(D_METHOD("set_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_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_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", "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_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_shader_instance_uniform", "uniform", "value"), &GeometryInstance3D::set_shader_instance_uniform);
+ ClassDB::bind_method(D_METHOD("get_shader_instance_uniform", "uniform"), &GeometryInstance3D::get_shader_instance_uniform);
ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance3D::set_extra_cull_margin);
ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance3D::get_extra_cull_margin);
@@ -369,8 +381,8 @@ void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_gi_mode", "mode"), &GeometryInstance3D::set_gi_mode);
ClassDB::bind_method(D_METHOD("get_gi_mode"), &GeometryInstance3D::get_gi_mode);
- 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_ignore_occlusion_culling", "ignore_culling"), &GeometryInstance3D::set_ignore_occlusion_culling);
+ ClassDB::bind_method(D_METHOD("is_ignoring_occlusion_culling"), &GeometryInstance3D::is_ignoring_occlusion_culling);
ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &GeometryInstance3D::set_custom_aabb);
@@ -381,15 +393,16 @@ void GeometryInstance3D::_bind_methods() {
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_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 7fed8095ef..2d5699859b 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -107,10 +107,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;
@@ -120,6 +123,7 @@ private:
float extra_cull_margin = 0.0;
LightmapScale lightmap_scale = LIGHTMAP_SCALE_1X;
GIMode gi_mode = GI_MODE_DISABLED;
+ bool ignore_occlusion_culling = false;
const StringName *_instance_uniform_get_remap(const StringName p_name) const;
@@ -135,17 +139,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_lod_max_distance(float p_dist);
- float get_lod_max_distance() const;
+ void set_visibility_range_end(float p_dist);
+ float get_visibility_range_end() const;
- void set_lod_min_hysteresis(float p_dist);
- float get_lod_min_hysteresis() const;
+ void set_visibility_range_begin_margin(float p_dist);
+ float get_visibility_range_begin_margin() const;
- void set_lod_max_hysteresis(float p_dist);
- float get_lod_max_hysteresis() const;
+ void set_visibility_range_end_margin(float p_dist);
+ float get_visibility_range_end_margin() 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;
@@ -167,6 +174,9 @@ public:
void set_custom_aabb(AABB aabb);
+ void set_ignore_occlusion_culling(bool p_enabled);
+ bool is_ignoring_occlusion_culling();
+
GeometryInstance3D();
};
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/voxel_gi.cpp
index 43f820e5d4..e00be9204c 100644
--- a/scene/3d/gi_probe.cpp
+++ b/scene/3d/voxel_gi.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* gi_probe.cpp */
+/* voxel_gi.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,14 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "gi_probe.h"
+#include "voxel_gi.h"
#include "core/os/os.h"
#include "mesh_instance_3d.h"
#include "voxelizer.h"
-void GIProbeData::_set_data(const Dictionary &p_data) {
+void VoxelGIData::_set_data(const Dictionary &p_data) {
ERR_FAIL_COND(!p_data.has("bounds"));
ERR_FAIL_COND(!p_data.has("octree_size"));
ERR_FAIL_COND(!p_data.has("octree_cells"));
@@ -62,12 +62,12 @@ void GIProbeData::_set_data(const Dictionary &p_data) {
octree_df = img->get_data();
}
Vector<int> octree_levels = p_data["level_counts"];
- Transform to_cell_xform = p_data["to_cell_xform"];
+ Transform3D to_cell_xform = p_data["to_cell_xform"];
allocate(to_cell_xform, bounds, octree_size, octree_cells, octree_data, octree_df, octree_levels);
}
-Dictionary GIProbeData::_get_data() const {
+Dictionary VoxelGIData::_get_data() const {
Dictionary d;
d["bounds"] = get_bounds();
Vector3i otsize = get_octree_size();
@@ -90,186 +90,186 @@ Dictionary GIProbeData::_get_data() const {
return d;
}
-void GIProbeData::allocate(const Transform &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) {
- RS::get_singleton()->gi_probe_allocate_data(probe, p_to_cell_xform, p_aabb, p_octree_size, p_octree_cells, p_data_cells, p_distance_field, p_level_counts);
+void VoxelGIData::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) {
+ RS::get_singleton()->voxel_gi_allocate_data(probe, p_to_cell_xform, p_aabb, p_octree_size, p_octree_cells, p_data_cells, p_distance_field, p_level_counts);
bounds = p_aabb;
to_cell_xform = p_to_cell_xform;
octree_size = p_octree_size;
}
-AABB GIProbeData::get_bounds() const {
+AABB VoxelGIData::get_bounds() const {
return bounds;
}
-Vector3 GIProbeData::get_octree_size() const {
+Vector3 VoxelGIData::get_octree_size() const {
return octree_size;
}
-Vector<uint8_t> GIProbeData::get_octree_cells() const {
- return RS::get_singleton()->gi_probe_get_octree_cells(probe);
+Vector<uint8_t> VoxelGIData::get_octree_cells() const {
+ return RS::get_singleton()->voxel_gi_get_octree_cells(probe);
}
-Vector<uint8_t> GIProbeData::get_data_cells() const {
- return RS::get_singleton()->gi_probe_get_data_cells(probe);
+Vector<uint8_t> VoxelGIData::get_data_cells() const {
+ return RS::get_singleton()->voxel_gi_get_data_cells(probe);
}
-Vector<uint8_t> GIProbeData::get_distance_field() const {
- return RS::get_singleton()->gi_probe_get_distance_field(probe);
+Vector<uint8_t> VoxelGIData::get_distance_field() const {
+ return RS::get_singleton()->voxel_gi_get_distance_field(probe);
}
-Vector<int> GIProbeData::get_level_counts() const {
- return RS::get_singleton()->gi_probe_get_level_counts(probe);
+Vector<int> VoxelGIData::get_level_counts() const {
+ return RS::get_singleton()->voxel_gi_get_level_counts(probe);
}
-Transform GIProbeData::get_to_cell_xform() const {
+Transform3D VoxelGIData::get_to_cell_xform() const {
return to_cell_xform;
}
-void GIProbeData::set_dynamic_range(float p_range) {
- RS::get_singleton()->gi_probe_set_dynamic_range(probe, p_range);
+void VoxelGIData::set_dynamic_range(float p_range) {
+ RS::get_singleton()->voxel_gi_set_dynamic_range(probe, p_range);
dynamic_range = p_range;
}
-float GIProbeData::get_dynamic_range() const {
+float VoxelGIData::get_dynamic_range() const {
return dynamic_range;
}
-void GIProbeData::set_propagation(float p_propagation) {
- RS::get_singleton()->gi_probe_set_propagation(probe, p_propagation);
+void VoxelGIData::set_propagation(float p_propagation) {
+ RS::get_singleton()->voxel_gi_set_propagation(probe, p_propagation);
propagation = p_propagation;
}
-float GIProbeData::get_propagation() const {
+float VoxelGIData::get_propagation() const {
return propagation;
}
-void GIProbeData::set_anisotropy_strength(float p_anisotropy_strength) {
- RS::get_singleton()->gi_probe_set_anisotropy_strength(probe, p_anisotropy_strength);
+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 GIProbeData::get_anisotropy_strength() const {
+float VoxelGIData::get_anisotropy_strength() const {
return anisotropy_strength;
}
-void GIProbeData::set_energy(float p_energy) {
- RS::get_singleton()->gi_probe_set_energy(probe, p_energy);
+void VoxelGIData::set_energy(float p_energy) {
+ RS::get_singleton()->voxel_gi_set_energy(probe, p_energy);
energy = p_energy;
}
-float GIProbeData::get_energy() const {
+float VoxelGIData::get_energy() const {
return energy;
}
-void GIProbeData::set_ao(float p_ao) {
- RS::get_singleton()->gi_probe_set_ao(probe, p_ao);
+void VoxelGIData::set_ao(float p_ao) {
+ RS::get_singleton()->voxel_gi_set_ao(probe, p_ao);
ao = p_ao;
}
-float GIProbeData::get_ao() const {
+float VoxelGIData::get_ao() const {
return ao;
}
-void GIProbeData::set_ao_size(float p_ao_size) {
- RS::get_singleton()->gi_probe_set_ao_size(probe, p_ao_size);
+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 GIProbeData::get_ao_size() const {
+float VoxelGIData::get_ao_size() const {
return ao_size;
}
-void GIProbeData::set_bias(float p_bias) {
- RS::get_singleton()->gi_probe_set_bias(probe, p_bias);
+void VoxelGIData::set_bias(float p_bias) {
+ RS::get_singleton()->voxel_gi_set_bias(probe, p_bias);
bias = p_bias;
}
-float GIProbeData::get_bias() const {
+float VoxelGIData::get_bias() const {
return bias;
}
-void GIProbeData::set_normal_bias(float p_normal_bias) {
- RS::get_singleton()->gi_probe_set_normal_bias(probe, p_normal_bias);
+void VoxelGIData::set_normal_bias(float p_normal_bias) {
+ RS::get_singleton()->voxel_gi_set_normal_bias(probe, p_normal_bias);
normal_bias = p_normal_bias;
}
-float GIProbeData::get_normal_bias() const {
+float VoxelGIData::get_normal_bias() const {
return normal_bias;
}
-void GIProbeData::set_interior(bool p_enable) {
- RS::get_singleton()->gi_probe_set_interior(probe, p_enable);
+void VoxelGIData::set_interior(bool p_enable) {
+ RS::get_singleton()->voxel_gi_set_interior(probe, p_enable);
interior = p_enable;
}
-bool GIProbeData::is_interior() const {
+bool VoxelGIData::is_interior() const {
return interior;
}
-void GIProbeData::set_use_two_bounces(bool p_enable) {
- RS::get_singleton()->gi_probe_set_use_two_bounces(probe, p_enable);
+void VoxelGIData::set_use_two_bounces(bool p_enable) {
+ RS::get_singleton()->voxel_gi_set_use_two_bounces(probe, p_enable);
use_two_bounces = p_enable;
}
-bool GIProbeData::is_using_two_bounces() const {
+bool VoxelGIData::is_using_two_bounces() const {
return use_two_bounces;
}
-RID GIProbeData::get_rid() const {
+RID VoxelGIData::get_rid() const {
return probe;
}
-void GIProbeData::_validate_property(PropertyInfo &property) const {
+void VoxelGIData::_validate_property(PropertyInfo &property) const {
if (property.name == "anisotropy_strength") {
- bool anisotropy_enabled = ProjectSettings::get_singleton()->get("rendering/global_illumination/gi_probes/anisotropic");
+ bool anisotropy_enabled = ProjectSettings::get_singleton()->get("rendering/global_illumination/voxel_gi/anisotropic");
if (!anisotropy_enabled) {
property.usage = PROPERTY_USAGE_NOEDITOR;
}
}
}
-void GIProbeData::_bind_methods() {
- ClassDB::bind_method(D_METHOD("allocate", "to_cell_xform", "aabb", "octree_size", "octree_cells", "data_cells", "distance_field", "level_counts"), &GIProbeData::allocate);
+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);
- ClassDB::bind_method(D_METHOD("get_bounds"), &GIProbeData::get_bounds);
- ClassDB::bind_method(D_METHOD("get_octree_size"), &GIProbeData::get_octree_size);
- ClassDB::bind_method(D_METHOD("get_to_cell_xform"), &GIProbeData::get_to_cell_xform);
- ClassDB::bind_method(D_METHOD("get_octree_cells"), &GIProbeData::get_octree_cells);
- ClassDB::bind_method(D_METHOD("get_data_cells"), &GIProbeData::get_data_cells);
- ClassDB::bind_method(D_METHOD("get_level_counts"), &GIProbeData::get_level_counts);
+ ClassDB::bind_method(D_METHOD("get_bounds"), &VoxelGIData::get_bounds);
+ ClassDB::bind_method(D_METHOD("get_octree_size"), &VoxelGIData::get_octree_size);
+ ClassDB::bind_method(D_METHOD("get_to_cell_xform"), &VoxelGIData::get_to_cell_xform);
+ ClassDB::bind_method(D_METHOD("get_octree_cells"), &VoxelGIData::get_octree_cells);
+ ClassDB::bind_method(D_METHOD("get_data_cells"), &VoxelGIData::get_data_cells);
+ ClassDB::bind_method(D_METHOD("get_level_counts"), &VoxelGIData::get_level_counts);
- ClassDB::bind_method(D_METHOD("set_dynamic_range", "dynamic_range"), &GIProbeData::set_dynamic_range);
- ClassDB::bind_method(D_METHOD("get_dynamic_range"), &GIProbeData::get_dynamic_range);
+ ClassDB::bind_method(D_METHOD("set_dynamic_range", "dynamic_range"), &VoxelGIData::set_dynamic_range);
+ ClassDB::bind_method(D_METHOD("get_dynamic_range"), &VoxelGIData::get_dynamic_range);
- ClassDB::bind_method(D_METHOD("set_energy", "energy"), &GIProbeData::set_energy);
- ClassDB::bind_method(D_METHOD("get_energy"), &GIProbeData::get_energy);
+ ClassDB::bind_method(D_METHOD("set_energy", "energy"), &VoxelGIData::set_energy);
+ ClassDB::bind_method(D_METHOD("get_energy"), &VoxelGIData::get_energy);
- ClassDB::bind_method(D_METHOD("set_bias", "bias"), &GIProbeData::set_bias);
- ClassDB::bind_method(D_METHOD("get_bias"), &GIProbeData::get_bias);
+ ClassDB::bind_method(D_METHOD("set_bias", "bias"), &VoxelGIData::set_bias);
+ ClassDB::bind_method(D_METHOD("get_bias"), &VoxelGIData::get_bias);
- ClassDB::bind_method(D_METHOD("set_normal_bias", "bias"), &GIProbeData::set_normal_bias);
- ClassDB::bind_method(D_METHOD("get_normal_bias"), &GIProbeData::get_normal_bias);
+ ClassDB::bind_method(D_METHOD("set_normal_bias", "bias"), &VoxelGIData::set_normal_bias);
+ ClassDB::bind_method(D_METHOD("get_normal_bias"), &VoxelGIData::get_normal_bias);
- ClassDB::bind_method(D_METHOD("set_propagation", "propagation"), &GIProbeData::set_propagation);
- ClassDB::bind_method(D_METHOD("get_propagation"), &GIProbeData::get_propagation);
+ 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"), &GIProbeData::set_anisotropy_strength);
- ClassDB::bind_method(D_METHOD("get_anisotropy_strength"), &GIProbeData::get_anisotropy_strength);
+ 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"), &GIProbeData::set_ao);
- ClassDB::bind_method(D_METHOD("get_ao"), &GIProbeData::get_ao);
+ 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"), &GIProbeData::set_ao_size);
- ClassDB::bind_method(D_METHOD("get_ao_size"), &GIProbeData::get_ao_size);
+ 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"), &GIProbeData::set_interior);
- ClassDB::bind_method(D_METHOD("is_interior"), &GIProbeData::is_interior);
+ ClassDB::bind_method(D_METHOD("set_interior", "interior"), &VoxelGIData::set_interior);
+ ClassDB::bind_method(D_METHOD("is_interior"), &VoxelGIData::is_interior);
- ClassDB::bind_method(D_METHOD("set_use_two_bounces", "enable"), &GIProbeData::set_use_two_bounces);
- ClassDB::bind_method(D_METHOD("is_using_two_bounces"), &GIProbeData::is_using_two_bounces);
+ ClassDB::bind_method(D_METHOD("set_use_two_bounces", "enable"), &VoxelGIData::set_use_two_bounces);
+ ClassDB::bind_method(D_METHOD("is_using_two_bounces"), &VoxelGIData::is_using_two_bounces);
- ClassDB::bind_method(D_METHOD("_set_data", "data"), &GIProbeData::_set_data);
- ClassDB::bind_method(D_METHOD("_get_data"), &GIProbeData::_get_data);
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &VoxelGIData::_set_data);
+ ClassDB::bind_method(D_METHOD("_get_data"), &VoxelGIData::_get_data);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
@@ -285,18 +285,18 @@ void GIProbeData::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior");
}
-GIProbeData::GIProbeData() {
- probe = RS::get_singleton()->gi_probe_create();
+VoxelGIData::VoxelGIData() {
+ probe = RS::get_singleton()->voxel_gi_create();
}
-GIProbeData::~GIProbeData() {
+VoxelGIData::~VoxelGIData() {
RS::get_singleton()->free(probe);
}
//////////////////////
//////////////////////
-void GIProbe::set_probe_data(const Ref<GIProbeData> &p_data) {
+void VoxelGI::set_probe_data(const Ref<VoxelGIData> &p_data) {
if (p_data.is_valid()) {
RS::get_singleton()->instance_set_base(get_instance(), p_data->get_rid());
} else {
@@ -306,44 +306,44 @@ void GIProbe::set_probe_data(const Ref<GIProbeData> &p_data) {
probe_data = p_data;
}
-Ref<GIProbeData> GIProbe::get_probe_data() const {
+Ref<VoxelGIData> VoxelGI::get_probe_data() const {
return probe_data;
}
-void GIProbe::set_subdiv(Subdiv p_subdiv) {
+void VoxelGI::set_subdiv(Subdiv p_subdiv) {
ERR_FAIL_INDEX(p_subdiv, SUBDIV_MAX);
subdiv = p_subdiv;
update_gizmo();
}
-GIProbe::Subdiv GIProbe::get_subdiv() const {
+VoxelGI::Subdiv VoxelGI::get_subdiv() const {
return subdiv;
}
-void GIProbe::set_extents(const Vector3 &p_extents) {
+void VoxelGI::set_extents(const Vector3 &p_extents) {
extents = p_extents;
update_gizmo();
}
-Vector3 GIProbe::get_extents() const {
+Vector3 VoxelGI::get_extents() const {
return extents;
}
-void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
+void VoxelGI::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node);
if (mi && mi->get_gi_mode() == GeometryInstance3D::GI_MODE_BAKED && mi->is_visible_in_tree()) {
Ref<Mesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
AABB aabb = mesh->get_aabb();
- Transform xf = get_global_transform().affine_inverse() * mi->get_global_transform();
+ Transform3D xf = get_global_transform().affine_inverse() * mi->get_global_transform();
if (AABB(-extents, extents * 2).intersects(xf.xform(aabb))) {
PlotMesh pm;
pm.local_xform = xf;
pm.mesh = mesh;
for (int i = 0; i < mesh->get_surface_count(); i++) {
- pm.instance_materials.push_back(mi->get_surface_material(i));
+ pm.instance_materials.push_back(mi->get_surface_override_material(i));
}
pm.override_material = mi->get_material_override();
plot_meshes.push_back(pm);
@@ -356,7 +356,7 @@ void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
if (s->is_visible_in_tree()) {
Array meshes = p_at_node->call("get_meshes");
for (int i = 0; i < meshes.size(); i += 2) {
- Transform mxf = meshes[i];
+ Transform3D mxf = meshes[i];
Ref<Mesh> mesh = meshes[i + 1];
if (!mesh.is_valid()) {
continue;
@@ -364,7 +364,7 @@ void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
AABB aabb = mesh->get_aabb();
- Transform xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf);
+ Transform3D xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf);
if (AABB(-extents, extents * 2).intersects(xf.xform(aabb))) {
PlotMesh pm;
@@ -382,11 +382,11 @@ void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
}
}
-GIProbe::BakeBeginFunc GIProbe::bake_begin_function = nullptr;
-GIProbe::BakeStepFunc GIProbe::bake_step_function = nullptr;
-GIProbe::BakeEndFunc GIProbe::bake_end_function = nullptr;
+VoxelGI::BakeBeginFunc VoxelGI::bake_begin_function = nullptr;
+VoxelGI::BakeStepFunc VoxelGI::bake_step_function = nullptr;
+VoxelGI::BakeEndFunc VoxelGI::bake_end_function = nullptr;
-Vector3i GIProbe::get_estimated_cell_size() const {
+Vector3i VoxelGI::get_estimated_cell_size() const {
static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 };
int cell_subdiv = subdiv_value[subdiv];
int axis_cell_size[3];
@@ -412,7 +412,7 @@ Vector3i GIProbe::get_estimated_cell_size() const {
return Vector3i(axis_cell_size[0], axis_cell_size[1], axis_cell_size[2]);
}
-void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
+void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) {
static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 };
p_from_node = p_from_node ? p_from_node : get_parent();
@@ -454,7 +454,7 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
mmi->set_multimesh(baker.create_debug_multimesh());
add_child(mmi);
#ifdef TOOLS_ENABLED
- if (get_tree()->get_edited_scene_root() == this) {
+ if (is_inside_tree() && get_tree()->get_edited_scene_root() == this) {
mmi->set_owner(this);
} else {
mmi->set_owner(get_owner());
@@ -464,7 +464,7 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
#endif
} else {
- Ref<GIProbeData> probe_data = get_probe_data();
+ Ref<VoxelGIData> probe_data = get_probe_data();
if (probe_data.is_null()) {
probe_data.instance();
@@ -476,7 +476,7 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
Vector<uint8_t> df = baker.get_sdf_3d_image();
- probe_data->allocate(baker.get_to_cell_space_xform(), AABB(-extents, extents * 2.0), baker.get_giprobe_octree_size(), baker.get_giprobe_octree_cells(), baker.get_giprobe_data_cells(), df, baker.get_giprobe_level_cell_count());
+ probe_data->allocate(baker.get_to_cell_space_xform(), AABB(-extents, extents * 2.0), baker.get_voxel_gi_octree_size(), baker.get_voxel_gi_octree_cells(), baker.get_voxel_gi_data_cells(), df, baker.get_voxel_gi_level_cell_count());
set_probe_data(probe_data);
#ifdef TOOLS_ENABLED
@@ -491,50 +491,46 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
notify_property_list_changed(); //bake property may have changed
}
-void GIProbe::_debug_bake() {
+void VoxelGI::_debug_bake() {
bake(nullptr, true);
}
-AABB GIProbe::get_aabb() const {
+AABB VoxelGI::get_aabb() const {
return AABB(-extents, extents * 2);
}
-Vector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const {
+Vector<Face3> VoxelGI::get_faces(uint32_t p_usage_flags) const {
return Vector<Face3>();
}
-String GIProbe::get_configuration_warning() const {
- String warning = VisualInstance3D::get_configuration_warning();
+TypedArray<String> VoxelGI::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (RenderingServer::get_singleton()->is_low_end()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead.");
+ warnings.push_back(TTR("VoxelGIs are not supported by the GLES2 video driver.\nUse a LightmapGI instead."));
} else if (probe_data.is_null()) {
- warning += TTR("No GIProbe data set, so this node is disabled. Bake static objects to enable GI.");
+ warnings.push_back(TTR("No VoxelGI data set, so this node is disabled. Bake static objects to enable GI."));
}
-
- return warning;
+ return warnings;
}
-void GIProbe::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_probe_data", "data"), &GIProbe::set_probe_data);
- ClassDB::bind_method(D_METHOD("get_probe_data"), &GIProbe::get_probe_data);
+void VoxelGI::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_probe_data", "data"), &VoxelGI::set_probe_data);
+ ClassDB::bind_method(D_METHOD("get_probe_data"), &VoxelGI::get_probe_data);
- ClassDB::bind_method(D_METHOD("set_subdiv", "subdiv"), &GIProbe::set_subdiv);
- ClassDB::bind_method(D_METHOD("get_subdiv"), &GIProbe::get_subdiv);
+ ClassDB::bind_method(D_METHOD("set_subdiv", "subdiv"), &VoxelGI::set_subdiv);
+ ClassDB::bind_method(D_METHOD("get_subdiv"), &VoxelGI::get_subdiv);
- ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GIProbe::set_extents);
- ClassDB::bind_method(D_METHOD("get_extents"), &GIProbe::get_extents);
+ ClassDB::bind_method(D_METHOD("set_extents", "extents"), &VoxelGI::set_extents);
+ ClassDB::bind_method(D_METHOD("get_extents"), &VoxelGI::get_extents);
- ClassDB::bind_method(D_METHOD("bake", "from_node", "create_visual_debug"), &GIProbe::bake, DEFVAL(Variant()), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("debug_bake"), &GIProbe::_debug_bake);
+ ClassDB::bind_method(D_METHOD("bake", "from_node", "create_visual_debug"), &VoxelGI::bake, DEFVAL(Variant()), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("debug_bake"), &VoxelGI::_debug_bake);
ClassDB::set_method_flags(get_class_static(), _scs_create("debug_bake"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdiv", PROPERTY_HINT_ENUM, "64,128,256,512"), "set_subdiv", "get_subdiv");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "GIProbeData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_probe_data", "get_probe_data");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "VoxelGIData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_probe_data", "get_probe_data");
BIND_ENUM_CONSTANT(SUBDIV_64);
BIND_ENUM_CONSTANT(SUBDIV_128);
@@ -543,11 +539,11 @@ void GIProbe::_bind_methods() {
BIND_ENUM_CONSTANT(SUBDIV_MAX);
}
-GIProbe::GIProbe() {
- gi_probe = RS::get_singleton()->gi_probe_create();
+VoxelGI::VoxelGI() {
+ voxel_gi = RS::get_singleton()->voxel_gi_create();
set_disable_scale(true);
}
-GIProbe::~GIProbe() {
- RS::get_singleton()->free(gi_probe);
+VoxelGI::~VoxelGI() {
+ RS::get_singleton()->free(voxel_gi);
}
diff --git a/scene/3d/gi_probe.h b/scene/3d/voxel_gi.h
index 534b425557..5b9ee28b33 100644
--- a/scene/3d/gi_probe.h
+++ b/scene/3d/voxel_gi.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* gi_probe.h */
+/* voxel_gi.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,21 +28,21 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GIPROBE_H
-#define GIPROBE_H
+#ifndef VOXEL_GI_H
+#define VOXEL_GI_H
#include "multimesh_instance_3d.h"
#include "scene/3d/visual_instance_3d.h"
-class GIProbeData : public Resource {
- GDCLASS(GIProbeData, Resource);
+class VoxelGIData : public Resource {
+ GDCLASS(VoxelGIData, Resource);
RID probe;
void _set_data(const Dictionary &p_data);
Dictionary _get_data() const;
- Transform to_cell_xform;
+ Transform3D to_cell_xform;
AABB bounds;
Vector3 octree_size;
@@ -62,14 +62,14 @@ protected:
void _validate_property(PropertyInfo &property) const override;
public:
- void allocate(const Transform &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);
+ 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);
AABB get_bounds() const;
Vector3 get_octree_size() const;
Vector<uint8_t> get_octree_cells() const;
Vector<uint8_t> get_data_cells() const;
Vector<uint8_t> get_distance_field() const;
Vector<int> get_level_counts() const;
- Transform get_to_cell_xform() const;
+ Transform3D get_to_cell_xform() const;
void set_dynamic_range(float p_range);
float get_dynamic_range() const;
@@ -103,12 +103,12 @@ public:
virtual RID get_rid() const override;
- GIProbeData();
- ~GIProbeData();
+ VoxelGIData();
+ ~VoxelGIData();
};
-class GIProbe : public VisualInstance3D {
- GDCLASS(GIProbe, VisualInstance3D);
+class VoxelGI : public VisualInstance3D {
+ GDCLASS(VoxelGI, VisualInstance3D);
public:
enum Subdiv {
@@ -125,9 +125,9 @@ public:
typedef void (*BakeEndFunc)();
private:
- Ref<GIProbeData> probe_data;
+ Ref<VoxelGIData> probe_data;
- RID gi_probe;
+ RID voxel_gi;
Subdiv subdiv = SUBDIV_128;
Vector3 extents = Vector3(10, 10, 10);
@@ -136,7 +136,7 @@ private:
Ref<Material> override_material;
Vector<Ref<Material>> instance_materials;
Ref<Mesh> mesh;
- Transform local_xform;
+ Transform3D local_xform;
};
void _find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes);
@@ -150,8 +150,8 @@ public:
static BakeStepFunc bake_step_function;
static BakeEndFunc bake_end_function;
- void set_probe_data(const Ref<GIProbeData> &p_data);
- Ref<GIProbeData> get_probe_data() const;
+ void set_probe_data(const Ref<VoxelGIData> &p_data);
+ Ref<VoxelGIData> get_probe_data() const;
void set_subdiv(Subdiv p_subdiv);
Subdiv get_subdiv() const;
@@ -165,12 +165,12 @@ public:
virtual AABB get_aabb() const override;
virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
- GIProbe();
- ~GIProbe();
+ VoxelGI();
+ ~VoxelGI();
};
-VARIANT_ENUM_CAST(GIProbe::Subdiv)
+VARIANT_ENUM_CAST(VoxelGI::Subdiv)
-#endif // GIPROBE_H
+#endif // VOXEL_GI_H
diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp
index 1b9ce0201f..ee0c3fe9b6 100644
--- a/scene/3d/voxelizer.cpp
+++ b/scene/3d/voxelizer.cpp
@@ -378,7 +378,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material
return mc;
}
-void Voxelizer::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material) {
+void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material) {
for (int i = 0; i < p_mesh->get_surface_count(); i++) {
if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
continue; //only triangles
@@ -647,11 +647,11 @@ void Voxelizer::begin_bake(int p_subdiv, const AABB &p_bounds) {
po2_bounds.size[i] = po2_bounds.size[longest_axis];
}
- Transform to_bounds;
+ Transform3D to_bounds;
to_bounds.basis.scale(Vector3(po2_bounds.size[longest_axis], po2_bounds.size[longest_axis], po2_bounds.size[longest_axis]));
to_bounds.origin = po2_bounds.position;
- Transform to_grid;
+ Transform3D to_grid;
to_grid.basis.scale(Vector3(axis_cell_size[longest_axis], axis_cell_size[longest_axis], axis_cell_size[longest_axis]));
to_cell_space = to_grid * to_bounds.affine_inverse();
@@ -668,19 +668,19 @@ void Voxelizer::end_bake() {
//create the data for visual server
-int Voxelizer::get_gi_probe_octree_depth() const {
+int Voxelizer::get_voxel_gi_octree_depth() const {
return cell_subdiv;
}
-Vector3i Voxelizer::get_giprobe_octree_size() const {
+Vector3i Voxelizer::get_voxel_gi_octree_size() const {
return Vector3i(axis_cell_size[0], axis_cell_size[1], axis_cell_size[2]);
}
-int Voxelizer::get_giprobe_cell_count() const {
+int Voxelizer::get_voxel_gi_cell_count() const {
return bake_cells.size();
}
-Vector<uint8_t> Voxelizer::get_giprobe_octree_cells() const {
+Vector<uint8_t> Voxelizer::get_voxel_gi_octree_cells() const {
Vector<uint8_t> data;
data.resize((8 * 4) * bake_cells.size()); //8 uint32t values
{
@@ -700,7 +700,7 @@ Vector<uint8_t> Voxelizer::get_giprobe_octree_cells() const {
return data;
}
-Vector<uint8_t> Voxelizer::get_giprobe_data_cells() const {
+Vector<uint8_t> Voxelizer::get_voxel_gi_data_cells() const {
Vector<uint8_t> data;
data.resize((4 * 4) * bake_cells.size()); //8 uint32t values
{
@@ -755,7 +755,7 @@ Vector<uint8_t> Voxelizer::get_giprobe_data_cells() const {
return data;
}
-Vector<int> Voxelizer::get_giprobe_level_cell_count() const {
+Vector<int> Voxelizer::get_voxel_gi_level_cell_count() const {
uint32_t cell_count = bake_cells.size();
const Cell *cells = bake_cells.ptr();
Vector<int> level_count;
@@ -819,7 +819,7 @@ static void edt(float *f, int stride, int n) {
#undef square
Vector<uint8_t> Voxelizer::get_sdf_3d_image() const {
- Vector3i octree_size = get_giprobe_octree_size();
+ Vector3i octree_size = get_voxel_gi_octree_size();
uint32_t float_count = octree_size.x * octree_size.y * octree_size.z;
float *work_memory = memnew_arr(float, float_count);
@@ -891,7 +891,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;
- Transform xform;
+ Transform3D xform;
xform.origin = center;
xform.basis.scale(p_aabb.size * 0.5);
p_multimesh->set_instance_transform(idx, xform);
@@ -1002,7 +1002,7 @@ Ref<MultiMesh> Voxelizer::create_debug_multimesh() {
return mm;
}
-Transform Voxelizer::get_to_cell_space_xform() const {
+Transform3D Voxelizer::get_to_cell_space_xform() const {
return to_cell_space;
}
diff --git a/scene/3d/voxelizer.h b/scene/3d/voxelizer.h
index 87f949e7db..e500d2d4c3 100644
--- a/scene/3d/voxelizer.h
+++ b/scene/3d/voxelizer.h
@@ -93,7 +93,7 @@ private:
AABB po2_bounds;
int axis_cell_size[3] = {};
- Transform to_cell_space;
+ Transform3D to_cell_space;
int color_scan_cell_width = 4;
int bake_texture_size = 128;
@@ -114,20 +114,20 @@ private:
public:
void begin_bake(int p_subdiv, const AABB &p_bounds);
- void plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material);
+ void plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material);
void end_bake();
- int get_gi_probe_octree_depth() const;
- Vector3i get_giprobe_octree_size() const;
- int get_giprobe_cell_count() const;
- Vector<uint8_t> get_giprobe_octree_cells() const;
- Vector<uint8_t> get_giprobe_data_cells() const;
- Vector<int> get_giprobe_level_cell_count() const;
+ int get_voxel_gi_octree_depth() const;
+ Vector3i get_voxel_gi_octree_size() const;
+ int get_voxel_gi_cell_count() const;
+ Vector<uint8_t> get_voxel_gi_octree_cells() const;
+ Vector<uint8_t> get_voxel_gi_data_cells() const;
+ Vector<int> get_voxel_gi_level_cell_count() const;
Vector<uint8_t> get_sdf_3d_image() const;
Ref<MultiMesh> create_debug_multimesh();
- Transform get_to_cell_space_xform() const;
+ Transform3D get_to_cell_space_xform() const;
Voxelizer();
};
diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp
index 214ffd6bd5..829ecc5ec2 100644
--- a/scene/3d/world_environment.cpp
+++ b/scene/3d/world_environment.cpp
@@ -65,7 +65,7 @@ void WorldEnvironment::_update_current_environment() {
} else {
get_viewport()->find_world_3d()->set_environment(Ref<Environment>());
}
- get_tree()->call_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warning");
+ get_tree()->call_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings");
}
void WorldEnvironment::_update_current_camera_effects() {
@@ -76,7 +76,7 @@ void WorldEnvironment::_update_current_camera_effects() {
get_viewport()->find_world_3d()->set_camera_effects(Ref<CameraEffects>());
}
- get_tree()->call_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warning");
+ get_tree()->call_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings");
}
void WorldEnvironment::set_environment(const Ref<Environment> &p_environment) {
@@ -96,7 +96,7 @@ void WorldEnvironment::set_environment(const Ref<Environment> &p_environment) {
if (is_inside_tree()) {
_update_current_environment();
} else {
- update_configuration_warning();
+ update_configuration_warnings();
}
}
@@ -121,7 +121,7 @@ void WorldEnvironment::set_camera_effects(const Ref<CameraEffects> &p_camera_eff
if (is_inside_tree()) {
_update_current_camera_effects();
} else {
- update_configuration_warning();
+ update_configuration_warnings();
}
}
@@ -129,35 +129,26 @@ Ref<CameraEffects> WorldEnvironment::get_camera_effects() const {
return camera_effects;
}
-String WorldEnvironment::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> WorldEnvironment::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!environment.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect.");
+ warnings.push_back(TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect."));
}
if (!is_inside_tree()) {
- return warning;
+ return warnings;
}
if (environment.is_valid() && get_viewport()->find_world_3d()->get_environment() != environment) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Only the first Environment has an effect in a scene (or set of instantiated scenes).");
+ warnings.push_back(("Only the first Environment has an effect in a scene (or set of instantiated scenes)."));
}
if (camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() != camera_effects) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Only the first CameraEffects has an effect in a scene (or set of instantiated scenes).");
+ warnings.push_back(TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."));
}
- return warning;
+ return warnings;
}
void WorldEnvironment::_bind_methods() {
diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h
index e3f28d6d6b..9e85982381 100644
--- a/scene/3d/world_environment.h
+++ b/scene/3d/world_environment.h
@@ -55,7 +55,7 @@ public:
void set_camera_effects(const Ref<CameraEffects> &p_camera_effects);
Ref<CameraEffects> get_camera_effects() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
WorldEnvironment();
};
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index 63be4352d5..4f2c816934 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -55,23 +55,18 @@ void XRCamera3D::_notification(int p_what) {
};
};
-String XRCamera3D::get_configuration_warning() const {
- if (!is_visible() || !is_inside_tree()) {
- return String();
+TypedArray<String> XRCamera3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
+ if (is_visible() && is_inside_tree()) {
+ // must be child node of XROrigin3D!
+ XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
+ if (origin == nullptr) {
+ warnings.push_back(TTR("XRCamera3D must have an XROrigin3D node as its parent."));
+ };
}
- String warning = Camera3D::get_configuration_warning();
-
- // must be child node of XROrigin3D!
- XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
- if (origin == nullptr) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("XRCamera3D must have an XROrigin3D node as its parent.");
- };
-
- return warning;
+ return warnings;
};
Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const {
@@ -91,7 +86,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();
@@ -113,7 +109,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);
@@ -142,7 +139,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();
@@ -170,7 +168,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());
};
@@ -265,7 +264,7 @@ void XRController3D::set_controller_id(int p_controller_id) {
// We don't check any bounds here, this controller may not yet be active and just be a place holder until it is.
// Note that setting this to 0 means this node is not bound to a controller yet.
controller_id = p_controller_id;
- update_configuration_warning();
+ update_configuration_warnings();
};
int XRController3D::get_controller_id() const {
@@ -362,30 +361,22 @@ XRPositionalTracker::TrackerHand XRController3D::get_tracker_hand() const {
return tracker->get_tracker_hand();
};
-String XRController3D::get_configuration_warning() const {
- if (!is_visible() || !is_inside_tree()) {
- return String();
- }
+TypedArray<String> XRController3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- String warning = Node3D::get_configuration_warning();
-
- // must be child node of XROrigin!
- XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
- if (origin == nullptr) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible() && is_inside_tree()) {
+ // must be child node of XROrigin!
+ XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
+ if (origin == nullptr) {
+ warnings.push_back(TTR("XRController3D must have an XROrigin3D node as its parent."));
}
- warning += TTR("XRController3D must have an XROrigin3D node as its parent.");
- };
- if (controller_id == 0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (controller_id == 0) {
+ warnings.push_back(TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller."));
}
- warning += TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller.");
- };
+ }
- return warning;
+ return warnings;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -410,7 +401,7 @@ void XRAnchor3D::_notification(int p_what) {
is_active = false;
} else {
is_active = true;
- Transform transform;
+ Transform3D transform;
// we'll need our world_scale
real_t world_scale = xr_server->get_world_scale();
@@ -459,7 +450,7 @@ void XRAnchor3D::set_anchor_id(int p_anchor_id) {
// We don't check any bounds here, this anchor may not yet be active and just be a place holder until it is.
// Note that setting this to 0 means this node is not bound to an anchor yet.
anchor_id = p_anchor_id;
- update_configuration_warning();
+ update_configuration_warnings();
};
int XRAnchor3D::get_anchor_id() const {
@@ -487,34 +478,26 @@ bool XRAnchor3D::get_is_active() const {
return is_active;
};
-String XRAnchor3D::get_configuration_warning() const {
- if (!is_visible() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> XRAnchor3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- // must be child node of XROrigin3D!
- XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
- if (origin == nullptr) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible() && is_inside_tree()) {
+ // must be child node of XROrigin3D!
+ XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
+ if (origin == nullptr) {
+ warnings.push_back(TTR("XRAnchor3D must have an XROrigin3D node as its parent."));
}
- warning += TTR("XRAnchor3D must have an XROrigin3D node as its parent.");
- };
- if (anchor_id == 0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (anchor_id == 0) {
+ warnings.push_back(TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor."));
}
- warning += TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor.");
- };
+ }
- return warning;
+ return warnings;
};
Plane XRAnchor3D::get_plane() const {
- Vector3 location = get_translation();
+ Vector3 location = get_position();
Basis orientation = get_transform().basis;
Plane plane(location, orientation.get_axis(1).normalized());
@@ -528,21 +511,21 @@ Ref<Mesh> XRAnchor3D::get_mesh() const {
////////////////////////////////////////////////////////////////////////////////////////////////////
-String XROrigin3D::get_configuration_warning() const {
- if (!is_visible() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> XROrigin3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- if (tracked_camera == nullptr) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible() && is_inside_tree()) {
+ if (tracked_camera == nullptr) {
+ warnings.push_back(TTR("XROrigin3D requires an XRCamera3D child node."));
}
- warning += TTR("XROrigin3D requires an XRCamera3D child node.");
}
- return warning;
+ 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;
};
void XROrigin3D::_bind_methods() {
@@ -597,7 +580,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
- Transform t = xr_interface->get_transform_for_eye(XRInterface::EYE_MONO, Transform());
+ 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 7cd6e2ac57..90079f5fe9 100644
--- a/scene/3d/xr_nodes.h
+++ b/scene/3d/xr_nodes.h
@@ -50,7 +50,7 @@ protected:
void _notification(int p_what);
public:
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const override;
virtual Point2 unproject_position(const Vector3 &p_pos) const override;
@@ -97,7 +97,7 @@ public:
Ref<Mesh> get_mesh() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
XRController3D() {}
~XRController3D() {}
@@ -133,7 +133,7 @@ public:
Ref<Mesh> get_mesh() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
XRAnchor3D() {}
~XRAnchor3D() {}
@@ -158,7 +158,7 @@ protected:
static void _bind_methods();
public:
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void set_tracked_camera(XRCamera3D *p_tracked_camera);
void clear_tracked_camera_if(XRCamera3D *p_tracked_camera);