summaryrefslogtreecommitdiff
path: root/scene/3d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d')
-rw-r--r--scene/3d/area_3d.cpp40
-rw-r--r--scene/3d/area_3d.h2
-rw-r--r--scene/3d/audio_stream_player_3d.cpp5
-rw-r--r--scene/3d/baked_lightmap.cpp2
-rw-r--r--scene/3d/baked_lightmap.h2
-rw-r--r--scene/3d/camera_3d.cpp6
-rw-r--r--scene/3d/camera_3d.h2
-rw-r--r--scene/3d/collision_polygon_3d.cpp14
-rw-r--r--scene/3d/collision_shape_3d.cpp49
-rw-r--r--scene/3d/collision_shape_3d.h2
-rw-r--r--scene/3d/cpu_particles_3d.cpp92
-rw-r--r--scene/3d/cpu_particles_3d.h21
-rw-r--r--scene/3d/gi_probe.cpp10
-rw-r--r--scene/3d/gpu_particles_3d.cpp68
-rw-r--r--scene/3d/gpu_particles_3d.h22
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp901
-rw-r--r--scene/3d/gpu_particles_collision_3d.h342
-rw-r--r--scene/3d/light_3d.cpp28
-rw-r--r--scene/3d/light_3d.h5
-rw-r--r--scene/3d/navigation_agent_3d.cpp11
-rw-r--r--scene/3d/navigation_agent_3d.h2
-rw-r--r--scene/3d/navigation_obstacle_3d.cpp9
-rw-r--r--scene/3d/navigation_region_3d.cpp16
-rw-r--r--scene/3d/node_3d.cpp41
-rw-r--r--scene/3d/node_3d.h9
-rw-r--r--scene/3d/path_3d.cpp16
-rw-r--r--scene/3d/path_3d.h1
-rw-r--r--scene/3d/physics_body_3d.cpp53
-rw-r--r--scene/3d/physics_body_3d.h11
-rw-r--r--scene/3d/physics_joint_3d.cpp55
-rw-r--r--scene/3d/physics_joint_3d.h5
-rw-r--r--scene/3d/ray_cast_3d.cpp22
-rw-r--r--scene/3d/ray_cast_3d.h6
-rw-r--r--scene/3d/remote_transform_3d.cpp9
-rw-r--r--scene/3d/skeleton_3d.cpp10
-rw-r--r--scene/3d/skeleton_3d.h3
-rw-r--r--scene/3d/skeleton_ik_3d.h4
-rw-r--r--scene/3d/soft_body_3d.cpp15
-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.cpp18
-rw-r--r--scene/3d/vehicle_body_3d.cpp10
-rw-r--r--scene/3d/velocity_tracker_3d.cpp2
-rw-r--r--scene/3d/visibility_notifier_3d.cpp2
-rw-r--r--scene/3d/visual_instance_3d.h2
-rw-r--r--scene/3d/voxelizer.cpp1
-rw-r--r--scene/3d/world_environment.cpp16
-rw-r--r--scene/3d/xr_nodes.cpp54
48 files changed, 1724 insertions, 296 deletions
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index a024757927..b1ffe76662 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -180,26 +180,20 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
E->get().shapes.erase(ShapePair(p_body_shape, p_area_shape));
}
- bool eraseit = false;
-
+ bool in_tree = E->get().in_tree;
if (E->get().rc == 0) {
+ body_map.erase(E);
if (node) {
node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree));
node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree));
- if (E->get().in_tree) {
+ if (in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_exited, obj);
}
}
-
- eraseit = true;
}
- if (node && E->get().in_tree) {
+ if (node && in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_shape_exited, objid, obj, p_body_shape, p_area_shape);
}
-
- if (eraseit) {
- body_map.erase(E);
- }
}
locked = false;
@@ -222,6 +216,9 @@ void Area3D::_clear_monitoring() {
}
//ERR_CONTINUE(!node);
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree));
+
if (!E->get().in_tree) {
continue;
}
@@ -231,9 +228,6 @@ void Area3D::_clear_monitoring() {
}
emit_signal(SceneStringNames::get_singleton()->body_exited, node);
-
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree));
}
}
@@ -251,6 +245,9 @@ void Area3D::_clear_monitoring() {
}
//ERR_CONTINUE(!node);
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree));
+
if (!E->get().in_tree) {
continue;
}
@@ -260,9 +257,6 @@ void Area3D::_clear_monitoring() {
}
emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
-
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree));
}
}
}
@@ -366,26 +360,20 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
E->get().shapes.erase(AreaShapePair(p_area_shape, p_self_shape));
}
- bool eraseit = false;
-
+ bool in_tree = E->get().in_tree;
if (E->get().rc == 0) {
+ area_map.erase(E);
if (node) {
node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree));
node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree));
- if (E->get().in_tree) {
+ if (in_tree) {
emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
}
}
-
- eraseit = true;
}
- if (!node || E->get().in_tree) {
+ if (!node || in_tree) {
emit_signal(SceneStringNames::get_singleton()->area_shape_exited, objid, obj, p_area_shape, p_self_shape);
}
-
- if (eraseit) {
- area_map.erase(E);
- }
}
locked = false;
diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h
index 07d24f39a7..7d1f030baf 100644
--- a/scene/3d/area_3d.h
+++ b/scene/3d/area_3d.h
@@ -31,7 +31,7 @@
#ifndef AREA_3D_H
#define AREA_3D_H
-#include "core/vset.h"
+#include "core/templates/vset.h"
#include "scene/3d/collision_object_3d.h"
class Area3D : public CollisionObject3D {
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 6e4db8f382..37bc032356 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -30,7 +30,7 @@
#include "audio_stream_player_3d.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
#include "scene/3d/area_3d.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/listener_3d.h"
@@ -327,9 +327,6 @@ float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const {
return att;
}
-void _update_sound() {
-}
-
void AudioStreamPlayer3D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
velocity_tracker->reset(get_global_transform().origin);
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index e867891ec0..38c9e96fbc 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/baked_lightmap.cpp
@@ -37,7 +37,7 @@
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
-#include "core/sort_array.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) {
diff --git a/scene/3d/baked_lightmap.h b/scene/3d/baked_lightmap.h
index bebb579252..8808569215 100644
--- a/scene/3d/baked_lightmap.h
+++ b/scene/3d/baked_lightmap.h
@@ -31,7 +31,7 @@
#ifndef BAKED_LIGHTMAP_H
#define BAKED_LIGHTMAP_H
-#include "core/local_vector.h"
+#include "core/templates/local_vector.h"
#include "scene/3d/light_3d.h"
#include "scene/3d/lightmapper.h"
#include "scene/3d/mesh_instance_3d.h"
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index ecbaca7bd1..191159448a 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -31,7 +31,7 @@
#include "camera_3d.h"
#include "collision_object_3d.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
#include "core/math/camera_matrix.h"
#include "scene/resources/material.h"
#include "scene/resources/surface_tool.h"
@@ -519,8 +519,8 @@ void Camera3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset"), "set_frustum_offset", "get_frustum_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01,or_greater"), "set_znear", "get_znear");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_zfar", "get_zfar");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_EXP_RANGE, "0.001,8192,0.001,or_greater"), "set_znear", "get_znear");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01,or_greater"), "set_zfar", "get_zfar");
BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE);
BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL);
diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h
index 6a778d45a2..04cec92b14 100644
--- a/scene/3d/camera_3d.h
+++ b/scene/3d/camera_3d.h
@@ -42,7 +42,6 @@ class Camera3D : public Node3D {
public:
enum Projection {
-
PROJECTION_PERSPECTIVE,
PROJECTION_ORTHOGONAL,
PROJECTION_FRUSTUM
@@ -103,7 +102,6 @@ protected:
public:
enum {
-
NOTIFICATION_BECAME_CURRENT = 50,
NOTIFICATION_LOST_CURRENT = 51
};
diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp
index e2d11c740a..b8a4ab74ee 100644
--- a/scene/3d/collision_polygon_3d.cpp
+++ b/scene/3d/collision_polygon_3d.cpp
@@ -156,15 +156,23 @@ bool CollisionPolygon3D::is_disabled() const {
}
String CollisionPolygon3D::get_configuration_warning() const {
+ String warning = Node3D::get_configuration_warning();
+
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- return 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.");
+ if (!warning.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.");
}
if (polygon.empty()) {
- return TTR("An empty CollisionPolygon3D has no effect on collision.");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ warning += TTR("An empty CollisionPolygon3D has no effect on collision.");
}
- return String();
+ return warning;
}
bool CollisionPolygon3D::_is_editable_3d_polygon() const {
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
index 56367e9bdd..e1c691b89a 100644
--- a/scene/3d/collision_shape_3d.cpp
+++ b/scene/3d/collision_shape_3d.cpp
@@ -44,23 +44,36 @@
//TODO: Implement CylinderShape and HeightMapShape?
-void CollisionShape3D::make_convex_from_brothers() {
+void CollisionShape3D::make_convex_from_siblings() {
Node *p = get_parent();
if (!p) {
return;
}
+ Vector<Vector3> vertices;
+
for (int i = 0; i < p->get_child_count(); i++) {
Node *n = p->get_child(i);
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(n);
if (mi) {
Ref<Mesh> m = mi->get_mesh();
if (m.is_valid()) {
- Ref<Shape3D> s = m->create_convex_shape();
- set_shape(s);
+ for (int j = 0; j < m->get_surface_count(); j++) {
+ Array a = m->surface_get_arrays(j);
+ if (!a.empty()) {
+ Vector<Vector3> v = a[RenderingServer::ARRAY_VERTEX];
+ for (int k = 0; k < v.size(); k++) {
+ vertices.append(mi->get_transform().xform(v[k]));
+ }
+ }
+ }
}
}
}
+
+ Ref<ConvexPolygonShape3D> shape = memnew(ConvexPolygonShape3D);
+ shape->set_points(vertices);
+ set_shape(shape);
}
void CollisionShape3D::_update_in_shape_owner(bool p_xform_only) {
@@ -111,23 +124,33 @@ void CollisionShape3D::resource_changed(RES res) {
}
String CollisionShape3D::get_configuration_warning() const {
+ String warning = Node3D::get_configuration_warning();
+
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- return 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.");
+ if (!warning.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.");
}
if (!shape.is_valid()) {
- return TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it.");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ warning += TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it.");
}
- if (Object::cast_to<RigidBody3D>(get_parent())) {
- if (Object::cast_to<ConcavePolygonShape3D>(*shape)) {
- if (Object::cast_to<RigidBody3D>(get_parent())->get_mode() != RigidBody3D::MODE_STATIC) {
- return TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static.");
- }
+ 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.empty()) {
+ warning += "\n\n";
}
+ warning += TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static.");
}
- return String();
+ return warning;
}
void CollisionShape3D::_bind_methods() {
@@ -137,8 +160,8 @@ void CollisionShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_shape"), &CollisionShape3D::get_shape);
ClassDB::bind_method(D_METHOD("set_disabled", "enable"), &CollisionShape3D::set_disabled);
ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionShape3D::is_disabled);
- ClassDB::bind_method(D_METHOD("make_convex_from_brothers"), &CollisionShape3D::make_convex_from_brothers);
- ClassDB::set_method_flags("CollisionShape3D", "make_convex_from_brothers", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
+ ClassDB::bind_method(D_METHOD("make_convex_from_siblings"), &CollisionShape3D::make_convex_from_siblings);
+ ClassDB::set_method_flags("CollisionShape3D", "make_convex_from_siblings", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ClassDB::bind_method(D_METHOD("_update_debug_shape"), &CollisionShape3D::_update_debug_shape);
diff --git a/scene/3d/collision_shape_3d.h b/scene/3d/collision_shape_3d.h
index a32a3efeb6..35f40d27b1 100644
--- a/scene/3d/collision_shape_3d.h
+++ b/scene/3d/collision_shape_3d.h
@@ -60,7 +60,7 @@ protected:
static void _bind_methods();
public:
- void make_convex_from_brothers();
+ void make_convex_from_siblings();
void set_shape(const Ref<Shape3D> &p_shape);
Ref<Shape3D> get_shape() const;
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index 4244a11592..215d9e062c 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -39,7 +39,7 @@ AABB CPUParticles3D::get_aabb() const {
return AABB();
}
-Vector<Face3> CPUParticles3D::get_faces(uint32_t p_usage_flags) const {
+Vector<Face3> CPUParticles3D::get_faces(uint32_t p_usage_particle_flags) const {
return Vector<Face3>();
}
@@ -189,7 +189,7 @@ bool CPUParticles3D::get_fractional_delta() const {
}
String CPUParticles3D::get_configuration_warning() const {
- String warnings;
+ String warnings = GeometryInstance3D::get_configuration_warning();
bool mesh_found = false;
bool anim_material_found = false;
@@ -368,17 +368,17 @@ Ref<Gradient> CPUParticles3D::get_color_ramp() const {
return color_ramp;
}
-void CPUParticles3D::set_particle_flag(Flags p_flag, bool p_enable) {
- ERR_FAIL_INDEX(p_flag, FLAG_MAX);
- flags[p_flag] = p_enable;
- if (p_flag == FLAG_DISABLE_Z) {
+void CPUParticles3D::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) {
+ ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX);
+ particle_flags[p_particle_flag] = p_enable;
+ if (p_particle_flag == PARTICLE_FLAG_DISABLE_Z) {
_change_notify();
}
}
-bool CPUParticles3D::get_particle_flag(Flags p_flag) const {
- ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
- return flags[p_flag];
+bool CPUParticles3D::get_particle_flag(ParticleFlags p_particle_flag) const {
+ ERR_FAIL_INDEX_V(p_particle_flag, PARTICLE_FLAG_MAX, false);
+ return particle_flags[p_particle_flag];
}
void CPUParticles3D::set_emission_shape(EmissionShape p_shape) {
@@ -459,7 +459,7 @@ void CPUParticles3D::_validate_property(PropertyInfo &property) const {
property.usage = 0;
}
- if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) {
+ if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
property.usage = 0;
}
}
@@ -675,7 +675,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
p.hue_rot_rand = Math::randf();
p.anim_offset_rand = Math::randf();
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
float angle1_rad = Math::atan2(direction.y, direction.x) + (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0;
Vector3 rot = Vector3(Math::cos(angle1_rad), Math::sin(angle1_rad), 0.0);
p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
@@ -725,14 +725,16 @@ void CPUParticles3D::_particles_process(float p_delta) {
p.transform.origin = emission_points.get(random_idx);
if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS && emission_normals.size() == pc) {
- if (flags[FLAG_DISABLE_Z]) {
- /*
- mat2 rotm;
- ";
- rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;
- rotm[1] = rotm[0].yx * vec2(1.0, -1.0);
- VELOCITY.xy = rotm * VELOCITY.xy;
- */
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
+ Vector3 normal = emission_normals.get(random_idx);
+ Vector2 normal_2d(normal.x, normal.y);
+ Transform2D m2;
+ m2.set_axis(0, normal_2d);
+ m2.set_axis(1, normal_2d.tangent());
+ Vector2 velocity_2d(p.velocity.x, p.velocity.y);
+ velocity_2d = m2.basis_xform(velocity_2d);
+ p.velocity.x = velocity_2d.x;
+ p.velocity.y = velocity_2d.y;
} else {
Vector3 normal = emission_normals.get(random_idx);
Vector3 v0 = Math::abs(normal.z) < 0.999 ? Vector3(0.0, 0.0, 1.0) : Vector3(0, 1.0, 0.0);
@@ -760,7 +762,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
p.transform = emission_xform * p.transform;
}
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
p.velocity.z = 0.0;
p.transform.origin.z = 0.0;
}
@@ -781,7 +783,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
}
float tex_orbit_velocity = 0.0;
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(p.custom[1]);
}
@@ -828,7 +830,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
Vector3 force = gravity;
Vector3 position = p.transform.origin;
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
position.z = 0.0;
}
//apply linear acceleration
@@ -838,7 +840,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
Vector3 diff = position - org;
force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector3();
//apply tangential acceleration;
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
Vector2 yx = Vector2(diff.y, diff.x);
Vector2 yx2 = (yx * Vector2(-1.0, 1.0)).normalized();
force += yx.length() > 0.0 ? Vector3(yx2.x, yx2.y, 0.0) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3();
@@ -850,7 +852,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
//apply attractor forces
p.velocity += force * local_delta;
//orbit velocity
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
float orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]);
if (orbit_amount != 0.0) {
float ang = orbit_amount * local_delta * Math_PI * 2.0;
@@ -921,8 +923,8 @@ void CPUParticles3D::_particles_process(float p_delta) {
p.color *= p.base_color;
- if (flags[FLAG_DISABLE_Z]) {
- if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) {
if (p.velocity.length() > 0.0) {
p.transform.basis.set_axis(1, p.velocity.normalized());
} else {
@@ -939,7 +941,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
} else {
//orient particle Y towards velocity
- if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
+ if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) {
if (p.velocity.length() > 0.0) {
p.transform.basis.set_axis(1, p.velocity.normalized());
} else {
@@ -957,7 +959,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
}
//turn particle by rotation in Y
- if (flags[FLAG_ROTATE_Y]) {
+ if (particle_flags[PARTICLE_FLAG_ROTATE_Y]) {
Basis rot_y(Vector3(0, 1, 0), p.custom[0]);
p.transform.basis = p.transform.basis * rot_y;
}
@@ -971,7 +973,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
p.transform.basis.scale(Vector3(1, 1, 1) * base_scale);
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
p.velocity.z = 0.0;
p.transform.origin.z = 0.0;
}
@@ -1197,9 +1199,9 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) {
set_color_ramp(gt->get_gradient());
}
- set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY));
- set_particle_flag(FLAG_ROTATE_Y, material->get_flag(ParticlesMaterial::FLAG_ROTATE_Y));
- set_particle_flag(FLAG_DISABLE_Z, material->get_flag(ParticlesMaterial::FLAG_DISABLE_Z));
+ set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY));
+ set_particle_flag(PARTICLE_FLAG_ROTATE_Y, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ROTATE_Y));
+ set_particle_flag(PARTICLE_FLAG_DISABLE_Z, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_DISABLE_Z));
set_emission_shape(EmissionShape(material->get_emission_shape()));
set_emission_sphere_radius(material->get_emission_sphere_radius());
@@ -1316,8 +1318,8 @@ void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &CPUParticles3D::set_color_ramp);
ClassDB::bind_method(D_METHOD("get_color_ramp"), &CPUParticles3D::get_color_ramp);
- ClassDB::bind_method(D_METHOD("set_particle_flag", "flag", "enable"), &CPUParticles3D::set_particle_flag);
- ClassDB::bind_method(D_METHOD("get_particle_flag", "flag"), &CPUParticles3D::get_particle_flag);
+ ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &CPUParticles3D::set_particle_flag);
+ ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &CPUParticles3D::get_particle_flag);
ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &CPUParticles3D::set_emission_shape);
ClassDB::bind_method(D_METHOD("get_emission_shape"), &CPUParticles3D::get_emission_shape);
@@ -1343,16 +1345,16 @@ void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles3D::convert_from_particles);
ADD_GROUP("Emission Shape", "emission_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_points"), "set_emission_points", "get_emission_points");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors");
- ADD_GROUP("Flags", "flag_");
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_particle_flag", "get_particle_flag", FLAG_ALIGN_Y_TO_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_particle_flag", "get_particle_flag", FLAG_ROTATE_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_disable_z"), "set_particle_flag", "get_particle_flag", FLAG_DISABLE_Z);
+ ADD_GROUP("Particle Flags", "particle_flag_");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_rotate_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ROTATE_Y);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_disable_z"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_DISABLE_Z);
ADD_GROUP("Direction", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "direction"), "set_direction", "get_direction");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread");
@@ -1424,10 +1426,10 @@ void CPUParticles3D::_bind_methods() {
BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET);
BIND_ENUM_CONSTANT(PARAM_MAX);
- BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY);
- BIND_ENUM_CONSTANT(FLAG_ROTATE_Y);
- BIND_ENUM_CONSTANT(FLAG_DISABLE_Z);
- BIND_ENUM_CONSTANT(FLAG_MAX);
+ BIND_ENUM_CONSTANT(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY);
+ BIND_ENUM_CONSTANT(PARTICLE_FLAG_ROTATE_Y);
+ BIND_ENUM_CONSTANT(PARTICLE_FLAG_DISABLE_Z);
+ BIND_ENUM_CONSTANT(PARTICLE_FLAG_MAX);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE);
@@ -1491,8 +1493,8 @@ CPUParticles3D::CPUParticles3D() {
set_param_randomness(Parameter(i), 0);
}
- for (int i = 0; i < FLAG_MAX; i++) {
- flags[i] = false;
+ for (int i = 0; i < PARTICLE_FLAG_MAX; i++) {
+ particle_flags[i] = false;
}
can_update = false;
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index f44d0dfcfa..8c1b8a684c 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -31,7 +31,7 @@
#ifndef CPU_PARTICLES_H
#define CPU_PARTICLES_H
-#include "core/rid.h"
+#include "core/templates/rid.h"
#include "scene/3d/visual_instance_3d.h"
class CPUParticles3D : public GeometryInstance3D {
@@ -46,7 +46,6 @@ public:
};
enum Parameter {
-
PARAM_INITIAL_LINEAR_VELOCITY,
PARAM_ANGULAR_VELOCITY,
PARAM_ORBIT_VELOCITY,
@@ -62,11 +61,11 @@ public:
PARAM_MAX
};
- enum Flags {
- FLAG_ALIGN_Y_TO_VELOCITY,
- FLAG_ROTATE_Y,
- FLAG_DISABLE_Z,
- FLAG_MAX
+ enum ParticleFlags {
+ PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY,
+ PARTICLE_FLAG_ROTATE_Y,
+ PARTICLE_FLAG_DISABLE_Z,
+ PARTICLE_FLAG_MAX
};
enum EmissionShape {
@@ -161,7 +160,7 @@ private:
Color color;
Ref<Gradient> color_ramp;
- bool flags[FLAG_MAX];
+ bool particle_flags[PARTICLE_FLAG_MAX];
EmissionShape emission_shape;
float emission_sphere_radius;
@@ -257,8 +256,8 @@ public:
void set_color_ramp(const Ref<Gradient> &p_ramp);
Ref<Gradient> get_color_ramp() const;
- void set_particle_flag(Flags p_flag, bool p_enable);
- bool get_particle_flag(Flags p_flag) const;
+ void set_particle_flag(ParticleFlags p_particle_flag, bool p_enable);
+ bool get_particle_flag(ParticleFlags p_particle_flag) const;
void set_emission_shape(EmissionShape p_shape);
void set_emission_sphere_radius(float p_radius);
@@ -291,7 +290,7 @@ public:
VARIANT_ENUM_CAST(CPUParticles3D::DrawOrder)
VARIANT_ENUM_CAST(CPUParticles3D::Parameter)
-VARIANT_ENUM_CAST(CPUParticles3D::Flags)
+VARIANT_ENUM_CAST(CPUParticles3D::ParticleFlags)
VARIANT_ENUM_CAST(CPUParticles3D::EmissionShape)
#endif // CPU_PARTICLES_H
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp
index 1b6f9b45b9..fd592012f8 100644
--- a/scene/3d/gi_probe.cpp
+++ b/scene/3d/gi_probe.cpp
@@ -32,7 +32,6 @@
#include "core/os/os.h"
-#include "core/method_bind_ext.gen.inc"
#include "mesh_instance_3d.h"
#include "voxelizer.h"
@@ -514,10 +513,15 @@ Vector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const {
}
String GIProbe::get_configuration_warning() const {
+ String warning = VisualInstance3D::get_configuration_warning();
+
if (RenderingServer::get_singleton()->is_low_end()) {
- return TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead.");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ warning += TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead.");
}
- return String();
+ return warning;
}
void GIProbe::_bind_methods() {
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index c4480e3ed2..ec33d7bcab 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -124,6 +124,11 @@ void GPUParticles3D::set_speed_scale(float p_scale) {
RS::get_singleton()->particles_set_speed_scale(particles, p_scale);
}
+void GPUParticles3D::set_collision_base_size(float p_size) {
+ collision_base_size = p_size;
+ RS::get_singleton()->particles_set_collision_base_size(particles, p_size);
+}
+
bool GPUParticles3D::is_emitting() const {
return RS::get_singleton()->particles_get_emitting(particles);
}
@@ -168,6 +173,10 @@ float GPUParticles3D::get_speed_scale() const {
return speed_scale;
}
+float GPUParticles3D::get_collision_base_size() const {
+ return collision_base_size;
+}
+
void GPUParticles3D::set_draw_order(DrawOrder p_order) {
draw_order = p_order;
RS::get_singleton()->particles_set_draw_order(particles, RS::ParticlesDrawOrder(p_order));
@@ -232,7 +241,7 @@ String GPUParticles3D::get_configuration_warning() const {
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.");
}
- String warnings;
+ String warnings = GeometryInstance3D::get_configuration_warning();
bool meshes_found = false;
bool anim_material_found = false;
@@ -301,6 +310,36 @@ 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) {
+ RS::get_singleton()->particles_emit(particles, p_transform, p_velocity, p_color, p_custom, p_emit_flags);
+}
+
+void GPUParticles3D::_attach_sub_emitter() {
+ Node *n = get_node_or_null(sub_emitter);
+ if (n) {
+ GPUParticles3D *sen = Object::cast_to<GPUParticles3D>(n);
+ if (sen && sen != this) {
+ RS::get_singleton()->particles_set_subemitter(particles, sen->particles);
+ }
+ }
+}
+
+void GPUParticles3D::set_sub_emitter(const NodePath &p_path) {
+ if (is_inside_tree()) {
+ RS::get_singleton()->particles_set_subemitter(particles, RID());
+ }
+
+ sub_emitter = p_path;
+
+ if (is_inside_tree() && sub_emitter != NodePath()) {
+ _attach_sub_emitter();
+ }
+}
+
+NodePath GPUParticles3D::get_sub_emitter() const {
+ return sub_emitter;
+}
+
void GPUParticles3D::_notification(int p_what) {
if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) {
if (can_process()) {
@@ -319,6 +358,16 @@ void GPUParticles3D::_notification(int p_what) {
}
}
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ if (sub_emitter != NodePath()) {
+ _attach_sub_emitter();
+ }
+ }
+
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+ RS::get_singleton()->particles_set_subemitter(particles, RID());
+ }
+
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
// make sure particles are updated before rendering occurs if they were active before
if (is_visible_in_tree() && !RS::get_singleton()->particles_is_inactive(particles)) {
@@ -341,6 +390,7 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &GPUParticles3D::set_fractional_delta);
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);
ClassDB::bind_method(D_METHOD("is_emitting"), &GPUParticles3D::is_emitting);
ClassDB::bind_method(D_METHOD("get_amount"), &GPUParticles3D::get_amount);
@@ -355,6 +405,7 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_fractional_delta"), &GPUParticles3D::get_fractional_delta);
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);
ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &GPUParticles3D::set_draw_order);
@@ -369,8 +420,14 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("restart"), &GPUParticles3D::restart);
ClassDB::bind_method(D_METHOD("capture_aabb"), &GPUParticles3D::capture_aabb);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter", "path"), &GPUParticles3D::set_sub_emitter);
+ ClassDB::bind_method(D_METHOD("get_sub_emitter"), &GPUParticles3D::get_sub_emitter);
+
+ ClassDB::bind_method(D_METHOD("emit_particle", "xform", "velocity", "color", "custom", "flags"), &GPUParticles3D::emit_particle);
+
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");
ADD_GROUP("Time", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
@@ -380,6 +437,8 @@ void GPUParticles3D::_bind_methods() {
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, "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");
@@ -396,6 +455,12 @@ void GPUParticles3D::_bind_methods() {
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
BIND_ENUM_CONSTANT(DRAW_ORDER_VIEW_DEPTH);
+ BIND_ENUM_CONSTANT(EMIT_FLAG_POSITION);
+ BIND_ENUM_CONSTANT(EMIT_FLAG_ROTATION_SCALE);
+ BIND_ENUM_CONSTANT(EMIT_FLAG_VELOCITY);
+ BIND_ENUM_CONSTANT(EMIT_FLAG_COLOR);
+ BIND_ENUM_CONSTANT(EMIT_FLAG_CUSTOM);
+
BIND_CONSTANT(MAX_DRAW_PASSES);
}
@@ -417,6 +482,7 @@ GPUParticles3D::GPUParticles3D() {
set_draw_passes(1);
set_draw_order(DRAW_ORDER_INDEX);
set_speed_scale(1);
+ set_collision_base_size(0.01);
}
GPUParticles3D::~GPUParticles3D() {
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index e04473727d..f0e5f05e5b 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -31,7 +31,7 @@
#ifndef PARTICLES_H
#define PARTICLES_H
-#include "core/rid.h"
+#include "core/templates/rid.h"
#include "scene/3d/visual_instance_3d.h"
#include "scene/resources/material.h"
@@ -64,6 +64,8 @@ private:
bool local_coords;
int fixed_fps;
bool fractional_delta;
+ NodePath sub_emitter;
+ float collision_base_size;
Ref<Material> process_material;
@@ -71,6 +73,8 @@ private:
Vector<Ref<Mesh>> draw_passes;
+ void _attach_sub_emitter();
+
protected:
static void _bind_methods();
void _notification(int p_what);
@@ -91,6 +95,7 @@ public:
void set_use_local_coordinates(bool p_enable);
void set_process_material(const Ref<Material> &p_material);
void set_speed_scale(float p_scale);
+ void set_collision_base_size(float p_ratio);
bool is_emitting() const;
int get_amount() const;
@@ -103,6 +108,7 @@ public:
bool get_use_local_coordinates() const;
Ref<Material> get_process_material() const;
float get_speed_scale() const;
+ float get_collision_base_size() const;
void set_fixed_fps(int p_count);
int get_fixed_fps() const;
@@ -121,13 +127,27 @@ public:
virtual String get_configuration_warning() const override;
+ void set_sub_emitter(const NodePath &p_path);
+ NodePath get_sub_emitter() const;
+
void restart();
+ enum EmitFlags {
+ EMIT_FLAG_POSITION = RS::PARTICLES_EMIT_FLAG_POSITION,
+ EMIT_FLAG_ROTATION_SCALE = RS::PARTICLES_EMIT_FLAG_ROTATION_SCALE,
+ EMIT_FLAG_VELOCITY = RS::PARTICLES_EMIT_FLAG_VELOCITY,
+ EMIT_FLAG_COLOR = RS::PARTICLES_EMIT_FLAG_COLOR,
+ 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);
+
AABB capture_aabb() const;
GPUParticles3D();
~GPUParticles3D();
};
VARIANT_ENUM_CAST(GPUParticles3D::DrawOrder)
+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
new file mode 100644
index 0000000000..1f0d5d587d
--- /dev/null
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -0,0 +1,901 @@
+/*************************************************************************/
+/* gpu_particles_collision_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "gpu_particles_collision_3d.h"
+
+#include "core/templates/thread_work_pool.h"
+#include "mesh_instance_3d.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/main/viewport.h"
+
+void GPUParticlesCollision3D::set_cull_mask(uint32_t p_cull_mask) {
+ cull_mask = p_cull_mask;
+ RS::get_singleton()->particles_collision_set_cull_mask(collision, p_cull_mask);
+}
+
+uint32_t GPUParticlesCollision3D::get_cull_mask() const {
+ return cull_mask;
+}
+
+void GPUParticlesCollision3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_cull_mask", "mask"), &GPUParticlesCollision3D::set_cull_mask);
+ ClassDB::bind_method(D_METHOD("get_cull_mask"), &GPUParticlesCollision3D::get_cull_mask);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
+}
+
+GPUParticlesCollision3D::GPUParticlesCollision3D(RS::ParticlesCollisionType p_type) {
+ collision = RS::get_singleton()->particles_collision_create();
+ RS::get_singleton()->particles_collision_set_collision_type(collision, p_type);
+ set_base(collision);
+}
+
+GPUParticlesCollision3D::~GPUParticlesCollision3D() {
+ RS::get_singleton()->free(collision);
+}
+
+/////////////////////////////////
+
+void GPUParticlesCollisionSphere::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_radius", "radius"), &GPUParticlesCollisionSphere::set_radius);
+ ClassDB::bind_method(D_METHOD("get_radius"), &GPUParticlesCollisionSphere::get_radius);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_radius", "get_radius");
+}
+
+void GPUParticlesCollisionSphere::set_radius(float p_radius) {
+ radius = p_radius;
+ RS::get_singleton()->particles_collision_set_sphere_radius(_get_collision(), radius);
+ update_gizmo();
+}
+
+float GPUParticlesCollisionSphere::get_radius() const {
+ return radius;
+}
+
+AABB GPUParticlesCollisionSphere::get_aabb() const {
+ return AABB(Vector3(-radius, -radius, -radius), Vector3(radius * 2, radius * 2, radius * 2));
+}
+
+GPUParticlesCollisionSphere::GPUParticlesCollisionSphere() :
+ GPUParticlesCollision3D(RS::PARTICLES_COLLISION_TYPE_SPHERE_COLLIDE) {
+}
+
+GPUParticlesCollisionSphere::~GPUParticlesCollisionSphere() {
+}
+
+///////////////////////////
+
+void GPUParticlesCollisionBox::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesCollisionBox::set_extents);
+ ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesCollisionBox::get_extents);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_extents", "get_extents");
+}
+
+void GPUParticlesCollisionBox::set_extents(const Vector3 &p_extents) {
+ extents = p_extents;
+ RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents);
+ update_gizmo();
+}
+
+Vector3 GPUParticlesCollisionBox::get_extents() const {
+ return extents;
+}
+
+AABB GPUParticlesCollisionBox::get_aabb() const {
+ return AABB(-extents, extents * 2);
+}
+
+GPUParticlesCollisionBox::GPUParticlesCollisionBox() :
+ GPUParticlesCollision3D(RS::PARTICLES_COLLISION_TYPE_BOX_COLLIDE) {
+}
+
+GPUParticlesCollisionBox::~GPUParticlesCollisionBox() {
+}
+
+///////////////////////////////
+///////////////////////////
+
+void GPUParticlesCollisionSDF::_find_meshes(const AABB &p_aabb, Node *p_at_node, List<PlotMesh> &plot_meshes) {
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node);
+ if (mi && mi->is_visible_in_tree()) {
+ 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();
+
+ if (p_aabb.intersects(xf.xform(aabb))) {
+ PlotMesh pm;
+ pm.local_xform = xf;
+ pm.mesh = mesh;
+ plot_meshes.push_back(pm);
+ }
+ }
+ }
+
+ Node3D *s = Object::cast_to<Node3D>(p_at_node);
+ if (s) {
+ 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];
+ Ref<Mesh> mesh = meshes[i + 1];
+ if (!mesh.is_valid()) {
+ continue;
+ }
+
+ AABB aabb = mesh->get_aabb();
+
+ Transform xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf);
+
+ if (p_aabb.intersects(xf.xform(aabb))) {
+ PlotMesh pm;
+ pm.local_xform = xf;
+ pm.mesh = mesh;
+ plot_meshes.push_back(pm);
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < p_at_node->get_child_count(); i++) {
+ Node *child = p_at_node->get_child(i);
+ _find_meshes(p_aabb, child, plot_meshes);
+ }
+}
+
+uint32_t GPUParticlesCollisionSDF::_create_bvh(LocalVector<BVH> &bvh_tree, FacePos *p_faces, uint32_t p_face_count, const Face3 *p_triangles, float p_thickness) {
+ if (p_face_count == 1) {
+ return BVH::LEAF_BIT | p_faces[0].index;
+ }
+
+ uint32_t index = bvh_tree.size();
+ {
+ BVH bvh;
+
+ for (uint32_t i = 0; i < p_face_count; i++) {
+ const Face3 &f = p_triangles[p_faces[i].index];
+ AABB aabb(f.vertex[0], Vector3());
+ aabb.expand_to(f.vertex[1]);
+ aabb.expand_to(f.vertex[2]);
+ if (p_thickness > 0.0) {
+ Vector3 normal = p_triangles[p_faces[i].index].get_plane().normal;
+ aabb.expand_to(f.vertex[0] - normal * p_thickness);
+ aabb.expand_to(f.vertex[1] - normal * p_thickness);
+ aabb.expand_to(f.vertex[2] - normal * p_thickness);
+ }
+ if (i == 0) {
+ bvh.bounds = aabb;
+ } else {
+ bvh.bounds.merge_with(aabb);
+ }
+ }
+ bvh_tree.push_back(bvh);
+ }
+
+ uint32_t middle = p_face_count / 2;
+
+ SortArray<FacePos, FaceSort> s;
+ s.compare.axis = bvh_tree[index].bounds.get_longest_axis_index();
+ s.sort(p_faces, p_face_count);
+
+ uint32_t left = _create_bvh(bvh_tree, p_faces, middle, p_triangles, p_thickness);
+ uint32_t right = _create_bvh(bvh_tree, p_faces + middle, p_face_count - middle, p_triangles, p_thickness);
+
+ bvh_tree[index].children[0] = left;
+ bvh_tree[index].children[1] = right;
+
+ return index;
+}
+
+static _FORCE_INLINE_ float Vector3_dot2(const Vector3 &p_vec3) {
+ return p_vec3.dot(p_vec3);
+}
+
+void GPUParticlesCollisionSDF::_find_closest_distance(const Vector3 &p_pos, const BVH *bvh, uint32_t p_bvh_cell, const Face3 *triangles, float thickness, float &closest_distance) {
+ if (p_bvh_cell & BVH::LEAF_BIT) {
+ p_bvh_cell &= BVH::LEAF_MASK; //remove bit
+
+ Vector3 point = p_pos;
+ Plane p = triangles[p_bvh_cell].get_plane();
+ float d = p.distance_to(point);
+ float inside_d = 1e20;
+ if (d < 0 && d > -thickness) {
+ //inside planes, do this in 2D
+
+ Vector3 x_axis = (triangles[p_bvh_cell].vertex[0] - triangles[p_bvh_cell].vertex[1]).normalized();
+ Vector3 y_axis = p.normal.cross(x_axis).normalized();
+
+ Vector2 points[3];
+ for (int i = 0; i < 3; i++) {
+ points[i] = Vector2(x_axis.dot(triangles[p_bvh_cell].vertex[i]), y_axis.dot(triangles[p_bvh_cell].vertex[i]));
+ }
+
+ Vector2 p2d = Vector2(x_axis.dot(point), y_axis.dot(point));
+
+ {
+ // https://www.shadertoy.com/view/XsXSz4
+
+ Vector2 e0 = points[1] - points[0];
+ Vector2 e1 = points[2] - points[1];
+ Vector2 e2 = points[0] - points[2];
+
+ Vector2 v0 = p2d - points[0];
+ Vector2 v1 = p2d - points[1];
+ Vector2 v2 = p2d - points[2];
+
+ Vector2 pq0 = v0 - e0 * CLAMP(v0.dot(e0) / e0.dot(e0), 0.0, 1.0);
+ Vector2 pq1 = v1 - e1 * CLAMP(v1.dot(e1) / e1.dot(e1), 0.0, 1.0);
+ Vector2 pq2 = v2 - e2 * CLAMP(v2.dot(e2) / e2.dot(e2), 0.0, 1.0);
+
+ float s = SGN(e0.x * e2.y - e0.y * e2.x);
+ Vector2 d2 = Vector2(pq0.dot(pq0), s * (v0.x * e0.y - v0.y * e0.x)).min(Vector2(pq1.dot(pq1), s * (v1.x * e1.y - v1.y * e1.x))).min(Vector2(pq2.dot(pq2), s * (v2.x * e2.y - v2.y * e2.x)));
+
+ inside_d = -Math::sqrt(d2.x) * SGN(d2.y);
+ }
+
+ //make sure distance to planes is not shorter if inside
+ if (inside_d < 0) {
+ inside_d = MAX(inside_d, d);
+ inside_d = MAX(inside_d, -(thickness + d));
+ }
+
+ closest_distance = MIN(closest_distance, inside_d);
+ } else {
+ if (d < 0) {
+ point -= p.normal * thickness; //flatten
+ }
+
+ // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm
+ Vector3 a = triangles[p_bvh_cell].vertex[0];
+ Vector3 b = triangles[p_bvh_cell].vertex[1];
+ Vector3 c = triangles[p_bvh_cell].vertex[2];
+
+ Vector3 ba = b - a;
+ Vector3 pa = point - a;
+ Vector3 cb = c - b;
+ Vector3 pb = point - b;
+ Vector3 ac = a - c;
+ Vector3 pc = point - c;
+ Vector3 nor = ba.cross(ac);
+
+ inside_d = Math::sqrt(
+ (SGN(ba.cross(nor).dot(pa)) +
+ SGN(cb.cross(nor).dot(pb)) +
+ SGN(ac.cross(nor).dot(pc)) <
+ 2.0) ?
+ MIN(MIN(
+ Vector3_dot2(ba * CLAMP(ba.dot(pa) / Vector3_dot2(ba), 0.0, 1.0) - pa),
+ Vector3_dot2(cb * CLAMP(cb.dot(pb) / Vector3_dot2(cb), 0.0, 1.0) - pb)),
+ Vector3_dot2(ac * CLAMP(ac.dot(pc) / Vector3_dot2(ac), 0.0, 1.0) - pc)) :
+ nor.dot(pa) * nor.dot(pa) / Vector3_dot2(nor));
+
+ closest_distance = MIN(closest_distance, inside_d);
+ }
+
+ } else {
+ bool pass = true;
+ if (!bvh[p_bvh_cell].bounds.has_point(p_pos)) {
+ //outside, find closest point
+ Vector3 he = bvh[p_bvh_cell].bounds.size * 0.5;
+ Vector3 center = bvh[p_bvh_cell].bounds.position + he;
+
+ Vector3 rel = (p_pos - center).abs();
+ Vector3 closest(MIN(rel.x, he.x), MIN(rel.y, he.y), MIN(rel.z, he.z));
+ float d = rel.distance_to(closest);
+
+ if (d >= closest_distance) {
+ pass = false; //already closer than this aabb, discard
+ }
+ }
+
+ if (pass) {
+ _find_closest_distance(p_pos, bvh, bvh[p_bvh_cell].children[0], triangles, thickness, closest_distance);
+ _find_closest_distance(p_pos, bvh, bvh[p_bvh_cell].children[1], triangles, thickness, closest_distance);
+ }
+ }
+}
+
+void GPUParticlesCollisionSDF::_compute_sdf_z(uint32_t p_z, ComputeSDFParams *params) {
+ int32_t z_ofs = p_z * params->size.y * params->size.x;
+ for (int32_t y = 0; y < params->size.y; y++) {
+ int32_t y_ofs = z_ofs + y * params->size.x;
+ for (int32_t x = 0; x < params->size.x; x++) {
+ int32_t x_ofs = y_ofs + x;
+ float &cell = params->cells[x_ofs];
+
+ Vector3 pos = params->cell_offset + Vector3(x, y, p_z) * params->cell_size;
+
+ cell = 1e20;
+
+ _find_closest_distance(pos, params->bvh, 0, params->triangles, params->thickness, cell);
+ }
+ }
+}
+
+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) {
+ OS::get_singleton()->delay_usec(10000);
+ bake_step_function(work_pool.get_work_index() * 100 / params->size.z, "Baking SDF");
+ }
+ work_pool.end_work();
+ work_pool.finish();
+}
+
+Vector3i GPUParticlesCollisionSDF::get_estimated_cell_size() const {
+ static const int subdivs[RESOLUTION_MAX] = { 16, 32, 64, 128, 256, 512 };
+ int subdiv = subdivs[get_resolution()];
+
+ AABB aabb(-extents, extents * 2);
+
+ float cell_size = aabb.get_longest_axis_size() / float(subdiv);
+
+ Vector3i sdf_size = Vector3i(aabb.size / cell_size);
+ sdf_size.x = MAX(1, sdf_size.x);
+ sdf_size.y = MAX(1, sdf_size.y);
+ sdf_size.z = MAX(1, sdf_size.z);
+ return sdf_size;
+}
+
+Ref<Image> GPUParticlesCollisionSDF::bake() {
+ static const int subdivs[RESOLUTION_MAX] = { 16, 32, 64, 128, 256, 512 };
+ int subdiv = subdivs[get_resolution()];
+
+ AABB aabb(-extents, extents * 2);
+
+ float cell_size = aabb.get_longest_axis_size() / float(subdiv);
+
+ Vector3i sdf_size = Vector3i(aabb.size / cell_size);
+ sdf_size.x = MAX(1, sdf_size.x);
+ sdf_size.y = MAX(1, sdf_size.y);
+ sdf_size.z = MAX(1, sdf_size.z);
+
+ if (bake_begin_function) {
+ bake_begin_function(100);
+ }
+
+ aabb.size = Vector3(sdf_size) * cell_size;
+
+ List<PlotMesh> plot_meshes;
+ _find_meshes(aabb, get_parent(), plot_meshes);
+
+ LocalVector<Face3> faces;
+
+ if (bake_step_function) {
+ bake_step_function(0, "Finding Meshes");
+ }
+
+ for (List<PlotMesh>::Element *E = plot_meshes.front(); E; E = E->next()) {
+ const PlotMesh &pm = E->get();
+
+ for (int i = 0; i < pm.mesh->get_surface_count(); i++) {
+ if (pm.mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
+ continue; //only triangles
+ }
+
+ Array a = pm.mesh->surface_get_arrays(i);
+
+ Vector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
+ const Vector3 *vr = vertices.ptr();
+ Vector<int> index = a[Mesh::ARRAY_INDEX];
+
+ if (index.size()) {
+ int facecount = index.size() / 3;
+ const int *ir = index.ptr();
+
+ for (int j = 0; j < facecount; j++) {
+ Face3 face;
+
+ for (int k = 0; k < 3; k++) {
+ face.vertex[k] = pm.local_xform.xform(vr[ir[j * 3 + k]]);
+ }
+
+ //test against original bounds
+ if (!Geometry3D::triangle_box_overlap(aabb.position + aabb.size * 0.5, aabb.size * 0.5, face.vertex)) {
+ continue;
+ }
+
+ faces.push_back(face);
+ }
+
+ } else {
+ int facecount = vertices.size() / 3;
+
+ for (int j = 0; j < facecount; j++) {
+ Face3 face;
+
+ for (int k = 0; k < 3; k++) {
+ face.vertex[k] = pm.local_xform.xform(vr[j * 3 + k]);
+ }
+
+ //test against original bounds
+ if (!Geometry3D::triangle_box_overlap(aabb.position + aabb.size * 0.5, aabb.size * 0.5, face.vertex)) {
+ continue;
+ }
+
+ faces.push_back(face);
+ }
+ }
+ }
+ }
+
+ //compute bvh
+
+ ERR_FAIL_COND_V(faces.size() <= 1, Ref<Image>());
+
+ LocalVector<FacePos> face_pos;
+
+ face_pos.resize(faces.size());
+
+ float th = cell_size * thickness;
+
+ for (uint32_t i = 0; i < faces.size(); i++) {
+ face_pos[i].index = i;
+ face_pos[i].center = (faces[i].vertex[0] + faces[i].vertex[1] + faces[i].vertex[2]) / 2;
+ if (th > 0.0) {
+ face_pos[i].center -= faces[i].get_plane().normal * th * 0.5;
+ }
+ }
+
+ if (bake_step_function) {
+ bake_step_function(0, "Creating BVH");
+ }
+
+ LocalVector<BVH> bvh;
+
+ _create_bvh(bvh, face_pos.ptr(), face_pos.size(), faces.ptr(), th);
+
+ Vector<uint8_t> data;
+ data.resize(sdf_size.z * sdf_size.y * sdf_size.x * sizeof(float));
+
+ if (bake_step_function) {
+ bake_step_function(0, "Baking SDF");
+ }
+
+ ComputeSDFParams params;
+ params.cells = (float *)data.ptrw();
+ params.size = sdf_size;
+ params.cell_size = cell_size;
+ params.cell_offset = aabb.position + Vector3(cell_size * 0.5, cell_size * 0.5, cell_size * 0.5);
+ params.bvh = bvh.ptr();
+ params.triangles = faces.ptr();
+ params.thickness = th;
+ _compute_sdf(&params);
+
+ Ref<Image> ret;
+ ret.instance();
+ ret->create(sdf_size.x, sdf_size.y * sdf_size.z, false, Image::FORMAT_RF, data);
+ ret->convert(Image::FORMAT_RH); //convert to half, save space
+ ret->set_meta("depth", sdf_size.z); //hack, make sure to add to the docs of this function
+
+ if (bake_end_function) {
+ bake_end_function();
+ }
+
+ return ret;
+}
+
+void GPUParticlesCollisionSDF::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesCollisionSDF::set_extents);
+ ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesCollisionSDF::get_extents);
+
+ ClassDB::bind_method(D_METHOD("set_resolution", "resolution"), &GPUParticlesCollisionSDF::set_resolution);
+ ClassDB::bind_method(D_METHOD("get_resolution"), &GPUParticlesCollisionSDF::get_resolution);
+
+ ClassDB::bind_method(D_METHOD("set_texture", "texture"), &GPUParticlesCollisionSDF::set_texture);
+ ClassDB::bind_method(D_METHOD("get_texture"), &GPUParticlesCollisionSDF::get_texture);
+
+ ClassDB::bind_method(D_METHOD("set_thickness", "thickness"), &GPUParticlesCollisionSDF::set_thickness);
+ ClassDB::bind_method(D_METHOD("get_thickness"), &GPUParticlesCollisionSDF::get_thickness);
+
+ 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, "16,32,64,128,256,512"), "set_resolution", "get_resolution");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "thickness", PROPERTY_HINT_RANGE, "0.0,2.0,0.01"), "set_thickness", "get_thickness");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture");
+
+ BIND_ENUM_CONSTANT(RESOLUTION_16);
+ BIND_ENUM_CONSTANT(RESOLUTION_32);
+ BIND_ENUM_CONSTANT(RESOLUTION_64);
+ BIND_ENUM_CONSTANT(RESOLUTION_128);
+ BIND_ENUM_CONSTANT(RESOLUTION_256);
+ BIND_ENUM_CONSTANT(RESOLUTION_512);
+ BIND_ENUM_CONSTANT(RESOLUTION_MAX);
+}
+
+void GPUParticlesCollisionSDF::set_thickness(float p_thickness) {
+ thickness = p_thickness;
+}
+
+float GPUParticlesCollisionSDF::get_thickness() const {
+ return thickness;
+}
+
+void GPUParticlesCollisionSDF::set_extents(const Vector3 &p_extents) {
+ extents = p_extents;
+ RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents);
+ update_gizmo();
+}
+
+Vector3 GPUParticlesCollisionSDF::get_extents() const {
+ return extents;
+}
+
+void GPUParticlesCollisionSDF::set_resolution(Resolution p_resolution) {
+ resolution = p_resolution;
+ update_gizmo();
+}
+
+GPUParticlesCollisionSDF::Resolution GPUParticlesCollisionSDF::get_resolution() const {
+ return resolution;
+}
+
+void GPUParticlesCollisionSDF::set_texture(const Ref<Texture3D> &p_texture) {
+ texture = p_texture;
+ RID tex = texture.is_valid() ? texture->get_rid() : RID();
+ RS::get_singleton()->particles_collision_set_field_texture(_get_collision(), tex);
+}
+
+Ref<Texture3D> GPUParticlesCollisionSDF::get_texture() const {
+ return texture;
+}
+
+AABB GPUParticlesCollisionSDF::get_aabb() const {
+ return AABB(-extents, extents * 2);
+}
+
+GPUParticlesCollisionSDF::BakeBeginFunc GPUParticlesCollisionSDF::bake_begin_function = nullptr;
+GPUParticlesCollisionSDF::BakeStepFunc GPUParticlesCollisionSDF::bake_step_function = nullptr;
+GPUParticlesCollisionSDF::BakeEndFunc GPUParticlesCollisionSDF::bake_end_function = nullptr;
+
+GPUParticlesCollisionSDF::GPUParticlesCollisionSDF() :
+ GPUParticlesCollision3D(RS::PARTICLES_COLLISION_TYPE_SDF_COLLIDE) {
+}
+
+GPUParticlesCollisionSDF::~GPUParticlesCollisionSDF() {
+}
+
+////////////////////////////
+////////////////////////////
+
+void GPUParticlesCollisionHeightField::_notification(int p_what) {
+ if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
+ if (update_mode == UPDATE_MODE_ALWAYS) {
+ RS::get_singleton()->particles_collision_height_field_update(_get_collision());
+ }
+
+ if (follow_camera_mode && get_viewport()) {
+ Camera3D *cam = get_viewport()->get_camera();
+ if (cam) {
+ Transform 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;
+
+ while (x_axis.dot(cam_pos - new_xform.origin) > x_len) {
+ new_xform.origin += x_axis * x_len;
+ }
+ while (x_axis.dot(cam_pos - new_xform.origin) < -x_len) {
+ new_xform.origin -= x_axis * x_len;
+ }
+
+ while (z_axis.dot(cam_pos - new_xform.origin) > z_len) {
+ new_xform.origin += z_axis * z_len;
+ }
+ while (z_axis.dot(cam_pos - new_xform.origin) < -z_len) {
+ new_xform.origin -= z_axis * z_len;
+ }
+
+ if (new_xform != xform) {
+ set_global_transform(new_xform);
+ RS::get_singleton()->particles_collision_height_field_update(_get_collision());
+ }
+ }
+ }
+ }
+
+ if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
+ RS::get_singleton()->particles_collision_height_field_update(_get_collision());
+ }
+}
+
+void GPUParticlesCollisionHeightField::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesCollisionHeightField::set_extents);
+ ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesCollisionHeightField::get_extents);
+
+ ClassDB::bind_method(D_METHOD("set_resolution", "resolution"), &GPUParticlesCollisionHeightField::set_resolution);
+ ClassDB::bind_method(D_METHOD("get_resolution"), &GPUParticlesCollisionHeightField::get_resolution);
+
+ ClassDB::bind_method(D_METHOD("set_update_mode", "update_mode"), &GPUParticlesCollisionHeightField::set_update_mode);
+ ClassDB::bind_method(D_METHOD("get_update_mode"), &GPUParticlesCollisionHeightField::get_update_mode);
+
+ ClassDB::bind_method(D_METHOD("set_follow_camera_mode", "enabled"), &GPUParticlesCollisionHeightField::set_follow_camera_mode);
+ ClassDB::bind_method(D_METHOD("is_follow_camera_mode_enabled"), &GPUParticlesCollisionHeightField::is_follow_camera_mode_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_follow_camera_push_ratio", "ratio"), &GPUParticlesCollisionHeightField::set_follow_camera_push_ratio);
+ ClassDB::bind_method(D_METHOD("get_follow_camera_push_ratio"), &GPUParticlesCollisionHeightField::get_follow_camera_push_ratio);
+
+ 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_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");
+
+ BIND_ENUM_CONSTANT(RESOLUTION_256);
+ BIND_ENUM_CONSTANT(RESOLUTION_512);
+ BIND_ENUM_CONSTANT(RESOLUTION_1024);
+ BIND_ENUM_CONSTANT(RESOLUTION_2048);
+ BIND_ENUM_CONSTANT(RESOLUTION_4096);
+ BIND_ENUM_CONSTANT(RESOLUTION_8192);
+ BIND_ENUM_CONSTANT(RESOLUTION_MAX);
+
+ BIND_ENUM_CONSTANT(UPDATE_MODE_WHEN_MOVED);
+ BIND_ENUM_CONSTANT(UPDATE_MODE_ALWAYS);
+}
+
+void GPUParticlesCollisionHeightField::set_follow_camera_push_ratio(float p_follow_camera_push_ratio) {
+ follow_camera_push_ratio = p_follow_camera_push_ratio;
+}
+
+float GPUParticlesCollisionHeightField::get_follow_camera_push_ratio() const {
+ return follow_camera_push_ratio;
+}
+
+void GPUParticlesCollisionHeightField::set_extents(const Vector3 &p_extents) {
+ extents = p_extents;
+ RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents);
+ update_gizmo();
+ RS::get_singleton()->particles_collision_height_field_update(_get_collision());
+}
+
+Vector3 GPUParticlesCollisionHeightField::get_extents() const {
+ return extents;
+}
+
+void GPUParticlesCollisionHeightField::set_resolution(Resolution p_resolution) {
+ resolution = p_resolution;
+ RS::get_singleton()->particles_collision_set_height_field_resolution(_get_collision(), RS::ParticlesCollisionHeightfieldResolution(resolution));
+ update_gizmo();
+ RS::get_singleton()->particles_collision_height_field_update(_get_collision());
+}
+
+GPUParticlesCollisionHeightField::Resolution GPUParticlesCollisionHeightField::get_resolution() const {
+ return resolution;
+}
+
+void GPUParticlesCollisionHeightField::set_update_mode(UpdateMode p_update_mode) {
+ update_mode = p_update_mode;
+ set_process_internal(follow_camera_mode || update_mode == UPDATE_MODE_ALWAYS);
+}
+
+GPUParticlesCollisionHeightField::UpdateMode GPUParticlesCollisionHeightField::get_update_mode() const {
+ return update_mode;
+}
+
+void GPUParticlesCollisionHeightField::set_follow_camera_mode(bool p_enabled) {
+ follow_camera_mode = p_enabled;
+ set_process_internal(follow_camera_mode || update_mode == UPDATE_MODE_ALWAYS);
+}
+
+bool GPUParticlesCollisionHeightField::is_follow_camera_mode_enabled() const {
+ return follow_camera_mode;
+}
+
+AABB GPUParticlesCollisionHeightField::get_aabb() const {
+ return AABB(-extents, extents * 2);
+}
+
+GPUParticlesCollisionHeightField::GPUParticlesCollisionHeightField() :
+ GPUParticlesCollision3D(RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE) {
+}
+
+GPUParticlesCollisionHeightField::~GPUParticlesCollisionHeightField() {
+}
+
+////////////////////////////
+////////////////////////////
+
+void GPUParticlesAttractor3D::set_cull_mask(uint32_t p_cull_mask) {
+ cull_mask = p_cull_mask;
+ RS::get_singleton()->particles_collision_set_cull_mask(collision, p_cull_mask);
+}
+
+uint32_t GPUParticlesAttractor3D::get_cull_mask() const {
+ return cull_mask;
+}
+
+void GPUParticlesAttractor3D::set_strength(float p_strength) {
+ strength = p_strength;
+ RS::get_singleton()->particles_collision_set_attractor_strength(collision, p_strength);
+}
+
+float GPUParticlesAttractor3D::get_strength() const {
+ return strength;
+}
+
+void GPUParticlesAttractor3D::set_attenuation(float p_attenuation) {
+ attenuation = p_attenuation;
+ RS::get_singleton()->particles_collision_set_attractor_attenuation(collision, p_attenuation);
+}
+
+float GPUParticlesAttractor3D::get_attenuation() const {
+ return attenuation;
+}
+
+void GPUParticlesAttractor3D::set_directionality(float p_directionality) {
+ directionality = p_directionality;
+ RS::get_singleton()->particles_collision_set_attractor_directionality(collision, p_directionality);
+ update_gizmo();
+}
+
+float GPUParticlesAttractor3D::get_directionality() const {
+ return directionality;
+}
+
+void GPUParticlesAttractor3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_cull_mask", "mask"), &GPUParticlesAttractor3D::set_cull_mask);
+ ClassDB::bind_method(D_METHOD("get_cull_mask"), &GPUParticlesAttractor3D::get_cull_mask);
+
+ ClassDB::bind_method(D_METHOD("set_strength", "strength"), &GPUParticlesAttractor3D::set_strength);
+ ClassDB::bind_method(D_METHOD("get_strength"), &GPUParticlesAttractor3D::get_strength);
+
+ ClassDB::bind_method(D_METHOD("set_attenuation", "attenuation"), &GPUParticlesAttractor3D::set_attenuation);
+ ClassDB::bind_method(D_METHOD("get_attenuation"), &GPUParticlesAttractor3D::get_attenuation);
+
+ ClassDB::bind_method(D_METHOD("set_directionality", "amount"), &GPUParticlesAttractor3D::set_directionality);
+ ClassDB::bind_method(D_METHOD("get_directionality"), &GPUParticlesAttractor3D::get_directionality);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "-128,128,0.01,or_greater,or_lesser"), "set_strength", "get_strength");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "attenuation", PROPERTY_HINT_EXP_EASING, "0,8,0.01"), "set_attenuation", "get_attenuation");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "directionality", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_directionality", "get_directionality");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
+}
+
+GPUParticlesAttractor3D::GPUParticlesAttractor3D(RS::ParticlesCollisionType p_type) {
+ collision = RS::get_singleton()->particles_collision_create();
+ RS::get_singleton()->particles_collision_set_collision_type(collision, p_type);
+ set_base(collision);
+}
+GPUParticlesAttractor3D::~GPUParticlesAttractor3D() {
+ RS::get_singleton()->free(collision);
+}
+
+/////////////////////////////////
+
+void GPUParticlesAttractorSphere::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_radius", "radius"), &GPUParticlesAttractorSphere::set_radius);
+ ClassDB::bind_method(D_METHOD("get_radius"), &GPUParticlesAttractorSphere::get_radius);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_radius", "get_radius");
+}
+
+void GPUParticlesAttractorSphere::set_radius(float p_radius) {
+ radius = p_radius;
+ RS::get_singleton()->particles_collision_set_sphere_radius(_get_collision(), radius);
+ update_gizmo();
+}
+
+float GPUParticlesAttractorSphere::get_radius() const {
+ return radius;
+}
+
+AABB GPUParticlesAttractorSphere::get_aabb() const {
+ return AABB(Vector3(-radius, -radius, -radius), Vector3(radius * 2, radius * 2, radius * 2));
+}
+
+GPUParticlesAttractorSphere::GPUParticlesAttractorSphere() :
+ GPUParticlesAttractor3D(RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT) {
+}
+
+GPUParticlesAttractorSphere::~GPUParticlesAttractorSphere() {
+}
+
+///////////////////////////
+
+void GPUParticlesAttractorBox::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesAttractorBox::set_extents);
+ ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesAttractorBox::get_extents);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_extents", "get_extents");
+}
+
+void GPUParticlesAttractorBox::set_extents(const Vector3 &p_extents) {
+ extents = p_extents;
+ RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents);
+ update_gizmo();
+}
+
+Vector3 GPUParticlesAttractorBox::get_extents() const {
+ return extents;
+}
+
+AABB GPUParticlesAttractorBox::get_aabb() const {
+ return AABB(-extents, extents * 2);
+}
+
+GPUParticlesAttractorBox::GPUParticlesAttractorBox() :
+ GPUParticlesAttractor3D(RS::PARTICLES_COLLISION_TYPE_BOX_ATTRACT) {
+}
+
+GPUParticlesAttractorBox::~GPUParticlesAttractorBox() {
+}
+
+///////////////////////////
+
+void GPUParticlesAttractorVectorField::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesAttractorVectorField::set_extents);
+ ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesAttractorVectorField::get_extents);
+
+ ClassDB::bind_method(D_METHOD("set_texture", "texture"), &GPUParticlesAttractorVectorField::set_texture);
+ ClassDB::bind_method(D_METHOD("get_texture"), &GPUParticlesAttractorVectorField::get_texture);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_extents", "get_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture");
+}
+
+void GPUParticlesAttractorVectorField::set_extents(const Vector3 &p_extents) {
+ extents = p_extents;
+ RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents);
+ update_gizmo();
+}
+
+Vector3 GPUParticlesAttractorVectorField::get_extents() const {
+ return extents;
+}
+
+void GPUParticlesAttractorVectorField::set_texture(const Ref<Texture3D> &p_texture) {
+ texture = p_texture;
+ RID tex = texture.is_valid() ? texture->get_rid() : RID();
+ RS::get_singleton()->particles_collision_set_field_texture(_get_collision(), tex);
+}
+
+Ref<Texture3D> GPUParticlesAttractorVectorField::get_texture() const {
+ return texture;
+}
+
+AABB GPUParticlesAttractorVectorField::get_aabb() const {
+ return AABB(-extents, extents * 2);
+}
+
+GPUParticlesAttractorVectorField::GPUParticlesAttractorVectorField() :
+ GPUParticlesAttractor3D(RS::PARTICLES_COLLISION_TYPE_VECTOR_FIELD_ATTRACT) {
+}
+
+GPUParticlesAttractorVectorField::~GPUParticlesAttractorVectorField() {
+}
diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h
new file mode 100644
index 0000000000..9b644ade6b
--- /dev/null
+++ b/scene/3d/gpu_particles_collision_3d.h
@@ -0,0 +1,342 @@
+/*************************************************************************/
+/* gpu_particles_collision_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 GPU_PARTICLES_COLLISION_3D_H
+#define GPU_PARTICLES_COLLISION_3D_H
+
+#include "core/templates/local_vector.h"
+#include "core/templates/rid.h"
+#include "scene/3d/visual_instance_3d.h"
+#include "scene/resources/material.h"
+
+class GPUParticlesCollision3D : public VisualInstance3D {
+ GDCLASS(GPUParticlesCollision3D, VisualInstance3D);
+
+ uint32_t cull_mask = 0xFFFFFFFF;
+ RID collision;
+
+protected:
+ _FORCE_INLINE_ RID _get_collision() { return collision; }
+ static void _bind_methods();
+
+ GPUParticlesCollision3D(RS::ParticlesCollisionType p_type);
+
+public:
+ void set_cull_mask(uint32_t p_cull_mask);
+ uint32_t get_cull_mask() const;
+
+ virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override { return Vector<Face3>(); }
+
+ ~GPUParticlesCollision3D();
+};
+
+class GPUParticlesCollisionSphere : public GPUParticlesCollision3D {
+ GDCLASS(GPUParticlesCollisionSphere, GPUParticlesCollision3D);
+
+ float radius = 1.0;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_radius(float p_radius);
+ float get_radius() const;
+
+ virtual AABB get_aabb() const override;
+
+ GPUParticlesCollisionSphere();
+ ~GPUParticlesCollisionSphere();
+};
+
+class GPUParticlesCollisionBox : public GPUParticlesCollision3D {
+ GDCLASS(GPUParticlesCollisionBox, GPUParticlesCollision3D);
+
+ Vector3 extents = Vector3(1, 1, 1);
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_extents(const Vector3 &p_extents);
+ Vector3 get_extents() const;
+
+ virtual AABB get_aabb() const override;
+
+ GPUParticlesCollisionBox();
+ ~GPUParticlesCollisionBox();
+};
+
+class GPUParticlesCollisionSDF : public GPUParticlesCollision3D {
+ GDCLASS(GPUParticlesCollisionSDF, GPUParticlesCollision3D);
+
+public:
+ enum Resolution {
+ RESOLUTION_16,
+ RESOLUTION_32,
+ RESOLUTION_64,
+ RESOLUTION_128,
+ RESOLUTION_256,
+ RESOLUTION_512,
+ RESOLUTION_MAX,
+ };
+
+ typedef void (*BakeBeginFunc)(int);
+ typedef void (*BakeStepFunc)(int, const String &);
+ typedef void (*BakeEndFunc)();
+
+private:
+ Vector3 extents = Vector3(1, 1, 1);
+ Resolution resolution = RESOLUTION_64;
+ Ref<Texture3D> texture;
+ float thickness = 1.0;
+
+ struct PlotMesh {
+ Ref<Mesh> mesh;
+ Transform local_xform;
+ };
+
+ void _find_meshes(const AABB &p_aabb, Node *p_at_node, List<PlotMesh> &plot_meshes);
+
+ struct BVH {
+ enum {
+ LEAF_BIT = 1 << 30,
+ LEAF_MASK = LEAF_BIT - 1
+ };
+ AABB bounds;
+ uint32_t children[2];
+ };
+
+ struct FacePos {
+ Vector3 center;
+ uint32_t index;
+ };
+
+ struct FaceSort {
+ uint32_t axis;
+ bool operator()(const FacePos &p_left, const FacePos &p_right) const {
+ return p_left.center[axis] < p_right.center[axis];
+ }
+ };
+
+ uint32_t _create_bvh(LocalVector<BVH> &bvh_tree, FacePos *p_faces, uint32_t p_face_count, const Face3 *p_triangles, float p_thickness);
+
+ struct ComputeSDFParams {
+ float *cells;
+ Vector3i size;
+ float cell_size;
+ Vector3 cell_offset;
+ const BVH *bvh;
+ const Face3 *triangles;
+ float thickness;
+ };
+
+ void _find_closest_distance(const Vector3 &p_pos, const BVH *bvh, uint32_t p_bvh_cell, const Face3 *triangles, float thickness, float &closest_distance);
+ void _compute_sdf_z(uint32_t p_z, ComputeSDFParams *params);
+ void _compute_sdf(ComputeSDFParams *params);
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_thickness(float p_thickness);
+ float get_thickness() const;
+
+ void set_extents(const Vector3 &p_extents);
+ Vector3 get_extents() const;
+
+ void set_resolution(Resolution p_resolution);
+ Resolution get_resolution() const;
+
+ void set_texture(const Ref<Texture3D> &p_texture);
+ Ref<Texture3D> get_texture() const;
+
+ Vector3i get_estimated_cell_size() const;
+ Ref<Image> bake();
+
+ virtual AABB get_aabb() const override;
+
+ static BakeBeginFunc bake_begin_function;
+ static BakeStepFunc bake_step_function;
+ static BakeEndFunc bake_end_function;
+
+ GPUParticlesCollisionSDF();
+ ~GPUParticlesCollisionSDF();
+};
+
+VARIANT_ENUM_CAST(GPUParticlesCollisionSDF::Resolution)
+
+class GPUParticlesCollisionHeightField : public GPUParticlesCollision3D {
+ GDCLASS(GPUParticlesCollisionHeightField, GPUParticlesCollision3D);
+
+public:
+ enum Resolution {
+ RESOLUTION_256,
+ RESOLUTION_512,
+ RESOLUTION_1024,
+ RESOLUTION_2048,
+ RESOLUTION_4096,
+ RESOLUTION_8192,
+ RESOLUTION_MAX,
+ };
+
+ enum UpdateMode {
+ UPDATE_MODE_WHEN_MOVED,
+ UPDATE_MODE_ALWAYS,
+ };
+
+private:
+ Vector3 extents = Vector3(1, 1, 1);
+ Resolution resolution = RESOLUTION_1024;
+ bool follow_camera_mode = false;
+ float follow_camera_push_ratio = 0.1;
+
+ UpdateMode update_mode = UPDATE_MODE_WHEN_MOVED;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_extents(const Vector3 &p_extents);
+ Vector3 get_extents() const;
+
+ void set_resolution(Resolution p_resolution);
+ Resolution get_resolution() const;
+
+ void set_update_mode(UpdateMode p_update_mode);
+ UpdateMode get_update_mode() const;
+
+ void set_follow_camera_mode(bool p_enabled);
+ bool is_follow_camera_mode_enabled() const;
+
+ void set_follow_camera_push_ratio(float p_ratio);
+ float get_follow_camera_push_ratio() const;
+
+ virtual AABB get_aabb() const override;
+
+ GPUParticlesCollisionHeightField();
+ ~GPUParticlesCollisionHeightField();
+};
+
+VARIANT_ENUM_CAST(GPUParticlesCollisionHeightField::Resolution)
+VARIANT_ENUM_CAST(GPUParticlesCollisionHeightField::UpdateMode)
+
+class GPUParticlesAttractor3D : public VisualInstance3D {
+ GDCLASS(GPUParticlesAttractor3D, VisualInstance3D);
+
+ uint32_t cull_mask = 0xFFFFFFFF;
+ RID collision;
+ float strength = 1.0;
+ float attenuation = 1.0;
+ float directionality = 0.0;
+
+protected:
+ _FORCE_INLINE_ RID _get_collision() { return collision; }
+ static void _bind_methods();
+
+ GPUParticlesAttractor3D(RS::ParticlesCollisionType p_type);
+
+public:
+ void set_cull_mask(uint32_t p_cull_mask);
+ uint32_t get_cull_mask() const;
+
+ void set_strength(float p_strength);
+ float get_strength() const;
+
+ void set_attenuation(float p_attenuation);
+ float get_attenuation() const;
+
+ void set_directionality(float p_directionality);
+ float get_directionality() const;
+
+ virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override { return Vector<Face3>(); }
+
+ ~GPUParticlesAttractor3D();
+};
+
+class GPUParticlesAttractorSphere : public GPUParticlesAttractor3D {
+ GDCLASS(GPUParticlesAttractorSphere, GPUParticlesAttractor3D);
+
+ float radius = 1.0;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_radius(float p_radius);
+ float get_radius() const;
+
+ virtual AABB get_aabb() const override;
+
+ GPUParticlesAttractorSphere();
+ ~GPUParticlesAttractorSphere();
+};
+
+class GPUParticlesAttractorBox : public GPUParticlesAttractor3D {
+ GDCLASS(GPUParticlesAttractorBox, GPUParticlesAttractor3D);
+
+ Vector3 extents = Vector3(1, 1, 1);
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_extents(const Vector3 &p_extents);
+ Vector3 get_extents() const;
+
+ virtual AABB get_aabb() const override;
+
+ GPUParticlesAttractorBox();
+ ~GPUParticlesAttractorBox();
+};
+
+class GPUParticlesAttractorVectorField : public GPUParticlesAttractor3D {
+ GDCLASS(GPUParticlesAttractorVectorField, GPUParticlesAttractor3D);
+
+ Vector3 extents = Vector3(1, 1, 1);
+ Ref<Texture3D> texture;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_extents(const Vector3 &p_extents);
+ Vector3 get_extents() const;
+
+ void set_texture(const Ref<Texture3D> &p_texture);
+ Ref<Texture3D> get_texture() const;
+
+ virtual AABB get_aabb() const override;
+
+ GPUParticlesAttractorVectorField();
+ ~GPUParticlesAttractorVectorField();
+};
+
+#endif // GPU_PARTICLES_COLLISION_3D_H
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index cc1622722e..3f816535f5 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -30,8 +30,8 @@
#include "light_3d.h"
-#include "core/engine.h"
-#include "core/project_settings.h"
+#include "core/config/engine.h"
+#include "core/config/project_settings.h"
#include "scene/resources/surface_tool.h"
bool Light3D::_can_gizmo_scale() const {
@@ -270,6 +270,7 @@ void Light3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_normal_bias", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_reverse_cull_face"), "set_shadow_reverse_cull_face", "get_shadow_reverse_cull_face");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_transmittance_bias", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_param", "get_param", PARAM_TRANSMITTANCE_BIAS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_fog_fade", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_param", "get_param", PARAM_SHADOW_VOLUMETRIC_FOG_FADE);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_blur", PROPERTY_HINT_RANGE, "0.1,8,0.01"), "set_param", "get_param", PARAM_SHADOW_BLUR);
ADD_GROUP("Editor", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only");
@@ -292,6 +293,7 @@ void Light3D::_bind_methods() {
BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS);
BIND_ENUM_CONSTANT(PARAM_SHADOW_PANCAKE_SIZE);
BIND_ENUM_CONSTANT(PARAM_SHADOW_BLUR);
+ BIND_ENUM_CONSTANT(PARAM_SHADOW_VOLUMETRIC_FOG_FADE);
BIND_ENUM_CONSTANT(PARAM_TRANSMITTANCE_BIAS);
BIND_ENUM_CONSTANT(PARAM_MAX);
@@ -345,6 +347,7 @@ Light3D::Light3D(RenderingServer::LightType p_type) {
set_param(PARAM_SHADOW_BIAS, 0.02);
set_param(PARAM_SHADOW_NORMAL_BIAS, 1.0);
set_param(PARAM_TRANSMITTANCE_BIAS, 0.05);
+ set_param(PARAM_SHADOW_VOLUMETRIC_FOG_FADE, 1.0);
set_param(PARAM_SHADOW_FADE_START, 1);
set_disable_scale(true);
}
@@ -391,6 +394,15 @@ bool DirectionalLight3D::is_blend_splits_enabled() const {
return blend_splits;
}
+void DirectionalLight3D::set_sky_only(bool p_sky_only) {
+ sky_only = p_sky_only;
+ RS::get_singleton()->light_directional_set_sky_only(light, p_sky_only);
+}
+
+bool DirectionalLight3D::is_sky_only() const {
+ return sky_only;
+}
+
void DirectionalLight3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shadow_mode", "mode"), &DirectionalLight3D::set_shadow_mode);
ClassDB::bind_method(D_METHOD("get_shadow_mode"), &DirectionalLight3D::get_shadow_mode);
@@ -401,6 +413,9 @@ void DirectionalLight3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_blend_splits", "enabled"), &DirectionalLight3D::set_blend_splits);
ClassDB::bind_method(D_METHOD("is_blend_splits_enabled"), &DirectionalLight3D::is_blend_splits_enabled);
+ ClassDB::bind_method(D_METHOD("set_sky_only", "priority"), &DirectionalLight3D::set_sky_only);
+ ClassDB::bind_method(D_METHOD("is_sky_only"), &DirectionalLight3D::is_sky_only);
+
ADD_GROUP("Directional Shadow", "directional_shadow_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_mode", PROPERTY_HINT_ENUM, "Orthogonal (Fast),PSSM 2 Splits (Average),PSSM 4 Splits (Slow)"), "set_shadow_mode", "get_shadow_mode");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_split_1", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_1_OFFSET);
@@ -412,6 +427,8 @@ void DirectionalLight3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_max_distance", PROPERTY_HINT_EXP_RANGE, "0,8192,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_pancake_size", PROPERTY_HINT_EXP_RANGE, "0,1024,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_PANCAKE_SIZE);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_in_sky_only"), "set_sky_only", "is_sky_only");
+
BIND_ENUM_CONSTANT(SHADOW_ORTHOGONAL);
BIND_ENUM_CONSTANT(SHADOW_PARALLEL_2_SPLITS);
BIND_ENUM_CONSTANT(SHADOW_PARALLEL_4_SPLITS);
@@ -445,7 +462,7 @@ String OmniLight3D::get_configuration_warning() const {
String warning = Light3D::get_configuration_warning();
if (!has_shadow() && get_projector().is_valid()) {
- if (warning != String()) {
+ if (!warning.empty()) {
warning += "\n\n";
}
warning += TTR("Projector texture only works with shadows active.");
@@ -479,15 +496,14 @@ String SpotLight3D::get_configuration_warning() const {
String warning = Light3D::get_configuration_warning();
if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) {
- if (warning != String()) {
+ if (!warning.empty()) {
warning += "\n\n";
}
-
warning += TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows.");
}
if (!has_shadow() && get_projector().is_valid()) {
- if (warning != String()) {
+ if (!warning.empty()) {
warning += "\n\n";
}
warning += TTR("Projector texture only works with shadows active.");
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index f106151472..08287a3313 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -58,6 +58,7 @@ public:
PARAM_SHADOW_BIAS = RS::LIGHT_PARAM_SHADOW_BIAS,
PARAM_SHADOW_PANCAKE_SIZE = RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE,
PARAM_SHADOW_BLUR = RS::LIGHT_PARAM_SHADOW_BLUR,
+ PARAM_SHADOW_VOLUMETRIC_FOG_FADE = RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE,
PARAM_TRANSMITTANCE_BIAS = RS::LIGHT_PARAM_TRANSMITTANCE_BIAS,
PARAM_MAX = RS::LIGHT_PARAM_MAX
};
@@ -157,6 +158,7 @@ private:
bool blend_splits;
ShadowMode shadow_mode;
ShadowDepthRange shadow_depth_range;
+ bool sky_only = false;
protected:
static void _bind_methods();
@@ -171,6 +173,9 @@ public:
void set_blend_splits(bool p_enable);
bool is_blend_splits_enabled() const;
+ void set_sky_only(bool p_sky_only);
+ bool is_sky_only() const;
+
DirectionalLight3D();
};
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index e179261002..f9f8f276a3 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -30,7 +30,7 @@
#include "navigation_agent_3d.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
#include "scene/3d/navigation_3d.h"
#include "servers/navigation_server_3d.h"
@@ -287,11 +287,16 @@ void NavigationAgent3D::_avoidance_done(Vector3 p_new_velocity) {
}
String NavigationAgent3D::get_configuration_warning() const {
+ String warning = Node::get_configuration_warning();
+
if (!Object::cast_to<Node3D>(get_parent())) {
- return TTR("The NavigationAgent3D can be used only under a spatial node.");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ warning += TTR("The NavigationAgent3D can be used only under a spatial node.");
}
- return String();
+ return warning;
}
void NavigationAgent3D::update_navigation() {
diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h
index e80367ea50..dcfd302561 100644
--- a/scene/3d/navigation_agent_3d.h
+++ b/scene/3d/navigation_agent_3d.h
@@ -31,7 +31,7 @@
#ifndef NAVIGATION_AGENT_H
#define NAVIGATION_AGENT_H
-#include "core/vector.h"
+#include "core/templates/vector.h"
#include "scene/main/node.h"
class Node3D;
diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp
index 69fd5b02fc..adbff06ed6 100644
--- a/scene/3d/navigation_obstacle_3d.cpp
+++ b/scene/3d/navigation_obstacle_3d.cpp
@@ -113,11 +113,16 @@ Node *NavigationObstacle3D::get_navigation_node() const {
}
String NavigationObstacle3D::get_configuration_warning() const {
+ String warning = Node::get_configuration_warning();
+
if (!Object::cast_to<Node3D>(get_parent())) {
- return TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object.");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ warning += TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object.");
}
- return String();
+ return warning;
}
void NavigationObstacle3D::update_agent_shape() {
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 15ed448a65..2ae01c7ab8 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -182,6 +182,7 @@ void NavigationRegion3D::bake_navigation_mesh() {
void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) {
set_navigation_mesh(p_nav_mesh);
bake_thread = nullptr;
+ emit_signal("bake_finished");
}
String NavigationRegion3D::get_configuration_warning() const {
@@ -189,19 +190,28 @@ String NavigationRegion3D::get_configuration_warning() const {
return String();
}
+ String warning = Node3D::get_configuration_warning();
+
if (!navmesh.is_valid()) {
- return TTR("A NavigationMesh resource must be set or created for this node to work.");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ warning += TTR("A NavigationMesh resource must be set or created for this node to work.");
}
+
const Node3D *c = this;
while (c) {
if (Object::cast_to<Navigation3D>(c)) {
- return String();
+ return warning;
}
c = Object::cast_to<Node3D>(c->get_parent());
}
- return TTR("NavigationRegion3D must be a child or grandchild to a Navigation3D node. It only provides navigation data.");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ return warning + TTR("NavigationRegion3D must be a child or grandchild to a Navigation3D node. It only provides navigation data.");
}
void NavigationRegion3D::_bind_methods() {
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index bd9e4f5bde..e8005f38ed 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -30,8 +30,8 @@
#include "node_3d.h"
-#include "core/engine.h"
-#include "core/message_queue.h"
+#include "core/config/engine.h"
+#include "core/object/message_queue.h"
#include "scene/main/scene_tree.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
@@ -103,8 +103,8 @@ void Node3D::_propagate_transform_changed(Node3D *p_origin) {
data.children_lock++;
for (List<Node3D *>::Element *E = data.children.front(); E; E = E->next()) {
- if (E->get()->data.toplevel_active) {
- continue; //don't propagate to a toplevel
+ if (E->get()->data.top_level_active) {
+ continue; //don't propagate to a top_level
}
E->get()->_propagate_transform_changed(p_origin);
}
@@ -136,12 +136,12 @@ void Node3D::_notification(int p_what) {
data.C = nullptr;
}
- if (data.toplevel && !Engine::get_singleton()->is_editor_hint()) {
+ if (data.top_level && !Engine::get_singleton()->is_editor_hint()) {
if (data.parent) {
data.local_transform = data.parent->get_global_transform() * get_transform();
data.dirty = DIRTY_VECTORS; //global is always dirty upon entering a scene
}
- data.toplevel_active = true;
+ data.top_level_active = true;
}
data.dirty |= DIRTY_GLOBAL; //global is always dirty upon entering a scene
@@ -160,7 +160,7 @@ void Node3D::_notification(int p_what) {
}
data.parent = nullptr;
data.C = nullptr;
- data.toplevel_active = false;
+ data.top_level_active = false;
} break;
case NOTIFICATION_ENTER_WORLD: {
data.inside_world = true;
@@ -238,7 +238,7 @@ void Node3D::set_transform(const Transform &p_transform) {
void Node3D::set_global_transform(const Transform &p_transform) {
Transform xform =
- (data.parent && !data.toplevel_active) ?
+ (data.parent && !data.top_level_active) ?
data.parent->get_global_transform().affine_inverse() * p_transform :
p_transform;
@@ -261,7 +261,7 @@ Transform Node3D::get_global_transform() const {
_update_local_transform();
}
- if (data.parent && !data.toplevel_active) {
+ if (data.parent && !data.top_level_active) {
data.global_transform = data.parent->get_global_transform() * data.local_transform;
} else {
data.global_transform = data.local_transform;
@@ -462,8 +462,8 @@ bool Node3D::is_scale_disabled() const {
return data.disable_scale;
}
-void Node3D::set_as_toplevel(bool p_enabled) {
- if (data.toplevel == p_enabled) {
+void Node3D::set_as_top_level(bool p_enabled) {
+ if (data.top_level == p_enabled) {
return;
}
if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint()) {
@@ -473,16 +473,16 @@ void Node3D::set_as_toplevel(bool p_enabled) {
set_transform(data.parent->get_global_transform().affine_inverse() * get_global_transform());
}
- data.toplevel = p_enabled;
- data.toplevel_active = p_enabled;
+ data.top_level = p_enabled;
+ data.top_level_active = p_enabled;
} else {
- data.toplevel = p_enabled;
+ data.top_level = p_enabled;
}
}
-bool Node3D::is_set_as_toplevel() const {
- return data.toplevel;
+bool Node3D::is_set_as_top_level() const {
+ return data.top_level;
}
Ref<World3D> Node3D::get_world_3d() const {
@@ -715,8 +715,8 @@ void Node3D::_bind_methods() {
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("set_ignore_transform_notification", "enabled"), &Node3D::set_ignore_transform_notification);
- ClassDB::bind_method(D_METHOD("set_as_toplevel", "enable"), &Node3D::set_as_toplevel);
- ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &Node3D::is_set_as_toplevel);
+ 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);
ClassDB::bind_method(D_METHOD("set_disable_scale", "disable"), &Node3D::set_disable_scale);
ClassDB::bind_method(D_METHOD("is_scale_disabled"), &Node3D::is_scale_disabled);
ClassDB::bind_method(D_METHOD("get_world_3d"), &Node3D::get_world_3d);
@@ -773,6 +773,7 @@ void Node3D::_bind_methods() {
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_GROUP("Visibility", "");
@@ -788,8 +789,8 @@ Node3D::Node3D() :
data.children_lock = 0;
data.ignore_notification = false;
- data.toplevel = false;
- data.toplevel_active = false;
+ data.top_level = false;
+ data.top_level_active = false;
data.scale = Vector3(1, 1, 1);
data.viewport = nullptr;
data.inside_world = false;
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index 327d4671e9..5fb421c930 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -71,8 +71,8 @@ class Node3D : public Node {
Viewport *viewport;
- bool toplevel_active;
- bool toplevel;
+ bool top_level_active;
+ bool top_level;
bool inside_world;
int children_lock;
@@ -111,7 +111,6 @@ protected:
public:
enum {
-
NOTIFICATION_TRANSFORM_CHANGED = SceneTree::NOTIFICATION_TRANSFORM_CHANGED,
NOTIFICATION_ENTER_WORLD = 41,
NOTIFICATION_EXIT_WORLD = 42,
@@ -144,8 +143,8 @@ public:
virtual Transform get_local_gizmo_transform() const;
#endif
- void set_as_toplevel(bool p_enabled);
- bool is_set_as_toplevel() const;
+ void set_as_top_level(bool p_enabled);
+ bool is_set_as_top_level() const;
void set_disable_scale(bool p_enabled);
bool is_scale_disabled() const;
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index bf69a8598d..f25a64c567 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -30,7 +30,7 @@
#include "path_3d.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
#include "scene/scene_string_names.h"
void Path3D::_notification(int p_what) {
@@ -250,16 +250,24 @@ String PathFollow3D::get_configuration_warning() const {
return String();
}
+ String warning = Node3D::get_configuration_warning();
+
if (!Object::cast_to<Path3D>(get_parent())) {
- return TTR("PathFollow3D only works when set as a child of a Path3D node.");
+ if (!warning.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) {
- return TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource.");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ warning += TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource.");
}
}
- return String();
+ return warning;
}
void PathFollow3D::_bind_methods() {
diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h
index 1aa9f7ffd2..1b0f5fa4e0 100644
--- a/scene/3d/path_3d.h
+++ b/scene/3d/path_3d.h
@@ -57,7 +57,6 @@ class PathFollow3D : public Node3D {
public:
enum RotationMode {
-
ROTATION_NONE,
ROTATION_Y,
ROTATION_XY,
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index fc021e5532..15cd2238e1 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -30,12 +30,11 @@
#include "physics_body_3d.h"
+#include "core/config/engine.h"
#include "core/core_string_names.h"
-#include "core/engine.h"
-#include "core/list.h"
-#include "core/method_bind_ext.gen.inc"
-#include "core/object.h"
-#include "core/rid.h"
+#include "core/object/class_db.h"
+#include "core/templates/list.h"
+#include "core/templates/rid.h"
#include "scene/3d/collision_shape_3d.h"
#include "scene/scene_string_names.h"
#include "servers/navigation_server_3d.h"
@@ -130,15 +129,6 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) {
PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid());
}
-void PhysicsBody3D::_set_layers(uint32_t p_mask) {
- set_collision_layer(p_mask);
- set_collision_mask(p_mask);
-}
-
-uint32_t PhysicsBody3D::_get_layers() const {
- return get_collision_layer();
-}
-
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);
@@ -152,9 +142,6 @@ void PhysicsBody3D::_bind_methods() {
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);
- ClassDB::bind_method(D_METHOD("_set_layers", "mask"), &PhysicsBody3D::_set_layers);
- ClassDB::bind_method(D_METHOD("_get_layers"), &PhysicsBody3D::_get_layers);
-
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");
@@ -491,8 +478,6 @@ RigidBody3D::Mode RigidBody3D::get_mode() const {
void RigidBody3D::set_mass(real_t p_mass) {
ERR_FAIL_COND(p_mass <= 0);
mass = p_mass;
- _change_notify("mass");
- _change_notify("weight");
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_MASS, mass);
}
@@ -500,14 +485,6 @@ real_t RigidBody3D::get_mass() const {
return mass;
}
-void RigidBody3D::set_weight(real_t p_weight) {
- set_mass(p_weight / real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8)));
-}
-
-real_t RigidBody3D::get_weight() const {
- return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8));
-}
-
void RigidBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
if (physics_material_override.is_valid()) {
if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics))) {
@@ -737,7 +714,7 @@ String RigidBody3D::get_configuration_warning() const {
String warning = CollisionObject3D::get_configuration_warning();
if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) {
- if (warning != String()) {
+ if (!warning.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.");
@@ -753,9 +730,6 @@ void RigidBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidBody3D::set_mass);
ClassDB::bind_method(D_METHOD("get_mass"), &RigidBody3D::get_mass);
- ClassDB::bind_method(D_METHOD("set_weight", "weight"), &RigidBody3D::set_weight);
- ClassDB::bind_method(D_METHOD("get_weight"), &RigidBody3D::get_weight);
-
ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody3D::set_physics_material_override);
ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody3D::get_physics_material_override);
@@ -815,7 +789,6 @@ void RigidBody3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Rigid,Static,Character,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::FLOAT, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", PROPERTY_USAGE_EDITOR), "set_weight", "get_weight");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
@@ -2134,9 +2107,6 @@ void PhysicalBone3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mass", "mass"), &PhysicalBone3D::set_mass);
ClassDB::bind_method(D_METHOD("get_mass"), &PhysicalBone3D::get_mass);
- ClassDB::bind_method(D_METHOD("set_weight", "weight"), &PhysicalBone3D::set_weight);
- ClassDB::bind_method(D_METHOD("get_weight"), &PhysicalBone3D::get_weight);
-
ClassDB::bind_method(D_METHOD("set_friction", "friction"), &PhysicalBone3D::set_friction);
ClassDB::bind_method(D_METHOD("get_friction"), &PhysicalBone3D::get_friction);
@@ -2167,7 +2137,6 @@ void PhysicalBone3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "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, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_weight", "get_weight");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-10,10,0.01"), "set_gravity_scale", "get_gravity_scale");
@@ -2469,14 +2438,6 @@ real_t PhysicalBone3D::get_mass() const {
return mass;
}
-void PhysicalBone3D::set_weight(real_t p_weight) {
- set_mass(p_weight / real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8)));
-}
-
-real_t PhysicalBone3D::get_weight() const {
- return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8));
-}
-
void PhysicalBone3D::set_friction(real_t p_friction) {
ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
@@ -2606,7 +2567,7 @@ void PhysicalBone3D::_start_physics_simulation() {
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");
- set_as_toplevel(true);
+ set_as_top_level(true);
_internal_simulate_physics = true;
}
@@ -2626,7 +2587,7 @@ void PhysicalBone3D::_stop_physics_simulation() {
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);
- set_as_toplevel(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 9830a55183..58eebc90ce 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -31,7 +31,7 @@
#ifndef PHYSICS_BODY_3D_H
#define PHYSICS_BODY_3D_H
-#include "core/vset.h"
+#include "core/templates/vset.h"
#include "scene/3d/collision_object_3d.h"
#include "scene/resources/physics_material.h"
#include "servers/physics_server_3d.h"
@@ -43,9 +43,6 @@ class PhysicsBody3D : public CollisionObject3D {
uint32_t collision_layer;
uint32_t collision_mask;
- void _set_layers(uint32_t p_mask);
- uint32_t _get_layers() const;
-
protected:
static void _bind_methods();
PhysicsBody3D(PhysicsServer3D::BodyMode p_mode);
@@ -188,9 +185,6 @@ public:
virtual float get_inverse_mass() const override { return 1.0 / mass; }
- void set_weight(real_t p_weight);
- real_t get_weight() const;
-
void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
Ref<PhysicsMaterial> get_physics_material_override() const;
@@ -575,9 +569,6 @@ public:
void set_mass(real_t p_mass);
real_t get_mass() const;
- void set_weight(real_t p_weight);
- real_t get_weight() const;
-
void set_friction(real_t p_friction);
real_t get_friction() const;
diff --git a/scene/3d/physics_joint_3d.cpp b/scene/3d/physics_joint_3d.cpp
index af4d6ae152..ab9cdb9fd8 100644
--- a/scene/3d/physics_joint_3d.cpp
+++ b/scene/3d/physics_joint_3d.cpp
@@ -43,6 +43,7 @@ void Joint3D::_update_joint(bool p_only_free) {
}
if (p_only_free || !is_inside_tree()) {
+ warning = String();
return;
}
@@ -52,20 +53,47 @@ void Joint3D::_update_joint(bool p_only_free) {
PhysicsBody3D *body_a = Object::cast_to<PhysicsBody3D>(node_a);
PhysicsBody3D *body_b = Object::cast_to<PhysicsBody3D>(node_b);
- if (!body_a && body_b) {
- SWAP(body_a, body_b);
+ if (node_a && !body_a && node_b && !body_b) {
+ warning = TTR("Node A and Node B must be PhysicsBody3Ds");
+ update_configuration_warning();
+ return;
}
- if (!body_a) {
+ if (node_a && !body_a) {
+ warning = TTR("Node A must be a PhysicsBody3D");
+ update_configuration_warning();
return;
}
- joint = _configure_joint(body_a, body_b);
+ if (node_b && !body_b) {
+ warning = TTR("Node B must be a PhysicsBody3D");
+ update_configuration_warning();
+ return;
+ }
- if (!joint.is_valid()) {
+ if (!body_a && !body_b) {
+ warning = TTR("Joint is not connected to any PhysicsBody3Ds");
+ update_configuration_warning();
return;
}
+ if (body_a == body_b) {
+ warning = TTR("Node A and Node B must be different PhysicsBody3Ds");
+ update_configuration_warning();
+ return;
+ }
+
+ if (!body_a) {
+ SWAP(body_a, body_b);
+ }
+
+ warning = String();
+ update_configuration_warning();
+
+ joint = _configure_joint(body_a, body_b);
+
+ ERR_FAIL_COND_MSG(!joint.is_valid(), "Failed to configure the joint.");
+
PhysicsServer3D::get_singleton()->joint_set_solver_priority(joint, solver_priority);
ba = body_a->get_rid();
@@ -137,6 +165,19 @@ 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();
+
+ if (!warning.empty()) {
+ if (!node_warning.empty()) {
+ node_warning += "\n\n";
+ }
+ node_warning += warning;
+ }
+
+ return node_warning;
+}
+
void Joint3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_node_a", "node"), &Joint3D::set_node_a);
ClassDB::bind_method(D_METHOD("get_node_a"), &Joint3D::get_node_a);
@@ -150,8 +191,8 @@ void Joint3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint3D::set_exclude_nodes_from_collision);
ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint3D::get_exclude_nodes_from_collision);
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject3D"), "set_node_a", "get_node_a");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject3D"), "set_node_b", "get_node_b");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody3D"), "set_node_a", "get_node_a");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody3D"), "set_node_b", "get_node_b");
ADD_PROPERTY(PropertyInfo(Variant::INT, "solver/priority", PROPERTY_HINT_RANGE, "1,8,1"), "set_solver_priority", "get_solver_priority");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision/exclude_nodes"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision");
diff --git a/scene/3d/physics_joint_3d.h b/scene/3d/physics_joint_3d.h
index 8e2de82527..a65f6db3bf 100644
--- a/scene/3d/physics_joint_3d.h
+++ b/scene/3d/physics_joint_3d.h
@@ -46,6 +46,7 @@ class Joint3D : public Node3D {
int solver_priority;
bool exclude_from_collision;
+ String warning;
protected:
void _update_joint(bool p_only_free = false);
@@ -57,6 +58,8 @@ protected:
static void _bind_methods();
public:
+ virtual String get_configuration_warning() const override;
+
void set_node_a(const NodePath &p_node_a);
NodePath get_node_a() const;
@@ -203,7 +206,6 @@ class ConeTwistJoint3D : public Joint3D {
public:
enum Param {
-
PARAM_SWING_SPAN,
PARAM_TWIST_SPAN,
PARAM_BIAS,
@@ -237,7 +239,6 @@ class Generic6DOFJoint3D : public Joint3D {
public:
enum Param {
-
PARAM_LINEAR_LOWER_LIMIT = PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT,
PARAM_LINEAR_UPPER_LIMIT = PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT,
PARAM_LINEAR_LIMIT_SOFTNESS = PhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS,
diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp
index 2a922e3cda..811e8a331b 100644
--- a/scene/3d/ray_cast_3d.cpp
+++ b/scene/3d/ray_cast_3d.cpp
@@ -31,12 +31,12 @@
#include "ray_cast_3d.h"
#include "collision_object_3d.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
#include "mesh_instance_3d.h"
#include "servers/physics_server_3d.h"
-void RayCast3D::set_cast_to(const Vector3 &p_point) {
- cast_to = p_point;
+void RayCast3D::set_target_position(const Vector3 &p_point) {
+ target_position = p_point;
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint())) {
update_gizmo();
}
@@ -45,8 +45,8 @@ void RayCast3D::set_cast_to(const Vector3 &p_point) {
}
}
-Vector3 RayCast3D::get_cast_to() const {
- return cast_to;
+Vector3 RayCast3D::get_target_position() const {
+ return target_position;
}
void RayCast3D::set_collision_mask(uint32_t p_mask) {
@@ -202,7 +202,7 @@ void RayCast3D::_update_raycast_state() {
Transform gt = get_global_transform();
- Vector3 to = cast_to;
+ Vector3 to = target_position;
if (to == Vector3()) {
to = Vector3(0, 0.01, 0);
}
@@ -276,8 +276,8 @@ void RayCast3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast3D::set_enabled);
ClassDB::bind_method(D_METHOD("is_enabled"), &RayCast3D::is_enabled);
- ClassDB::bind_method(D_METHOD("set_cast_to", "local_point"), &RayCast3D::set_cast_to);
- ClassDB::bind_method(D_METHOD("get_cast_to"), &RayCast3D::get_cast_to);
+ ClassDB::bind_method(D_METHOD("set_target_position", "local_point"), &RayCast3D::set_target_position);
+ ClassDB::bind_method(D_METHOD("get_target_position"), &RayCast3D::get_target_position);
ClassDB::bind_method(D_METHOD("is_colliding"), &RayCast3D::is_colliding);
ClassDB::bind_method(D_METHOD("force_raycast_update"), &RayCast3D::force_raycast_update);
@@ -312,7 +312,7 @@ void RayCast3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cast_to"), "set_cast_to", "get_cast_to");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_position"), "set_target_position", "get_target_position");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_GROUP("Collide With", "collide_with");
@@ -360,7 +360,7 @@ void RayCast3D::_update_debug_shape() {
Vector<Vector3> verts;
verts.push_back(Vector3());
- verts.push_back(cast_to);
+ verts.push_back(target_position);
a[Mesh::ARRAY_VERTEX] = verts;
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a);
@@ -387,7 +387,7 @@ RayCast3D::RayCast3D() {
collided = false;
against_shape = 0;
collision_mask = 1;
- cast_to = Vector3(0, -1, 0);
+ target_position = Vector3(0, -1, 0);
debug_shape = nullptr;
exclude_parent_body = true;
collide_with_areas = false;
diff --git a/scene/3d/ray_cast_3d.h b/scene/3d/ray_cast_3d.h
index 8f617e5491..f4fe7ba621 100644
--- a/scene/3d/ray_cast_3d.h
+++ b/scene/3d/ray_cast_3d.h
@@ -43,7 +43,7 @@ class RayCast3D : public Node3D {
Vector3 collision_point;
Vector3 collision_normal;
- Vector3 cast_to;
+ Vector3 target_position;
Set<RID> exclude;
uint32_t collision_mask;
@@ -74,8 +74,8 @@ public:
void set_enabled(bool p_enabled);
bool is_enabled() const;
- void set_cast_to(const Vector3 &p_point);
- Vector3 get_cast_to() const;
+ void set_target_position(const Vector3 &p_point);
+ Vector3 get_target_position() const;
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
diff --git a/scene/3d/remote_transform_3d.cpp b/scene/3d/remote_transform_3d.cpp
index 95fce6b802..358f9346f8 100644
--- a/scene/3d/remote_transform_3d.cpp
+++ b/scene/3d/remote_transform_3d.cpp
@@ -180,11 +180,16 @@ void RemoteTransform3D::force_update_cache() {
}
String RemoteTransform3D::get_configuration_warning() const {
+ String warning = Node3D::get_configuration_warning();
+
if (!has_node(remote_node) || !Object::cast_to<Node3D>(get_node(remote_node))) {
- return TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work.");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ warning += TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work.");
}
- return String();
+ return warning;
}
void RemoteTransform3D::_bind_methods() {
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 6723ca04b9..4425af26f9 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -30,10 +30,10 @@
#include "skeleton_3d.h"
-#include "core/engine.h"
-#include "core/message_queue.h"
-#include "core/project_settings.h"
-#include "core/type_info.h"
+#include "core/config/engine.h"
+#include "core/config/project_settings.h"
+#include "core/object/message_queue.h"
+#include "core/variant/type_info.h"
#include "scene/3d/physics_body_3d.h"
#include "scene/resources/surface_tool.h"
#include "scene/scene_string_names.h"
@@ -848,7 +848,7 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
skin_bindings.insert(skin_ref.operator->());
- skin->connect_compat("changed", skin_ref.operator->(), "_skin_changed");
+ skin->connect("changed", Callable(skin_ref.operator->(), "_skin_changed"));
_make_dirty(); //skin needs to be updated, so update skeleton
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index a21891a32e..c54f89d3ce 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -31,7 +31,7 @@
#ifndef SKELETON_3D_H
#define SKELETON_3D_H
-#include "core/rid.h"
+#include "core/templates/rid.h"
#include "scene/3d/node_3d.h"
#include "scene/resources/skin.h"
@@ -149,7 +149,6 @@ protected:
public:
enum {
-
NOTIFICATION_UPDATE_SKELETON = 50
};
diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h
index 80acc3e937..6c1db6dd33 100644
--- a/scene/3d/skeleton_ik_3d.h
+++ b/scene/3d/skeleton_ik_3d.h
@@ -76,10 +76,6 @@ class FabrikInverseKinematic {
ChainTip(ChainItem *p_chain_item, const EndEffector *p_end_effector) :
chain_item(p_chain_item),
end_effector(p_end_effector) {}
-
- ChainTip(const ChainTip &p_other_ct) :
- chain_item(p_other_ct.chain_item),
- end_effector(p_other_ct.end_effector) {}
};
struct Chain {
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index a267c57f5e..d811b2e852 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -30,10 +30,10 @@
#include "soft_body_3d.h"
-#include "core/list.h"
-#include "core/object.h"
+#include "core/object/class_db.h"
#include "core/os/os.h"
-#include "core/rid.h"
+#include "core/templates/list.h"
+#include "core/templates/rid.h"
#include "scene/3d/collision_object_3d.h"
#include "scene/3d/physics_body_3d.h"
#include "scene/3d/skeleton_3d.h"
@@ -106,7 +106,7 @@ SoftBody3D::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) {
offset = obj_tocopy.offset;
}
-SoftBody3D::PinnedPoint SoftBody3D::PinnedPoint::operator=(const PinnedPoint &obj) {
+SoftBody3D::PinnedPoint &SoftBody3D::PinnedPoint::operator=(const PinnedPoint &obj) {
point_index = obj.point_index;
spatial_attachment_path = obj.spatial_attachment_path;
spatial_attachment = obj.spatial_attachment;
@@ -282,7 +282,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_toplevel(true);
+ set_as_top_level(true);
set_transform(Transform());
set_notify_transform(true);
@@ -425,7 +425,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_toplevel", true);
+ call_deferred("set_as_top_level", true);
call_deferred("set_transform", Transform());
}
@@ -480,7 +480,6 @@ void SoftBody3D::become_mesh_owner() {
Dictionary surface_lods = mesh->surface_get_lods(0);
uint32_t surface_format = mesh->surface_get_format(0);
- surface_format &= ~(Mesh::ARRAY_COMPRESS_NORMAL);
surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;
Ref<ArrayMesh> soft_mesh;
@@ -725,7 +724,7 @@ void SoftBody3D::_update_cache_pin_points_datas() {
w[i].spatial_attachment = Object::cast_to<Node3D>(get_node(w[i].spatial_attachment_path));
}
if (!w[i].spatial_attachment) {
- ERR_PRINT("Node3D node not defined in the pinned point, Softbody undefined behaviour!");
+ ERR_PRINT("Node3D node not defined in the pinned point, this is undefined behavior for SoftBody3D!");
}
}
}
diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h
index 85cfb81637..c59a0b3aa3 100644
--- a/scene/3d/soft_body_3d.h
+++ b/scene/3d/soft_body_3d.h
@@ -74,7 +74,7 @@ public:
PinnedPoint();
PinnedPoint(const PinnedPoint &obj_tocopy);
- PinnedPoint operator=(const PinnedPoint &obj);
+ PinnedPoint &operator=(const PinnedPoint &obj);
};
private:
diff --git a/scene/3d/spring_arm_3d.cpp b/scene/3d/spring_arm_3d.cpp
index 9775ecc6c6..287d760db0 100644
--- a/scene/3d/spring_arm_3d.cpp
+++ b/scene/3d/spring_arm_3d.cpp
@@ -30,7 +30,7 @@
#include "spring_arm_3d.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
#include "scene/3d/collision_object_3d.h"
#include "scene/resources/sphere_shape_3d.h"
#include "servers/physics_server_3d.h"
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 3b76cb6499..1d20a9cd3b 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -204,7 +204,6 @@ Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const {
float pixel_size = get_pixel_size();
Vector2 vertices[4] = {
-
(final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
(final_rect.position + final_rect.size) * pixel_size,
(final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
@@ -414,7 +413,6 @@ void Sprite3D::_draw() {
float pixel_size = get_pixel_size();
Vector2 vertices[4] = {
-
(final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
(final_rect.position + final_rect.size) * pixel_size,
(final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
@@ -488,7 +486,7 @@ void Sprite3D::_draw() {
RS::get_singleton()->immediate_normal(immediate, normal);
RS::get_singleton()->immediate_tangent(immediate, tangent);
RS::get_singleton()->immediate_color(immediate, color);
- RS::get_singleton()->immediate_uv(immediate, uvs[i]);
+ RS::get_singleton()->immediate_uv(immediate, uvs[index[i]]);
Vector3 vtx;
vtx[x_axis] = vertices[index[i]][0];
@@ -667,8 +665,8 @@ void Sprite3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
ADD_GROUP("Animation", "");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
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_GROUP("Region", "region_");
@@ -740,7 +738,6 @@ void AnimatedSprite3D::_draw() {
float pixel_size = get_pixel_size();
Vector2 vertices[4] = {
-
(final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
(final_rect.position + final_rect.size) * pixel_size,
(final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
@@ -818,7 +815,7 @@ void AnimatedSprite3D::_draw() {
RS::get_singleton()->immediate_normal(immediate, normal);
RS::get_singleton()->immediate_tangent(immediate, tangent);
RS::get_singleton()->immediate_color(immediate, color);
- RS::get_singleton()->immediate_uv(immediate, uvs[i]);
+ RS::get_singleton()->immediate_uv(immediate, uvs[indices[i]]);
Vector3 vtx;
vtx[x_axis] = vertices[indices[i]][0];
@@ -1074,11 +1071,16 @@ StringName AnimatedSprite3D::get_animation() const {
}
String AnimatedSprite3D::get_configuration_warning() const {
+ String warning = SpriteBase3D::get_configuration_warning();
+
if (frames.is_null()) {
- return TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames.");
+ if (!warning.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.");
}
- return String();
+ return warning;
}
void AnimatedSprite3D::_bind_methods() {
diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp
index 4c71ab470b..e27307e75f 100644
--- a/scene/3d/vehicle_body_3d.cpp
+++ b/scene/3d/vehicle_body_3d.cpp
@@ -103,11 +103,16 @@ void VehicleWheel3D::_notification(int p_what) {
}
String VehicleWheel3D::get_configuration_warning() const {
+ String warning = Node3D::get_configuration_warning();
+
if (!Object::cast_to<VehicleBody3D>(get_parent())) {
- return TTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D.");
+ if (!warning.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.");
}
- return String();
+ return warning;
}
void VehicleWheel3D::_update(PhysicsDirectBodyState3D *s) {
@@ -629,7 +634,6 @@ VehicleBody3D::btVehicleWheelContactPoint::btVehicleWheelContactPoint(PhysicsDir
/* TODO: Why is this code unused?
if (body1) {
-
Vector3 r0 = frictionPosWorld - body1->get_global_transform().origin;
Vector3 c0 = (r0).cross(frictionDirectionWorld);
Vector3 vec = s->get_inverse_inertia_tensor().xform_inv(c0).cross(r0);
diff --git a/scene/3d/velocity_tracker_3d.cpp b/scene/3d/velocity_tracker_3d.cpp
index db10f3273b..eba7d44c16 100644
--- a/scene/3d/velocity_tracker_3d.cpp
+++ b/scene/3d/velocity_tracker_3d.cpp
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "velocity_tracker_3d.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
void VelocityTracker3D::set_track_physics_step(bool p_track_physics_step) {
physics_step = p_track_physics_step;
diff --git a/scene/3d/visibility_notifier_3d.cpp b/scene/3d/visibility_notifier_3d.cpp
index a64b0df1cc..9f5c40caf4 100644
--- a/scene/3d/visibility_notifier_3d.cpp
+++ b/scene/3d/visibility_notifier_3d.cpp
@@ -30,7 +30,7 @@
#include "visibility_notifier_3d.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/physics_body_3d.h"
#include "scene/animation/animation_player.h"
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 195674f62d..51bcb411da 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -32,7 +32,7 @@
#define VISUAL_INSTANCE_H
#include "core/math/face3.h"
-#include "core/rid.h"
+#include "core/templates/rid.h"
#include "scene/3d/node_3d.h"
#include "scene/resources/material.h"
diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp
index de5496ee35..c570fc7b7c 100644
--- a/scene/3d/voxelizer.cpp
+++ b/scene/3d/voxelizer.cpp
@@ -580,7 +580,6 @@ void Voxelizer::_fixup_plot(int p_idx, int p_level) {
/*if (bake_light.size()) {
for(int i=0;i<6;i++) {
-
}
}*/
diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp
index 5e73e460ed..3c12d4991e 100644
--- a/scene/3d/world_environment.cpp
+++ b/scene/3d/world_environment.cpp
@@ -110,22 +110,30 @@ Ref<CameraEffects> WorldEnvironment::get_camera_effects() const {
}
String WorldEnvironment::get_configuration_warning() const {
+ String warning = Node::get_configuration_warning();
+
if (!environment.is_valid()) {
- return TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect.");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ warning += TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect.");
}
if (!is_inside_tree()) {
- return String();
+ return warning;
}
List<Node *> nodes;
get_tree()->get_nodes_in_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), &nodes);
if (nodes.size() > 1) {
- return TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes).");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ warning += TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes).");
}
- return String();
+ return warning;
}
void WorldEnvironment::_bind_methods() {
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index f4a514cdd6..763461880f 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -60,13 +60,18 @@ String XRCamera3D::get_configuration_warning() const {
return String();
}
+ String warning = Camera3D::get_configuration_warning();
+
// must be child node of XROrigin3D!
XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
if (origin == nullptr) {
- return TTR("XRCamera3D must have an XROrigin3D node as its parent.");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ warning += TTR("XRCamera3D must have an XROrigin3D node as its parent.");
};
- return String();
+ return warning;
};
Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const {
@@ -206,7 +211,7 @@ void XRController3D::_notification(int p_what) {
emit_signal("button_pressed", i);
button_states += mask;
} else if (was_pressed && !is_pressed) {
- emit_signal("button_release", i);
+ emit_signal("button_released", i);
button_states -= mask;
};
@@ -252,7 +257,7 @@ void XRController3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_mesh"), &XRController3D::get_mesh);
ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::INT, "button")));
- ADD_SIGNAL(MethodInfo("button_release", PropertyInfo(Variant::INT, "button")));
+ ADD_SIGNAL(MethodInfo("button_released", PropertyInfo(Variant::INT, "button")));
ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")));
};
@@ -277,7 +282,7 @@ String XRController3D::get_controller_name() const {
return String("Not connected");
};
- return tracker->get_name();
+ return tracker->get_tracker_name();
};
int XRController3D::get_joystick_id() const {
@@ -362,17 +367,25 @@ String XRController3D::get_configuration_warning() const {
return String();
}
+ String warning = Node3D::get_configuration_warning();
+
// must be child node of XROrigin!
XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
if (origin == nullptr) {
- return TTR("XRController3D must have an XROrigin3D node as its parent.");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ warning += TTR("XRController3D must have an XROrigin3D node as its parent.");
};
if (controller_id == 0) {
- return TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller.");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ warning += TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller.");
};
- return String();
+ return warning;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -467,7 +480,7 @@ String XRAnchor3D::get_anchor_name() const {
return String("Not connected");
};
- return tracker->get_name();
+ return tracker->get_tracker_name();
};
bool XRAnchor3D::get_is_active() const {
@@ -479,17 +492,25 @@ String XRAnchor3D::get_configuration_warning() const {
return String();
}
+ String warning = Node3D::get_configuration_warning();
+
// must be child node of XROrigin3D!
XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
if (origin == nullptr) {
- return TTR("XRAnchor3D must have an XROrigin3D node as its parent.");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ warning += TTR("XRAnchor3D must have an XROrigin3D node as its parent.");
};
if (anchor_id == 0) {
- return TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor.");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ warning += TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor.");
};
- return String();
+ return warning;
};
Plane XRAnchor3D::get_plane() const {
@@ -512,11 +533,16 @@ String XROrigin3D::get_configuration_warning() const {
return String();
}
+ String warning = Node3D::get_configuration_warning();
+
if (tracked_camera == nullptr) {
- return TTR("XROrigin3D requires an XRCamera3D child node.");
+ if (!warning.empty()) {
+ warning += "\n\n";
+ }
+ warning += TTR("XROrigin3D requires an XRCamera3D child node.");
}
- return String();
+ return warning;
};
void XROrigin3D::_bind_methods() {