diff options
Diffstat (limited to 'scene/3d')
35 files changed, 640 insertions, 303 deletions
diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp index e58e26d2d1..4247266e3d 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; @@ -750,13 +752,12 @@ Area::Area() : gravity_is_point = false; gravity_distance_scale = 0; linear_damp = 0.1; - angular_damp = 1; + angular_damp = 0.1; priority = 0; monitoring = false; 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..dfa8fce9be 100644 --- a/scene/3d/arvr_nodes.cpp +++ b/scene/3d/arvr_nodes.cpp @@ -127,7 +127,7 @@ Point2 ARVRCamera::unproject_position(const Vector3 &p_pos) const { return res; }; -Vector3 ARVRCamera::project_position(const Point2 &p_point) const { +Vector3 ARVRCamera::project_position(const Point2 &p_point, float p_z_depth) const { // get our ARVRServer ARVRServer *arvr_server = ARVRServer::get_singleton(); ERR_FAIL_NULL_V(arvr_server, Vector3()); @@ -135,7 +135,7 @@ Vector3 ARVRCamera::project_position(const Point2 &p_point) const { Ref<ARVRInterface> arvr_interface = arvr_server->get_primary_interface(); if (arvr_interface.is_null()) { // we might be in the editor or have VR turned off, just call superclass - return Camera::project_position(p_point); + return Camera::project_position(p_point, p_z_depth); } if (!is_inside_tree()) { @@ -155,7 +155,7 @@ Vector3 ARVRCamera::project_position(const Point2 &p_point) const { point.y = (1.0 - (p_point.y / viewport_size.y)) * 2.0 - 1.0; point *= vp_size; - Vector3 p(point.x, point.y, -get_znear()); + Vector3 p(point.x, point.y, -p_z_depth); return get_camera_transform().xform(p); }; @@ -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: @@ -257,9 +264,13 @@ void ARVRController::_bind_methods() { ClassDB::bind_method(D_METHOD("get_rumble"), &ARVRController::get_rumble); 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"); + ADD_PROPERTY_DEFAULT("rumble", 0.0); + + 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 +352,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,18 +380,18 @@ 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(); }; ARVRController::ARVRController() { - controller_id = 0; + controller_id = 1; is_active = true; button_states = 0; }; @@ -423,6 +438,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 +463,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 +507,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,8 +526,12 @@ Plane ARVRAnchor::get_plane() const { return plane; }; +Ref<Mesh> ARVRAnchor::get_mesh() const { + return mesh; +} + ARVRAnchor::ARVRAnchor() { - anchor_id = 0; + anchor_id = 1; is_active = true; }; @@ -517,7 +546,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 +584,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 +596,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 +612,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..8e735f7110 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" /** @@ -54,7 +55,7 @@ public: virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const; virtual Point2 unproject_position(const Vector3 &p_pos) const; - virtual Vector3 project_position(const Point2 &p_point) const; + virtual Vector3 project_position(const Point2 &p_point, float p_z_depth = 0) const; virtual Vector<Plane> get_frustum() const; ARVRCamera(); @@ -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 4b3934c4ea..ff28f60d4f 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -38,7 +38,7 @@ void AudioStreamPlayer3D::_mix_audio() { if (!stream_playback.is_valid() || !active || - (stream_paused && !stream_fade_out)) { + (stream_paused && !stream_paused_fade_out)) { return; } @@ -53,7 +53,7 @@ void AudioStreamPlayer3D::_mix_audio() { AudioFrame *buffer = mix_buffer.ptrw(); int buffer_size = mix_buffer.size(); - if (stream_fade_out) { + if (stream_paused_fade_out) { // Short fadeout ramp buffer_size = MIN(buffer_size, 128); } @@ -93,7 +93,7 @@ void AudioStreamPlayer3D::_mix_audio() { } bool interpolate_filter = !started; - ; + if (!found) { //create new if was not used before if (prev_output_count < MAX_OUTPUTS) { @@ -109,10 +109,10 @@ void AudioStreamPlayer3D::_mix_audio() { int buffers = AudioServer::get_singleton()->get_channel_count(); for (int k = 0; k < buffers; k++) { - AudioFrame target_volume = stream_fade_out ? AudioFrame(0.f, 0.f) : current.vol[k]; - AudioFrame vol_prev = stream_fade_in ? AudioFrame(0.f, 0.f) : prev_outputs[i].vol[k]; + AudioFrame target_volume = stream_paused_fade_out ? AudioFrame(0.f, 0.f) : current.vol[k]; + AudioFrame vol_prev = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : prev_outputs[i].vol[k]; AudioFrame vol_inc = (target_volume - vol_prev) / float(buffer_size); - AudioFrame vol = stream_fade_in ? AudioFrame(0.f, 0.f) : current.vol[k]; + AudioFrame vol = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : current.vol[k]; if (!AudioServer::get_singleton()->thread_has_channel_mix_buffer(current.bus_index, k)) continue; //may have been deleted, will be updated on process @@ -198,15 +198,9 @@ void AudioStreamPlayer3D::_mix_audio() { active = false; } - if (stream_stop) { - active = false; - set_physics_process_internal(false); - setplay = -1; - } - output_ready = false; - stream_fade_in = false; - stream_fade_out = false; + stream_paused_fade_in = false; + stream_paused_fade_out = false; } float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const { @@ -224,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; @@ -662,7 +657,6 @@ float AudioStreamPlayer3D::get_pitch_scale() const { void AudioStreamPlayer3D::play(float p_from_pos) { if (stream_playback.is_valid()) { - stream_stop = false; active = true; setplay = p_from_pos; output_ready = false; @@ -680,8 +674,9 @@ void AudioStreamPlayer3D::seek(float p_seconds) { void AudioStreamPlayer3D::stop() { if (stream_playback.is_valid()) { - stream_stop = true; - stream_fade_out = true; + active = false; + set_physics_process_internal(false); + setplay = -1; } } @@ -831,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; } @@ -877,8 +872,8 @@ void AudioStreamPlayer3D::set_stream_paused(bool p_pause) { if (p_pause != stream_paused) { stream_paused = p_pause; - stream_fade_in = stream_paused ? false : true; - stream_fade_out = stream_paused ? true : false; + stream_paused_fade_in = !stream_paused; + stream_paused_fade_out = stream_paused; } } @@ -887,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); @@ -953,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"); @@ -981,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); @@ -1016,9 +1018,8 @@ AudioStreamPlayer3D::AudioStreamPlayer3D() { out_of_range_mode = OUT_OF_RANGE_MIX; doppler_tracking = DOPPLER_TRACKING_DISABLED; stream_paused = false; - stream_fade_in = false; - stream_fade_out = false; - stream_stop = false; + stream_paused_fade_in = false; + stream_paused_fade_out = false; velocity_tracker.instance(); AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed"); diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h index e467c170fb..93954e758a 100644 --- a/scene/3d/audio_stream_player_3d.h +++ b/scene/3d/audio_stream_player_3d.h @@ -40,12 +40,14 @@ class Camera; class AudioStreamPlayer3D : public Spatial { - GDCLASS(AudioStreamPlayer3D, Spatial) + GDCLASS(AudioStreamPlayer3D, Spatial); + public: enum AttenuationModel { ATTENUATION_INVERSE_DISTANCE, ATTENUATION_INVERSE_SQUARE_DISTANCE, ATTENUATION_LOGARITHMIC, + ATTENUATION_DISABLED, }; enum OutOfRangeMode { @@ -69,7 +71,7 @@ private: struct Output { AudioFilterSW filter; - AudioFilterSW::Processor filter_process[6]; + AudioFilterSW::Processor filter_process[8]; AudioFrame vol[4]; float filter_gain; float pitch_scale; @@ -109,9 +111,8 @@ private: float pitch_scale; bool autoplay; bool stream_paused; - bool stream_fade_in; - bool stream_fade_out; - bool stream_stop; + bool stream_paused_fade_in; + bool stream_paused_fade_out; StringName bus; void _mix_audio(); @@ -206,6 +207,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/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp index d66e6cc83d..2b12e78158 100644 --- a/scene/3d/baked_lightmap.cpp +++ b/scene/3d/baked_lightmap.cpp @@ -173,7 +173,7 @@ void BakedLightmapData::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::AABB, "bounds", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_bounds", "get_bounds"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "cell_space_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_space_transform", "get_cell_space_transform"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_subdiv", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_subdiv", "get_cell_subdiv"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_energy", "get_energy"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_energy", "get_energy"); ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "octree", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_octree", "get_octree"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_user_data", "_get_user_data"); } diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index 368cebeeab..c7d6919a2b 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; } } @@ -99,9 +106,15 @@ void Camera::_notification(int p_what) { case NOTIFICATION_ENTER_WORLD: { - bool first_camera = get_viewport()->_camera_add(this); - if (!get_tree()->is_node_being_edited(this) && (current || first_camera)) - make_current(); + // Needs to track the Viewport because it's needed on NOTIFICATION_EXIT_WORLD + // and Spatial will handle it first, including clearing its reference to the Viewport, + // therefore making it impossible to subclasses to access it + viewport = get_viewport(); + ERR_FAIL_COND(!viewport); + + bool first_camera = viewport->_camera_add(this); + if (current || first_camera) + viewport->_camera_set(this); } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -123,17 +136,20 @@ void Camera::_notification(int p_what) { } } - get_viewport()->_camera_remove(this); + if (viewport) { + viewport->_camera_remove(this); + viewport = NULL; + } } break; case NOTIFICATION_BECAME_CURRENT: { - if (get_world().is_valid()) { - get_world()->_register_camera(this); + if (viewport) { + viewport->find_world()->_register_camera(this); } } break; case NOTIFICATION_LOST_CURRENT: { - if (get_world().is_valid()) { - get_world()->_remove_camera(this); + if (viewport) { + viewport->find_world()->_remove_camera(this); } } break; } @@ -177,8 +193,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(); @@ -232,8 +264,6 @@ bool Camera::is_current() const { return get_viewport()->get_camera() == this; } else return current; - - return false; } bool Camera::_can_gizmo_scale() const { @@ -368,13 +398,17 @@ Point2 Camera::unproject_position(const Vector3 &p_pos) const { return res; } -Vector3 Camera::project_position(const Point2 &p_point) const { +Vector3 Camera::project_position(const Point2 &p_point, float p_z_depth) const { if (!is_inside_tree()) { ERR_EXPLAIN("Camera is not inside scene."); ERR_FAIL_COND_V(!is_inside_tree(), Vector3()); } + if (p_z_depth == 0) { + return get_global_transform().origin; + } + Size2 viewport_size = get_viewport()->get_visible_rect().size; CameraMatrix cm; @@ -392,7 +426,7 @@ Vector3 Camera::project_position(const Point2 &p_point) const { point.y = (1.0 - (p_point.y / viewport_size.y)) * 2.0 - 1.0; point *= vp_size; - Vector3 p(point.x, point.y, -near); + Vector3 p(point.x, point.y, -p_z_depth); return get_camera_transform().xform(p); } @@ -467,19 +501,22 @@ void Camera::_bind_methods() { ClassDB::bind_method(D_METHOD("project_ray_origin", "screen_point"), &Camera::project_ray_origin); ClassDB::bind_method(D_METHOD("unproject_position", "world_point"), &Camera::unproject_position); ClassDB::bind_method(D_METHOD("is_position_behind", "world_point"), &Camera::is_position_behind); - ClassDB::bind_method(D_METHOD("project_position", "screen_point"), &Camera::project_position); + ClassDB::bind_method(D_METHOD("project_position", "screen_point", "z_depth"), &Camera::project_position, DEFVAL(0)); 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); @@ -498,6 +535,7 @@ void Camera::_bind_methods() { 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); @@ -510,15 +548,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); @@ -543,6 +583,10 @@ float Camera::get_znear() const { return near; } +Vector2 Camera::get_frustum_offset() const { + return frustum_offset; +} + float Camera::get_zfar() const { return far; @@ -570,6 +614,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(); @@ -648,9 +697,11 @@ Camera::Camera() { camera = VisualServer::get_singleton()->camera_create(); size = 1; fov = 0; + frustum_offset = Vector2(); near = 0; far = 0; current = false; + viewport = NULL; force_change = false; mode = PROJECTION_PERSPECTIVE; set_perspective(70.0, 0.05, 100.0); @@ -684,8 +735,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; @@ -748,7 +800,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(); @@ -817,6 +869,11 @@ void ClippedCamera::clear_exceptions() { exclude.clear(); } +float ClippedCamera::get_clip_offset() const { + + return clip_offset; +} + void ClippedCamera::set_clip_to_areas(bool p_clip) { clip_to_areas = p_clip; @@ -860,6 +917,8 @@ void ClippedCamera::_bind_methods() { ClassDB::bind_method(D_METHOD("set_clip_to_areas", "enable"), &ClippedCamera::set_clip_to_areas); ClassDB::bind_method(D_METHOD("is_clip_to_areas_enabled"), &ClippedCamera::is_clip_to_areas_enabled); + ClassDB::bind_method(D_METHOD("get_clip_offset"), &ClippedCamera::get_clip_offset); + ClassDB::bind_method(D_METHOD("set_clip_to_bodies", "enable"), &ClippedCamera::set_clip_to_bodies); ClassDB::bind_method(D_METHOD("is_clip_to_bodies_enabled"), &ClippedCamera::is_clip_to_bodies_enabled); diff --git a/scene/3d/camera.h b/scene/3d/camera.h index a531324a85..6460f17e85 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 { @@ -63,11 +64,13 @@ public: private: bool force_change; bool current; + Viewport *viewport; Projection mode; float fov; float size; + Vector2 frustum_offset; float near, far; float v_offset; float h_offset; @@ -110,6 +113,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_z_near, float p_z_far); void set_projection(Camera::Projection p_mode); void make_current(); @@ -123,12 +127,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; @@ -137,7 +144,7 @@ public: virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const; virtual Point2 unproject_position(const Vector3 &p_pos) const; bool is_position_behind(const Vector3 &p_pos) const; - virtual Vector3 project_position(const Point2 &p_point) const; + virtual Vector3 project_position(const Point2 &p_point, float p_z_depth = 0) const; Vector<Vector3> get_near_plane_points() const; @@ -227,6 +234,8 @@ public: void remove_exception(const Object *p_object); void clear_exceptions(); + float get_clip_offset() const; + ClippedCamera(); ~ClippedCamera(); }; 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 ac33e2b714..219ea56681 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: { @@ -142,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); @@ -161,6 +167,8 @@ void CollisionShape::set_shape(const Ref<Shape> &p_shape) { } } + if (is_inside_tree()) + _shape_changed(); update_configuration_warning(); } @@ -199,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(); @@ -207,15 +216,24 @@ 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 + if (parent) { + _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 6415b0ff28..358c4bdb44 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; @@ -237,6 +225,8 @@ void CPUParticles::restart() { frame_remainder = 0; cycle = 0; + set_emitting(true); + { int pc = particles.size(); PoolVector<Particle>::Write w = particles.write(); @@ -324,9 +314,9 @@ void CPUParticles::set_param_curve(Parameter p_param, const Ref<Curve> &p_curve) case PARAM_ANGULAR_VELOCITY: { _adjust_curve_range(p_curve, -360, 360); } break; - /*case PARAM_ORBIT_VELOCITY: { + case PARAM_ORBIT_VELOCITY: { _adjust_curve_range(p_curve, -500, 500); - } break;*/ + } break; case PARAM_LINEAR_ACCEL: { _adjust_curve_range(p_curve, -200, 200); } break; @@ -353,7 +343,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 { @@ -482,11 +473,10 @@ void CPUParticles::_validate_property(PropertyInfo &property) const { if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { property.usage = 0; } - /* + if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) { property.usage = 0; } - */ } static uint32_t idhash(uint32_t x) { @@ -525,7 +515,8 @@ void CPUParticles::_particles_process(float p_delta) { time = Math::fmod(time, lifetime); cycle++; if (one_shot && cycle > 0) { - emitting = false; + set_emitting(false); + _change_notify(); } } @@ -536,6 +527,8 @@ void CPUParticles::_particles_process(float p_delta) { velocity_xform = emission_xform.basis; } + float system_phase = time / lifetime; + for (int i = 0; i < pcount; i++) { Particle &p = parray[i]; @@ -543,21 +536,26 @@ void CPUParticles::_particles_process(float p_delta) { if (!emitting && !p.active) continue; - float restart_time = (float(i) / float(pcount)) * lifetime; float local_delta = p_delta; + // The phase is a ratio between 0 (birth) and 1 (end of life) for each particle. + // While we use time in tests later on, for randomness we use the phase as done in the + // original shader code, and we later multiply by lifetime to get the time. + float restart_phase = float(i) / float(pcount); + if (randomness_ratio > 0.0) { uint32_t seed = cycle; - if (restart_time >= time) { + if (restart_phase >= system_phase) { seed -= uint32_t(1); } seed *= uint32_t(pcount); seed += uint32_t(i); float random = float(idhash(seed) % uint32_t(65536)) / 65536.0; - restart_time += randomness_ratio * random * 1.0 / float(pcount); + restart_phase += randomness_ratio * random * 1.0 / float(pcount); } - restart_time *= (1.0 - explosiveness_ratio); + restart_phase *= (1.0 - explosiveness_ratio); + float restart_time = restart_phase * lifetime; bool restart = false; if (time > prev_time) { @@ -566,7 +564,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; } } @@ -574,13 +572,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; } } } @@ -712,16 +710,14 @@ void CPUParticles::_particles_process(float p_delta) { if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(p.custom[1]); } - /* - float tex_orbit_velocity = 0.0; + float tex_orbit_velocity = 0.0; if (flags[FLAG_DISABLE_Z]) { - - if (curve_parameters[PARAM_INITIAL_ORBIT_VELOCITY].is_valid()) { - tex_orbit_velocity = curve_parameters[PARAM_INITIAL_ORBIT_VELOCITY]->interpolate(p.custom[1]); + if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { + tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(p.custom[1]); } } -*/ + float tex_angular_velocity = 0.0; if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(p.custom[1]); @@ -775,8 +771,9 @@ void CPUParticles::_particles_process(float p_delta) { //apply tangential acceleration; if (flags[FLAG_DISABLE_Z]) { - Vector3 yx = Vector3(diff.y, 0, diff.x); - force += yx.length() > 0.0 ? (yx * Vector3(-1.0, 0, 1.0)) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3(); + 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(); } else { Vector3 crossDiff = diff.normalized().cross(gravity.normalized()); @@ -785,18 +782,18 @@ void CPUParticles::_particles_process(float p_delta) { //apply attractor forces p.velocity += force * local_delta; //orbit velocity -#if 0 if (flags[FLAG_DISABLE_Z]) { - - float orbit_amount = (orbit_velocity + tex_orbit_velocity) * mix(1.0, rand_from_seed(alt_seed), orbit_velocity_random); + 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 * DELTA * pi * 2.0; - mat2 rot = mat2(vec2(cos(ang), -sin(ang)), vec2(sin(ang), cos(ang))); - TRANSFORM[3].xy -= diff.xy; - TRANSFORM[3].xy += rot * diff.xy; + float ang = orbit_amount * local_delta * Math_PI * 2.0; + // Not sure why the ParticlesMaterial code uses a clockwise rotation matrix, + // but we use -ang here to reproduce its behavior. + Transform2D rot = Transform2D(-ang, Vector2()); + Vector2 rotv = rot.basis_xform(Vector2(diff.x, diff.y)); + p.transform.origin -= Vector3(diff.x, diff.y, 0); + p.transform.origin += Vector3(rotv.x, rotv.y, 0); } } -#endif if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { p.velocity = p.velocity.normalized() * tex_linear_velocity; } @@ -931,11 +928,6 @@ void CPUParticles::_update_particle_data_buffer() { PoolVector<Particle>::Read r = particles.read(); float *ptr = w.ptr(); - Transform un_transform; - if (!local_coords) { - un_transform = get_global_transform().affine_inverse(); - } - if (draw_order != DRAW_ORDER_INDEX) { ow = particle_order.write(); order = ow.ptr(); @@ -953,7 +945,12 @@ void CPUParticles::_update_particle_data_buffer() { Vector3 dir = c->get_global_transform().basis.get_axis(2); //far away to close if (local_coords) { - dir = un_transform.basis.xform(dir).normalized(); + + // will look different from Particles in editor as this is based on the camera in the scenetree + // and not the editor camera + dir = inv_emission_transform.xform(dir).normalized(); + } else { + dir = dir.normalized(); } SortArray<int, SortAxis> sorter; @@ -971,7 +968,7 @@ void CPUParticles::_update_particle_data_buffer() { Transform t = r[idx].transform; if (!local_coords) { - t = un_transform * t; + t = inv_emission_transform * t; } if (r[idx].active) { @@ -1014,6 +1011,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 @@ -1032,31 +1050,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) { @@ -1064,26 +1062,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; @@ -1092,6 +1084,7 @@ void CPUParticles::_notification(int p_what) { return; } } + _set_redraw(true); bool processed = false; @@ -1141,6 +1134,46 @@ void CPUParticles::_notification(int p_what) { _update_particle_data_buffer(); } } + + if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { + + inv_emission_transform = get_global_transform().affine_inverse(); + + if (!local_coords) { + + int pc = particles.size(); + + PoolVector<float>::Write w = particle_data.write(); + PoolVector<Particle>::Read r = particles.read(); + float *ptr = w.ptr(); + + for (int i = 0; i < pc; i++) { + + Transform t = inv_emission_transform * r[i].transform; + + if (r[i].active) { + ptr[0] = t.basis.elements[0][0]; + ptr[1] = t.basis.elements[0][1]; + ptr[2] = t.basis.elements[0][2]; + ptr[3] = t.origin.x; + ptr[4] = t.basis.elements[1][0]; + ptr[5] = t.basis.elements[1][1]; + ptr[6] = t.basis.elements[1][2]; + ptr[7] = t.origin.y; + ptr[8] = t.basis.elements[2][0]; + ptr[9] = t.basis.elements[2][1]; + ptr[10] = t.basis.elements[2][2]; + ptr[11] = t.origin.z; + } else { + zeromem(ptr, sizeof(float) * 12); + } + + ptr += 17; + } + + can_update = true; + } + } } void CPUParticles::convert_from_particles(Node *p_particles) { @@ -1197,7 +1230,7 @@ void CPUParticles::convert_from_particles(Node *p_particles) { CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY); CONVERT_PARAM(PARAM_ANGULAR_VELOCITY); - // CONVERT_PARAM(PARAM_ORBIT_VELOCITY); + CONVERT_PARAM(PARAM_ORBIT_VELOCITY); CONVERT_PARAM(PARAM_LINEAR_ACCEL); CONVERT_PARAM(PARAM_RADIAL_ACCEL); CONVERT_PARAM(PARAM_TANGENTIAL_ACCEL); @@ -1344,12 +1377,10 @@ void CPUParticles::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY); - /* ADD_GROUP("Orbit Velocity", "orbit_"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY); -*/ ADD_GROUP("Linear Accel", "linear_"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL); @@ -1392,7 +1423,7 @@ void CPUParticles::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY); BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY); - //BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY); + BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY); BIND_ENUM_CONSTANT(PARAM_LINEAR_ACCEL); BIND_ENUM_CONSTANT(PARAM_RADIAL_ACCEL); BIND_ENUM_CONSTANT(PARAM_TANGENTIAL_ACCEL); @@ -1406,6 +1437,7 @@ void CPUParticles::_bind_methods() { 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(EMISSION_SHAPE_POINT); @@ -1421,8 +1453,12 @@ CPUParticles::CPUParticles() { inactive_time = 0; frame_remainder = 0; cycle = 0; + redraw = false; + + set_notify_transform(true); multimesh = VisualServer::get_singleton()->multimesh_create(); + VisualServer::get_singleton()->multimesh_set_visible_instances(multimesh, 0); set_base(multimesh); set_emitting(true); @@ -1442,8 +1478,9 @@ CPUParticles::CPUParticles() { set_direction(Vector3(1, 0, 0)); set_spread(45); set_flatness(0); - set_param(PARAM_INITIAL_LINEAR_VELOCITY, 1); - //set_param(PARAM_ORBIT_VELOCITY, 0); + set_param(PARAM_INITIAL_LINEAR_VELOCITY, 0); + set_param(PARAM_ANGULAR_VELOCITY, 0); + set_param(PARAM_ORBIT_VELOCITY, 0); set_param(PARAM_LINEAR_ACCEL, 0); set_param(PARAM_RADIAL_ACCEL, 0); set_param(PARAM_TANGENTIAL_ACCEL, 0); diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h index 05a9d7abe8..517df8490d 100644 --- a/scene/3d/cpu_particles.h +++ b/scene/3d/cpu_particles.h @@ -53,7 +53,7 @@ public: PARAM_INITIAL_LINEAR_VELOCITY, PARAM_ANGULAR_VELOCITY, - //PARAM_ORBIT_VELOCITY, + PARAM_ORBIT_VELOCITY, PARAM_LINEAR_ACCEL, PARAM_RADIAL_ACCEL, PARAM_TANGENTIAL_ACCEL, @@ -104,6 +104,7 @@ private: float inactive_time; float frame_remainder; int cycle; + bool redraw; RID multimesh; @@ -115,7 +116,7 @@ private: const Particle *particles; bool operator()(int p_a, int p_b) const { - return particles[p_a].time < particles[p_b].time; + return particles[p_a].time > particles[p_b].time; } }; @@ -141,6 +142,8 @@ private: int fixed_fps; bool fractional_delta; + Transform inv_emission_transform; + volatile bool can_update; DrawOrder draw_order; @@ -179,6 +182,8 @@ private: void _update_render_thread(); + void _set_redraw(bool p_redraw); + protected: static void _bind_methods(); void _notification(int p_what); @@ -248,7 +253,7 @@ public: void set_color(const Color &p_color); Color get_color() const; - void set_color_ramp(const Ref<Gradient> &p_texture); + 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); diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index c491275f00..414e932f61 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -539,7 +539,7 @@ void GIProbe::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "subdiv", PROPERTY_HINT_ENUM, "64,128,256,512"), "set_subdiv", "get_subdiv"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents"); ADD_PROPERTY(PropertyInfo(Variant::INT, "dynamic_range", PROPERTY_HINT_RANGE, "1,16,1"), "set_dynamic_range", "get_dynamic_range"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_energy", "get_energy"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_energy", "get_energy"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "bias", PROPERTY_HINT_RANGE, "0,4,0.001"), "set_bias", "get_bias"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "normal_bias", PROPERTY_HINT_RANGE, "0,4,0.001"), "set_normal_bias", "get_normal_bias"); diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index cf1af918f7..2e64872616 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 { @@ -248,8 +249,8 @@ void Light::_bind_methods() { ADD_GROUP("Light", "light_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_color", "get_color"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_ENERGY); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_INDIRECT_ENERGY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_ENERGY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_INDIRECT_ENERGY); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "is_negative"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_specular", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SPECULAR); ADD_PROPERTY(PropertyInfo(Variant::INT, "light_bake_mode", PROPERTY_HINT_ENUM, "Disable,Indirect,All"), "set_bake_mode", "get_bake_mode"); @@ -293,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/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..12d562c0c6 100644 --- a/scene/3d/navigation.cpp +++ b/scene/3d/navigation.cpp @@ -90,7 +90,6 @@ void Navigation::_navmesh_link(int p_id) { if (!valid) { nm.polygons.pop_back(); ERR_CONTINUE(!valid); - continue; } p.center = center; @@ -340,16 +339,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 +365,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 +378,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 +391,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 +410,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 +526,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 93731c4023..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 { @@ -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 57ab01f7be..2bcd0eaa46 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -47,6 +47,12 @@ PoolVector<Face3> Particles::get_faces(uint32_t p_usage_flags) const { void Particles::set_emitting(bool p_emitting) { VS::get_singleton()->particles_set_emitting(particles, p_emitting); + + if (p_emitting && one_shot) { + set_process_internal(true); + } else if (!p_emitting) { + set_process_internal(false); + } } void Particles::set_amount(int p_amount) { @@ -66,8 +72,16 @@ void Particles::set_one_shot(bool p_one_shot) { one_shot = p_one_shot; VS::get_singleton()->particles_set_one_shot(particles, one_shot); - if (!one_shot && is_emitting()) - VisualServer::get_singleton()->particles_restart(particles); + + if (is_emitting()) { + + set_process_internal(true); + if (!one_shot) + VisualServer::get_singleton()->particles_restart(particles); + } + + if (!one_shot) + set_process_internal(false); } void Particles::set_pre_process_time(float p_time) { @@ -268,7 +282,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\"."); } } @@ -278,6 +292,7 @@ String Particles::get_configuration_warning() const { void Particles::restart() { VisualServer::get_singleton()->particles_restart(particles); + VisualServer::get_singleton()->particles_set_emitting(particles, true); } AABB Particles::capture_aabb() const { @@ -306,6 +321,16 @@ void Particles::_notification(int p_what) { VS::get_singleton()->particles_set_speed_scale(particles, 0); } } + + // Use internal process when emitting and one_shot are on so that when + // the shot ends the editor can properly update + if (p_what == NOTIFICATION_INTERNAL_PROCESS) { + + if (one_shot && !is_emitting()) { + _change_notify(); + set_process_internal(false); + } + } } void Particles::_bind_methods() { diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp index 190967d76c..84078911cb 100644 --- a/scene/3d/path.cpp +++ b/scene/3d/path.cpp @@ -173,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; @@ -184,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); } } @@ -193,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; @@ -203,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 05214ed669..d3aad7000d 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -192,8 +192,8 @@ void StaticBody::set_friction(real_t p_friction) { return; } - ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; ERR_FAIL_COND(p_friction < 0 || p_friction > 1); @@ -206,8 +206,8 @@ void StaticBody::set_friction(real_t p_friction) { real_t StaticBody::get_friction() const { - ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; if (physics_material_override.is_null()) { return 1; @@ -222,8 +222,8 @@ void StaticBody::set_bounce(real_t p_bounce) { return; } - ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); @@ -236,8 +236,8 @@ void StaticBody::set_bounce(real_t p_bounce) { real_t StaticBody::get_bounce() const { - ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; if (physics_material_override.is_null()) { return 0; @@ -636,8 +636,8 @@ void RigidBody::set_friction(real_t p_friction) { return; } - ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; ERR_FAIL_COND(p_friction < 0 || p_friction > 1); @@ -649,8 +649,8 @@ void RigidBody::set_friction(real_t p_friction) { } real_t RigidBody::get_friction() const { - ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; if (physics_material_override.is_null()) { return 1; @@ -665,8 +665,8 @@ void RigidBody::set_bounce(real_t p_bounce) { return; } - ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); @@ -677,8 +677,8 @@ void RigidBody::set_bounce(real_t p_bounce) { physics_material_override->set_bounce(p_bounce); } real_t RigidBody::get_bounce() const { - ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; if (physics_material_override.is_null()) { return 0; } @@ -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 ((lv_n + p_floor_direction).length() < 0.01) { + 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); @@ -1243,21 +1237,18 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve motion = motion.slide(p_floor_direction); lv = lv.slide(p_floor_direction); } else { - Vector3 n = collision.normal; motion = motion.slide(n); 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; @@ -1479,7 +1470,7 @@ Vector3 KinematicCollision::get_remainder() const { return collision.remainder; } Object *KinematicCollision::get_local_shape() const { - ERR_FAIL_COND_V(!owner, NULL); + if (!owner) return NULL; uint32_t ownerid = owner->shape_find_owner(collision.local_shape); return owner->shape_owner_get_owner(ownerid); } diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index 589af98062..aa6030d44e 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -317,7 +317,7 @@ protected: static void _bind_methods(); public: - bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collisionz, bool p_exclude_raycast_shapes = true, 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/proximity_group.cpp b/scene/3d/proximity_group.cpp index 12eab2e4e8..96dc3304f2 100644 --- a/scene/3d/proximity_group.cpp +++ b/scene/3d/proximity_group.cpp @@ -204,6 +204,7 @@ ProximityGroup::ProximityGroup() { group_version = 0; dispatch_mode = MODE_PROXY; + cell_size = 1.0; grid_radius = Vector3(1, 1, 1); set_notify_transform(true); }; diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index b7279e4d4f..e192e040f2 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -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++) { @@ -540,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 { @@ -772,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); diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp index ac20609c21..a9d96292a1 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(); @@ -691,7 +699,6 @@ bool SoftBody::is_ray_pickable() const { } SoftBody::SoftBody() : - MeshInstance(), physics_rid(PhysicsServer::get_singleton()->soft_body_create()), mesh_owner(false), collision_mask(1), 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..1a41a31253 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: { + } } } @@ -505,6 +506,8 @@ bool Spatial::is_set_as_toplevel() const { Ref<World> Spatial::get_world() const { ERR_FAIL_COND_V(!is_inside_world(), Ref<World>()); + ERR_FAIL_COND_V(!data.viewport, Ref<World>()); + return data.viewport->find_world(); } @@ -675,26 +678,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/spatial_velocity_tracker.h b/scene/3d/spatial_velocity_tracker.h index 795f56091f..8260cf3f06 100644 --- a/scene/3d/spatial_velocity_tracker.h +++ b/scene/3d/spatial_velocity_tracker.h @@ -34,7 +34,7 @@ #include "scene/3d/spatial.h" class SpatialVelocityTracker : public Reference { - GDCLASS(SpatialVelocityTracker, Reference) + GDCLASS(SpatialVelocityTracker, Reference); struct PositionHistory { uint64_t frame; diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 6b70eef662..9f73484b6a 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -163,6 +163,7 @@ float SpriteBase3D::get_opacity() const { void SpriteBase3D::set_axis(Vector3::Axis p_axis) { + ERR_FAIL_INDEX(p_axis, 3); axis = p_axis; _queue_update(); } diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp index c7f7b14a8f..89e96e0227 100644 --- a/scene/3d/vehicle_body.cpp +++ b/scene/3d/vehicle_body.cpp @@ -270,6 +270,8 @@ void VehicleWheel::_bind_methods() { ClassDB::bind_method(D_METHOD("get_skidinfo"), &VehicleWheel::get_skidinfo); + ClassDB::bind_method(D_METHOD("get_rpm"), &VehicleWheel::get_rpm); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_traction"), "set_use_as_traction", "is_used_as_traction"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_steering"), "set_use_as_steering", "is_used_as_steering"); ADD_GROUP("Wheel", "wheel_"); @@ -311,6 +313,11 @@ float VehicleWheel::get_skidinfo() const { return m_skidInfo; } +float VehicleWheel::get_rpm() const { + + return m_rpm; +} + VehicleWheel::VehicleWheel() { steers = false; @@ -578,7 +585,7 @@ void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vec if (p_rollInfluence > 0.0) { // !BAS! But seeing we apply this frame by frame, makes more sense to me to make this time based // keeping in mind our anti roll factor if it is set - contactDamping = s->get_step() / p_rollInfluence; + contactDamping = MIN(contactDamping, s->get_step() / p_rollInfluence); } #define ONLY_USE_LINEAR_MASS @@ -716,7 +723,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) { rollingFriction = -engine_force * s->get_step(); } else { real_t defaultRollingFrictionImpulse = 0.f; @@ -865,12 +872,11 @@ void VehicleBody::_direct_state_changed(Object *p_state) { real_t proj2 = fwd.dot(vel); wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelRadius); - wheel.m_rotation += wheel.m_deltaRotation; - - } else { - wheel.m_rotation += wheel.m_deltaRotation; } + wheel.m_rotation += wheel.m_deltaRotation; + wheel.m_rpm = ((wheel.m_deltaRotation / step) * 60) / Math_TAU; + wheel.m_deltaRotation *= real_t(0.99); //damping of rotation when not in contact } @@ -922,8 +928,7 @@ void VehicleBody::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering"); } -VehicleBody::VehicleBody() : - RigidBody() { +VehicleBody::VehicleBody() { m_pitchControl = 0; m_currentVehicleSpeedKmHour = real_t(0.); diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h index 7e7571df4d..9e3fe72282 100644 --- a/scene/3d/vehicle_body.h +++ b/scene/3d/vehicle_body.h @@ -68,6 +68,7 @@ class VehicleWheel : public Spatial { real_t m_steering; real_t m_rotation; real_t m_deltaRotation; + real_t m_rpm; real_t m_rollInfluence; //real_t m_engineForce; real_t m_brake; @@ -134,6 +135,8 @@ public: float get_skidinfo() const; + float get_rpm() const; + String get_configuration_warning() const; VehicleWheel(); diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index 1bbf1b7bc7..5141c84803 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -60,7 +60,7 @@ void VisualInstance::_notification(int p_what) { if (skeleton) VisualServer::get_singleton()->instance_attach_skeleton( instance, skeleton->get_skeleton() ); */ - + ERR_FAIL_COND(get_world().is_null()); VisualServer::get_singleton()->instance_set_scenario(instance, get_world()->get_scenario()); _update_visibility(); @@ -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() { @@ -263,6 +271,11 @@ float GeometryInstance::get_extra_cull_margin() const { return extra_cull_margin; } +void GeometryInstance::set_custom_aabb(AABB aabb) { + + VS::get_singleton()->instance_set_custom_aabb(get_instance(), aabb); +} + void GeometryInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("set_material_override", "material"), &GeometryInstance::set_material_override); @@ -289,6 +302,8 @@ void GeometryInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance::set_extra_cull_margin); ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance::get_extra_cull_margin); + ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &GeometryInstance::set_custom_aabb); + ClassDB::bind_method(D_METHOD("get_aabb"), &GeometryInstance::get_aabb); ADD_GROUP("Geometry", ""); @@ -311,6 +326,7 @@ void GeometryInstance::_bind_methods() { BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_SHADOWS_ONLY); BIND_ENUM_CONSTANT(FLAG_USE_BAKED_LIGHT); + BIND_ENUM_CONSTANT(FLAG_DRAW_NEXT_FRAME_IF_VISIBLE); BIND_ENUM_CONSTANT(FLAG_MAX); } diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h index 3b6fccf65f..3b924e0454 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; @@ -87,6 +89,7 @@ class GeometryInstance : public VisualInstance { public: enum Flags { FLAG_USE_BAKED_LIGHT = VS::INSTANCE_FLAG_USE_BAKED_LIGHT, + FLAG_DRAW_NEXT_FRAME_IF_VISIBLE = VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, FLAG_MAX = VS::INSTANCE_FLAG_MAX, }; @@ -137,6 +140,8 @@ public: void set_extra_cull_margin(float p_margin); float get_extra_cull_margin() const; + void set_custom_aabb(AABB aabb); + GeometryInstance(); }; diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp index 750ed97ae6..5fa8c43f9f 100644 --- a/scene/3d/voxel_light_baker.cpp +++ b/scene/3d/voxel_light_baker.cpp @@ -212,9 +212,7 @@ static bool fast_tri_box_overlap(const Vector3 &boxcenter, const Vector3 boxhalf /* compute plane equation of triangle: normal*x+d=0 */ normal = e0.cross(e1); d = -normal.dot(v0); /* plane eq: normal.x+d=0 */ - if (!planeBoxOverlap(normal, d, boxhalfsize)) return false; - - return true; /* box and triangle overlaps */ + return planeBoxOverlap(normal, d, boxhalfsize); /* if true, box and triangle overlaps */ } static _FORCE_INLINE_ void get_uv_and_normal(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv, const Vector3 *p_normal, Vector2 &r_uv, Vector3 &r_normal) { @@ -835,7 +833,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; @@ -978,7 +976,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; @@ -1113,7 +1111,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; |