summaryrefslogtreecommitdiff
path: root/scene/3d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d')
-rw-r--r--scene/3d/SCsub2
-rw-r--r--scene/3d/area.cpp9
-rw-r--r--scene/3d/arvr_nodes.cpp54
-rw-r--r--scene/3d/arvr_nodes.h7
-rw-r--r--scene/3d/audio_stream_player_3d.cpp74
-rw-r--r--scene/3d/audio_stream_player_3d.h3
-rw-r--r--scene/3d/camera.cpp59
-rw-r--r--scene/3d/camera.h8
-rw-r--r--scene/3d/collision_object.cpp6
-rw-r--r--scene/3d/collision_shape.cpp36
-rw-r--r--scene/3d/collision_shape.h4
-rw-r--r--scene/3d/cpu_particles.cpp89
-rw-r--r--scene/3d/cpu_particles.h3
-rw-r--r--scene/3d/gi_probe.cpp10
-rw-r--r--scene/3d/gi_probe.h2
-rw-r--r--scene/3d/light.cpp11
-rw-r--r--scene/3d/light.h1
-rw-r--r--scene/3d/mesh_instance.cpp2
-rw-r--r--scene/3d/navigation.cpp64
-rw-r--r--scene/3d/navigation_mesh.cpp116
-rw-r--r--scene/3d/navigation_mesh.h21
-rw-r--r--scene/3d/particles.cpp10
-rw-r--r--scene/3d/path.cpp14
-rw-r--r--scene/3d/physics_body.cpp61
-rw-r--r--scene/3d/physics_body.h4
-rw-r--r--scene/3d/reflection_probe.h2
-rw-r--r--scene/3d/skeleton.cpp67
-rw-r--r--scene/3d/skeleton.h4
-rw-r--r--scene/3d/soft_body.cpp10
-rw-r--r--scene/3d/soft_body.h1
-rw-r--r--scene/3d/spatial.cpp26
-rw-r--r--scene/3d/sprite_3d.cpp34
-rw-r--r--scene/3d/vehicle_body.cpp2
-rw-r--r--scene/3d/visual_instance.cpp8
-rw-r--r--scene/3d/visual_instance.h2
-rw-r--r--scene/3d/voxel_light_baker.cpp40
-rw-r--r--scene/3d/world_environment.cpp (renamed from scene/3d/scenario_fx.cpp)4
-rw-r--r--scene/3d/world_environment.h (renamed from scene/3d/scenario_fx.h)2
38 files changed, 574 insertions, 298 deletions
diff --git a/scene/3d/SCsub b/scene/3d/SCsub
index 35cc7479d8..200cf4316f 100644
--- a/scene/3d/SCsub
+++ b/scene/3d/SCsub
@@ -7,6 +7,6 @@ if env['disable_3d']:
env.scene_sources.append("3d/skeleton.cpp")
env.scene_sources.append("3d/particles.cpp")
env.scene_sources.append("3d/visual_instance.cpp")
- env.scene_sources.append("3d/scenario_fx.cpp")
+ env.scene_sources.append("3d/world_environment.cpp")
else:
env.add_source_files(env.scene_sources, "*.cpp")
diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp
index 99f43b1242..3557f0425c 100644
--- a/scene/3d/area.cpp
+++ b/scene/3d/area.cpp
@@ -356,7 +356,9 @@ void Area::_area_inout(int p_status, const RID &p_area, int p_instance, int p_ar
Map<ObjectID, AreaState>::Element *E = area_map.find(objid);
- ERR_FAIL_COND(!area_in && !E);
+ if (!area_in && !E) {
+ return; //likely removed from the tree
+ }
locked = true;
@@ -439,10 +441,10 @@ Array Area::get_overlapping_bodies() const {
void Area::set_monitorable(bool p_enable) {
- if (locked || PhysicsServer::get_singleton()->is_flushing_queries()) {
+ if (locked || (is_inside_tree() && PhysicsServer::get_singleton()->is_flushing_queries())) {
ERR_EXPLAIN("Function blocked during in/out signal. Use set_deferred(\"monitorable\",true/false)");
+ ERR_FAIL();
}
- ERR_FAIL_COND(locked || PhysicsServer::get_singleton()->is_flushing_queries());
if (p_enable == monitorable)
return;
@@ -756,7 +758,6 @@ Area::Area() :
monitorable = false;
collision_mask = 1;
collision_layer = 1;
- set_ray_pickable(false);
set_monitoring(true);
set_monitorable(true);
diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp
index 17b698c1b8..52fa96ee4a 100644
--- a/scene/3d/arvr_nodes.cpp
+++ b/scene/3d/arvr_nodes.cpp
@@ -233,6 +233,13 @@ void ARVRController::_notification(int p_what) {
} else {
button_states = 0;
};
+
+ // check for an updated mesh
+ Ref<Mesh> trackerMesh = tracker->get_mesh();
+ if (mesh != trackerMesh) {
+ mesh = trackerMesh;
+ emit_signal("mesh_updated", mesh);
+ }
};
}; break;
default:
@@ -258,8 +265,11 @@ void ARVRController::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &ARVRController::set_rumble);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "rumble", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_rumble", "get_rumble");
+ ClassDB::bind_method(D_METHOD("get_mesh"), &ARVRController::get_mesh);
+
ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::INT, "button")));
ADD_SIGNAL(MethodInfo("button_release", PropertyInfo(Variant::INT, "button")));
+ ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")));
};
void ARVRController::set_controller_id(int p_controller_id) {
@@ -341,6 +351,10 @@ void ARVRController::set_rumble(real_t p_rumble) {
};
};
+Ref<Mesh> ARVRController::get_mesh() const {
+ return mesh;
+}
+
bool ARVRController::get_is_active() const {
return is_active;
};
@@ -365,11 +379,11 @@ String ARVRController::get_configuration_warning() const {
// must be child node of ARVROrigin!
ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
if (origin == NULL) {
- return TTR("ARVRController must have an ARVROrigin node as its parent");
+ return TTR("ARVRController must have an ARVROrigin node as its parent.");
};
if (controller_id == 0) {
- return TTR("The controller id must not be 0 or this controller will not be bound to an actual controller");
+ return TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller.");
};
return String();
@@ -423,6 +437,13 @@ void ARVRAnchor::_notification(int p_what) {
// apply our reference frame and set our transform
set_transform(arvr_server->get_reference_frame() * transform);
+
+ // check for an updated mesh
+ Ref<Mesh> trackerMesh = tracker->get_mesh();
+ if (mesh != trackerMesh) {
+ mesh = trackerMesh;
+ emit_signal("mesh_updated", mesh);
+ }
};
}; break;
default:
@@ -441,6 +462,9 @@ void ARVRAnchor::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_size"), &ARVRAnchor::get_size);
ClassDB::bind_method(D_METHOD("get_plane"), &ARVRAnchor::get_plane);
+
+ ClassDB::bind_method(D_METHOD("get_mesh"), &ARVRAnchor::get_mesh);
+ ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")));
};
void ARVRAnchor::set_anchor_id(int p_anchor_id) {
@@ -482,11 +506,11 @@ String ARVRAnchor::get_configuration_warning() const {
// must be child node of ARVROrigin!
ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
if (origin == NULL) {
- return TTR("ARVRAnchor must have an ARVROrigin node as its parent");
+ return TTR("ARVRAnchor must have an ARVROrigin node as its parent.");
};
if (anchor_id == 0) {
- return TTR("The anchor id must not be 0 or this anchor will not be bound to an actual anchor");
+ return TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor.");
};
return String();
@@ -501,6 +525,10 @@ Plane ARVRAnchor::get_plane() const {
return plane;
};
+Ref<Mesh> ARVRAnchor::get_mesh() const {
+ return mesh;
+}
+
ARVRAnchor::ARVRAnchor() {
anchor_id = 0;
is_active = true;
@@ -517,7 +545,7 @@ String ARVROrigin::get_configuration_warning() const {
return String();
if (tracked_camera == NULL)
- return TTR("ARVROrigin requires an ARVRCamera child node");
+ return TTR("ARVROrigin requires an ARVRCamera child node.");
return String();
};
@@ -555,6 +583,10 @@ void ARVROrigin::set_world_scale(float p_world_scale) {
};
void ARVROrigin::_notification(int p_what) {
+ // get our ARVRServer
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL(arvr_server);
+
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
set_process_internal(true);
@@ -563,10 +595,6 @@ void ARVROrigin::_notification(int p_what) {
set_process_internal(false);
}; break;
case NOTIFICATION_INTERNAL_PROCESS: {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL(arvr_server);
-
// set our world origin to our node transform
arvr_server->set_world_origin(get_global_transform());
@@ -583,6 +611,14 @@ void ARVROrigin::_notification(int p_what) {
default:
break;
};
+
+ // send our notification to all active ARVR interfaces, they may need to react to it also
+ for (int i = 0; i < arvr_server->get_interface_count(); i++) {
+ Ref<ARVRInterface> interface = arvr_server->get_interface(i);
+ if (interface.is_valid() && interface->is_initialized()) {
+ interface->notification(p_what);
+ }
+ }
};
ARVROrigin::ARVROrigin() {
diff --git a/scene/3d/arvr_nodes.h b/scene/3d/arvr_nodes.h
index 523bc112c1..0833e18d48 100644
--- a/scene/3d/arvr_nodes.h
+++ b/scene/3d/arvr_nodes.h
@@ -33,6 +33,7 @@
#include "scene/3d/camera.h"
#include "scene/3d/spatial.h"
+#include "scene/resources/mesh.h"
#include "servers/arvr/arvr_positional_tracker.h"
/**
@@ -75,6 +76,7 @@ private:
int controller_id;
bool is_active;
int button_states;
+ Ref<Mesh> mesh;
protected:
void _notification(int p_what);
@@ -95,6 +97,8 @@ public:
bool get_is_active() const;
ARVRPositionalTracker::TrackerHand get_hand() const;
+ Ref<Mesh> get_mesh(void) const;
+
String get_configuration_warning() const;
ARVRController();
@@ -113,6 +117,7 @@ private:
int anchor_id;
bool is_active;
Vector3 size;
+ Ref<Mesh> mesh;
protected:
void _notification(int p_what);
@@ -128,6 +133,8 @@ public:
Plane get_plane() const;
+ Ref<Mesh> get_mesh(void) const;
+
String get_configuration_warning() const;
ARVRAnchor();
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 0f4d0383a4..ff8c218575 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -32,6 +32,7 @@
#include "core/engine.h"
#include "scene/3d/area.h"
#include "scene/3d/camera.h"
+#include "scene/3d/listener.h"
#include "scene/main/viewport.h"
void AudioStreamPlayer3D::_mix_audio() {
@@ -217,6 +218,7 @@ float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const {
case ATTENUATION_LOGARITHMIC: {
att = -20 * Math::log(p_distance / unit_size + CMP_EPSILON);
} break;
+ case ATTENUATION_DISABLED: break;
default: {
ERR_PRINT("Unknown attenuation type");
break;
@@ -324,16 +326,25 @@ void AudioStreamPlayer3D::_notification(int p_what) {
if (!vp->is_audio_listener())
continue;
- Vector3 local_pos = camera->get_global_transform().orthonormalized().affine_inverse().xform(global_pos);
+ bool listener_is_camera = true;
+ Spatial *listener_node = camera;
+
+ Listener *listener = vp->get_listener();
+ if (listener) {
+ listener_node = listener;
+ listener_is_camera = false;
+ }
+
+ Vector3 local_pos = listener_node->get_global_transform().orthonormalized().affine_inverse().xform(global_pos);
float dist = local_pos.length();
Vector3 area_sound_pos;
- Vector3 cam_area_pos;
+ Vector3 listener_area_pos;
if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) {
- area_sound_pos = space_state->get_closest_point_to_object_volume(area->get_rid(), camera->get_global_transform().origin);
- cam_area_pos = camera->get_global_transform().affine_inverse().xform(area_sound_pos);
+ area_sound_pos = space_state->get_closest_point_to_object_volume(area->get_rid(), listener_node->get_global_transform().origin);
+ listener_area_pos = listener_node->get_global_transform().affine_inverse().xform(area_sound_pos);
}
if (max_distance > 0) {
@@ -341,10 +352,10 @@ void AudioStreamPlayer3D::_notification(int p_what) {
float total_max = max_distance;
if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) {
- total_max = MAX(total_max, cam_area_pos.length());
+ total_max = MAX(total_max, listener_area_pos.length());
}
if (total_max > max_distance) {
- continue; //can't hear this sound in this camera
+ continue; //can't hear this sound in this listener
}
}
@@ -361,8 +372,8 @@ void AudioStreamPlayer3D::_notification(int p_what) {
float db_att = (1.0 - MIN(1.0, multiplier)) * attenuation_filter_db;
if (emission_angle_enabled) {
- Vector3 camtopos = global_pos - camera->get_global_transform().origin;
- float c = camtopos.normalized().dot(get_global_transform().basis.get_axis(2).normalized()); //it's z negative
+ Vector3 listenertopos = global_pos - listener_node->get_global_transform().origin;
+ float c = listenertopos.normalized().dot(get_global_transform().basis.get_axis(2).normalized()); //it's z negative
float angle = Math::rad2deg(Math::acos(c));
if (angle > emission_angle)
db_att -= -emission_angle_filter_attenuation_db;
@@ -382,8 +393,8 @@ void AudioStreamPlayer3D::_notification(int p_what) {
output.vol[0].l = 1.0 - c;
output.vol[0].r = c;
} else {
- Vector3 camtopos = global_pos - camera->get_global_transform().origin;
- float c = camtopos.normalized().dot(get_global_transform().basis.get_axis(2).normalized()); //it's z negative
+ Vector3 listenertopos = global_pos - listener_node->get_global_transform().origin;
+ float c = listenertopos.normalized().dot(get_global_transform().basis.get_axis(2).normalized()); //it's z negative
float angle = Math::rad2deg(Math::acos(c));
float av = angle * (flat_pos.x < 0 ? -1 : 1) / 180.0;
@@ -406,20 +417,20 @@ void AudioStreamPlayer3D::_notification(int p_what) {
if (cc >= 3) {
// Side pair
- float sl = Math::abs(1.0 - Math::abs(-0.4 - av));
- float sr = Math::abs(1.0 - Math::abs(0.4 - av));
+ float sleft = Math::abs(1.0 - Math::abs(-0.4 - av));
+ float sright = Math::abs(1.0 - Math::abs(0.4 - av));
- output.vol[2].l = sl;
- output.vol[2].r = sr;
+ output.vol[2].l = sleft;
+ output.vol[2].r = sright;
}
if (cc >= 4) {
// Rear pair
- float rl = Math::abs(1.0 - Math::abs(-0.2 - av));
- float rr = Math::abs(1.0 - Math::abs(0.2 - av));
+ float rleft = Math::abs(1.0 - Math::abs(-0.2 - av));
+ float rright = Math::abs(1.0 - Math::abs(0.2 - av));
- output.vol[3].l = rl;
- output.vol[3].r = rr;
+ output.vol[3].l = rleft;
+ output.vol[3].r = rright;
}
}
@@ -449,7 +460,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
if (uniformity > 0.0) {
- float distance = cam_area_pos.length();
+ float distance = listener_area_pos.length();
float attenuation = Math::db2linear(_get_attenuation_db(distance));
//float dist_att_db = -20 * Math::log(dist + 0.00001); //logarithmic attenuation, like in real life
@@ -459,7 +470,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
if (attenuation < 1.0) {
//pan the uniform sound
- Vector3 rev_pos = cam_area_pos;
+ Vector3 rev_pos = listener_area_pos;
rev_pos.y = 0;
rev_pos.normalize();
@@ -518,9 +529,13 @@ void AudioStreamPlayer3D::_notification(int p_what) {
if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
- Vector3 camera_velocity = camera->get_doppler_tracked_velocity();
+ Vector3 listener_velocity;
+
+ if (listener_is_camera) {
+ listener_velocity = camera->get_doppler_tracked_velocity();
+ }
- Vector3 local_velocity = camera->get_global_transform().orthonormalized().basis.xform_inv(linear_velocity - camera_velocity);
+ Vector3 local_velocity = listener_node->get_global_transform().orthonormalized().basis.xform_inv(linear_velocity - listener_velocity);
if (local_velocity == Vector3()) {
output.pitch_scale = 1.0;
@@ -811,7 +826,7 @@ float AudioStreamPlayer3D::get_attenuation_filter_db() const {
}
void AudioStreamPlayer3D::set_attenuation_model(AttenuationModel p_model) {
- ERR_FAIL_INDEX(p_model, 3);
+ ERR_FAIL_INDEX((int)p_model, 4);
attenuation_model = p_model;
}
@@ -840,7 +855,9 @@ void AudioStreamPlayer3D::set_doppler_tracking(DopplerTracking p_tracking) {
if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
set_notify_transform(true);
velocity_tracker->set_track_physics_step(doppler_tracking == DOPPLER_TRACKING_PHYSICS_STEP);
- velocity_tracker->reset(get_global_transform().origin);
+ if (is_inside_tree()) {
+ velocity_tracker->reset(get_global_transform().origin);
+ }
} else {
set_notify_transform(false);
}
@@ -865,6 +882,10 @@ bool AudioStreamPlayer3D::get_stream_paused() const {
return stream_paused;
}
+Ref<AudioStreamPlayback> AudioStreamPlayer3D::get_stream_playback() {
+ return stream_playback;
+}
+
void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer3D::set_stream);
@@ -931,10 +952,12 @@ void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer3D::set_stream_paused);
ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer3D::get_stream_paused);
+ ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer3D::get_stream_playback);
+
ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer3D::_bus_layout_changed);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "attenuation_model", PROPERTY_HINT_ENUM, "Inverse,InverseSquare,Log"), "set_attenuation_model", "get_attenuation_model");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "attenuation_model", PROPERTY_HINT_ENUM, "Inverse,InverseSquare,Log,Disabled"), "set_attenuation_model", "get_attenuation_model");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_db", PROPERTY_HINT_RANGE, "-80,80"), "set_unit_db", "get_unit_db");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_size", PROPERTY_HINT_RANGE, "0.1,100,0.1"), "set_unit_size", "get_unit_size");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_db", PROPERTY_HINT_RANGE, "-24,6"), "set_max_db", "get_max_db");
@@ -959,6 +982,7 @@ void AudioStreamPlayer3D::_bind_methods() {
BIND_ENUM_CONSTANT(ATTENUATION_INVERSE_DISTANCE);
BIND_ENUM_CONSTANT(ATTENUATION_INVERSE_SQUARE_DISTANCE);
BIND_ENUM_CONSTANT(ATTENUATION_LOGARITHMIC);
+ BIND_ENUM_CONSTANT(ATTENUATION_DISABLED);
BIND_ENUM_CONSTANT(OUT_OF_RANGE_MIX);
BIND_ENUM_CONSTANT(OUT_OF_RANGE_PAUSE);
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index 881652da64..98bc74b2e4 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -46,6 +46,7 @@ public:
ATTENUATION_INVERSE_DISTANCE,
ATTENUATION_INVERSE_SQUARE_DISTANCE,
ATTENUATION_LOGARITHMIC,
+ ATTENUATION_DISABLED,
};
enum OutOfRangeMode {
@@ -205,6 +206,8 @@ public:
void set_stream_paused(bool p_pause);
bool get_stream_paused() const;
+ Ref<AudioStreamPlayback> get_stream_playback();
+
AudioStreamPlayer3D();
~AudioStreamPlayer3D();
};
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
index fd28b876f3..e360de5b8e 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -55,16 +55,23 @@ void Camera::_update_camera_mode() {
case PROJECTION_ORTHOGONAL: {
set_orthogonal(size, near, far);
} break;
+ case PROJECTION_FRUSTUM: {
+ set_frustum(size, frustum_offset, near, far);
+ } break;
}
}
void Camera::_validate_property(PropertyInfo &p_property) const {
if (p_property.name == "fov") {
- if (mode == PROJECTION_ORTHOGONAL) {
+ if (mode != PROJECTION_PERSPECTIVE) {
p_property.usage = PROPERTY_USAGE_NOEDITOR;
}
} else if (p_property.name == "size") {
- if (mode == PROJECTION_PERSPECTIVE) {
+ if (mode != PROJECTION_ORTHOGONAL && mode != PROJECTION_FRUSTUM) {
+ p_property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+ } else if (p_property.name == "frustum_offset") {
+ if (mode != PROJECTION_FRUSTUM) {
p_property.usage = PROPERTY_USAGE_NOEDITOR;
}
}
@@ -177,8 +184,24 @@ void Camera::set_orthogonal(float p_size, float p_z_near, float p_z_far) {
update_gizmo();
}
+void Camera::set_frustum(float p_size, Vector2 p_offset, float p_z_near, float p_z_far) {
+ if (!force_change && size == p_size && frustum_offset == p_offset && p_z_near == near && p_z_far == far && mode == PROJECTION_FRUSTUM)
+ return;
+
+ size = p_size;
+ frustum_offset = p_offset;
+
+ near = p_z_near;
+ far = p_z_far;
+ mode = PROJECTION_FRUSTUM;
+ force_change = false;
+
+ VisualServer::get_singleton()->camera_set_frustum(camera, size, frustum_offset, near, far);
+ update_gizmo();
+}
+
void Camera::set_projection(Camera::Projection p_mode) {
- if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL) {
+ if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL || p_mode == PROJECTION_FRUSTUM) {
mode = p_mode;
_update_camera_mode();
_change_notify();
@@ -449,7 +472,9 @@ void Camera::set_doppler_tracking(DopplerTracking p_tracking) {
doppler_tracking = p_tracking;
if (p_tracking != DOPPLER_TRACKING_DISABLED) {
velocity_tracker->set_track_physics_step(doppler_tracking == DOPPLER_TRACKING_PHYSICS_STEP);
- velocity_tracker->reset(get_global_transform().origin);
+ if (is_inside_tree()) {
+ velocity_tracker->reset(get_global_transform().origin);
+ }
}
_update_camera_mode();
}
@@ -468,16 +493,19 @@ void Camera::_bind_methods() {
ClassDB::bind_method(D_METHOD("project_position", "screen_point"), &Camera::project_position);
ClassDB::bind_method(D_METHOD("set_perspective", "fov", "z_near", "z_far"), &Camera::set_perspective);
ClassDB::bind_method(D_METHOD("set_orthogonal", "size", "z_near", "z_far"), &Camera::set_orthogonal);
+ ClassDB::bind_method(D_METHOD("set_frustum", "size", "offset", "z_near", "z_far"), &Camera::set_frustum);
ClassDB::bind_method(D_METHOD("make_current"), &Camera::make_current);
ClassDB::bind_method(D_METHOD("clear_current", "enable_next"), &Camera::clear_current, DEFVAL(true));
ClassDB::bind_method(D_METHOD("set_current"), &Camera::set_current);
ClassDB::bind_method(D_METHOD("is_current"), &Camera::is_current);
ClassDB::bind_method(D_METHOD("get_camera_transform"), &Camera::get_camera_transform);
ClassDB::bind_method(D_METHOD("get_fov"), &Camera::get_fov);
+ ClassDB::bind_method(D_METHOD("get_frustum_offset"), &Camera::get_frustum_offset);
ClassDB::bind_method(D_METHOD("get_size"), &Camera::get_size);
ClassDB::bind_method(D_METHOD("get_zfar"), &Camera::get_zfar);
ClassDB::bind_method(D_METHOD("get_znear"), &Camera::get_znear);
ClassDB::bind_method(D_METHOD("set_fov"), &Camera::set_fov);
+ ClassDB::bind_method(D_METHOD("set_frustum_offset"), &Camera::set_frustum_offset);
ClassDB::bind_method(D_METHOD("set_size"), &Camera::set_size);
ClassDB::bind_method(D_METHOD("set_zfar"), &Camera::set_zfar);
ClassDB::bind_method(D_METHOD("set_znear"), &Camera::set_znear);
@@ -495,6 +523,8 @@ void Camera::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_keep_aspect_mode"), &Camera::get_keep_aspect_mode);
ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera::set_doppler_tracking);
ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera::get_doppler_tracking);
+ ClassDB::bind_method(D_METHOD("get_frustum"), &Camera::get_frustum);
+ ClassDB::bind_method(D_METHOD("get_camera_rid"), &Camera::get_camera);
ClassDB::bind_method(D_METHOD("set_cull_mask_bit", "layer", "enable"), &Camera::set_cull_mask_bit);
ClassDB::bind_method(D_METHOD("get_cull_mask_bit", "layer"), &Camera::get_cull_mask_bit);
@@ -507,15 +537,17 @@ void Camera::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset");
ADD_PROPERTY(PropertyInfo(Variant::INT, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"), "set_doppler_tracking", "get_doppler_tracking");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal"), "set_projection", "get_projection");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal,Frustum"), "set_projection", "get_projection");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset"), "set_frustum_offset", "get_frustum_offset");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "near", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01,or_greater"), "set_znear", "get_znear");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "far", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_zfar", "get_zfar");
BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE);
BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL);
+ BIND_ENUM_CONSTANT(PROJECTION_FRUSTUM);
BIND_ENUM_CONSTANT(KEEP_WIDTH);
BIND_ENUM_CONSTANT(KEEP_HEIGHT);
@@ -540,6 +572,10 @@ float Camera::get_znear() const {
return near;
}
+Vector2 Camera::get_frustum_offset() const {
+ return frustum_offset;
+}
+
float Camera::get_zfar() const {
return far;
@@ -567,6 +603,11 @@ void Camera::set_znear(float p_znear) {
_update_camera_mode();
}
+void Camera::set_frustum_offset(Vector2 p_offset) {
+ frustum_offset = p_offset;
+ _update_camera_mode();
+}
+
void Camera::set_zfar(float p_zfar) {
far = p_zfar;
_update_camera_mode();
@@ -645,6 +686,7 @@ Camera::Camera() {
camera = VisualServer::get_singleton()->camera_create();
size = 1;
fov = 0;
+ frustum_offset = Vector2();
near = 0;
far = 0;
current = false;
@@ -681,8 +723,9 @@ void ClippedCamera::set_process_mode(ProcessMode p_mode) {
if (process_mode == p_mode) {
return;
}
- set_process_internal(p_mode == CLIP_PROCESS_IDLE);
- set_physics_process_internal(p_mode == CLIP_PROCESS_PHYSICS);
+ process_mode = p_mode;
+ set_process_internal(process_mode == CLIP_PROCESS_IDLE);
+ set_physics_process_internal(process_mode == CLIP_PROCESS_PHYSICS);
}
ClippedCamera::ProcessMode ClippedCamera::get_process_mode() const {
return process_mode;
@@ -745,7 +788,7 @@ void ClippedCamera::_notification(int p_what) {
float csafe, cunsafe;
if (dspace->cast_motion(pyramid_shape, xf, cam_pos - ray_from, margin, csafe, cunsafe, exclude, collision_mask, clip_to_bodies, clip_to_areas)) {
- clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from).normalized() * csafe);
+ clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from) * csafe);
}
_update_camera();
diff --git a/scene/3d/camera.h b/scene/3d/camera.h
index a531324a85..fe8cb84f0d 100644
--- a/scene/3d/camera.h
+++ b/scene/3d/camera.h
@@ -46,7 +46,8 @@ public:
enum Projection {
PROJECTION_PERSPECTIVE,
- PROJECTION_ORTHOGONAL
+ PROJECTION_ORTHOGONAL,
+ PROJECTION_FRUSTUM
};
enum KeepAspect {
@@ -68,6 +69,7 @@ private:
float fov;
float size;
+ Vector2 frustum_offset;
float near, far;
float v_offset;
float h_offset;
@@ -110,6 +112,7 @@ public:
void set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far);
void set_orthogonal(float p_size, float p_z_near, float p_z_far);
+ void set_frustum(float p_size, Vector2 p_offset, float p_near, float p_far);
void set_projection(Camera::Projection p_mode);
void make_current();
@@ -123,12 +126,15 @@ public:
float get_size() const;
float get_zfar() const;
float get_znear() const;
+ Vector2 get_frustum_offset() const;
+
Projection get_projection() const;
void set_fov(float p_fov);
void set_size(float p_size);
void set_zfar(float p_zfar);
void set_znear(float p_znear);
+ void set_frustum_offset(Vector2 p_offset);
virtual Transform get_camera_transform() const;
diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp
index d8c2042c88..fc46cf5bdb 100644
--- a/scene/3d/collision_object.cpp
+++ b/scene/3d/collision_object.cpp
@@ -52,7 +52,7 @@ void CollisionObject::_notification(int p_what) {
_update_pickable();
//get space
- };
+ } break;
case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -259,9 +259,9 @@ void CollisionObject::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape> &
s.index = total_subshapes;
s.shape = p_shape;
if (area) {
- PhysicsServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform);
+ PhysicsServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
} else {
- PhysicsServer::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform);
+ PhysicsServer::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
}
sd.shapes.push_back(s);
diff --git a/scene/3d/collision_shape.cpp b/scene/3d/collision_shape.cpp
index daee291ba3..3190e1e0b2 100644
--- a/scene/3d/collision_shape.cpp
+++ b/scene/3d/collision_shape.cpp
@@ -65,7 +65,6 @@ void CollisionShape::make_convex_from_brothers() {
}
void CollisionShape::_update_in_shape_owner(bool p_xform_only) {
-
parent->shape_owner_set_transform(owner_id, get_transform());
if (p_xform_only)
return;
@@ -91,7 +90,7 @@ void CollisionShape::_notification(int p_what) {
_update_in_shape_owner();
}
if (get_tree()->is_debugging_collisions_hint()) {
- _create_debug_shape();
+ _update_debug_shape();
}
} break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
@@ -124,6 +123,10 @@ String CollisionShape::get_configuration_warning() const {
return TTR("A shape must be provided for CollisionShape to function. Please create a shape resource for it!");
}
+ if (shape->is_class("PlaneShape")) {
+ return TTR("Plane shapes don't work well and will be removed in future versions. Please don't use them.");
+ }
+
return String();
}
@@ -138,17 +141,24 @@ void CollisionShape::_bind_methods() {
ClassDB::bind_method(D_METHOD("make_convex_from_brothers"), &CollisionShape::make_convex_from_brothers);
ClassDB::set_method_flags("CollisionShape", "make_convex_from_brothers", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
+ ClassDB::bind_method(D_METHOD("_shape_changed"), &CollisionShape::_shape_changed);
+ ClassDB::bind_method(D_METHOD("_update_debug_shape"), &CollisionShape::_update_debug_shape);
+
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), "set_shape", "get_shape");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
}
void CollisionShape::set_shape(const Ref<Shape> &p_shape) {
- if (!shape.is_null())
+ if (!shape.is_null()) {
shape->unregister_owner(this);
+ shape->disconnect("changed", this, "_shape_changed");
+ }
shape = p_shape;
- if (!shape.is_null())
+ if (!shape.is_null()) {
shape->register_owner(this);
+ shape->connect("changed", this, "_shape_changed");
+ }
update_gizmo();
if (parent) {
parent->shape_owner_clear_shapes(owner_id);
@@ -157,6 +167,8 @@ void CollisionShape::set_shape(const Ref<Shape> &p_shape) {
}
}
+ if (is_inside_tree())
+ _shape_changed();
update_configuration_warning();
}
@@ -195,7 +207,8 @@ CollisionShape::~CollisionShape() {
//VisualServer::get_singleton()->free(indicator);
}
-void CollisionShape::_create_debug_shape() {
+void CollisionShape::_update_debug_shape() {
+ debug_shape_dirty = false;
if (debug_shape) {
debug_shape->queue_delete();
@@ -203,15 +216,22 @@ void CollisionShape::_create_debug_shape() {
}
Ref<Shape> s = get_shape();
-
if (s.is_null())
return;
Ref<Mesh> mesh = s->get_debug_mesh();
-
MeshInstance *mi = memnew(MeshInstance);
mi->set_mesh(mesh);
-
add_child(mi);
debug_shape = mi;
}
+
+void CollisionShape::_shape_changed() {
+ // If this is a heightfield shape our center may have changed
+ _update_in_shape_owner(true);
+
+ if (is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !debug_shape_dirty) {
+ debug_shape_dirty = true;
+ call_deferred("_update_debug_shape");
+ }
+}
diff --git a/scene/3d/collision_shape.h b/scene/3d/collision_shape.h
index 0c8e383a7f..98427b8590 100644
--- a/scene/3d/collision_shape.h
+++ b/scene/3d/collision_shape.h
@@ -45,12 +45,14 @@ class CollisionShape : public Spatial {
CollisionObject *parent;
Node *debug_shape;
+ bool debug_shape_dirty;
void resource_changed(RES res);
bool disabled;
protected:
- void _create_debug_shape();
+ void _update_debug_shape();
+ void _shape_changed();
void _update_in_shape_owner(bool p_xform_only = false);
diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp
index 29610cb0bf..138c446fea 100644
--- a/scene/3d/cpu_particles.cpp
+++ b/scene/3d/cpu_particles.cpp
@@ -47,20 +47,8 @@ PoolVector<Face3> CPUParticles::get_faces(uint32_t p_usage_flags) const {
void CPUParticles::set_emitting(bool p_emitting) {
emitting = p_emitting;
- if (!is_processing_internal()) {
+ if (emitting)
set_process_internal(true);
- if (is_inside_tree()) {
-#ifndef NO_THREADS
- update_mutex->lock();
-#endif
- VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread");
- VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true);
-
-#ifndef NO_THREADS
- update_mutex->unlock();
-#endif
- }
- }
}
void CPUParticles::set_amount(int p_amount) {
@@ -224,7 +212,7 @@ String CPUParticles::get_configuration_warning() const {
get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid())) {
if (warnings != String())
warnings += "\n";
- warnings += "- " + TTR("CPUParticles animation requires the usage of a SpatialMaterial with \"Billboard Particles\" enabled.");
+ warnings += "- " + TTR("CPUParticles animation requires the usage of a SpatialMaterial whose Billboard Mode is set to \"Particle Billboard\".");
}
return warnings;
@@ -343,7 +331,8 @@ void CPUParticles::set_param_curve(Parameter p_param, const Ref<Curve> &p_curve)
} break;
case PARAM_ANIM_OFFSET: {
} break;
- default: {}
+ default: {
+ }
}
}
Ref<Curve> CPUParticles::get_param_curve(Parameter p_param) const {
@@ -556,7 +545,7 @@ void CPUParticles::_particles_process(float p_delta) {
if (restart_time >= prev_time && restart_time < time) {
restart = true;
if (fractional_delta) {
- local_delta = (time - restart_time) * lifetime;
+ local_delta = time - restart_time;
}
}
@@ -564,13 +553,13 @@ void CPUParticles::_particles_process(float p_delta) {
if (restart_time >= prev_time) {
restart = true;
if (fractional_delta) {
- local_delta = (1.0 - restart_time + time) * lifetime;
+ local_delta = lifetime - restart_time + time;
}
} else if (restart_time < time) {
restart = true;
if (fractional_delta) {
- local_delta = (time - restart_time) * lifetime;
+ local_delta = time - restart_time;
}
}
}
@@ -1004,6 +993,27 @@ void CPUParticles::_update_particle_data_buffer() {
#endif
}
+void CPUParticles::_set_redraw(bool p_redraw) {
+ if (redraw == p_redraw)
+ return;
+ redraw = p_redraw;
+#ifndef NO_THREADS
+ update_mutex->lock();
+#endif
+ if (redraw) {
+ VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread");
+ VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true);
+ VS::get_singleton()->multimesh_set_visible_instances(multimesh, -1);
+ } else {
+ VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false);
+ VS::get_singleton()->multimesh_set_visible_instances(multimesh, 0);
+ }
+#ifndef NO_THREADS
+ update_mutex->unlock();
+#endif
+}
+
void CPUParticles::_update_render_thread() {
#ifndef NO_THREADS
@@ -1022,31 +1032,11 @@ void CPUParticles::_update_render_thread() {
void CPUParticles::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
- if (is_processing_internal()) {
-
-#ifndef NO_THREADS
- update_mutex->lock();
-#endif
- VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread");
- VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true);
-#ifndef NO_THREADS
- update_mutex->unlock();
-#endif
- }
+ set_process_internal(emitting);
}
if (p_what == NOTIFICATION_EXIT_TREE) {
- if (is_processing_internal()) {
-
-#ifndef NO_THREADS
- update_mutex->lock();
-#endif
- VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
- VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false);
-#ifndef NO_THREADS
- update_mutex->unlock();
-#endif
- }
+ _set_redraw(false);
}
if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) {
@@ -1054,26 +1044,20 @@ void CPUParticles::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
- if (particles.size() == 0 || !is_visible_in_tree())
+ if (particles.size() == 0 || !is_visible_in_tree()) {
+ _set_redraw(false);
return;
+ }
float delta = get_process_delta_time();
if (emitting) {
-
inactive_time = 0;
} else {
inactive_time += delta;
if (inactive_time > lifetime * 1.2) {
set_process_internal(false);
-#ifndef NO_THREADS
- update_mutex->lock();
-#endif
- VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
- VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false);
+ _set_redraw(false);
-#ifndef NO_THREADS
- update_mutex->unlock();
-#endif
//reset variables
time = 0;
inactive_time = 0;
@@ -1082,6 +1066,7 @@ void CPUParticles::_notification(int p_what) {
return;
}
}
+ _set_redraw(true);
bool processed = false;
@@ -1238,7 +1223,7 @@ void CPUParticles::_bind_methods() {
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_GROUP("Time", "");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
@@ -1406,8 +1391,10 @@ CPUParticles::CPUParticles() {
inactive_time = 0;
frame_remainder = 0;
cycle = 0;
+ redraw = false;
multimesh = VisualServer::get_singleton()->multimesh_create();
+ VisualServer::get_singleton()->multimesh_set_visible_instances(multimesh, 0);
set_base(multimesh);
set_emitting(true);
diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h
index b50befe7be..b863a3cb3f 100644
--- a/scene/3d/cpu_particles.h
+++ b/scene/3d/cpu_particles.h
@@ -104,6 +104,7 @@ private:
float inactive_time;
float frame_remainder;
int cycle;
+ bool redraw;
RID multimesh;
@@ -178,6 +179,8 @@ private:
void _update_render_thread();
+ void _set_redraw(bool p_redraw);
+
protected:
static void _bind_methods();
void _notification(int p_what);
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp
index 5b08ea7790..c491275f00 100644
--- a/scene/3d/gi_probe.cpp
+++ b/scene/3d/gi_probe.cpp
@@ -30,6 +30,8 @@
#include "gi_probe.h"
+#include "core/os/os.h"
+
#include "mesh_instance.h"
#include "voxel_light_baker.h"
@@ -490,6 +492,14 @@ PoolVector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const {
return PoolVector<Face3>();
}
+String GIProbe::get_configuration_warning() const {
+
+ if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) {
+ return TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead.");
+ }
+ return String();
+}
+
void GIProbe::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_probe_data", "data"), &GIProbe::set_probe_data);
diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h
index 87664e06b8..4badabbadf 100644
--- a/scene/3d/gi_probe.h
+++ b/scene/3d/gi_probe.h
@@ -168,6 +168,8 @@ public:
virtual AABB get_aabb() const;
virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
+ virtual String get_configuration_warning() const;
+
GIProbe();
~GIProbe();
};
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index 3b514dab8c..2377068ede 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -152,6 +152,7 @@ PoolVector<Face3> Light::get_faces(uint32_t p_usage_flags) const {
void Light::set_bake_mode(BakeMode p_mode) {
bake_mode = p_mode;
+ VS::get_singleton()->light_set_use_gi(light, p_mode != BAKE_DISABLED);
}
Light::BakeMode Light::get_bake_mode() const {
@@ -210,6 +211,13 @@ bool Light::is_editor_only() const {
return editor_only;
}
+void Light::_validate_property(PropertyInfo &property) const {
+
+ if (VisualServer::get_singleton()->is_low_end() && property.name == "shadow_contact") {
+ property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
+ }
+}
+
void Light::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_editor_only", "editor_only"), &Light::set_editor_only);
@@ -286,7 +294,8 @@ Light::Light(VisualServer::LightType p_type) {
case VS::LIGHT_DIRECTIONAL: light = VisualServer::get_singleton()->directional_light_create(); break;
case VS::LIGHT_OMNI: light = VisualServer::get_singleton()->omni_light_create(); break;
case VS::LIGHT_SPOT: light = VisualServer::get_singleton()->spot_light_create(); break;
- default: {};
+ default: {
+ };
}
VS::get_singleton()->instance_set_base(get_instance(), light);
diff --git a/scene/3d/light.h b/scene/3d/light.h
index 85e0ce3c24..ddd5bc6b3a 100644
--- a/scene/3d/light.h
+++ b/scene/3d/light.h
@@ -92,6 +92,7 @@ protected:
static void _bind_methods();
void _notification(int p_what);
+ virtual void _validate_property(PropertyInfo &property) const;
Light(VisualServer::LightType p_type);
diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp
index 848889155b..89072519d5 100644
--- a/scene/3d/mesh_instance.cpp
+++ b/scene/3d/mesh_instance.cpp
@@ -96,7 +96,7 @@ void MeshInstance::_get_property_list(List<PropertyInfo> *p_list) const {
ls.sort();
for (List<String>::Element *E = ls.front(); E; E = E->next()) {
- p_list->push_back(PropertyInfo(Variant::REAL, E->get(), PROPERTY_HINT_RANGE, "0,1,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, E->get(), PROPERTY_HINT_RANGE, "0,1,0.00001"));
}
if (mesh.is_valid()) {
diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp
index 5a3c8223ff..612d91c6e1 100644
--- a/scene/3d/navigation.cpp
+++ b/scene/3d/navigation.cpp
@@ -340,16 +340,12 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
};
Vector3 entry = Geometry::get_closest_point_to_segment(begin_poly->entry, edge);
- begin_poly->edges[i].C->distance = begin_poly->entry.distance_to(entry);
+ begin_poly->edges[i].C->distance = begin_point.distance_to(entry);
begin_poly->edges[i].C->entry = entry;
#else
begin_poly->edges[i].C->distance = begin_poly->center.distance_to(begin_poly->edges[i].C->center);
#endif
open_list.push_back(begin_poly->edges[i].C);
-
- if (begin_poly->edges[i].C == end_poly) {
- found_route = true;
- }
}
}
@@ -370,28 +366,7 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
float cost = p->distance;
#ifdef USE_ENTRY_POINT
- int es = p->edges.size();
-
- float shortest_distance = 1e30;
-
- for (int i = 0; i < es; i++) {
- Polygon::Edge &e = p->edges.write[i];
-
- if (!e.C)
- continue;
-
- Vector3 edge[2] = {
- _get_vertex(p->edges[i].point),
- _get_vertex(p->edges[(i + 1) % es].point)
- };
-
- Vector3 edge_point = Geometry::get_closest_point_to_segment(p->entry, edge);
- float dist = p->entry.distance_to(edge_point);
- if (dist < shortest_distance)
- shortest_distance = dist;
- }
-
- cost += shortest_distance;
+ cost += p->entry.distance_to(end_point);
#else
cost += p->center.distance_to(end_point);
#endif
@@ -404,6 +379,12 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
Polygon *p = least_cost_poly->get();
//open the neighbours for search
+ if (p == end_poly) {
+ //oh my reached end! stop algorithm
+ found_route = true;
+ break;
+ }
+
for (int i = 0; i < p->edges.size(); i++) {
Polygon::Edge &e = p->edges.write[i];
@@ -411,7 +392,17 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
if (!e.C)
continue;
+#ifdef USE_ENTRY_POINT
+ Vector3 edge[2] = {
+ _get_vertex(p->edges[i].point),
+ _get_vertex(p->edges[(i + 1) % p->edges.size()].point)
+ };
+
+ Vector3 entry = Geometry::get_closest_point_to_segment(p->entry, edge);
+ float distance = p->entry.distance_to(entry) + p->distance;
+#else
float distance = p->center.distance_to(e.C->center) + p->distance;
+#endif
if (e.C->prev_edge != -1) {
//oh this was visited already, can we win the cost?
@@ -420,25 +411,22 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
e.C->prev_edge = e.C_edge;
e.C->distance = distance;
+#ifdef USE_ENTRY_POINT
+ e.C->entry = entry;
+#endif
}
} else {
//add to open neighbours
e.C->prev_edge = e.C_edge;
e.C->distance = distance;
+#ifdef USE_ENTRY_POINT
+ e.C->entry = entry;
+#endif
open_list.push_back(e.C);
-
- if (e.C == end_poly) {
- //oh my reached end! stop algorithm
- found_route = true;
- break;
- }
}
}
- if (found_route)
- break;
-
open_list.erase(least_cost_poly);
}
@@ -539,8 +527,12 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
path.push_back(end_point);
while (true) {
int prev = p->prev_edge;
+#ifdef USE_ENTRY_POINT
+ Vector3 point = p->entry;
+#else
int prev_n = (p->prev_edge + 1) % p->edges.size();
Vector3 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point)) * 0.5;
+#endif
path.push_back(point);
p = p->edges[prev].C;
if (p == begin_poly)
diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp
index 75301af657..f82543b789 100644
--- a/scene/3d/navigation_mesh.cpp
+++ b/scene/3d/navigation_mesh.cpp
@@ -73,6 +73,41 @@ int NavigationMesh::get_sample_partition_type() const {
return static_cast<int>(partition_type);
}
+void NavigationMesh::set_parsed_geometry_type(int p_value) {
+ ERR_FAIL_COND(p_value >= PARSED_GEOMETRY_MAX);
+ parsed_geometry_type = static_cast<ParsedGeometryType>(p_value);
+ _change_notify();
+}
+
+int NavigationMesh::get_parsed_geometry_type() const {
+ return parsed_geometry_type;
+}
+
+void NavigationMesh::set_collision_mask(uint32_t p_mask) {
+
+ collision_mask = p_mask;
+}
+
+uint32_t NavigationMesh::get_collision_mask() const {
+
+ return collision_mask;
+}
+
+void NavigationMesh::set_collision_mask_bit(int p_bit, bool p_value) {
+
+ uint32_t mask = get_collision_mask();
+ if (p_value)
+ mask |= 1 << p_bit;
+ else
+ mask &= ~(1 << p_bit);
+ set_collision_mask(mask);
+}
+
+bool NavigationMesh::get_collision_mask_bit(int p_bit) const {
+
+ return get_collision_mask() & (1 << p_bit);
+}
+
void NavigationMesh::set_cell_size(float p_value) {
cell_size = p_value;
}
@@ -204,6 +239,7 @@ bool NavigationMesh::get_filter_walkable_low_height_spans() const {
void NavigationMesh::set_vertices(const PoolVector<Vector3> &p_vertices) {
vertices = p_vertices;
+ _change_notify();
}
PoolVector<Vector3> NavigationMesh::get_vertices() const {
@@ -217,6 +253,7 @@ void NavigationMesh::_set_polygons(const Array &p_array) {
for (int i = 0; i < p_array.size(); i++) {
polygons.write[i].indices = p_array[i];
}
+ _change_notify();
}
Array NavigationMesh::_get_polygons() const {
@@ -235,6 +272,7 @@ void NavigationMesh::add_polygon(const Vector<int> &p_polygon) {
Polygon polygon;
polygon.indices = p_polygon;
polygons.push_back(polygon);
+ _change_notify();
}
int NavigationMesh::get_polygon_count() const {
@@ -292,11 +330,11 @@ Ref<Mesh> NavigationMesh::get_debug_mesh() {
if (ek.from < ek.to)
SWAP(ek.from, ek.to);
- Map<_EdgeKey, bool>::Element *E = edge_map.find(ek);
+ Map<_EdgeKey, bool>::Element *F = edge_map.find(ek);
- if (E) {
+ if (F) {
- E->get() = false;
+ F->get() = false;
} else {
@@ -340,6 +378,15 @@ void NavigationMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sample_partition_type", "sample_partition_type"), &NavigationMesh::set_sample_partition_type);
ClassDB::bind_method(D_METHOD("get_sample_partition_type"), &NavigationMesh::get_sample_partition_type);
+ ClassDB::bind_method(D_METHOD("set_parsed_geometry_type", "geometry_type"), &NavigationMesh::set_parsed_geometry_type);
+ ClassDB::bind_method(D_METHOD("get_parsed_geometry_type"), &NavigationMesh::get_parsed_geometry_type);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &NavigationMesh::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &NavigationMesh::get_collision_mask);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &NavigationMesh::set_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &NavigationMesh::get_collision_mask_bit);
+
ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &NavigationMesh::set_cell_size);
ClassDB::bind_method(D_METHOD("get_cell_size"), &NavigationMesh::get_cell_size);
@@ -405,30 +452,45 @@ void NavigationMesh::_bind_methods() {
BIND_CONSTANT(SAMPLE_PARTITION_MONOTONE);
BIND_CONSTANT(SAMPLE_PARTITION_LAYERS);
+ BIND_CONSTANT(PARSED_GEOMETRY_MESH_INSTANCES);
+ BIND_CONSTANT(PARSED_GEOMETRY_STATIC_COLLIDERS);
+ BIND_CONSTANT(PARSED_GEOMETRY_BOTH);
+
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type/sample_partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_sample_partition_type", "get_sample_partition_type");
-
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/size", PROPERTY_HINT_RANGE, "0.1,1.0,0.01"), "set_cell_size", "get_cell_size");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/height", PROPERTY_HINT_RANGE, "0.1,1.0,0.01"), "set_cell_height", "get_cell_height");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/height", PROPERTY_HINT_RANGE, "0.1,5.0,0.01"), "set_agent_height", "get_agent_height");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/radius", PROPERTY_HINT_RANGE, "0.1,5.0,0.01"), "set_agent_radius", "get_agent_radius");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/max_climb", PROPERTY_HINT_RANGE, "0.1,5.0,0.01"), "set_agent_max_climb", "get_agent_max_climb");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/size", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_size", "get_cell_size");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/height", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_height", "get_cell_height");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/height", PROPERTY_HINT_RANGE, "0.1,5.0,0.01,or_greater"), "set_agent_height", "get_agent_height");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/radius", PROPERTY_HINT_RANGE, "0.1,5.0,0.01,or_greater"), "set_agent_radius", "get_agent_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/max_climb", PROPERTY_HINT_RANGE, "0.1,5.0,0.01,or_greater"), "set_agent_max_climb", "get_agent_max_climb");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/max_slope", PROPERTY_HINT_RANGE, "0.0,90.0,0.1"), "set_agent_max_slope", "get_agent_max_slope");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "region/min_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01"), "set_region_min_size", "get_region_min_size");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "region/merge_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01"), "set_region_merge_size", "get_region_merge_size");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "edge/max_length", PROPERTY_HINT_RANGE, "0.0,50.0,0.01"), "set_edge_max_length", "get_edge_max_length");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "edge/max_error", PROPERTY_HINT_RANGE, "0.1,3.0,0.01"), "set_edge_max_error", "get_edge_max_error");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "polygon/verts_per_poly", PROPERTY_HINT_RANGE, "3.0,12.0,1.0"), "set_verts_per_poly", "get_verts_per_poly");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "detail/sample_distance", PROPERTY_HINT_RANGE, "0.0,16.0,0.01"), "set_detail_sample_distance", "get_detail_sample_distance");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "detail/sample_max_error", PROPERTY_HINT_RANGE, "0.0,16.0,0.01"), "set_detail_sample_max_error", "get_detail_sample_max_error");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "region/min_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_min_size", "get_region_min_size");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "region/merge_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_merge_size", "get_region_merge_size");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "edge/max_length", PROPERTY_HINT_RANGE, "0.0,50.0,0.01,or_greater"), "set_edge_max_length", "get_edge_max_length");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "edge/max_error", PROPERTY_HINT_RANGE, "0.1,3.0,0.01,or_greater"), "set_edge_max_error", "get_edge_max_error");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "polygon/verts_per_poly", PROPERTY_HINT_RANGE, "3.0,12.0,1.0,or_greater"), "set_verts_per_poly", "get_verts_per_poly");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "detail/sample_distance", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater"), "set_detail_sample_distance", "get_detail_sample_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "detail/sample_max_error", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater"), "set_detail_sample_max_error", "get_detail_sample_max_error");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/low_hanging_obstacles"), "set_filter_low_hanging_obstacles", "get_filter_low_hanging_obstacles");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/ledge_spans"), "set_filter_ledge_spans", "get_filter_ledge_spans");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/filter_walkable_low_height_spans"), "set_filter_walkable_low_height_spans", "get_filter_walkable_low_height_spans");
}
+void NavigationMesh::_validate_property(PropertyInfo &property) const {
+ if (property.name == "geometry/collision_mask") {
+ if (parsed_geometry_type == PARSED_GEOMETRY_MESH_INSTANCES) {
+ property.usage = 0;
+ return;
+ }
+ }
+}
+
NavigationMesh::NavigationMesh() {
cell_size = 0.3f;
cell_height = 0.2f;
@@ -445,7 +507,8 @@ NavigationMesh::NavigationMesh() {
detail_sample_max_error = 1.0f;
partition_type = SAMPLE_PARTITION_WATERSHED;
-
+ parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES;
+ collision_mask = 0xFFFFFFFF;
filter_low_hanging_obstacles = false;
filter_ledge_spans = false;
filter_walkable_low_height_spans = false;
@@ -566,8 +629,17 @@ void NavigationMeshInstance::set_navigation_mesh(const Ref<NavigationMesh> &p_na
navigation->navmesh_remove(nav_id);
nav_id = -1;
}
+
+ if (navmesh.is_valid()) {
+ navmesh->remove_change_receptor(this);
+ }
+
navmesh = p_navmesh;
+ if (navmesh.is_valid()) {
+ navmesh->add_change_receptor(this);
+ }
+
if (navigation && navmesh.is_valid() && enabled) {
nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this);
}
@@ -617,6 +689,11 @@ void NavigationMeshInstance::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
}
+void NavigationMeshInstance::_changed_callback(Object *p_changed, const char *p_prop) {
+ update_gizmo();
+ update_configuration_warning();
+}
+
NavigationMeshInstance::NavigationMeshInstance() {
debug_view = NULL;
@@ -625,3 +702,8 @@ NavigationMeshInstance::NavigationMeshInstance() {
enabled = true;
set_notify_transform(true);
}
+
+NavigationMeshInstance::~NavigationMeshInstance() {
+ if (navmesh.is_valid())
+ navmesh->remove_change_receptor(this);
+}
diff --git a/scene/3d/navigation_mesh.h b/scene/3d/navigation_mesh.h
index 74531e2423..5fbf3998ff 100644
--- a/scene/3d/navigation_mesh.h
+++ b/scene/3d/navigation_mesh.h
@@ -57,6 +57,7 @@ class NavigationMesh : public Resource {
protected:
static void _bind_methods();
+ virtual void _validate_property(PropertyInfo &property) const;
void _set_polygons(const Array &p_array);
Array _get_polygons() const;
@@ -69,6 +70,13 @@ public:
SAMPLE_PARTITION_MAX
};
+ enum ParsedGeometryType {
+ PARSED_GEOMETRY_MESH_INSTANCES = 0,
+ PARSED_GEOMETRY_STATIC_COLLIDERS,
+ PARSED_GEOMETRY_BOTH,
+ PARSED_GEOMETRY_MAX
+ };
+
protected:
float cell_size;
float cell_height;
@@ -85,6 +93,8 @@ protected:
float detail_sample_max_error;
SamplePartitionType partition_type;
+ ParsedGeometryType parsed_geometry_type;
+ uint32_t collision_mask;
bool filter_low_hanging_obstacles;
bool filter_ledge_spans;
@@ -95,6 +105,15 @@ public:
void set_sample_partition_type(int p_value);
int get_sample_partition_type() const;
+ void set_parsed_geometry_type(int p_value);
+ int get_parsed_geometry_type() const;
+
+ void set_collision_mask(uint32_t p_mask);
+ uint32_t get_collision_mask() const;
+
+ void set_collision_mask_bit(int p_bit, bool p_value);
+ bool get_collision_mask_bit(int p_bit) const;
+
void set_cell_size(float p_value);
float get_cell_size() const;
@@ -174,6 +193,7 @@ class NavigationMeshInstance : public Spatial {
protected:
void _notification(int p_what);
static void _bind_methods();
+ void _changed_callback(Object *p_changed, const char *p_prop);
public:
void set_enabled(bool p_enabled);
@@ -185,6 +205,7 @@ public:
String get_configuration_warning() const;
NavigationMeshInstance();
+ ~NavigationMeshInstance();
};
#endif // NAVIGATION_MESH_H
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index 2add50dd5d..156560f802 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -29,6 +29,8 @@
/*************************************************************************/
#include "particles.h"
+
+#include "core/os/os.h"
#include "scene/resources/particles_material.h"
#include "servers/visual_server.h"
@@ -224,6 +226,10 @@ bool Particles::get_fractional_delta() const {
String Particles::get_configuration_warning() const {
+ if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) {
+ return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles node instead. You can use the \"Convert to CPUParticles\" option for this purpose.");
+ }
+
String warnings;
bool meshes_found = false;
@@ -262,7 +268,7 @@ String Particles::get_configuration_warning() const {
process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
if (warnings != String())
warnings += "\n";
- warnings += "- " + TTR("Particles animation requires the usage of a SpatialMaterial with \"Billboard Particles\" enabled.");
+ warnings += "- " + TTR("Particles animation requires the usage of a SpatialMaterial whose Billboard Mode is set to \"Particle Billboard\".");
}
}
@@ -348,7 +354,7 @@ void Particles::_bind_methods() {
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_GROUP("Time", "");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp
index 9fae5a9a54..84078911cb 100644
--- a/scene/3d/path.cpp
+++ b/scene/3d/path.cpp
@@ -107,6 +107,9 @@ void PathFollow::_update_transform() {
}
float bl = c->get_baked_length();
+ if (bl == 0.0) {
+ return;
+ }
float bi = c->get_bake_interval();
float o = offset;
float o_next = offset + bi;
@@ -122,11 +125,10 @@ void PathFollow::_update_transform() {
Vector3 pos = c->interpolate_baked(o, cubic);
Transform t = get_transform();
// Vector3 pos_offset = Vector3(h_offset, v_offset, 0); not used in all cases
- // will be replaced by "Vector3(h_offset, v_offset, 0)" where it was formely used
+ // will be replaced by "Vector3(h_offset, v_offset, 0)" where it was formerly used
if (rotation_mode == ROTATION_ORIENTED) {
- Vector3 pos = c->interpolate_baked(o, cubic);
Vector3 forward = c->interpolate_baked(o_next, cubic) - pos;
if (forward.length_squared() < CMP_EPSILON2)
@@ -171,7 +173,7 @@ void PathFollow::_update_transform() {
float dot = t_prev.dot(t_cur);
float angle = Math::acos(CLAMP(dot, -1, 1));
- if (likely(Math::abs(angle) > CMP_EPSILON)) {
+ if (likely(!Math::is_zero_approx(angle))) {
if (rotation_mode == ROTATION_Y) {
// assuming we're referring to global Y-axis. is this correct?
axis.x = 0;
@@ -182,7 +184,7 @@ void PathFollow::_update_transform() {
// all components are allowed
}
- if (likely(axis.length() > CMP_EPSILON)) {
+ if (likely(!Math::is_zero_approx(axis.length()))) {
t.rotate_basis(axis.normalized(), angle);
}
}
@@ -191,7 +193,7 @@ void PathFollow::_update_transform() {
float tilt_angle = c->interpolate_baked_tilt(o);
Vector3 tilt_axis = t_cur; // not sure what tilt is supposed to do, is this correct??
- if (likely(Math::abs(tilt_angle) > CMP_EPSILON)) {
+ if (likely(!Math::is_zero_approx(Math::abs(tilt_angle)))) {
if (rotation_mode == ROTATION_Y) {
tilt_axis.x = 0;
tilt_axis.z = 0;
@@ -201,7 +203,7 @@ void PathFollow::_update_transform() {
// all components are allowed
}
- if (likely(tilt_axis.length() > CMP_EPSILON)) {
+ if (likely(!Math::is_zero_approx(tilt_axis.length()))) {
t.rotate_basis(tilt_axis.normalized(), tilt_angle);
}
}
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index 50abbd483a..57af951110 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -1104,10 +1104,10 @@ void RigidBody::_reload_physics_characteristics() {
//////////////////////////////////////////////////////
//////////////////////////
-Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_infinite_inertia, bool p_test_only) {
+Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only) {
Collision col;
- if (move_and_collide(p_motion, p_infinite_inertia, col, p_test_only)) {
+ if (move_and_collide(p_motion, p_infinite_inertia, col, p_exclude_raycast_shapes, p_test_only)) {
if (motion_cache.is_null()) {
motion_cache.instance();
motion_cache->owner = this;
@@ -1121,11 +1121,11 @@ Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_inf
return Ref<KinematicCollision>();
}
-bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_test_only) {
+bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only) {
Transform gt = get_global_transform();
PhysicsServer::MotionResult result;
- bool colliding = PhysicsServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, &result);
+ bool colliding = PhysicsServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, &result, p_exclude_raycast_shapes);
if (colliding) {
r_collision.collider_metadata = result.collider_metadata;
@@ -1181,19 +1181,16 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
while (p_max_slides) {
Collision collision;
-
bool found_collision = false;
- int test_type = 0;
-
- do {
+ for (int i = 0; i < 2; ++i) {
bool collided;
- if (test_type == 0) { //collide
+ if (i == 0) { //collide
collided = move_and_collide(motion, p_infinite_inertia, collision);
if (!collided) {
motion = Vector3(); //clear because no collision happened and motion completed
}
- } else {
+ } else { //separate raycasts (if any)
collided = separate_raycast_shapes(p_infinite_inertia, collision);
if (collided) {
collision.remainder = motion; //keep
@@ -1203,9 +1200,6 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
if (collided) {
found_collision = true;
- }
-
- if (collided) {
colliders.push_back(collision);
motion = collision.remainder;
@@ -1222,7 +1216,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
floor_velocity = collision.collider_vel;
if (p_stop_on_slope) {
- if (Vector3() == lv_n + p_floor_direction) {
+ if ((lv_n + p_floor_direction).length() < 0.01 && collision.travel.length() < 1) {
Transform gt = get_global_transform();
gt.origin -= collision.travel;
set_global_transform(gt);
@@ -1248,15 +1242,13 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
lv = lv.slide(n);
}
- for (int i = 0; i < 3; i++) {
- if (locked_axis & (1 << i)) {
- lv[i] = 0;
+ for (int j = 0; j < 3; j++) {
+ if (locked_axis & (1 << j)) {
+ lv[j] = 0;
}
}
}
-
- ++test_type;
- } while (!p_stop_on_slope && test_type < 2);
+ }
if (!found_collision || motion == Vector3())
break;
@@ -1279,14 +1271,27 @@ Vector3 KinematicBody::move_and_slide_with_snap(const Vector3 &p_linear_velocity
Collision col;
Transform gt = get_global_transform();
- if (move_and_collide(p_snap, p_infinite_inertia, col, true)) {
- gt.origin += col.travel;
- if (p_floor_direction != Vector3() && Math::acos(p_floor_direction.normalized().dot(col.normal)) < p_floor_max_angle) {
- on_floor = true;
- on_floor_body = col.collider_rid;
- floor_velocity = col.collider_vel;
+ if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) {
+
+ bool apply = true;
+ if (p_floor_direction != Vector3()) {
+ if (Math::acos(p_floor_direction.normalized().dot(col.normal)) < p_floor_max_angle) {
+ on_floor = true;
+ on_floor_body = col.collider_rid;
+ floor_velocity = col.collider_vel;
+ if (p_stop_on_slope) {
+ // move and collide may stray the object a bit because of pre un-stucking,
+ // so only ensure that motion happens on floor direction in this case.
+ col.travel = p_floor_direction * p_floor_direction.dot(col.travel);
+ }
+ } else {
+ apply = false; //snapped with floor direction, but did not snap to a floor, do not snap.
+ }
+ }
+ if (apply) {
+ gt.origin += col.travel;
+ set_global_transform(gt);
}
- set_global_transform(gt);
}
return ret;
@@ -1401,7 +1406,7 @@ Ref<KinematicCollision> KinematicBody::_get_slide_collision(int p_bounce) {
void KinematicBody::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "test_only"), &KinematicBody::_move, DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false));
ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true));
ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "floor_normal", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody::move_and_slide_with_snap, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true));
diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h
index 5570d0c86b..aa6030d44e 100644
--- a/scene/3d/physics_body.h
+++ b/scene/3d/physics_body.h
@@ -310,14 +310,14 @@ private:
_FORCE_INLINE_ bool _ignores_mode(PhysicsServer::BodyMode) const;
- Ref<KinematicCollision> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_test_only = false);
+ Ref<KinematicCollision> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
Ref<KinematicCollision> _get_slide_collision(int p_bounce);
protected:
static void _bind_methods();
public:
- bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collisionz, bool p_test_only = false);
+ bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
bool test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia);
bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision);
diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h
index 2921a3a881..48d65b79f7 100644
--- a/scene/3d/reflection_probe.h
+++ b/scene/3d/reflection_probe.h
@@ -32,7 +32,7 @@
#define REFLECTIONPROBE_H
#include "scene/3d/visual_instance.h"
-#include "scene/resources/sky_box.h"
+#include "scene/resources/sky.h"
#include "scene/resources/texture.h"
#include "servers/visual_server.h"
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index 8caf4e8e39..e192e040f2 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -70,9 +70,9 @@ bool Skeleton::_set(const StringName &p_path, const Variant &p_value) {
for (int i = 0; i < children.size(); i++) {
- NodePath path = children[i];
- ERR_CONTINUE(path.operator String() == "");
- Node *node = get_node(path);
+ NodePath npath = children[i];
+ ERR_CONTINUE(npath.operator String() == "");
+ Node *node = get_node(npath);
ERR_CONTINUE(!node);
bind_child_node_to_bone(which, node);
}
@@ -115,8 +115,8 @@ bool Skeleton::_get(const StringName &p_path, Variant &r_ret) const {
ERR_CONTINUE(!obj);
Node *node = Object::cast_to<Node>(obj);
ERR_CONTINUE(!node);
- NodePath path = get_path_to(node);
- children.push_back(path);
+ NodePath npath = get_path_to(node);
+ children.push_back(npath);
}
r_ret = children;
@@ -162,7 +162,7 @@ void Skeleton::_update_process_order() {
//now check process order
int pass_count = 0;
while (pass_count < len * len) {
- //using bubblesort because of simplicity, it wont run every frame though.
+ //using bubblesort because of simplicity, it won't run every frame though.
//bublesort worst case is O(n^2), and this may be an infinite loop if cyclic
bool swapped = false;
for (int i = 0; i < len; i++) {
@@ -198,11 +198,7 @@ void Skeleton::_notification(int p_what) {
case NOTIFICATION_ENTER_WORLD: {
- if (dirty) {
-
- dirty = false;
- _make_dirty(); // property make it dirty
- }
+ VS::get_singleton()->skeleton_set_world_transform(skeleton, use_bones_in_world_transform, get_global_transform());
} break;
case NOTIFICATION_EXIT_WORLD: {
@@ -210,21 +206,7 @@ void Skeleton::_notification(int p_what) {
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
- if (dirty)
- break; //will be eventually updated
-
- //if moved, just update transforms
- VisualServer *vs = VisualServer::get_singleton();
- const Bone *bonesptr = bones.ptr();
- int len = bones.size();
- Transform global_transform = get_global_transform();
- Transform global_transform_inverse = global_transform.affine_inverse();
-
- for (int i = 0; i < len; i++) {
-
- const Bone &b = bonesptr[i];
- vs->skeleton_bone_set_transform(skeleton, i, global_transform * (b.transform_final * global_transform_inverse));
- }
+ VS::get_singleton()->skeleton_set_world_transform(skeleton, use_bones_in_world_transform, get_global_transform());
} break;
case NOTIFICATION_UPDATE_SKELETON: {
@@ -232,7 +214,7 @@ void Skeleton::_notification(int p_what) {
Bone *bonesptr = bones.ptrw();
int len = bones.size();
- vs->skeleton_allocate(skeleton, len); // if same size, nothin really happens
+ vs->skeleton_allocate(skeleton, len); // if same size, nothing really happens
_update_process_order();
@@ -257,9 +239,6 @@ void Skeleton::_notification(int p_what) {
rest_global_inverse_dirty = false;
}
- Transform global_transform = get_global_transform();
- Transform global_transform_inverse = global_transform.affine_inverse();
-
for (int i = 0; i < len; i++) {
Bone &b = bonesptr[order[i]];
@@ -320,7 +299,7 @@ void Skeleton::_notification(int p_what) {
}
b.transform_final = b.pose_global * b.rest_global_inverse;
- vs->skeleton_bone_set_transform(skeleton, order[i], global_transform * (b.transform_final * global_transform_inverse));
+ vs->skeleton_bone_set_transform(skeleton, order[i], b.transform_final);
for (List<uint32_t>::Element *E = b.nodes_bound.front(); E; E = E->next()) {
@@ -561,10 +540,11 @@ void Skeleton::clear_bones() {
void Skeleton::set_bone_pose(int p_bone, const Transform &p_pose) {
ERR_FAIL_INDEX(p_bone, bones.size());
- ERR_FAIL_COND(!is_inside_tree());
bones.write[p_bone].pose = p_pose;
- _make_dirty();
+ if (is_inside_tree()) {
+ _make_dirty();
+ }
}
Transform Skeleton::get_bone_pose(int p_bone) const {
@@ -594,10 +574,6 @@ void Skeleton::_make_dirty() {
if (dirty)
return;
- if (!is_inside_tree()) {
- dirty = true;
- return;
- }
MessageQueue::get_singleton()->push_notification(this, NOTIFICATION_UPDATE_SKELETON);
dirty = true;
}
@@ -771,6 +747,16 @@ void Skeleton::physical_bones_remove_collision_exception(RID p_exception) {
#endif // _3D_DISABLED
+void Skeleton::set_use_bones_in_world_transform(bool p_enable) {
+ use_bones_in_world_transform = p_enable;
+ if (is_inside_tree()) {
+ VS::get_singleton()->skeleton_set_world_transform(skeleton, use_bones_in_world_transform, get_global_transform());
+ }
+}
+bool Skeleton::is_using_bones_in_world_transform() const {
+ return use_bones_in_world_transform;
+}
+
void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton::add_bone);
@@ -787,6 +773,8 @@ void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_rest", "bone_idx"), &Skeleton::get_bone_rest);
ClassDB::bind_method(D_METHOD("set_bone_rest", "bone_idx", "rest"), &Skeleton::set_bone_rest);
+ ClassDB::bind_method(D_METHOD("localize_rests"), &Skeleton::localize_rests);
+
ClassDB::bind_method(D_METHOD("set_bone_disable_rest", "bone_idx", "disable"), &Skeleton::set_bone_disable_rest);
ClassDB::bind_method(D_METHOD("is_bone_rest_disabled", "bone_idx"), &Skeleton::is_bone_rest_disabled);
@@ -807,6 +795,9 @@ void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_transform", "bone_idx"), &Skeleton::get_bone_transform);
+ ClassDB::bind_method(D_METHOD("set_use_bones_in_world_transform", "enable"), &Skeleton::set_use_bones_in_world_transform);
+ ClassDB::bind_method(D_METHOD("is_using_bones_in_world_transform"), &Skeleton::is_using_bones_in_world_transform);
+
#ifndef _3D_DISABLED
ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation);
@@ -818,6 +809,7 @@ void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bone_ignore_animation", "bone", "ignore"), &Skeleton::set_bone_ignore_animation);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bones_in_world_transform"), "set_use_bones_in_world_transform", "is_using_bones_in_world_transform");
BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
}
@@ -828,6 +820,7 @@ Skeleton::Skeleton() {
process_order_dirty = true;
skeleton = VisualServer::get_singleton()->skeleton_create();
set_notify_transform(true);
+ use_bones_in_world_transform = false;
}
Skeleton::~Skeleton() {
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index 0f463c9ea7..5f43b3c6c3 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -100,6 +100,7 @@ class Skeleton : public Spatial {
void _make_dirty();
bool dirty;
+ bool use_bones_in_world_transform;
// bind helpers
Array _get_bound_child_nodes_to_bone(int p_bone) const {
@@ -179,6 +180,9 @@ public:
void localize_rests(); // used for loaders and tools
int get_process_order(int p_idx);
+ void set_use_bones_in_world_transform(bool p_enable);
+ bool is_using_bones_in_world_transform() const;
+
#ifndef _3D_DISABLED
// Physical bone API
diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp
index ac20609c21..909d4fda34 100644
--- a/scene/3d/soft_body.cpp
+++ b/scene/3d/soft_body.cpp
@@ -104,6 +104,14 @@ SoftBody::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) {
offset = obj_tocopy.offset;
}
+SoftBody::PinnedPoint SoftBody::PinnedPoint::operator=(const PinnedPoint &obj) {
+ point_index = obj.point_index;
+ spatial_attachment_path = obj.spatial_attachment_path;
+ spatial_attachment = obj.spatial_attachment;
+ offset = obj.offset;
+ return *this;
+}
+
void SoftBody::_update_pickable() {
if (!is_inside_tree())
return;
@@ -397,7 +405,7 @@ String SoftBody::get_configuration_warning() const {
if (!warning.empty())
warning += "\n\n";
- warning += TTR("This body will be ignored until you set a mesh");
+ warning += TTR("This body will be ignored until you set a mesh.");
}
Transform t = get_transform();
diff --git a/scene/3d/soft_body.h b/scene/3d/soft_body.h
index 2516d39552..ee455f8dab 100644
--- a/scene/3d/soft_body.h
+++ b/scene/3d/soft_body.h
@@ -75,6 +75,7 @@ public:
PinnedPoint();
PinnedPoint(const PinnedPoint &obj_tocopy);
+ PinnedPoint operator=(const PinnedPoint &obj);
};
private:
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index d6544c39da..efd418e3c7 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -178,7 +178,7 @@ void Spatial::_notification(int p_what) {
get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_enter_world, NULL, 0);
}
#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
+ if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) {
//get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this);
get_tree()->call_group_flags(0, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this);
@@ -224,7 +224,8 @@ void Spatial::_notification(int p_what) {
#endif
} break;
- default: {}
+ default: {
+ }
}
}
@@ -675,26 +676,29 @@ void Spatial::set_identity() {
void Spatial::look_at(const Vector3 &p_target, const Vector3 &p_up) {
- Transform lookat;
- lookat.origin = get_global_transform().origin;
- if (lookat.origin == p_target) {
+ Vector3 origin(get_global_transform().origin);
+ look_at_from_position(origin, p_target, p_up);
+}
+
+void Spatial::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) {
+
+ if (p_pos == p_target) {
ERR_EXPLAIN("Node origin and target are in the same position, look_at() failed");
ERR_FAIL();
}
- if (p_up.cross(p_target - lookat.origin) == Vector3()) {
+ if (p_up.cross(p_target - p_pos) == Vector3()) {
ERR_EXPLAIN("Up vector and direction between node origin and target are aligned, look_at() failed");
ERR_FAIL();
}
- lookat = lookat.looking_at(p_target, p_up);
- set_global_transform(lookat);
-}
-
-void Spatial::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) {
Transform lookat;
lookat.origin = p_pos;
+
+ Vector3 original_scale(get_global_transform().basis.get_scale());
lookat = lookat.looking_at(p_target, p_up);
+ // as basis was normalized, we just need to apply original scale back
+ lookat.basis.scale(original_scale);
set_global_transform(lookat);
}
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index a3fa2ac98d..6b70eef662 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -382,36 +382,30 @@ void Sprite3D::_draw() {
VS::get_singleton()->immediate_clear(immediate);
if (!texture.is_valid())
- return; //no texuture no life
+ return;
Vector2 tsize = texture->get_size();
if (tsize.x == 0 || tsize.y == 0)
return;
- Size2i s;
- Rect2 src_rect;
-
- if (region) {
-
- s = region_rect.size;
- src_rect = region_rect;
- } else {
- s = texture->get_size();
- s = s / Size2(hframes, vframes);
+ Rect2 base_rect;
+ if (region)
+ base_rect = region_rect;
+ else
+ base_rect = Rect2(0, 0, texture->get_width(), texture->get_height());
- src_rect.size = s;
- src_rect.position.x += (frame % hframes) * s.x;
- src_rect.position.y += (frame / hframes) * s.y;
- }
+ Size2 frame_size = base_rect.size / Size2(hframes, vframes);
+ Point2 frame_offset = Point2(frame % hframes, frame / hframes);
+ frame_offset *= frame_size;
- Point2 ofs = get_offset();
+ Point2 dest_offset = get_offset();
if (is_centered())
- ofs -= s / 2;
-
- Rect2 dst_rect(ofs, s);
+ dest_offset -= frame_size / 2;
+ Rect2 src_rect(base_rect.position + frame_offset, frame_size);
+ Rect2 final_dst_rect(dest_offset, frame_size);
Rect2 final_rect;
Rect2 final_src_rect;
- if (!texture->get_rect_region(dst_rect, src_rect, final_rect, final_src_rect))
+ if (!texture->get_rect_region(final_dst_rect, src_rect, final_rect, final_src_rect))
return;
if (final_rect.size.x == 0 || final_rect.size.y == 0)
diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp
index c7f7b14a8f..fde135c972 100644
--- a/scene/3d/vehicle_body.cpp
+++ b/scene/3d/vehicle_body.cpp
@@ -716,7 +716,7 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
real_t rollingFriction = 0.f;
if (wheelInfo.m_raycastInfo.m_isInContact) {
- if (engine_force != 0.f) {
+ if (engine_force != 0.f && wheelInfo.engine_traction != false) {
rollingFriction = -engine_force * s->get_step();
} else {
real_t defaultRollingFrictionImpulse = 0.f;
diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp
index 1bbf1b7bc7..1aded826c0 100644
--- a/scene/3d/visual_instance.cpp
+++ b/scene/3d/visual_instance.cpp
@@ -123,6 +123,8 @@ void VisualInstance::_bind_methods() {
ClassDB::bind_method(D_METHOD("_get_visual_instance_rid"), &VisualInstance::_get_visual_instance_rid);
ClassDB::bind_method(D_METHOD("set_base", "base"), &VisualInstance::set_base);
+ ClassDB::bind_method(D_METHOD("get_base"), &VisualInstance::get_base);
+ ClassDB::bind_method(D_METHOD("get_instance"), &VisualInstance::get_instance);
ClassDB::bind_method(D_METHOD("set_layer_mask", "mask"), &VisualInstance::set_layer_mask);
ClassDB::bind_method(D_METHOD("get_layer_mask"), &VisualInstance::get_layer_mask);
ClassDB::bind_method(D_METHOD("set_layer_mask_bit", "layer", "enabled"), &VisualInstance::set_layer_mask_bit);
@@ -136,6 +138,12 @@ void VisualInstance::_bind_methods() {
void VisualInstance::set_base(const RID &p_base) {
VisualServer::get_singleton()->instance_set_base(instance, p_base);
+ base = p_base;
+}
+
+RID VisualInstance::get_base() const {
+
+ return base;
}
VisualInstance::VisualInstance() {
diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h
index 3b6fccf65f..f5b7479bb1 100644
--- a/scene/3d/visual_instance.h
+++ b/scene/3d/visual_instance.h
@@ -43,6 +43,7 @@ class VisualInstance : public Spatial {
GDCLASS(VisualInstance, Spatial);
OBJ_CATEGORY("3D Visual Nodes");
+ RID base;
RID instance;
uint32_t layers;
@@ -69,6 +70,7 @@ public:
virtual AABB get_transformed_aabb() const; // helper
void set_base(const RID &p_base);
+ RID get_base() const;
void set_layer_mask(uint32_t p_mask);
uint32_t get_layer_mask() const;
diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp
index 30e38c8ee2..75b419ca58 100644
--- a/scene/3d/voxel_light_baker.cpp
+++ b/scene/3d/voxel_light_baker.cpp
@@ -835,7 +835,7 @@ void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const C
for (int i = 0; i < 3; i++) {
- if (ABS(light_axis[i]) < CMP_EPSILON)
+ if (Math::is_zero_approx(light_axis[i]))
continue;
clip[clip_planes].normal[i] = 1.0;
@@ -887,7 +887,7 @@ void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const C
distance -= distance_adv;
}
- if (result == idx) {
+ if (result == (uint32_t)idx) {
//cell hit itself! hooray!
Vector3 normal(cells[idx].normal[0], cells[idx].normal[1], cells[idx].normal[2]);
@@ -978,7 +978,7 @@ void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color
for (int c = 0; c < 3; c++) {
- if (ABS(light_axis[c]) < CMP_EPSILON)
+ if (Math::is_zero_approx(light_axis[c]))
continue;
clip[clip_planes].normal[c] = 1.0;
@@ -1018,7 +1018,7 @@ void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color
distance -= distance_adv;
}
- if (result == idx) {
+ if (result == (uint32_t)idx) {
//cell hit itself! hooray!
if (normal == Vector3()) {
@@ -1113,7 +1113,7 @@ void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axi
for (int c = 0; c < 3; c++) {
- if (ABS(light_axis[c]) < CMP_EPSILON)
+ if (Math::is_zero_approx(light_axis[c]))
continue;
clip[clip_planes].normal[c] = 1.0;
@@ -1152,7 +1152,7 @@ void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axi
distance -= distance_adv;
}
- if (result == idx) {
+ if (result == (uint32_t)idx) {
//cell hit itself! hooray!
if (normal == Vector3()) {
@@ -1730,7 +1730,7 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V
//int level_limit = max_level;
cell = 0; //start from root
- for (int i = 0; i < max_level; i++) {
+ for (int j = 0; j < max_level; j++) {
const Cell *bc = &cells[cell];
@@ -1759,14 +1759,14 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V
}
if (unlikely(cell != CHILD_EMPTY)) {
- for (int i = 0; i < 6; i++) {
+ for (int j = 0; j < 6; j++) {
//anisotropic read light
- float amount = direction.dot(aniso_normal[i]);
+ float amount = direction.dot(aniso_normal[j]);
if (amount <= 0)
continue;
- accum.x += light[cell].accum[i][0] * amount;
- accum.y += light[cell].accum[i][1] * amount;
- accum.z += light[cell].accum[i][2] * amount;
+ accum.x += light[cell].accum[j][0] * amount;
+ accum.y += light[cell].accum[j][1] * amount;
+ accum.z += light[cell].accum[j][2] * amount;
}
accum.x += cells[cell].emission[0];
accum.y += cells[cell].emission[1];
@@ -1833,16 +1833,16 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
}
int faces = ic ? ic / 3 : vc / 3;
- for (int i = 0; i < faces; i++) {
+ for (int j = 0; j < faces; j++) {
Vector3 vertex[3];
Vector3 normal[3];
Vector2 uv[3];
- for (int j = 0; j < 3; j++) {
- int idx = ic ? ir[i * 3 + j] : i * 3 + j;
- vertex[j] = xform.xform(vr[idx]);
- normal[j] = xform.basis.xform(nr[idx]).normalized();
- uv[j] = u2r[idx];
+ for (int k = 0; k < 3; k++) {
+ int idx = ic ? ir[j * 3 + k] : j * 3 + k;
+ vertex[k] = xform.xform(vr[idx]);
+ normal[k] = xform.basis.xform(nr[idx]).normalized();
+ uv[k] = u2r[idx];
}
_plot_triangle(uv, vertex, normal, lightmap.ptrw(), width, height);
@@ -2208,7 +2208,7 @@ PoolVector<int> VoxelLightBaker::create_gi_probe_data() {
}
{
- uint16_t alpha = CLAMP(uint32_t(bake_cells[i].alpha * 65535.0), 0, 65535);
+ uint16_t alpha = MIN(uint32_t(bake_cells[i].alpha * 65535.0), 65535);
uint16_t level = bake_cells[i].level;
w32[ofs++] = (uint32_t(level) << 16) | uint32_t(alpha);
@@ -2252,7 +2252,7 @@ void VoxelLightBaker::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Re
uint32_t child = bake_cells[p_idx].children[i];
- if (child == CHILD_EMPTY || child >= max_original_cells)
+ if (child == CHILD_EMPTY || child >= (uint32_t)max_original_cells)
continue;
AABB aabb = p_aabb;
diff --git a/scene/3d/scenario_fx.cpp b/scene/3d/world_environment.cpp
index ad9b61e1ff..3cd43cbf5b 100644
--- a/scene/3d/scenario_fx.cpp
+++ b/scene/3d/world_environment.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* scenario_fx.cpp */
+/* world_environment.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "scenario_fx.h"
+#include "world_environment.h"
#include "scene/main/viewport.h"
void WorldEnvironment::_notification(int p_what) {
diff --git a/scene/3d/scenario_fx.h b/scene/3d/world_environment.h
index 6317dae75d..bf36a0a532 100644
--- a/scene/3d/scenario_fx.h
+++ b/scene/3d/world_environment.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* scenario_fx.h */
+/* world_environment.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */