diff options
Diffstat (limited to 'scene/3d')
60 files changed, 3619 insertions, 5571 deletions
diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp index 67f57a1aa3..321926d841 100644 --- a/scene/3d/area.cpp +++ b/scene/3d/area.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "area.h" + #include "scene/scene_string_names.h" #include "servers/audio_server.h" #include "servers/physics_server.h" @@ -147,7 +148,7 @@ void Area::_body_exit_tree(ObjectID p_id) { } } -void Area::_body_inout(int p_status, const RID &p_body, int p_instance, int p_body_shape, int p_area_shape) { +void Area::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape) { bool body_in = p_status == PhysicsServer::AREA_BODY_ADDED; ObjectID objid = p_instance; @@ -170,8 +171,8 @@ void Area::_body_inout(int p_status, const RID &p_body, int p_instance, int p_bo E->get().rc = 0; E->get().in_tree = node && node->is_inside_tree(); if (node) { - node->connect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree, make_binds(objid)); - node->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area::_body_enter_tree), make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area::_body_exit_tree), make_binds(objid)); if (E->get().in_tree) { emit_signal(SceneStringNames::get_singleton()->body_entered, node); } @@ -197,8 +198,8 @@ void Area::_body_inout(int p_status, const RID &p_body, int p_instance, int p_bo if (E->get().rc == 0) { if (node) { - node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree); - node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree); + node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area::_body_enter_tree)); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area::_body_exit_tree)); if (E->get().in_tree) emit_signal(SceneStringNames::get_singleton()->body_exited, obj); } @@ -244,8 +245,8 @@ void Area::_clear_monitoring() { emit_signal(SceneStringNames::get_singleton()->body_exited, node); - node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree); - node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree); + node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area::_body_enter_tree)); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area::_body_exit_tree)); } } @@ -274,8 +275,8 @@ void Area::_clear_monitoring() { emit_signal(SceneStringNames::get_singleton()->area_exited, obj); - node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_area_enter_tree); - node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_area_exit_tree); + node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area::_area_enter_tree)); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area::_area_exit_tree)); } } } @@ -340,7 +341,7 @@ void Area::_area_exit_tree(ObjectID p_id) { } } -void Area::_area_inout(int p_status, const RID &p_area, int p_instance, int p_area_shape, int p_self_shape) { +void Area::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, int p_area_shape, int p_self_shape) { bool area_in = p_status == PhysicsServer::AREA_BODY_ADDED; ObjectID objid = p_instance; @@ -363,8 +364,8 @@ void Area::_area_inout(int p_status, const RID &p_area, int p_instance, int p_ar E->get().rc = 0; E->get().in_tree = node && node->is_inside_tree(); if (node) { - node->connect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_area_enter_tree, make_binds(objid)); - node->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_area_exit_tree, make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area::_area_enter_tree), make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area::_area_exit_tree), make_binds(objid)); if (E->get().in_tree) { emit_signal(SceneStringNames::get_singleton()->area_entered, node); } @@ -390,8 +391,8 @@ void Area::_area_inout(int p_status, const RID &p_area, int p_instance, int p_ar if (E->get().rc == 0) { if (node) { - node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_area_enter_tree); - node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_area_exit_tree); + node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area::_area_enter_tree)); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area::_area_exit_tree)); if (E->get().in_tree) { emit_signal(SceneStringNames::get_singleton()->area_exited, obj); } @@ -618,13 +619,6 @@ void Area::_validate_property(PropertyInfo &property) const { } void Area::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_body_enter_tree", "id"), &Area::_body_enter_tree); - ClassDB::bind_method(D_METHOD("_body_exit_tree", "id"), &Area::_body_exit_tree); - - ClassDB::bind_method(D_METHOD("_area_enter_tree", "id"), &Area::_area_enter_tree); - ClassDB::bind_method(D_METHOD("_area_exit_tree", "id"), &Area::_area_exit_tree); - ClassDB::bind_method(D_METHOD("set_space_override_mode", "enable"), &Area::set_space_override_mode); ClassDB::bind_method(D_METHOD("get_space_override_mode"), &Area::get_space_override_mode); @@ -706,11 +700,11 @@ void Area::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_vec"), "set_gravity_vector", "get_gravity_vector"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_gravity", "get_gravity"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_gravity", "get_gravity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable"); @@ -719,12 +713,12 @@ void Area::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); ADD_GROUP("Audio Bus", "audio_bus_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_bus_override"), "set_audio_bus_override", "is_overriding_audio_bus"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus", "get_audio_bus"); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus", "get_audio_bus"); ADD_GROUP("Reverb Bus", "reverb_bus_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reverb_bus_enable"), "set_use_reverb_bus", "is_using_reverb_bus"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "reverb_bus_name", PROPERTY_HINT_ENUM, ""), "set_reverb_bus", "get_reverb_bus"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "reverb_bus_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_amount", "get_reverb_amount"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "reverb_bus_uniformity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_uniformity", "get_reverb_uniformity"); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "reverb_bus_name", PROPERTY_HINT_ENUM, ""), "set_reverb_bus", "get_reverb_bus"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "reverb_bus_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_amount", "get_reverb_amount"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "reverb_bus_uniformity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_uniformity", "get_reverb_uniformity"); BIND_ENUM_CONSTANT(SPACE_OVERRIDE_DISABLED); BIND_ENUM_CONSTANT(SPACE_OVERRIDE_COMBINE); diff --git a/scene/3d/area.h b/scene/3d/area.h index ca66f41f60..7fe61430fa 100644 --- a/scene/3d/area.h +++ b/scene/3d/area.h @@ -62,7 +62,7 @@ private: bool monitorable; bool locked; - void _body_inout(int p_status, const RID &p_body, int p_instance, int p_body_shape, int p_area_shape); + void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape); void _body_enter_tree(ObjectID p_id); void _body_exit_tree(ObjectID p_id); @@ -94,7 +94,7 @@ private: Map<ObjectID, BodyState> body_map; - void _area_inout(int p_status, const RID &p_area, int p_instance, int p_area_shape, int p_self_shape); + void _area_inout(int p_status, const RID &p_area, ObjectID p_instance, int p_area_shape, int p_self_shape); void _area_enter_tree(ObjectID p_id); void _area_exit_tree(ObjectID p_id); diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp index 8d1556ef1c..bf85a8bd53 100644 --- a/scene/3d/arvr_nodes.cpp +++ b/scene/3d/arvr_nodes.cpp @@ -252,7 +252,7 @@ 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(PropertyInfo(Variant::FLOAT, "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); @@ -544,7 +544,7 @@ String ARVROrigin::get_configuration_warning() const { void ARVROrigin::_bind_methods() { ClassDB::bind_method(D_METHOD("set_world_scale", "world_scale"), &ARVROrigin::set_world_scale); ClassDB::bind_method(D_METHOD("get_world_scale"), &ARVROrigin::get_world_scale); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "world_scale"), "set_world_scale", "get_world_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale"); }; void ARVROrigin::set_tracked_camera(ARVRCamera *p_tracked_camera) { diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 596ef78fb5..855d254bd6 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -45,12 +45,12 @@ private: mutable real_t squared_gain; // temporary }; - PoolVector<Speaker> speakers; + Vector<Speaker> speakers; public: Spcap(unsigned int speaker_count, const Vector3 *speaker_directions) { this->speakers.resize(speaker_count); - PoolVector<Speaker>::Write w = this->speakers.write(); + Speaker *w = this->speakers.ptrw(); for (unsigned int speaker_num = 0; speaker_num < speaker_count; speaker_num++) { w[speaker_num].direction = speaker_directions[speaker_num]; w[speaker_num].squared_gain = 0.0; @@ -66,11 +66,11 @@ public: } Vector3 get_speaker_direction(unsigned int index) const { - return this->speakers.read()[index].direction; + return this->speakers.ptr()[index].direction; } void calculate(const Vector3 &source_direction, real_t tightness, unsigned int volume_count, real_t *volumes) const { - PoolVector<Speaker>::Read r = this->speakers.read(); + const Speaker *r = this->speakers.ptr(); real_t sum_squared_gains = 0.0; for (unsigned int speaker_num = 0; speaker_num < (unsigned int)this->speakers.size(); speaker_num++) { real_t initial_gain = 0.5 * powf(1.0 + r[speaker_num].direction.dot(source_direction), tightness) / r[speaker_num].effective_number_of_speakers; @@ -98,11 +98,18 @@ static const Vector3 speaker_directions[7] = { void AudioStreamPlayer3D::_calc_output_vol(const Vector3 &source_dir, real_t tightness, AudioStreamPlayer3D::Output &output) { unsigned int speaker_count; // only main speakers (no LFE) switch (AudioServer::get_singleton()->get_speaker_mode()) { - default: //fallthrough - case AudioServer::SPEAKER_MODE_STEREO: speaker_count = 2; break; - case AudioServer::SPEAKER_SURROUND_31: speaker_count = 3; break; - case AudioServer::SPEAKER_SURROUND_51: speaker_count = 5; break; - case AudioServer::SPEAKER_SURROUND_71: speaker_count = 7; break; + case AudioServer::SPEAKER_MODE_STEREO: + speaker_count = 2; + break; + case AudioServer::SPEAKER_SURROUND_31: + speaker_count = 3; + break; + case AudioServer::SPEAKER_SURROUND_51: + speaker_count = 5; + break; + case AudioServer::SPEAKER_SURROUND_71: + speaker_count = 7; + break; } Spcap spcap(speaker_count, speaker_directions); //TODO: should only be created/recreated once the speaker mode / speaker positions changes @@ -113,18 +120,19 @@ void AudioStreamPlayer3D::_calc_output_vol(const Vector3 &source_dir, real_t tig case AudioServer::SPEAKER_SURROUND_71: output.vol[3].l = volumes[5]; // side-left output.vol[3].r = volumes[6]; // side-right - //fallthrough + [[fallthrough]]; case AudioServer::SPEAKER_SURROUND_51: output.vol[2].l = volumes[3]; // rear-left output.vol[2].r = volumes[4]; // rear-right - //fallthrough + [[fallthrough]]; case AudioServer::SPEAKER_SURROUND_31: output.vol[1].r = 1.0; // LFE - always full power output.vol[1].l = volumes[2]; // center - //fallthrough + [[fallthrough]]; case AudioServer::SPEAKER_MODE_STEREO: output.vol[0].r = volumes[1]; // front-right output.vol[0].l = volumes[0]; // front-left + break; } } @@ -1000,28 +1008,26 @@ void AudioStreamPlayer3D::_bind_methods() { 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,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"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,32,0.01"), "set_pitch_scale", "get_pitch_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_db", PROPERTY_HINT_RANGE, "-80,80"), "set_unit_db", "get_unit_db"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_size", PROPERTY_HINT_RANGE, "0.1,100,0.1"), "set_unit_size", "get_unit_size"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_db", PROPERTY_HINT_RANGE, "-24,6"), "set_max_db", "get_max_db"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,4,0.01,or_greater"), "set_pitch_scale", "get_pitch_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,4096,1,or_greater"), "set_max_distance", "get_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,4096,1,or_greater"), "set_max_distance", "get_max_distance"); ADD_PROPERTY(PropertyInfo(Variant::INT, "out_of_range_mode", PROPERTY_HINT_ENUM, "Mix,Pause"), "set_out_of_range_mode", "get_out_of_range_mode"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus"); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus"); ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask"); ADD_GROUP("Emission Angle", "emission_angle"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emission_angle_enabled"), "set_emission_angle_enabled", "is_emission_angle_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_angle_degrees", PROPERTY_HINT_RANGE, "0.1,90,0.1"), "set_emission_angle", "get_emission_angle"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_angle_filter_attenuation_db", PROPERTY_HINT_RANGE, "-80,0,0.1"), "set_emission_angle_filter_attenuation_db", "get_emission_angle_filter_attenuation_db"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_angle_degrees", PROPERTY_HINT_RANGE, "0.1,90,0.1"), "set_emission_angle", "get_emission_angle"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_angle_filter_attenuation_db", PROPERTY_HINT_RANGE, "-80,0,0.1"), "set_emission_angle_filter_attenuation_db", "get_emission_angle_filter_attenuation_db"); ADD_GROUP("Attenuation Filter", "attenuation_filter_"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation_filter_cutoff_hz", PROPERTY_HINT_RANGE, "1,20500,1"), "set_attenuation_filter_cutoff_hz", "get_attenuation_filter_cutoff_hz"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation_filter_db", PROPERTY_HINT_RANGE, "-80,0,0.1"), "set_attenuation_filter_db", "get_attenuation_filter_db"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "attenuation_filter_cutoff_hz", PROPERTY_HINT_RANGE, "1,20500,1"), "set_attenuation_filter_cutoff_hz", "get_attenuation_filter_cutoff_hz"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "attenuation_filter_db", PROPERTY_HINT_RANGE, "-80,0,0.1"), "set_attenuation_filter_db", "get_attenuation_filter_db"); ADD_GROUP("Doppler", "doppler_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"), "set_doppler_tracking", "get_doppler_tracking"); @@ -1068,7 +1074,7 @@ AudioStreamPlayer3D::AudioStreamPlayer3D() { stream_paused_fade_out = false; velocity_tracker.instance(); - AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed"); + AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer3D::_bus_layout_changed)); set_disable_scale(true); } AudioStreamPlayer3D::~AudioStreamPlayer3D() { diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp index 071afd1a69..73b1d450f0 100644 --- a/scene/3d/baked_lightmap.cpp +++ b/scene/3d/baked_lightmap.cpp @@ -28,6 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#if 0 #include "baked_lightmap.h" #include "core/io/config_file.h" #include "core/io/resource_saver.h" @@ -46,12 +47,12 @@ AABB BakedLightmapData::get_bounds() const { return bounds; } -void BakedLightmapData::set_octree(const PoolVector<uint8_t> &p_octree) { +void BakedLightmapData::set_octree(const Vector<uint8_t> &p_octree) { VS::get_singleton()->lightmap_capture_set_octree(baked_light, p_octree); } -PoolVector<uint8_t> BakedLightmapData::get_octree() const { +Vector<uint8_t> BakedLightmapData::get_octree() const { return VS::get_singleton()->lightmap_capture_get_octree(baked_light); } @@ -86,7 +87,7 @@ float BakedLightmapData::get_energy() const { return energy; } -void BakedLightmapData::add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap, int p_instance) { +void BakedLightmapData::add_user(const NodePath &p_path, const Ref<Texture2D> &p_lightmap, int p_instance) { ERR_FAIL_COND_MSG(p_lightmap.is_null(), "It's not a reference to a valid Texture object."); User user; @@ -105,9 +106,9 @@ NodePath BakedLightmapData::get_user_path(int p_user) const { ERR_FAIL_INDEX_V(p_user, users.size(), NodePath()); return users[p_user].path; } -Ref<Texture> BakedLightmapData::get_user_lightmap(int p_user) const { +Ref<Texture2D> BakedLightmapData::get_user_lightmap(int p_user) const { - ERR_FAIL_INDEX_V(p_user, users.size(), Ref<Texture>()); + ERR_FAIL_INDEX_V(p_user, users.size(), Ref<Texture2D>()); return users[p_user].lightmap; } @@ -173,8 +174,8 @@ 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,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::FLOAT, "energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_energy", "get_energy"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_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"); } @@ -368,7 +369,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi Ref<BakedLightmapData> new_light_data; new_light_data.instance(); - VoxelLightBaker baker; + Voxelizer baker; int bake_subdiv; int capture_subdiv; @@ -413,7 +414,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi } pmc = 0; - baker.begin_bake_light(VoxelLightBaker::BakeQuality(bake_quality), VoxelLightBaker::BakeMode(bake_mode), propagation, energy); + baker.begin_bake_light(Voxelizer::BakeQuality(bake_quality), Voxelizer::BakeMode(bake_mode), propagation, energy); for (List<PlotLight>::Element *E = light_list.front(); E; E = E->next()) { @@ -465,7 +466,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi used_mesh_names.insert(mesh_name); pmc++; - VoxelLightBaker::LightMapData lm; + Voxelizer::LightMapData lm; Error err; if (bake_step_function) { @@ -491,17 +492,16 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi Ref<Image> image; image.instance(); - uint32_t tex_flags = Texture::FLAGS_DEFAULT; if (hdr) { //just save a regular image - PoolVector<uint8_t> data; + Vector<uint8_t> data; int s = lm.light.size(); data.resize(lm.light.size() * 2); { - PoolVector<uint8_t>::Write w = data.write(); - PoolVector<float>::Read r = lm.light.read(); + uint8_t* w = data.ptrw(); + const float* r = lm.light.ptr(); uint16_t *hfw = (uint16_t *)w.ptr(); for (int i = 0; i < s; i++) { hfw[i] = Math::make_half_float(r[i]); @@ -513,13 +513,13 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi } else { //just save a regular image - PoolVector<uint8_t> data; + Vector<uint8_t> data; int s = lm.light.size(); data.resize(lm.light.size()); { - PoolVector<uint8_t>::Write w = data.write(); - PoolVector<float>::Read r = lm.light.read(); + uint8_t* w = data.ptrw(); + const float* r = lm.light.ptr(); for (int i = 0; i < s; i += 3) { Color c(r[i + 0], r[i + 1], r[i + 2]); c = c.to_srgb(); @@ -534,11 +534,10 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi //This texture is saved to SRGB for two reasons: // 1) first is so it looks better when doing the LINEAR->SRGB conversion (more accurate) // 2) So it can be used in the GLES2 backend, which does not support linkear workflow - tex_flags |= Texture::FLAG_CONVERT_TO_LINEAR; } String image_path = save_path.plus_file(mesh_name); - Ref<Texture> texture; + Ref<Texture2D> texture; if (ResourceLoader::import) { @@ -583,7 +582,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi tex.instance(); } - tex->create_from_image(image, tex_flags); + tex->create_from_image(image); err = ResourceSaver::save(image_path, tex, ResourceSaver::FLAG_CHANGE_PATH); if (set_path) { @@ -628,7 +627,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi if (p_create_visual_debug) { MultiMeshInstance *mmi = memnew(MultiMeshInstance); - mmi->set_multimesh(baker.create_debug_multimesh(VoxelLightBaker::DEBUG_LIGHT)); + mmi->set_multimesh(baker.create_debug_multimesh(Voxelizer::DEBUG_LIGHT)); add_child(mmi); #ifdef TOOLS_ENABLED if (get_tree()->get_edited_scene_root() == this) { @@ -668,7 +667,7 @@ void BakedLightmap::_assign_lightmaps() { ERR_FAIL_COND(!light_data.is_valid()); for (int i = 0; i < light_data->get_user_count(); i++) { - Ref<Texture> lightmap = light_data->get_user_lightmap(i); + Ref<Texture2D> lightmap = light_data->get_user_lightmap(i); ERR_CONTINUE(!lightmap.is_valid()); Node *node = get_node(light_data->get_user_path(i)); @@ -776,8 +775,8 @@ String BakedLightmap::get_image_path() const { AABB BakedLightmap::get_aabb() const { return AABB(-extents, extents * 2); } -PoolVector<Face3> BakedLightmap::get_faces(uint32_t p_usage_flags) const { - return PoolVector<Face3>(); +Vector<Face3> BakedLightmap::get_faces(uint32_t p_usage_flags) const { + return Vector<Face3>(); } void BakedLightmap::_bind_methods() { @@ -820,16 +819,16 @@ void BakedLightmap::_bind_methods() { ClassDB::set_method_flags(get_class_static(), _scs_create("debug_bake"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ADD_GROUP("Bake", "bake_"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_bake_cell_size", "get_bake_cell_size"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_bake_cell_size", "get_bake_cell_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), "set_bake_quality", "get_bake_quality"); ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mode", PROPERTY_HINT_ENUM, "ConeTrace,RayTrace"), "set_bake_mode", "get_bake_mode"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_energy", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_energy", "get_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_energy", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_energy", "get_energy"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bake_hdr"), "set_hdr", "is_hdr"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "bake_extents"), "set_extents", "get_extents"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_default_texels_per_unit"), "set_bake_default_texels_per_unit", "get_bake_default_texels_per_unit"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_default_texels_per_unit"), "set_bake_default_texels_per_unit", "get_bake_default_texels_per_unit"); ADD_GROUP("Capture", "capture_"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "capture_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_capture_cell_size", "get_capture_cell_size"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "capture_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_capture_cell_size", "get_capture_cell_size"); ADD_GROUP("Data", ""); ADD_PROPERTY(PropertyInfo(Variant::STRING, "image_path", PROPERTY_HINT_DIR), "set_image_path", "get_image_path"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_data", PROPERTY_HINT_RESOURCE_TYPE, "BakedLightmapData"), "set_light_data", "get_light_data"); @@ -862,3 +861,4 @@ BakedLightmap::BakedLightmap() { image_path = "."; set_disable_scale(true); } +#endif diff --git a/scene/3d/baked_lightmap.h b/scene/3d/baked_lightmap.h index 82354cc9f0..bc9e3f55ea 100644 --- a/scene/3d/baked_lightmap.h +++ b/scene/3d/baked_lightmap.h @@ -28,6 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#if 0 #ifndef BAKED_INDIRECT_LIGHT_H #define BAKED_INDIRECT_LIGHT_H @@ -47,7 +48,7 @@ class BakedLightmapData : public Resource { struct User { NodePath path; - Ref<Texture> lightmap; + Ref<Texture2D> lightmap; int instance_index; }; @@ -63,8 +64,8 @@ public: void set_bounds(const AABB &p_bounds); AABB get_bounds() const; - void set_octree(const PoolVector<uint8_t> &p_octree); - PoolVector<uint8_t> get_octree() const; + void set_octree(const Vector<uint8_t> &p_octree); + Vector<uint8_t> get_octree() const; void set_cell_space_transform(const Transform &p_xform); Transform get_cell_space_transform() const; @@ -75,10 +76,10 @@ public: void set_energy(float p_energy); float get_energy() const; - void add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap, int p_instance = -1); + void add_user(const NodePath &p_path, const Ref<Texture2D> &p_lightmap, int p_instance = -1); int get_user_count() const; NodePath get_user_path(int p_user) const; - Ref<Texture> get_user_lightmap(int p_user) const; + Ref<Texture2D> get_user_lightmap(int p_user) const; int get_user_instance(int p_user) const; void clear_users(); @@ -201,7 +202,7 @@ public: String get_image_path() const; AABB get_aabb() const; - PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; + Vector<Face3> get_faces(uint32_t p_usage_flags) const; BakeError bake(Node *p_from_node, bool p_create_visual_debug = false); BakedLightmap(); @@ -211,4 +212,5 @@ VARIANT_ENUM_CAST(BakedLightmap::BakeQuality); VARIANT_ENUM_CAST(BakedLightmap::BakeMode); VARIANT_ENUM_CAST(BakedLightmap::BakeError); +#endif #endif // BAKED_INDIRECT_LIGHT_H diff --git a/scene/3d/bone_attachment.cpp b/scene/3d/bone_attachment.cpp index e94e174b92..b1cd9bfe8b 100644 --- a/scene/3d/bone_attachment.cpp +++ b/scene/3d/bone_attachment.cpp @@ -123,5 +123,5 @@ void BoneAttachment::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bone_name", "bone_name"), &BoneAttachment::set_bone_name); ClassDB::bind_method(D_METHOD("get_bone_name"), &BoneAttachment::get_bone_name); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "bone_name"), "set_bone_name", "get_bone_name"); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bone_name"), "set_bone_name", "get_bone_name"); } diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index 640189a26e..741712025c 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -445,6 +445,21 @@ Ref<Environment> Camera::get_environment() const { return environment; } +void Camera::set_effects(const Ref<CameraEffects> &p_effects) { + + effects = p_effects; + if (effects.is_valid()) + VS::get_singleton()->camera_set_camera_effects(camera, effects->get_rid()); + else + VS::get_singleton()->camera_set_camera_effects(camera, RID()); + _update_camera_mode(); +} + +Ref<CameraEffects> Camera::get_effects() const { + + return effects; +} + void Camera::set_keep_aspect_mode(KeepAspect p_aspect) { keep_aspect = p_aspect; VisualServer::get_singleton()->camera_set_use_vertical_aspect(camera, p_aspect == KEEP_WIDTH); @@ -512,6 +527,8 @@ void Camera::_bind_methods() { ClassDB::bind_method(D_METHOD("get_cull_mask"), &Camera::get_cull_mask); ClassDB::bind_method(D_METHOD("set_environment", "env"), &Camera::set_environment); ClassDB::bind_method(D_METHOD("get_environment"), &Camera::get_environment); + ClassDB::bind_method(D_METHOD("set_effects", "env"), &Camera::set_effects); + ClassDB::bind_method(D_METHOD("get_effects"), &Camera::get_effects); ClassDB::bind_method(D_METHOD("set_keep_aspect_mode", "mode"), &Camera::set_keep_aspect_mode); ClassDB::bind_method(D_METHOD("get_keep_aspect_mode"), &Camera::get_keep_aspect_mode); ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera::set_doppler_tracking); @@ -527,16 +544,17 @@ void Camera::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "keep_aspect", PROPERTY_HINT_ENUM, "Keep Width,Keep Height"), "set_keep_aspect_mode", "get_keep_aspect_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment"); - 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::OBJECT, "effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_effects", "get_effects"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset"), "set_h_offset", "get_h_offset"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "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,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::FLOAT, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset"), "set_frustum_offset", "get_frustum_offset"); - ADD_PROPERTY(PropertyInfo(Variant::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"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01,or_greater"), "set_znear", "get_znear"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_zfar", "get_zfar"); BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE); BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL); @@ -908,7 +926,7 @@ void ClippedCamera::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_exceptions"), &ClippedCamera::clear_exceptions); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_margin", "get_margin"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_margin", "get_margin"); ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); diff --git a/scene/3d/camera.h b/scene/3d/camera.h index e215783a58..6ac3ece798 100644 --- a/scene/3d/camera.h +++ b/scene/3d/camera.h @@ -82,6 +82,7 @@ private: uint32_t layers; Ref<Environment> environment; + Ref<CameraEffects> effects; virtual bool _can_gizmo_scale() const; @@ -157,6 +158,9 @@ public: void set_environment(const Ref<Environment> &p_environment); Ref<Environment> get_environment() const; + void set_effects(const Ref<CameraEffects> &p_effects); + Ref<CameraEffects> get_effects() const; + void set_keep_aspect_mode(KeepAspect p_aspect); KeepAspect get_keep_aspect_mode() const; diff --git a/scene/3d/collision_polygon.cpp b/scene/3d/collision_polygon.cpp index cc07072962..636b859477 100644 --- a/scene/3d/collision_polygon.cpp +++ b/scene/3d/collision_polygon.cpp @@ -53,11 +53,11 @@ void CollisionPolygon::_build_polygon() { for (int i = 0; i < decomp.size(); i++) { Ref<ConvexPolygonShape> convex = memnew(ConvexPolygonShape); - PoolVector<Vector3> cp; + Vector<Vector3> cp; int cs = decomp[i].size(); cp.resize(cs * 2); { - PoolVector<Vector3>::Write w = cp.write(); + Vector3 *w = cp.ptrw(); int idx = 0; for (int j = 0; j < cs; j++) { @@ -191,9 +191,9 @@ void CollisionPolygon::_bind_methods() { ClassDB::bind_method(D_METHOD("_is_editable_3d_polygon"), &CollisionPolygon::_is_editable_3d_polygon); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "depth"), "set_depth", "get_depth"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth"), "set_depth", "get_depth"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); - ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); } CollisionPolygon::CollisionPolygon() { diff --git a/scene/3d/collision_shape.cpp b/scene/3d/collision_shape.cpp index bf2816fd41..35e4a61cd6 100644 --- a/scene/3d/collision_shape.cpp +++ b/scene/3d/collision_shape.cpp @@ -33,9 +33,9 @@ #include "scene/resources/capsule_shape.h" #include "scene/resources/concave_polygon_shape.h" #include "scene/resources/convex_polygon_shape.h" -#include "scene/resources/plane_shape.h" #include "scene/resources/ray_shape.h" #include "scene/resources/sphere_shape.h" +#include "scene/resources/world_margin_shape.h" #include "servers/visual_server.h" //TODO: Implement CylinderShape and HeightMapShape? #include "core/math/quick_hull.h" @@ -123,10 +123,6 @@ String CollisionShape::get_configuration_warning() const { return TTR("A shape must be provided for CollisionShape to function. Please create a shape resource for it."); } - if (shape->is_class("PlaneShape")) { - return TTR("Plane shapes don't work well and will be removed in future versions. Please don't use them."); - } - return String(); } @@ -141,7 +137,6 @@ 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"); @@ -152,12 +147,12 @@ void CollisionShape::set_shape(const Ref<Shape> &p_shape) { if (!shape.is_null()) { shape->unregister_owner(this); - shape->disconnect("changed", this, "_shape_changed"); + shape->disconnect("changed", callable_mp(this, &CollisionShape::_shape_changed)); } shape = p_shape; if (!shape.is_null()) { shape->register_owner(this); - shape->connect("changed", this, "_shape_changed"); + shape->connect("changed", callable_mp(this, &CollisionShape::_shape_changed)); } update_gizmo(); if (parent) { diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp index aa7a413548..bde578d0af 100644 --- a/scene/3d/cpu_particles.cpp +++ b/scene/3d/cpu_particles.cpp @@ -39,9 +39,9 @@ AABB CPUParticles::get_aabb() const { return AABB(); } -PoolVector<Face3> CPUParticles::get_faces(uint32_t p_usage_flags) const { +Vector<Face3> CPUParticles::get_faces(uint32_t p_usage_flags) const { - return PoolVector<Face3>(); + return Vector<Face3>(); } void CPUParticles::set_emitting(bool p_emitting) { @@ -65,15 +65,15 @@ void CPUParticles::set_amount(int p_amount) { particles.resize(p_amount); { - PoolVector<Particle>::Write w = particles.write(); + Particle *w = particles.ptrw(); for (int i = 0; i < p_amount; i++) { w[i].active = false; } } - particle_data.resize((12 + 4 + 1) * p_amount); - VS::get_singleton()->multimesh_allocate(multimesh, p_amount, VS::MULTIMESH_TRANSFORM_3D, VS::MULTIMESH_COLOR_8BIT, VS::MULTIMESH_CUSTOM_DATA_FLOAT); + particle_data.resize((12 + 4 + 4) * p_amount); + VS::get_singleton()->multimesh_allocate(multimesh, p_amount, VS::MULTIMESH_TRANSFORM_3D, true, true); particle_order.resize(p_amount); } @@ -209,14 +209,14 @@ String CPUParticles::get_configuration_warning() const { mesh_found = true; for (int j = 0; j < get_mesh()->get_surface_count(); j++) { anim_material_found = Object::cast_to<ShaderMaterial>(get_mesh()->surface_get_material(j).ptr()) != NULL; - SpatialMaterial *spat = Object::cast_to<SpatialMaterial>(get_mesh()->surface_get_material(j).ptr()); - anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == SpatialMaterial::BILLBOARD_PARTICLES); + StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(get_mesh()->surface_get_material(j).ptr()); + anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES); } } anim_material_found = anim_material_found || Object::cast_to<ShaderMaterial>(get_material_override().ptr()) != NULL; - SpatialMaterial *spat = Object::cast_to<SpatialMaterial>(get_material_override().ptr()); - anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == SpatialMaterial::BILLBOARD_PARTICLES); + StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(get_material_override().ptr()); + anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES); if (!mesh_found) { if (warnings != String()) @@ -228,7 +228,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 whose Billboard Mode is set to \"Particle Billboard\"."); + warnings += "- " + TTR("CPUParticles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."); } return warnings; @@ -244,7 +244,7 @@ void CPUParticles::restart() { { int pc = particles.size(); - PoolVector<Particle>::Write w = particles.write(); + Particle *w = particles.ptrw(); for (int i = 0; i < pc; i++) { w[i].active = false; @@ -419,17 +419,17 @@ void CPUParticles::set_emission_box_extents(Vector3 p_extents) { emission_box_extents = p_extents; } -void CPUParticles::set_emission_points(const PoolVector<Vector3> &p_points) { +void CPUParticles::set_emission_points(const Vector<Vector3> &p_points) { emission_points = p_points; } -void CPUParticles::set_emission_normals(const PoolVector<Vector3> &p_normals) { +void CPUParticles::set_emission_normals(const Vector<Vector3> &p_normals) { emission_normals = p_normals; } -void CPUParticles::set_emission_colors(const PoolVector<Color> &p_colors) { +void CPUParticles::set_emission_colors(const Vector<Color> &p_colors) { emission_colors = p_colors; } @@ -442,16 +442,16 @@ Vector3 CPUParticles::get_emission_box_extents() const { return emission_box_extents; } -PoolVector<Vector3> CPUParticles::get_emission_points() const { +Vector<Vector3> CPUParticles::get_emission_points() const { return emission_points; } -PoolVector<Vector3> CPUParticles::get_emission_normals() const { +Vector<Vector3> CPUParticles::get_emission_normals() const { return emission_normals; } -PoolVector<Color> CPUParticles::get_emission_colors() const { +Vector<Color> CPUParticles::get_emission_colors() const { return emission_colors; } @@ -597,9 +597,9 @@ void CPUParticles::_particles_process(float p_delta) { p_delta *= speed_scale; int pcount = particles.size(); - PoolVector<Particle>::Write w = particles.write(); + Particle *w = particles.ptrw(); - Particle *parray = w.ptr(); + Particle *parray = w; float prev_time = time; time += p_delta; @@ -1017,140 +1017,125 @@ void CPUParticles::_particles_process(float p_delta) { } void CPUParticles::_update_particle_data_buffer() { -#ifndef NO_THREADS - update_mutex->lock(); -#endif + MutexLock lock(update_mutex); - { + int pc = particles.size(); - int pc = particles.size(); + int *ow; + int *order = NULL; - PoolVector<int>::Write ow; - int *order = NULL; + float *w = particle_data.ptrw(); + const Particle *r = particles.ptr(); + float *ptr = w; - PoolVector<float>::Write w = particle_data.write(); - PoolVector<Particle>::Read r = particles.read(); - float *ptr = w.ptr(); + if (draw_order != DRAW_ORDER_INDEX) { + ow = particle_order.ptrw(); + order = ow; - if (draw_order != DRAW_ORDER_INDEX) { - ow = particle_order.write(); - order = ow.ptr(); + for (int i = 0; i < pc; i++) { + order[i] = i; + } + if (draw_order == DRAW_ORDER_LIFETIME) { + SortArray<int, SortLifetime> sorter; + sorter.compare.particles = r; + sorter.sort(order, pc); + } else if (draw_order == DRAW_ORDER_VIEW_DEPTH) { + Camera *c = get_viewport()->get_camera(); + if (c) { + Vector3 dir = c->get_global_transform().basis.get_axis(2); //far away to close + + if (local_coords) { + + // 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(); + } - for (int i = 0; i < pc; i++) { - order[i] = i; - } - if (draw_order == DRAW_ORDER_LIFETIME) { - SortArray<int, SortLifetime> sorter; - sorter.compare.particles = r.ptr(); + SortArray<int, SortAxis> sorter; + sorter.compare.particles = r; + sorter.compare.axis = dir; sorter.sort(order, pc); - } else if (draw_order == DRAW_ORDER_VIEW_DEPTH) { - Camera *c = get_viewport()->get_camera(); - if (c) { - Vector3 dir = c->get_global_transform().basis.get_axis(2); //far away to close - - if (local_coords) { - - // 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; - sorter.compare.particles = r.ptr(); - sorter.compare.axis = dir; - sorter.sort(order, pc); - } } } + } - for (int i = 0; i < pc; i++) { + for (int i = 0; i < pc; i++) { - int idx = order ? order[i] : i; + int idx = order ? order[i] : i; - Transform t = r[idx].transform; + Transform t = r[idx].transform; - if (!local_coords) { - t = inv_emission_transform * t; - } + if (!local_coords) { + t = inv_emission_transform * t; + } - if (r[idx].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); - } + if (r[idx].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); + } - Color c = r[idx].color; - uint8_t *data8 = (uint8_t *)&ptr[12]; - data8[0] = CLAMP(c.r * 255.0, 0, 255); - data8[1] = CLAMP(c.g * 255.0, 0, 255); - data8[2] = CLAMP(c.b * 255.0, 0, 255); - data8[3] = CLAMP(c.a * 255.0, 0, 255); + Color c = r[idx].color; - ptr[13] = r[idx].custom[0]; - ptr[14] = r[idx].custom[1]; - ptr[15] = r[idx].custom[2]; - ptr[16] = r[idx].custom[3]; + ptr[12] = c.r; + ptr[13] = c.g; + ptr[14] = c.b; + ptr[15] = c.a; - ptr += 17; - } + ptr[16] = r[idx].custom[0]; + ptr[17] = r[idx].custom[1]; + ptr[18] = r[idx].custom[2]; + ptr[19] = r[idx].custom[3]; - can_update = true; + ptr += 20; } -#ifndef NO_THREADS - update_mutex->unlock(); -#endif + can_update = true; } 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 { - if (VS::get_singleton()->is_connected("frame_pre_draw", this, "_update_render_thread")) { - VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); + + { + MutexLock lock(update_mutex); + + if (redraw) { + VS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &CPUParticles::_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 { + if (VS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &CPUParticles::_update_render_thread))) { + VS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &CPUParticles::_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); } - 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 - update_mutex->lock(); -#endif + MutexLock lock(update_mutex); + if (can_update) { - VS::get_singleton()->multimesh_set_as_bulk_array(multimesh, particle_data); + VS::get_singleton()->multimesh_set_buffer(multimesh, particle_data); can_update = false; //wait for next time } - -#ifndef NO_THREADS - update_mutex->unlock(); -#endif } void CPUParticles::_notification(int p_what) { @@ -1185,9 +1170,9 @@ void CPUParticles::_notification(int p_what) { int pc = particles.size(); - PoolVector<float>::Write w = particle_data.write(); - PoolVector<Particle>::Read r = particles.read(); - float *ptr = w.ptr(); + float *w = particle_data.ptrw(); + const Particle *r = particles.ptr(); + float *ptr = w; for (int i = 0; i < pc; i++) { @@ -1210,7 +1195,7 @@ void CPUParticles::_notification(int p_what) { zeromem(ptr, sizeof(float) * 12); } - ptr += 17; + ptr += 20; } can_update = true; @@ -1327,13 +1312,13 @@ void CPUParticles::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount"); ADD_GROUP("Time", ""); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness"); ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta"); ADD_GROUP("Drawing", ""); @@ -1397,74 +1382,72 @@ void CPUParticles::_bind_methods() { ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles::convert_from_particles); - ClassDB::bind_method(D_METHOD("_update_render_thread"), &CPUParticles::_update_render_thread); - ADD_GROUP("Emission Shape", "emission_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents"); - ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "emission_points"), "set_emission_points", "get_emission_points"); - ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals"); - ADD_PROPERTY(PropertyInfo(Variant::POOL_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_points"), "set_emission_points", "get_emission_points"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors"); ADD_GROUP("Flags", "flag_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_particle_flag", "get_particle_flag", FLAG_ALIGN_Y_TO_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_particle_flag", "get_particle_flag", FLAG_ROTATE_Y); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_disable_z"), "set_particle_flag", "get_particle_flag", FLAG_DISABLE_Z); ADD_GROUP("Direction", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "direction"), "set_direction", "get_direction"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness"); ADD_GROUP("Gravity", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity"); ADD_GROUP("Initial Velocity", "initial_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY); ADD_GROUP("Angular Velocity", "angular_"); - 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::FLOAT, "angular_velocity", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::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::FLOAT, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::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); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL); ADD_GROUP("Radial Accel", "radial_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_RADIAL_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_RADIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL); ADD_GROUP("Tangential Accel", "tangential_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL); ADD_GROUP("Damping", ""); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param", "get_param", PARAM_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param", "get_param", PARAM_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING); ADD_GROUP("Angle", ""); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGLE); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE); ADD_GROUP("Scale", ""); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale_amount", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale_amount_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_amount_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_SCALE); ADD_GROUP("Color", ""); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp"); ADD_GROUP("Hue Variation", "hue_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param", "get_param", PARAM_HUE_VARIATION); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param", "get_param", PARAM_HUE_VARIATION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION); ADD_GROUP("Animation", "anim_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_param", "get_param", PARAM_ANIM_SPEED); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_param", "get_param", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_OFFSET); BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY); @@ -1556,16 +1539,8 @@ CPUParticles::CPUParticles() { can_update = false; set_color(Color(1, 1, 1, 1)); - -#ifndef NO_THREADS - update_mutex = Mutex::create(); -#endif } CPUParticles::~CPUParticles() { VS::get_singleton()->free(multimesh); - -#ifndef NO_THREADS - memdelete(update_mutex); -#endif } diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h index d5a549b976..231e1f1ad9 100644 --- a/scene/3d/cpu_particles.h +++ b/scene/3d/cpu_particles.h @@ -106,9 +106,9 @@ private: RID multimesh; - PoolVector<Particle> particles; - PoolVector<float> particle_data; - PoolVector<int> particle_order; + Vector<Particle> particles; + Vector<float> particle_data; + Vector<int> particle_order; struct SortLifetime { const Particle *particles; @@ -167,9 +167,9 @@ private: EmissionShape emission_shape; float emission_sphere_radius; Vector3 emission_box_extents; - PoolVector<Vector3> emission_points; - PoolVector<Vector3> emission_normals; - PoolVector<Color> emission_colors; + Vector<Vector3> emission_points; + Vector<Vector3> emission_normals; + Vector<Color> emission_colors; int emission_point_count; Vector3 gravity; @@ -178,7 +178,7 @@ private: void _particles_process(float p_delta); void _update_particle_data_buffer(); - Mutex *update_mutex; + Mutex update_mutex; void _update_render_thread(); @@ -191,7 +191,7 @@ protected: public: AABB get_aabb() const; - PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; + Vector<Face3> get_faces(uint32_t p_usage_flags) const; void set_emitting(bool p_emitting); void set_amount(int p_amount); @@ -264,17 +264,17 @@ public: void set_emission_shape(EmissionShape p_shape); void set_emission_sphere_radius(float p_radius); void set_emission_box_extents(Vector3 p_extents); - void set_emission_points(const PoolVector<Vector3> &p_points); - void set_emission_normals(const PoolVector<Vector3> &p_normals); - void set_emission_colors(const PoolVector<Color> &p_colors); + void set_emission_points(const Vector<Vector3> &p_points); + void set_emission_normals(const Vector<Vector3> &p_normals); + void set_emission_colors(const Vector<Color> &p_colors); void set_emission_point_count(int p_count); EmissionShape get_emission_shape() const; float get_emission_sphere_radius() const; Vector3 get_emission_box_extents() const; - PoolVector<Vector3> get_emission_points() const; - PoolVector<Vector3> get_emission_normals() const; - PoolVector<Color> get_emission_colors() const; + Vector<Vector3> get_emission_points() const; + Vector<Vector3> get_emission_normals() const; + Vector<Color> get_emission_colors() const; int get_emission_point_count() const; void set_gravity(const Vector3 &p_gravity); diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index 99bc78f5d2..c3f039ae85 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -32,116 +32,183 @@ #include "core/os/os.h" +#include "core/method_bind_ext.gen.inc" #include "mesh_instance.h" -#include "voxel_light_baker.h" +#include "voxelizer.h" + +void GIProbeData::_set_data(const Dictionary &p_data) { + ERR_FAIL_COND(!p_data.has("bounds")); + ERR_FAIL_COND(!p_data.has("octree_size")); + ERR_FAIL_COND(!p_data.has("octree_cells")); + ERR_FAIL_COND(!p_data.has("octree_data")); + ERR_FAIL_COND(!p_data.has("octree_df") && !p_data.has("octree_df_png")); + ERR_FAIL_COND(!p_data.has("level_counts")); + ERR_FAIL_COND(!p_data.has("to_cell_xform")); + + AABB bounds = p_data["bounds"]; + Vector3 octree_size = p_data["octree_size"]; + Vector<uint8_t> octree_cells = p_data["octree_cells"]; + Vector<uint8_t> octree_data = p_data["octree_data"]; + + Vector<uint8_t> octree_df; + if (p_data.has("octree_df")) { + octree_df = p_data["octree_df"]; + } else if (p_data.has("octree_df_png")) { + Vector<uint8_t> octree_df_png = p_data["octree_df_png"]; + Ref<Image> img; + img.instance(); + Error err = img->load_png_from_buffer(octree_df_png); + ERR_FAIL_COND(err != OK); + ERR_FAIL_COND(img->get_format() != Image::FORMAT_L8); + octree_df = img->get_data(); + } + Vector<int> octree_levels = p_data["level_counts"]; + Transform to_cell_xform = p_data["to_cell_xform"]; + + allocate(to_cell_xform, bounds, octree_size, octree_cells, octree_data, octree_df, octree_levels); +} + +Dictionary GIProbeData::_get_data() const { + Dictionary d; + d["bounds"] = get_bounds(); + Vector3i otsize = get_octree_size(); + d["octree_size"] = Vector3(otsize); + d["octree_cells"] = get_octree_cells(); + d["octree_data"] = get_data_cells(); + if (otsize != Vector3i()) { + Ref<Image> img; + img.instance(); + img->create(otsize.x * otsize.y, otsize.z, false, Image::FORMAT_L8, get_distance_field()); + Vector<uint8_t> df_png = img->save_png_to_buffer(); + ERR_FAIL_COND_V(df_png.size() == 0, Dictionary()); + d["octree_df_png"] = df_png; + } else { + d["octree_df"] = Vector<uint8_t>(); + } -void GIProbeData::set_bounds(const AABB &p_bounds) { + d["level_counts"] = get_level_counts(); + d["to_cell_xform"] = get_to_cell_xform(); + return d; +} - VS::get_singleton()->gi_probe_set_bounds(probe, p_bounds); +void GIProbeData::allocate(const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) { + VS::get_singleton()->gi_probe_allocate(probe, p_to_cell_xform, p_aabb, p_octree_size, p_octree_cells, p_data_cells, p_distance_field, p_level_counts); + bounds = p_aabb; + to_cell_xform = p_to_cell_xform; + octree_size = p_octree_size; } AABB GIProbeData::get_bounds() const { - - return VS::get_singleton()->gi_probe_get_bounds(probe); + return bounds; } - -void GIProbeData::set_cell_size(float p_size) { - - VS::get_singleton()->gi_probe_set_cell_size(probe, p_size); +Vector3 GIProbeData::get_octree_size() const { + return octree_size; } - -float GIProbeData::get_cell_size() const { - - return VS::get_singleton()->gi_probe_get_cell_size(probe); +Vector<uint8_t> GIProbeData::get_octree_cells() const { + return VS::get_singleton()->gi_probe_get_octree_cells(probe); } - -void GIProbeData::set_to_cell_xform(const Transform &p_xform) { - - VS::get_singleton()->gi_probe_set_to_cell_xform(probe, p_xform); +Vector<uint8_t> GIProbeData::get_data_cells() const { + return VS::get_singleton()->gi_probe_get_data_cells(probe); +} +Vector<uint8_t> GIProbeData::get_distance_field() const { + return VS::get_singleton()->gi_probe_get_distance_field(probe); } +Vector<int> GIProbeData::get_level_counts() const { + return VS::get_singleton()->gi_probe_get_level_counts(probe); +} Transform GIProbeData::get_to_cell_xform() const { - - return VS::get_singleton()->gi_probe_get_to_cell_xform(probe); + return to_cell_xform; } -void GIProbeData::set_dynamic_data(const PoolVector<int> &p_data) { +void GIProbeData::set_dynamic_range(float p_range) { + VS::get_singleton()->gi_probe_set_dynamic_range(probe, p_range); + dynamic_range = p_range; +} - VS::get_singleton()->gi_probe_set_dynamic_data(probe, p_data); +float GIProbeData::get_dynamic_range() const { + return dynamic_range; } -PoolVector<int> GIProbeData::get_dynamic_data() const { - return VS::get_singleton()->gi_probe_get_dynamic_data(probe); +void GIProbeData::set_propagation(float p_propagation) { + VS::get_singleton()->gi_probe_set_propagation(probe, p_propagation); + propagation = p_propagation; } -void GIProbeData::set_dynamic_range(int p_range) { +float GIProbeData::get_propagation() const { + return propagation; +} - VS::get_singleton()->gi_probe_set_dynamic_range(probe, p_range); +void GIProbeData::set_anisotropy_strength(float p_anisotropy_strength) { + VS::get_singleton()->gi_probe_set_anisotropy_strength(probe, p_anisotropy_strength); + anisotropy_strength = p_anisotropy_strength; } -void GIProbeData::set_energy(float p_range) { +float GIProbeData::get_anisotropy_strength() const { + return anisotropy_strength; +} - VS::get_singleton()->gi_probe_set_energy(probe, p_range); +void GIProbeData::set_energy(float p_energy) { + VS::get_singleton()->gi_probe_set_energy(probe, p_energy); + energy = p_energy; } float GIProbeData::get_energy() const { - - return VS::get_singleton()->gi_probe_get_energy(probe); + return energy; } -void GIProbeData::set_bias(float p_range) { - - VS::get_singleton()->gi_probe_set_bias(probe, p_range); +void GIProbeData::set_ao(float p_ao) { + VS::get_singleton()->gi_probe_set_ao(probe, p_ao); + ao = p_ao; } -float GIProbeData::get_bias() const { - - return VS::get_singleton()->gi_probe_get_bias(probe); +float GIProbeData::get_ao() const { + return ao; } -void GIProbeData::set_normal_bias(float p_range) { - - VS::get_singleton()->gi_probe_set_normal_bias(probe, p_range); +void GIProbeData::set_ao_size(float p_ao_size) { + VS::get_singleton()->gi_probe_set_ao_size(probe, p_ao_size); + ao_size = p_ao_size; } -float GIProbeData::get_normal_bias() const { - - return VS::get_singleton()->gi_probe_get_normal_bias(probe); +float GIProbeData::get_ao_size() const { + return ao_size; } -void GIProbeData::set_propagation(float p_range) { +void GIProbeData::set_bias(float p_bias) { + VS::get_singleton()->gi_probe_set_bias(probe, p_bias); + bias = p_bias; +} - VS::get_singleton()->gi_probe_set_propagation(probe, p_range); +float GIProbeData::get_bias() const { + return bias; } -float GIProbeData::get_propagation() const { +void GIProbeData::set_normal_bias(float p_normal_bias) { + VS::get_singleton()->gi_probe_set_normal_bias(probe, p_normal_bias); + normal_bias = p_normal_bias; +} - return VS::get_singleton()->gi_probe_get_propagation(probe); +float GIProbeData::get_normal_bias() const { + return normal_bias; } void GIProbeData::set_interior(bool p_enable) { - VS::get_singleton()->gi_probe_set_interior(probe, p_enable); + interior = p_enable; } bool GIProbeData::is_interior() const { - - return VS::get_singleton()->gi_probe_is_interior(probe); + return interior; } -bool GIProbeData::is_compressed() const { - - return VS::get_singleton()->gi_probe_is_compressed(probe); +void GIProbeData::set_use_two_bounces(bool p_enable) { + VS::get_singleton()->gi_probe_set_use_two_bounces(probe, p_enable); + use_two_bounces = p_enable; } -void GIProbeData::set_compress(bool p_enable) { - - VS::get_singleton()->gi_probe_set_compress(probe, p_enable); -} - -int GIProbeData::get_dynamic_range() const { - - return VS::get_singleton()->gi_probe_get_dynamic_range(probe); +bool GIProbeData::is_using_two_bounces() const { + return use_two_bounces; } RID GIProbeData::get_rid() const { @@ -149,19 +216,24 @@ RID GIProbeData::get_rid() const { return probe; } +void GIProbeData::_validate_property(PropertyInfo &property) const { + if (property.name == "anisotropy_strength") { + bool anisotropy_enabled = ProjectSettings::get_singleton()->get("rendering/quality/gi_probes/anisotropic"); + if (!anisotropy_enabled) { + property.usage = PROPERTY_USAGE_NOEDITOR; + } + } +} + void GIProbeData::_bind_methods() { + ClassDB::bind_method(D_METHOD("allocate", "to_cell_xform", "aabb", "octree_size", "octree_cells", "data_cells", "distance_field", "level_counts"), &GIProbeData::allocate); - ClassDB::bind_method(D_METHOD("set_bounds", "bounds"), &GIProbeData::set_bounds); ClassDB::bind_method(D_METHOD("get_bounds"), &GIProbeData::get_bounds); - - ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &GIProbeData::set_cell_size); - ClassDB::bind_method(D_METHOD("get_cell_size"), &GIProbeData::get_cell_size); - - ClassDB::bind_method(D_METHOD("set_to_cell_xform", "to_cell_xform"), &GIProbeData::set_to_cell_xform); + ClassDB::bind_method(D_METHOD("get_octree_size"), &GIProbeData::get_octree_size); ClassDB::bind_method(D_METHOD("get_to_cell_xform"), &GIProbeData::get_to_cell_xform); - - ClassDB::bind_method(D_METHOD("set_dynamic_data", "dynamic_data"), &GIProbeData::set_dynamic_data); - ClassDB::bind_method(D_METHOD("get_dynamic_data"), &GIProbeData::get_dynamic_data); + ClassDB::bind_method(D_METHOD("get_octree_cells"), &GIProbeData::get_octree_cells); + ClassDB::bind_method(D_METHOD("get_data_cells"), &GIProbeData::get_data_cells); + ClassDB::bind_method(D_METHOD("get_level_counts"), &GIProbeData::get_level_counts); ClassDB::bind_method(D_METHOD("set_dynamic_range", "dynamic_range"), &GIProbeData::set_dynamic_range); ClassDB::bind_method(D_METHOD("get_dynamic_range"), &GIProbeData::get_dynamic_range); @@ -178,28 +250,50 @@ void GIProbeData::_bind_methods() { ClassDB::bind_method(D_METHOD("set_propagation", "propagation"), &GIProbeData::set_propagation); ClassDB::bind_method(D_METHOD("get_propagation"), &GIProbeData::get_propagation); + ClassDB::bind_method(D_METHOD("set_anisotropy_strength", "strength"), &GIProbeData::set_anisotropy_strength); + ClassDB::bind_method(D_METHOD("get_anisotropy_strength"), &GIProbeData::get_anisotropy_strength); + + ClassDB::bind_method(D_METHOD("set_ao", "ao"), &GIProbeData::set_ao); + ClassDB::bind_method(D_METHOD("get_ao"), &GIProbeData::get_ao); + + ClassDB::bind_method(D_METHOD("set_ao_size", "strength"), &GIProbeData::set_ao_size); + ClassDB::bind_method(D_METHOD("get_ao_size"), &GIProbeData::get_ao_size); + ClassDB::bind_method(D_METHOD("set_interior", "interior"), &GIProbeData::set_interior); ClassDB::bind_method(D_METHOD("is_interior"), &GIProbeData::is_interior); - ClassDB::bind_method(D_METHOD("set_compress", "compress"), &GIProbeData::set_compress); - ClassDB::bind_method(D_METHOD("is_compressed"), &GIProbeData::is_compressed); + ClassDB::bind_method(D_METHOD("set_use_two_bounces", "enable"), &GIProbeData::set_use_two_bounces); + ClassDB::bind_method(D_METHOD("is_using_two_bounces"), &GIProbeData::is_using_two_bounces); + + ClassDB::bind_method(D_METHOD("_set_data", "data"), &GIProbeData::_set_data); + ClassDB::bind_method(D_METHOD("_get_data"), &GIProbeData::_get_data); - ADD_PROPERTY(PropertyInfo(Variant::AABB, "bounds", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_bounds", "get_bounds"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_size", "get_cell_size"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "to_cell_xform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_to_cell_xform", "get_to_cell_xform"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); - ADD_PROPERTY(PropertyInfo(Variant::POOL_INT_ARRAY, "dynamic_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_dynamic_data", "get_dynamic_data"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "dynamic_range", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_dynamic_range", "get_dynamic_range"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_energy", "get_energy"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "bias", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_bias", "get_bias"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "normal_bias", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_normal_bias", "get_normal_bias"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "propagation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_propagation", "get_propagation"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_interior", "is_interior"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "compress", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_compress", "is_compressed"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "dynamic_range", PROPERTY_HINT_RANGE, "0,8,0.01"), "set_dynamic_range", "get_dynamic_range"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_energy", "get_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0,8,0.01"), "set_bias", "get_bias"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "normal_bias", PROPERTY_HINT_RANGE, "0,8,0.01"), "set_normal_bias", "get_normal_bias"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "anisotropy_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_anisotropy_strength", "get_anisotropy_strength"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ao", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ao", "get_ao"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ao_size", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ao_size", "get_ao_size"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_two_bounces"), "set_use_two_bounces", "is_using_two_bounces"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior"); } GIProbeData::GIProbeData() { + ao = 0.0; + ao_size = 0.5; + dynamic_range = 4; + energy = 1.0; + bias = 1.5; + normal_bias = 0.0; + propagation = 0.7; + anisotropy_strength = 0.5; + interior = false; + probe = VS::get_singleton()->gi_probe_create(); } @@ -251,89 +345,6 @@ Vector3 GIProbe::get_extents() const { return extents; } -void GIProbe::set_dynamic_range(int p_dynamic_range) { - - dynamic_range = p_dynamic_range; -} -int GIProbe::get_dynamic_range() const { - - return dynamic_range; -} - -void GIProbe::set_energy(float p_energy) { - - energy = p_energy; - if (probe_data.is_valid()) { - probe_data->set_energy(energy); - } -} -float GIProbe::get_energy() const { - - return energy; -} - -void GIProbe::set_bias(float p_bias) { - - bias = p_bias; - if (probe_data.is_valid()) { - probe_data->set_bias(bias); - } -} -float GIProbe::get_bias() const { - - return bias; -} - -void GIProbe::set_normal_bias(float p_normal_bias) { - - normal_bias = p_normal_bias; - if (probe_data.is_valid()) { - probe_data->set_normal_bias(normal_bias); - } -} -float GIProbe::get_normal_bias() const { - - return normal_bias; -} - -void GIProbe::set_propagation(float p_propagation) { - - propagation = p_propagation; - if (probe_data.is_valid()) { - probe_data->set_propagation(propagation); - } -} -float GIProbe::get_propagation() const { - - return propagation; -} - -void GIProbe::set_interior(bool p_enable) { - - interior = p_enable; - if (probe_data.is_valid()) { - probe_data->set_interior(p_enable); - } -} - -bool GIProbe::is_interior() const { - - return interior; -} - -void GIProbe::set_compress(bool p_enable) { - - compress = p_enable; - if (probe_data.is_valid()) { - probe_data->set_compress(p_enable); - } -} - -bool GIProbe::is_compressed() const { - - return compress; -} - void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) { MeshInstance *mi = Object::cast_to<MeshInstance>(p_at_node); @@ -395,11 +406,36 @@ GIProbe::BakeBeginFunc GIProbe::bake_begin_function = NULL; GIProbe::BakeStepFunc GIProbe::bake_step_function = NULL; GIProbe::BakeEndFunc GIProbe::bake_end_function = NULL; +Vector3i GIProbe::get_estimated_cell_size() const { + static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 }; + int cell_subdiv = subdiv_value[subdiv]; + int axis_cell_size[3]; + AABB bounds = AABB(-extents, extents * 2.0); + int longest_axis = bounds.get_longest_axis_index(); + axis_cell_size[longest_axis] = 1 << cell_subdiv; + + for (int i = 0; i < 3; i++) { + + if (i == longest_axis) + continue; + + axis_cell_size[i] = axis_cell_size[longest_axis]; + float axis_size = bounds.size[longest_axis]; + + //shrink until fit subdiv + while (axis_size / 2.0 >= bounds.size[i]) { + axis_size /= 2.0; + axis_cell_size[i] >>= 1; + } + } + + return Vector3i(axis_cell_size[0], axis_cell_size[1], axis_cell_size[2]); +} void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { - static const int subdiv_value[SUBDIV_MAX] = { 7, 8, 9, 10 }; + static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 }; - VoxelLightBaker baker; + Voxelizer baker; baker.begin_bake(subdiv_value[subdiv], AABB(-extents, extents * 2.0)); @@ -431,8 +467,6 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { //create the data for visual server - PoolVector<int> data = baker.create_gi_probe_data(); - if (p_create_visual_debug) { MultiMeshInstance *mmi = memnew(MultiMeshInstance); mmi->set_multimesh(baker.create_debug_multimesh()); @@ -454,24 +488,25 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { if (probe_data.is_null()) probe_data.instance(); - probe_data->set_bounds(AABB(-extents, extents * 2.0)); - probe_data->set_cell_size(baker.get_cell_size()); - probe_data->set_dynamic_data(data); - probe_data->set_dynamic_range(dynamic_range); - probe_data->set_energy(energy); - probe_data->set_bias(bias); - probe_data->set_normal_bias(normal_bias); - probe_data->set_propagation(propagation); - probe_data->set_interior(interior); - probe_data->set_compress(compress); - probe_data->set_to_cell_xform(baker.get_to_cell_space_xform()); + if (bake_step_function) { + bake_step_function(pmc++, RTR("Generating Distance Field")); + } + + Vector<uint8_t> df = baker.get_sdf_3d_image(); + + probe_data->allocate(baker.get_to_cell_space_xform(), AABB(-extents, extents * 2.0), baker.get_giprobe_octree_size(), baker.get_giprobe_octree_cells(), baker.get_giprobe_data_cells(), df, baker.get_giprobe_level_cell_count()); set_probe_data(probe_data); +#ifdef TOOLS_ENABLED + probe_data->set_edited(true); //so it gets saved +#endif } if (bake_end_function) { bake_end_function(); } + + _change_notify(); //bake property may have changed } void GIProbe::_debug_bake() { @@ -484,9 +519,9 @@ AABB GIProbe::get_aabb() const { return AABB(-extents, extents * 2); } -PoolVector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const { +Vector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const { - return PoolVector<Face3>(); + return Vector<Face3>(); } String GIProbe::get_configuration_warning() const { @@ -508,40 +543,12 @@ void GIProbe::_bind_methods() { ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GIProbe::set_extents); ClassDB::bind_method(D_METHOD("get_extents"), &GIProbe::get_extents); - ClassDB::bind_method(D_METHOD("set_dynamic_range", "max"), &GIProbe::set_dynamic_range); - ClassDB::bind_method(D_METHOD("get_dynamic_range"), &GIProbe::get_dynamic_range); - - ClassDB::bind_method(D_METHOD("set_energy", "max"), &GIProbe::set_energy); - ClassDB::bind_method(D_METHOD("get_energy"), &GIProbe::get_energy); - - ClassDB::bind_method(D_METHOD("set_bias", "max"), &GIProbe::set_bias); - ClassDB::bind_method(D_METHOD("get_bias"), &GIProbe::get_bias); - - ClassDB::bind_method(D_METHOD("set_normal_bias", "max"), &GIProbe::set_normal_bias); - ClassDB::bind_method(D_METHOD("get_normal_bias"), &GIProbe::get_normal_bias); - - ClassDB::bind_method(D_METHOD("set_propagation", "max"), &GIProbe::set_propagation); - ClassDB::bind_method(D_METHOD("get_propagation"), &GIProbe::get_propagation); - - ClassDB::bind_method(D_METHOD("set_interior", "enable"), &GIProbe::set_interior); - ClassDB::bind_method(D_METHOD("is_interior"), &GIProbe::is_interior); - - ClassDB::bind_method(D_METHOD("set_compress", "enable"), &GIProbe::set_compress); - ClassDB::bind_method(D_METHOD("is_compressed"), &GIProbe::is_compressed); - ClassDB::bind_method(D_METHOD("bake", "from_node", "create_visual_debug"), &GIProbe::bake, DEFVAL(Variant()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("debug_bake"), &GIProbe::_debug_bake); ClassDB::set_method_flags(get_class_static(), _scs_create("debug_bake"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdiv", PROPERTY_HINT_ENUM, "64,128,256,512"), "set_subdiv", "get_subdiv"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents"); - ADD_PROPERTY(PropertyInfo(Variant::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,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"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "compress"), "set_compress", "is_compressed"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "GIProbeData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_probe_data", "get_probe_data"); BIND_ENUM_CONSTANT(SUBDIV_64); @@ -554,14 +561,7 @@ void GIProbe::_bind_methods() { GIProbe::GIProbe() { subdiv = SUBDIV_128; - dynamic_range = 4; - energy = 1.0; - bias = 1.5; - normal_bias = 0.0; - propagation = 0.7; extents = Vector3(10, 10, 10); - interior = false; - compress = false; gi_probe = VS::get_singleton()->gi_probe_create(); set_disable_scale(true); diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h index 7c58f862e4..354eaad7c0 100644 --- a/scene/3d/gi_probe.h +++ b/scene/3d/gi_probe.h @@ -40,42 +40,67 @@ class GIProbeData : public Resource { RID probe; + void _set_data(const Dictionary &p_data); + Dictionary _get_data() const; + + Transform to_cell_xform; + AABB bounds; + Vector3 octree_size; + + float dynamic_range; + float energy; + float bias; + float normal_bias; + float propagation; + float anisotropy_strength; + float ao; + float ao_size; + bool interior; + bool use_two_bounces; + protected: static void _bind_methods(); + void _validate_property(PropertyInfo &property) const; public: - void set_bounds(const AABB &p_bounds); + void allocate(const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts); AABB get_bounds() const; + Vector3 get_octree_size() const; + Vector<uint8_t> get_octree_cells() const; + Vector<uint8_t> get_data_cells() const; + Vector<uint8_t> get_distance_field() const; + Vector<int> get_level_counts() const; + Transform get_to_cell_xform() const; - void set_cell_size(float p_size); - float get_cell_size() const; + void set_dynamic_range(float p_range); + float get_dynamic_range() const; - void set_to_cell_xform(const Transform &p_xform); - Transform get_to_cell_xform() const; + void set_propagation(float p_propagation); + float get_propagation() const; - void set_dynamic_data(const PoolVector<int> &p_data); - PoolVector<int> get_dynamic_data() const; + void set_anisotropy_strength(float p_anisotropy_strength); + float get_anisotropy_strength() const; - void set_dynamic_range(int p_range); - int get_dynamic_range() const; + void set_ao(float p_ao); + float get_ao() const; - void set_propagation(float p_range); - float get_propagation() const; + void set_ao_size(float p_ao_size); + float get_ao_size() const; - void set_energy(float p_range); + void set_energy(float p_energy); float get_energy() const; - void set_bias(float p_range); + void set_bias(float p_bias); float get_bias() const; - void set_normal_bias(float p_range); + void set_normal_bias(float p_normal_bias); float get_normal_bias() const; void set_interior(bool p_enable); bool is_interior() const; - void set_compress(bool p_enable); - bool is_compressed() const; + void set_use_two_bounces(bool p_enable); + bool is_using_two_bounces() const; virtual RID get_rid() const; @@ -107,13 +132,6 @@ private: Subdiv subdiv; Vector3 extents; - int dynamic_range; - float energy; - float bias; - float normal_bias; - float propagation; - bool interior; - bool compress; struct PlotMesh { Ref<Material> override_material; @@ -141,32 +159,12 @@ public: void set_extents(const Vector3 &p_extents); Vector3 get_extents() const; - - void set_dynamic_range(int p_dynamic_range); - int get_dynamic_range() const; - - void set_energy(float p_energy); - float get_energy() const; - - void set_bias(float p_bias); - float get_bias() const; - - void set_normal_bias(float p_normal_bias); - float get_normal_bias() const; - - void set_propagation(float p_propagation); - float get_propagation() const; - - void set_interior(bool p_enable); - bool is_interior() const; - - void set_compress(bool p_enable); - bool is_compressed() const; + Vector3i get_estimated_cell_size() const; void bake(Node *p_from_node = NULL, bool p_create_visual_debug = false); virtual AABB get_aabb() const; - virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; + virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const; virtual String get_configuration_warning() const; diff --git a/scene/3d/immediate_geometry.cpp b/scene/3d/immediate_geometry.cpp index 0a1beaf3f4..f5b08b86e1 100644 --- a/scene/3d/immediate_geometry.cpp +++ b/scene/3d/immediate_geometry.cpp @@ -30,7 +30,7 @@ #include "immediate_geometry.h" -void ImmediateGeometry::begin(Mesh::PrimitiveType p_primitive, const Ref<Texture> &p_texture) { +void ImmediateGeometry::begin(Mesh::PrimitiveType p_primitive, const Ref<Texture2D> &p_texture) { VS::get_singleton()->immediate_begin(im, (VS::PrimitiveType)p_primitive, p_texture.is_valid() ? p_texture->get_rid() : RID()); if (p_texture.is_valid()) @@ -90,9 +90,9 @@ AABB ImmediateGeometry::get_aabb() const { return aabb; } -PoolVector<Face3> ImmediateGeometry::get_faces(uint32_t p_usage_flags) const { +Vector<Face3> ImmediateGeometry::get_faces(uint32_t p_usage_flags) const { - return PoolVector<Face3>(); + return Vector<Face3>(); } void ImmediateGeometry::add_sphere(int p_lats, int p_lons, float p_radius, bool p_add_uv) { @@ -144,7 +144,7 @@ void ImmediateGeometry::add_sphere(int p_lats, int p_lons, float p_radius, bool void ImmediateGeometry::_bind_methods() { - ClassDB::bind_method(D_METHOD("begin", "primitive", "texture"), &ImmediateGeometry::begin, DEFVAL(Ref<Texture>())); + ClassDB::bind_method(D_METHOD("begin", "primitive", "texture"), &ImmediateGeometry::begin, DEFVAL(Ref<Texture2D>())); ClassDB::bind_method(D_METHOD("set_normal", "normal"), &ImmediateGeometry::set_normal); ClassDB::bind_method(D_METHOD("set_tangent", "tangent"), &ImmediateGeometry::set_tangent); ClassDB::bind_method(D_METHOD("set_color", "color"), &ImmediateGeometry::set_color); diff --git a/scene/3d/immediate_geometry.h b/scene/3d/immediate_geometry.h index f45ebd6724..77a20e8d4d 100644 --- a/scene/3d/immediate_geometry.h +++ b/scene/3d/immediate_geometry.h @@ -41,7 +41,7 @@ class ImmediateGeometry : public GeometryInstance { RID im; //a list of textures drawn need to be kept, to avoid references // in VisualServer from becoming invalid if the texture is no longer used - List<Ref<Texture> > cached_textures; + List<Ref<Texture2D> > cached_textures; bool empty; AABB aabb; @@ -49,7 +49,7 @@ protected: static void _bind_methods(); public: - void begin(Mesh::PrimitiveType p_primitive, const Ref<Texture> &p_texture = Ref<Texture>()); + void begin(Mesh::PrimitiveType p_primitive, const Ref<Texture2D> &p_texture = Ref<Texture2D>()); void set_normal(const Vector3 &p_normal); void set_tangent(const Plane &p_tangent); void set_color(const Color &p_color); @@ -64,7 +64,7 @@ public: void add_sphere(int p_lats, int p_lons, float p_radius, bool p_add_uv = true); virtual AABB get_aabb() const; - virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; + virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const; ImmediateGeometry(); ~ImmediateGeometry(); diff --git a/scene/3d/interpolated_camera.cpp b/scene/3d/interpolated_camera.cpp index baf5ac4be6..592d592a38 100644 --- a/scene/3d/interpolated_camera.cpp +++ b/scene/3d/interpolated_camera.cpp @@ -144,7 +144,7 @@ void InterpolatedCamera::_bind_methods() { ClassDB::bind_method(D_METHOD("is_interpolation_enabled"), &InterpolatedCamera::is_interpolation_enabled); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target"), "set_target_path", "get_target_path"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed"), "set_speed", "get_speed"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed"), "set_speed", "get_speed"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_interpolation_enabled", "is_interpolation_enabled"); } diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 593d0b95b7..7c922ce1cd 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -152,9 +152,9 @@ AABB Light::get_aabb() const { return AABB(); } -PoolVector<Face3> Light::get_faces(uint32_t p_usage_flags) const { +Vector<Face3> Light::get_faces(uint32_t p_usage_flags) const { - return PoolVector<Face3>(); + return Vector<Face3>(); } void Light::set_bake_mode(BakeMode p_mode) { @@ -253,17 +253,17 @@ 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,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_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_ENERGY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "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_PROPERTYI(PropertyInfo(Variant::FLOAT, "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"); ADD_PROPERTY(PropertyInfo(Variant::INT, "light_cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask"); ADD_GROUP("Shadow", "shadow_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_enabled"), "set_shadow", "has_shadow"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_shadow_color", "get_shadow_color"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "shadow_bias", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_param", "get_param", PARAM_SHADOW_BIAS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "shadow_contact", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_CONTACT_SHADOW_SIZE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_bias", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_param", "get_param", PARAM_SHADOW_BIAS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_contact", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_CONTACT_SHADOW_SIZE); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_reverse_cull_face"), "set_shadow_reverse_cull_face", "get_shadow_reverse_cull_face"); ADD_GROUP("Editor", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only"); @@ -281,6 +281,7 @@ void Light::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_SHADOW_SPLIT_1_OFFSET); BIND_ENUM_CONSTANT(PARAM_SHADOW_SPLIT_2_OFFSET); BIND_ENUM_CONSTANT(PARAM_SHADOW_SPLIT_3_OFFSET); + BIND_ENUM_CONSTANT(PARAM_SHADOW_FADE_START); BIND_ENUM_CONSTANT(PARAM_SHADOW_NORMAL_BIAS); BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS); BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS_SPLIT_SCALE); @@ -325,8 +326,10 @@ Light::Light(VisualServer::LightType p_type) { set_param(PARAM_SHADOW_SPLIT_1_OFFSET, 0.1); set_param(PARAM_SHADOW_SPLIT_2_OFFSET, 0.2); set_param(PARAM_SHADOW_SPLIT_3_OFFSET, 0.5); + set_param(PARAM_SHADOW_FADE_START, 0.8); set_param(PARAM_SHADOW_NORMAL_BIAS, 0.0); set_param(PARAM_SHADOW_BIAS, 0.15); + set_param(PARAM_SHADOW_FADE_START, 1); set_disable_scale(true); } @@ -390,14 +393,15 @@ void DirectionalLight::_bind_methods() { ADD_GROUP("Directional Shadow", "directional_shadow_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_mode", PROPERTY_HINT_ENUM, "Orthogonal,PSSM 2 Splits,PSSM 4 Splits"), "set_shadow_mode", "get_shadow_mode"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_split_1", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_1_OFFSET); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_split_2", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_2_OFFSET); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_split_3", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_3_OFFSET); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_split_1", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_1_OFFSET); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_split_2", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_2_OFFSET); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_split_3", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_3_OFFSET); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_fade_start", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_FADE_START); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "directional_shadow_blend_splits"), "set_blend_splits", "is_blend_splits_enabled"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_normal_bias", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_bias_split_scale", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_BIAS_SPLIT_SCALE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_normal_bias", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_bias_split_scale", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_BIAS_SPLIT_SCALE); ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_depth_range", PROPERTY_HINT_ENUM, "Stable,Optimized"), "set_shadow_depth_range", "get_shadow_depth_range"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_max_distance", PROPERTY_HINT_EXP_RANGE, "0,8192,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_max_distance", PROPERTY_HINT_EXP_RANGE, "0,8192,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE); BIND_ENUM_CONSTANT(SHADOW_ORTHOGONAL); BIND_ENUM_CONSTANT(SHADOW_PARALLEL_2_SPLITS); @@ -413,6 +417,7 @@ DirectionalLight::DirectionalLight() : set_param(PARAM_SHADOW_NORMAL_BIAS, 0.8); set_param(PARAM_SHADOW_BIAS, 0.1); set_param(PARAM_SHADOW_MAX_DISTANCE, 100); + set_param(PARAM_SHADOW_FADE_START, 0.8); set_param(PARAM_SHADOW_BIAS_SPLIT_SCALE, 0.25); set_shadow_mode(SHADOW_PARALLEL_4_SPLITS); set_shadow_depth_range(SHADOW_DEPTH_RANGE_STABLE); @@ -431,42 +436,24 @@ OmniLight::ShadowMode OmniLight::get_shadow_mode() const { return shadow_mode; } -void OmniLight::set_shadow_detail(ShadowDetail p_detail) { - - shadow_detail = p_detail; - VS::get_singleton()->light_omni_set_shadow_detail(light, VS::LightOmniShadowDetail(p_detail)); -} -OmniLight::ShadowDetail OmniLight::get_shadow_detail() const { - - return shadow_detail; -} - void OmniLight::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shadow_mode", "mode"), &OmniLight::set_shadow_mode); ClassDB::bind_method(D_METHOD("get_shadow_mode"), &OmniLight::get_shadow_mode); - ClassDB::bind_method(D_METHOD("set_shadow_detail", "detail"), &OmniLight::set_shadow_detail); - ClassDB::bind_method(D_METHOD("get_shadow_detail"), &OmniLight::get_shadow_detail); - ADD_GROUP("Omni", "omni_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "omni_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "omni_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION); ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_mode", PROPERTY_HINT_ENUM, "Dual Paraboloid,Cube"), "set_shadow_mode", "get_shadow_mode"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_detail", PROPERTY_HINT_ENUM, "Vertical,Horizontal"), "set_shadow_detail", "get_shadow_detail"); BIND_ENUM_CONSTANT(SHADOW_DUAL_PARABOLOID); BIND_ENUM_CONSTANT(SHADOW_CUBE); - - BIND_ENUM_CONSTANT(SHADOW_DETAIL_VERTICAL); - BIND_ENUM_CONSTANT(SHADOW_DETAIL_HORIZONTAL); } OmniLight::OmniLight() : Light(VisualServer::LIGHT_OMNI) { set_shadow_mode(SHADOW_CUBE); - set_shadow_detail(SHADOW_DETAIL_HORIZONTAL); } String SpotLight::get_configuration_warning() const { @@ -486,8 +473,8 @@ String SpotLight::get_configuration_warning() const { void SpotLight::_bind_methods() { ADD_GROUP("Spot", "spot_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_param", "get_param", PARAM_SPOT_ANGLE); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_SPOT_ATTENUATION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_angle", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_param", "get_param", PARAM_SPOT_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_angle_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_SPOT_ATTENUATION); } diff --git a/scene/3d/light.h b/scene/3d/light.h index 272ee8d7a9..16e0c47083 100644 --- a/scene/3d/light.h +++ b/scene/3d/light.h @@ -54,6 +54,7 @@ public: PARAM_SHADOW_SPLIT_1_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET, PARAM_SHADOW_SPLIT_2_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET, PARAM_SHADOW_SPLIT_3_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET, + PARAM_SHADOW_FADE_START = VS::LIGHT_PARAM_SHADOW_FADE_START, PARAM_SHADOW_NORMAL_BIAS = VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS, PARAM_SHADOW_BIAS = VS::LIGHT_PARAM_SHADOW_BIAS, PARAM_SHADOW_BIAS_SPLIT_SCALE = VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE, @@ -123,7 +124,7 @@ public: BakeMode get_bake_mode() const; virtual AABB get_aabb() const; - virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; + virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const; Light(); ~Light(); @@ -183,15 +184,8 @@ public: SHADOW_CUBE, }; - // omni light - enum ShadowDetail { - SHADOW_DETAIL_VERTICAL, - SHADOW_DETAIL_HORIZONTAL - }; - private: ShadowMode shadow_mode; - ShadowDetail shadow_detail; protected: static void _bind_methods(); @@ -200,14 +194,10 @@ public: void set_shadow_mode(ShadowMode p_mode); ShadowMode get_shadow_mode() const; - void set_shadow_detail(ShadowDetail p_detail); - ShadowDetail get_shadow_detail() const; - OmniLight(); }; VARIANT_ENUM_CAST(OmniLight::ShadowMode) -VARIANT_ENUM_CAST(OmniLight::ShadowDetail) class SpotLight : public Light { diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp index e14fa9e9af..4ca139ebbc 100644 --- a/scene/3d/mesh_instance.cpp +++ b/scene/3d/mesh_instance.cpp @@ -34,7 +34,6 @@ #include "core/core_string_names.h" #include "physics_body.h" #include "scene/resources/material.h" -#include "scene/scene_string_names.h" #include "skeleton.h" bool MeshInstance::_set(const StringName &p_name, const Variant &p_value) { @@ -96,12 +95,12 @@ 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.00001")); + p_list->push_back(PropertyInfo(Variant::FLOAT, E->get(), PROPERTY_HINT_RANGE, "0,1,0.00001")); } if (mesh.is_valid()) { for (int i = 0; i < mesh->get_surface_count(); i++) { - p_list->push_back(PropertyInfo(Variant::OBJECT, "material/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,SpatialMaterial")); + p_list->push_back(PropertyInfo(Variant::OBJECT, "material/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE)); } } } @@ -112,7 +111,7 @@ void MeshInstance::set_mesh(const Ref<Mesh> &p_mesh) { return; if (mesh.is_valid()) { - mesh->disconnect(CoreStringNames::get_singleton()->changed, this, SceneStringNames::get_singleton()->_mesh_changed); + mesh->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &MeshInstance::_mesh_changed)); materials.clear(); } @@ -129,7 +128,7 @@ void MeshInstance::set_mesh(const Ref<Mesh> &p_mesh) { blend_shape_tracks["blend_shapes/" + String(mesh->get_blend_shape_name(i))] = mt; } - mesh->connect(CoreStringNames::get_singleton()->changed, this, SceneStringNames::get_singleton()->_mesh_changed); + mesh->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &MeshInstance::_mesh_changed)); materials.resize(mesh->get_surface_count()); set_base(mesh->get_rid()); @@ -204,13 +203,13 @@ AABB MeshInstance::get_aabb() const { return AABB(); } -PoolVector<Face3> MeshInstance::get_faces(uint32_t p_usage_flags) const { +Vector<Face3> MeshInstance::get_faces(uint32_t p_usage_flags) const { if (!(p_usage_flags & (FACES_SOLID | FACES_ENCLOSING))) - return PoolVector<Face3>(); + return Vector<Face3>(); if (mesh.is_null()) - return PoolVector<Face3>(); + return Vector<Face3>(); return mesh->get_faces(); } @@ -355,12 +354,12 @@ void MeshInstance::create_debug_tangents() { if (lines.size()) { - Ref<SpatialMaterial> sm; + Ref<StandardMaterial3D> sm; sm.instance(); - sm->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - sm->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - sm->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + sm->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); + sm->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); + sm->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); Ref<ArrayMesh> am; am.instance(); @@ -403,14 +402,15 @@ void MeshInstance::_bind_methods() { ClassDB::set_method_flags("MeshInstance", "create_trimesh_collision", METHOD_FLAGS_DEFAULT); ClassDB::bind_method(D_METHOD("create_convex_collision"), &MeshInstance::create_convex_collision); ClassDB::set_method_flags("MeshInstance", "create_convex_collision", METHOD_FLAGS_DEFAULT); - ClassDB::bind_method(D_METHOD("_mesh_changed"), &MeshInstance::_mesh_changed); ClassDB::bind_method(D_METHOD("create_debug_tangents"), &MeshInstance::create_debug_tangents); ClassDB::set_method_flags("MeshInstance", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); + ADD_GROUP("Skeleton", ""); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path"); + ADD_GROUP("", ""); } MeshInstance::MeshInstance() { diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h index fd5f60a5d7..d49d9ed98f 100644 --- a/scene/3d/mesh_instance.h +++ b/scene/3d/mesh_instance.h @@ -94,7 +94,7 @@ public: void create_debug_tangents(); virtual AABB get_aabb() const; - virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; + virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const; MeshInstance(); ~MeshInstance(); diff --git a/scene/3d/multimesh_instance.cpp b/scene/3d/multimesh_instance.cpp index 245dbdaf58..075eb0a1ec 100644 --- a/scene/3d/multimesh_instance.cpp +++ b/scene/3d/multimesh_instance.cpp @@ -51,9 +51,9 @@ Ref<MultiMesh> MultiMeshInstance::get_multimesh() const { return multimesh; } -PoolVector<Face3> MultiMeshInstance::get_faces(uint32_t p_usage_flags) const { +Vector<Face3> MultiMeshInstance::get_faces(uint32_t p_usage_flags) const { - return PoolVector<Face3>(); + return Vector<Face3>(); } AABB MultiMeshInstance::get_aabb() const { diff --git a/scene/3d/multimesh_instance.h b/scene/3d/multimesh_instance.h index 855bd54910..2b59c3b96c 100644 --- a/scene/3d/multimesh_instance.h +++ b/scene/3d/multimesh_instance.h @@ -44,7 +44,7 @@ protected: // bind helpers public: - virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; + virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const; void set_multimesh(const Ref<MultiMesh> &p_multimesh); Ref<MultiMesh> get_multimesh() const; diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp index 4a82fe0080..8c543bc97f 100644 --- a/scene/3d/navigation.cpp +++ b/scene/3d/navigation.cpp @@ -30,669 +30,33 @@ #include "navigation.h" -#define USE_ENTRY_POINT +#include "servers/navigation_server.h" -void Navigation::_navmesh_link(int p_id) { +Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector3 &p_end, bool p_optimize) const { - ERR_FAIL_COND(!navmesh_map.has(p_id)); - NavMesh &nm = navmesh_map[p_id]; - ERR_FAIL_COND(nm.linked); - ERR_FAIL_COND(nm.navmesh.is_null()); - - PoolVector<Vector3> vertices = nm.navmesh->get_vertices(); - int len = vertices.size(); - if (len == 0) - return; - - PoolVector<Vector3>::Read r = vertices.read(); - - for (int i = 0; i < nm.navmesh->get_polygon_count(); i++) { - - //build - - List<Polygon>::Element *P = nm.polygons.push_back(Polygon()); - Polygon &p = P->get(); - p.owner = &nm; - - Vector<int> poly = nm.navmesh->get_polygon(i); - int plen = poly.size(); - const int *indices = poly.ptr(); - bool valid = true; - p.edges.resize(plen); - - Vector3 center; - float sum = 0; - - for (int j = 0; j < plen; j++) { - - int idx = indices[j]; - if (idx < 0 || idx >= len) { - valid = false; - break; - } - - Polygon::Edge e; - Vector3 ep = nm.xform.xform(r[idx]); - center += ep; - e.point = _get_point(ep); - p.edges.write[j] = e; - - if (j >= 2) { - Vector3 epa = nm.xform.xform(r[indices[j - 2]]); - Vector3 epb = nm.xform.xform(r[indices[j - 1]]); - - sum += up.dot((epb - epa).cross(ep - epa)); - } - } - - p.clockwise = sum > 0; - - if (!valid) { - nm.polygons.pop_back(); - ERR_CONTINUE(!valid); - } - - p.center = center; - if (plen != 0) { - p.center /= plen; - } - - //connect - - for (int j = 0; j < plen; j++) { - - int next = (j + 1) % plen; - EdgeKey ek(p.edges[j].point, p.edges[next].point); - - Map<EdgeKey, Connection>::Element *C = connections.find(ek); - if (!C) { - - Connection c; - c.A = &p; - c.A_edge = j; - c.B = NULL; - c.B_edge = -1; - connections[ek] = c; - } else { - - if (C->get().B != NULL) { - ConnectionPending pending; - pending.polygon = &p; - pending.edge = j; - p.edges.write[j].P = C->get().pending.push_back(pending); - continue; - } - - C->get().B = &p; - C->get().B_edge = j; - C->get().A->edges.write[C->get().A_edge].C = &p; - C->get().A->edges.write[C->get().A_edge].C_edge = j; - p.edges.write[j].C = C->get().A; - p.edges.write[j].C_edge = C->get().A_edge; - //connection successful. - } - } - } - - nm.linked = true; + return NavigationServer::get_singleton()->map_get_path(map, p_start, p_end, p_optimize); } -void Navigation::_navmesh_unlink(int p_id) { - - ERR_FAIL_COND(!navmesh_map.has(p_id)); - NavMesh &nm = navmesh_map[p_id]; - ERR_FAIL_COND(!nm.linked); - - for (List<Polygon>::Element *E = nm.polygons.front(); E; E = E->next()) { - - Polygon &p = E->get(); - - int ec = p.edges.size(); - Polygon::Edge *edges = p.edges.ptrw(); - - for (int i = 0; i < ec; i++) { - int next = (i + 1) % ec; - - EdgeKey ek(edges[i].point, edges[next].point); - Map<EdgeKey, Connection>::Element *C = connections.find(ek); - - ERR_CONTINUE(!C); - - if (edges[i].P) { - C->get().pending.erase(edges[i].P); - edges[i].P = NULL; - } else if (C->get().B) { - //disconnect - - C->get().B->edges.write[C->get().B_edge].C = NULL; - C->get().B->edges.write[C->get().B_edge].C_edge = -1; - C->get().A->edges.write[C->get().A_edge].C = NULL; - C->get().A->edges.write[C->get().A_edge].C_edge = -1; - - if (C->get().A == &E->get()) { - - C->get().A = C->get().B; - C->get().A_edge = C->get().B_edge; - } - C->get().B = NULL; - C->get().B_edge = -1; - - if (C->get().pending.size()) { - //reconnect if something is pending - ConnectionPending cp = C->get().pending.front()->get(); - C->get().pending.pop_front(); - - C->get().B = cp.polygon; - C->get().B_edge = cp.edge; - C->get().A->edges.write[C->get().A_edge].C = cp.polygon; - C->get().A->edges.write[C->get().A_edge].C_edge = cp.edge; - cp.polygon->edges.write[cp.edge].C = C->get().A; - cp.polygon->edges.write[cp.edge].C_edge = C->get().A_edge; - cp.polygon->edges.write[cp.edge].P = NULL; - } - - } else { - connections.erase(C); - //erase - } - } - } - - nm.polygons.clear(); - - nm.linked = false; +Vector3 Navigation::get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision) const { + return NavigationServer::get_singleton()->map_get_closest_point_to_segment(map, p_from, p_to, p_use_collision); } -int Navigation::navmesh_add(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner) { - - int id = last_id++; - NavMesh nm; - nm.linked = false; - nm.navmesh = p_mesh; - nm.xform = p_xform; - nm.owner = p_owner; - navmesh_map[id] = nm; - - _navmesh_link(id); - - return id; +Vector3 Navigation::get_closest_point(const Vector3 &p_point) const { + return NavigationServer::get_singleton()->map_get_closest_point(map, p_point); } -void Navigation::navmesh_set_transform(int p_id, const Transform &p_xform) { - - ERR_FAIL_COND(!navmesh_map.has(p_id)); - NavMesh &nm = navmesh_map[p_id]; - if (nm.xform == p_xform) - return; //bleh - _navmesh_unlink(p_id); - nm.xform = p_xform; - _navmesh_link(p_id); +Vector3 Navigation::get_closest_point_normal(const Vector3 &p_point) const { + return NavigationServer::get_singleton()->map_get_closest_point_normal(map, p_point); } -void Navigation::navmesh_remove(int p_id) { - ERR_FAIL_COND_MSG(!navmesh_map.has(p_id), "Trying to remove nonexisting navmesh with id: " + itos(p_id)); - _navmesh_unlink(p_id); - navmesh_map.erase(p_id); -} - -void Navigation::_clip_path(Vector<Vector3> &path, Polygon *from_poly, const Vector3 &p_to_point, Polygon *p_to_poly) { - - Vector3 from = path[path.size() - 1]; - - if (from.distance_to(p_to_point) < CMP_EPSILON) - return; - Plane cut_plane; - cut_plane.normal = (from - p_to_point).cross(up); - if (cut_plane.normal == Vector3()) - return; - cut_plane.normal.normalize(); - cut_plane.d = cut_plane.normal.dot(from); - - while (from_poly != p_to_poly) { - - int pe = from_poly->prev_edge; - Vector3 a = _get_vertex(from_poly->edges[pe].point); - Vector3 b = _get_vertex(from_poly->edges[(pe + 1) % from_poly->edges.size()].point); - - from_poly = from_poly->edges[pe].C; - ERR_FAIL_COND(!from_poly); - - if (a.distance_to(b) > CMP_EPSILON) { - - Vector3 inters; - if (cut_plane.intersects_segment(a, b, &inters)) { - if (inters.distance_to(p_to_point) > CMP_EPSILON && inters.distance_to(path[path.size() - 1]) > CMP_EPSILON) { - path.push_back(inters); - } - } - } - } -} - -Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector3 &p_end, bool p_optimize) { - - Polygon *begin_poly = NULL; - Polygon *end_poly = NULL; - Vector3 begin_point; - Vector3 end_point; - float begin_d = 1e20; - float end_d = 1e20; - - for (Map<int, NavMesh>::Element *E = navmesh_map.front(); E; E = E->next()) { - - if (!E->get().linked) - continue; - for (List<Polygon>::Element *F = E->get().polygons.front(); F; F = F->next()) { - - Polygon &p = F->get(); - for (int i = 2; i < p.edges.size(); i++) { - - Face3 f(_get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point)); - Vector3 spoint = f.get_closest_point_to(p_start); - float dpoint = spoint.distance_to(p_start); - if (dpoint < begin_d) { - begin_d = dpoint; - begin_poly = &p; - begin_point = spoint; - } - - spoint = f.get_closest_point_to(p_end); - dpoint = spoint.distance_to(p_end); - if (dpoint < end_d) { - end_d = dpoint; - end_poly = &p; - end_point = spoint; - } - } - - p.prev_edge = -1; - } - } - - if (!begin_poly || !end_poly) { - - return Vector<Vector3>(); //no path - } - - if (begin_poly == end_poly) { - - Vector<Vector3> path; - path.resize(2); - path.write[0] = begin_point; - path.write[1] = end_point; - return path; - } - - bool found_route = false; - - List<Polygon *> open_list; - - for (int i = 0; i < begin_poly->edges.size(); i++) { - - if (begin_poly->edges[i].C) { - - begin_poly->edges[i].C->prev_edge = begin_poly->edges[i].C_edge; -#ifdef USE_ENTRY_POINT - Vector3 edge[2] = { - _get_vertex(begin_poly->edges[i].point), - _get_vertex(begin_poly->edges[(i + 1) % begin_poly->edges.size()].point) - }; - - Vector3 entry = Geometry::get_closest_point_to_segment(begin_poly->entry, edge); - 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); - } - } - - while (!found_route) { - - if (open_list.size() == 0) { - break; - } - //check open list - - List<Polygon *>::Element *least_cost_poly = NULL; - float least_cost = 1e30; - - //this could be faster (cache previous results) - for (List<Polygon *>::Element *E = open_list.front(); E; E = E->next()) { - - Polygon *p = E->get(); - - float cost = p->distance; -#ifdef USE_ENTRY_POINT - cost += p->entry.distance_to(end_point); -#else - cost += p->center.distance_to(end_point); -#endif - if (cost < least_cost) { - least_cost_poly = E; - least_cost = cost; - } - } - - 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]; - - 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? - - if (e.C->distance > distance) { - - 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); - } - } - - open_list.erase(least_cost_poly); - } - - if (found_route) { - - Vector<Vector3> path; - - if (p_optimize) { - //string pulling - - Polygon *apex_poly = end_poly; - Vector3 apex_point = end_point; - Vector3 portal_left = apex_point; - Vector3 portal_right = apex_point; - Polygon *left_poly = end_poly; - Polygon *right_poly = end_poly; - Polygon *p = end_poly; - path.push_back(end_point); - - while (p) { - - Vector3 left; - Vector3 right; - -#define CLOCK_TANGENT(m_a, m_b, m_c) (((m_a) - (m_c)).cross((m_a) - (m_b))) - - if (p == begin_poly) { - left = begin_point; - right = begin_point; - } else { - int prev = p->prev_edge; - int prev_n = (p->prev_edge + 1) % p->edges.size(); - left = _get_vertex(p->edges[prev].point); - right = _get_vertex(p->edges[prev_n].point); - - //if (CLOCK_TANGENT(apex_point,left,(left+right)*0.5).dot(up) < 0){ - if (p->clockwise) { - SWAP(left, right); - } - } - - bool skip = false; - - if (CLOCK_TANGENT(apex_point, portal_left, left).dot(up) >= 0) { - //process - if (portal_left == apex_point || CLOCK_TANGENT(apex_point, left, portal_right).dot(up) > 0) { - left_poly = p; - portal_left = left; - } else { - - _clip_path(path, apex_poly, portal_right, right_poly); - - apex_point = portal_right; - p = right_poly; - left_poly = p; - apex_poly = p; - portal_left = apex_point; - portal_right = apex_point; - path.push_back(apex_point); - skip = true; - } - } - - if (!skip && CLOCK_TANGENT(apex_point, portal_right, right).dot(up) <= 0) { - //process - if (portal_right == apex_point || CLOCK_TANGENT(apex_point, right, portal_left).dot(up) < 0) { - right_poly = p; - portal_right = right; - } else { - - _clip_path(path, apex_poly, portal_left, left_poly); - - apex_point = portal_left; - p = left_poly; - right_poly = p; - apex_poly = p; - portal_right = apex_point; - portal_left = apex_point; - path.push_back(apex_point); - } - } - - if (p != begin_poly) - p = p->edges[p->prev_edge].C; - else - p = NULL; - } - - if (path[path.size() - 1] != begin_point) - path.push_back(begin_point); - - path.invert(); - - } else { - //midpoints - Polygon *p = end_poly; - - 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) - break; - } - - path.push_back(begin_point); - - path.invert(); - } - - return path; - } - - return Vector<Vector3>(); -} - -Vector3 Navigation::get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, const bool &p_use_collision) { - - bool use_collision = p_use_collision; - Vector3 closest_point; - float closest_point_d = 1e20; - - for (Map<int, NavMesh>::Element *E = navmesh_map.front(); E; E = E->next()) { - - if (!E->get().linked) - continue; - for (List<Polygon>::Element *F = E->get().polygons.front(); F; F = F->next()) { - - Polygon &p = F->get(); - for (int i = 2; i < p.edges.size(); i++) { - - Face3 f(_get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point)); - Vector3 inters; - if (f.intersects_segment(p_from, p_to, &inters)) { - - if (!use_collision) { - closest_point = inters; - use_collision = true; - closest_point_d = p_from.distance_to(inters); - } else if (closest_point_d > inters.distance_to(p_from)) { - - closest_point = inters; - closest_point_d = p_from.distance_to(inters); - } - } - } - - if (!use_collision) { - - for (int i = 0; i < p.edges.size(); i++) { - - Vector3 a, b; - - Geometry::get_closest_points_between_segments(p_from, p_to, _get_vertex(p.edges[i].point), _get_vertex(p.edges[(i + 1) % p.edges.size()].point), a, b); - - float d = a.distance_to(b); - if (d < closest_point_d) { - - closest_point_d = d; - closest_point = b; - } - } - } - } - } - - return closest_point; -} - -Vector3 Navigation::get_closest_point(const Vector3 &p_point) { - - Vector3 closest_point; - float closest_point_d = 1e20; - - for (Map<int, NavMesh>::Element *E = navmesh_map.front(); E; E = E->next()) { - - if (!E->get().linked) - continue; - for (List<Polygon>::Element *F = E->get().polygons.front(); F; F = F->next()) { - - Polygon &p = F->get(); - for (int i = 2; i < p.edges.size(); i++) { - - Face3 f(_get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point)); - Vector3 inters = f.get_closest_point_to(p_point); - float d = inters.distance_to(p_point); - if (d < closest_point_d) { - closest_point = inters; - closest_point_d = d; - } - } - } - } - - return closest_point; -} - -Vector3 Navigation::get_closest_point_normal(const Vector3 &p_point) { - - Vector3 closest_point; - Vector3 closest_normal; - float closest_point_d = 1e20; - - for (Map<int, NavMesh>::Element *E = navmesh_map.front(); E; E = E->next()) { - - if (!E->get().linked) - continue; - for (List<Polygon>::Element *F = E->get().polygons.front(); F; F = F->next()) { - - Polygon &p = F->get(); - for (int i = 2; i < p.edges.size(); i++) { - - Face3 f(_get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point)); - Vector3 inters = f.get_closest_point_to(p_point); - float d = inters.distance_to(p_point); - if (d < closest_point_d) { - closest_point = inters; - closest_point_d = d; - closest_normal = f.get_plane().normal; - } - } - } - } - - return closest_normal; -} - -Object *Navigation::get_closest_point_owner(const Vector3 &p_point) { - - Vector3 closest_point; - Object *owner = NULL; - float closest_point_d = 1e20; - - for (Map<int, NavMesh>::Element *E = navmesh_map.front(); E; E = E->next()) { - - if (!E->get().linked) - continue; - for (List<Polygon>::Element *F = E->get().polygons.front(); F; F = F->next()) { - - Polygon &p = F->get(); - for (int i = 2; i < p.edges.size(); i++) { - - Face3 f(_get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point)); - Vector3 inters = f.get_closest_point_to(p_point); - float d = inters.distance_to(p_point); - if (d < closest_point_d) { - closest_point = inters; - closest_point_d = d; - owner = E->get().owner; - } - } - } - } - - return owner; +RID Navigation::get_closest_point_owner(const Vector3 &p_point) const { + return NavigationServer::get_singleton()->map_get_closest_point_owner(map, p_point); } void Navigation::set_up_vector(const Vector3 &p_up) { up = p_up; + NavigationServer::get_singleton()->map_set_up(map, up); } Vector3 Navigation::get_up_vector() const { @@ -700,11 +64,19 @@ Vector3 Navigation::get_up_vector() const { return up; } +void Navigation::set_cell_size(float p_cell_size) { + cell_size = p_cell_size; + NavigationServer::get_singleton()->map_set_cell_size(map, cell_size); +} + +void Navigation::set_edge_connection_margin(float p_edge_connection_margin) { + edge_connection_margin = p_edge_connection_margin; + NavigationServer::get_singleton()->map_set_edge_connection_margin(map, edge_connection_margin); +} + void Navigation::_bind_methods() { - ClassDB::bind_method(D_METHOD("navmesh_add", "mesh", "xform", "owner"), &Navigation::navmesh_add, DEFVAL(Variant())); - ClassDB::bind_method(D_METHOD("navmesh_set_transform", "id", "xform"), &Navigation::navmesh_set_transform); - ClassDB::bind_method(D_METHOD("navmesh_remove", "id"), &Navigation::navmesh_remove); + ClassDB::bind_method(D_METHOD("get_rid"), &Navigation::get_rid); ClassDB::bind_method(D_METHOD("get_simple_path", "start", "end", "optimize"), &Navigation::get_simple_path, DEFVAL(true)); ClassDB::bind_method(D_METHOD("get_closest_point_to_segment", "start", "end", "use_collision"), &Navigation::get_closest_point_to_segment, DEFVAL(false)); @@ -715,13 +87,39 @@ void Navigation::_bind_methods() { ClassDB::bind_method(D_METHOD("set_up_vector", "up"), &Navigation::set_up_vector); ClassDB::bind_method(D_METHOD("get_up_vector"), &Navigation::get_up_vector); + ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &Navigation::set_cell_size); + ClassDB::bind_method(D_METHOD("get_cell_size"), &Navigation::get_cell_size); + + ClassDB::bind_method(D_METHOD("set_edge_connection_margin", "margin"), &Navigation::set_edge_connection_margin); + ClassDB::bind_method(D_METHOD("get_edge_connection_margin"), &Navigation::get_edge_connection_margin); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "up_vector"), "set_up_vector", "get_up_vector"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size"), "set_cell_size", "get_cell_size"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_connection_margin"), "set_edge_connection_margin", "get_edge_connection_margin"); +} + +void Navigation::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_READY: { + NavigationServer::get_singleton()->map_set_active(map, true); + } break; + case NOTIFICATION_EXIT_TREE: { + + NavigationServer::get_singleton()->map_set_active(map, false); + } break; + } } Navigation::Navigation() { - ERR_FAIL_COND(sizeof(Point) != 8); - cell_size = 0.01; //one centimeter - last_id = 1; + map = NavigationServer::get_singleton()->map_create(); + + set_cell_size(0.3); + set_edge_connection_margin(5.0); // Five meters, depends alot on the agents radius + up = Vector3(0, 1, 0); } + +Navigation::~Navigation() { + NavigationServer::get_singleton()->free(map); +} diff --git a/scene/3d/navigation.h b/scene/3d/navigation.h index 31dbc9d4b5..08f306611f 100644 --- a/scene/3d/navigation.h +++ b/scene/3d/navigation.h @@ -31,154 +31,49 @@ #ifndef NAVIGATION_H #define NAVIGATION_H -#include "scene/3d/navigation_mesh.h" +#include "scene/3d/navigation_region.h" #include "scene/3d/spatial.h" class Navigation : public Spatial { GDCLASS(Navigation, Spatial); - union Point { - - struct { - int64_t x : 21; - int64_t y : 22; - int64_t z : 21; - }; - - uint64_t key; - bool operator<(const Point &p_key) const { return key < p_key.key; } - }; - - struct EdgeKey { - - Point a; - Point b; - - bool operator<(const EdgeKey &p_key) const { - return (a.key == p_key.a.key) ? (b.key < p_key.b.key) : (a.key < p_key.a.key); - }; - - EdgeKey(const Point &p_a = Point(), const Point &p_b = Point()) : - a(p_a), - b(p_b) { - if (a.key > b.key) { - SWAP(a, b); - } - } - }; - - struct NavMesh; - struct Polygon; - - struct ConnectionPending { - - Polygon *polygon; - int edge; - }; - - struct Polygon { - - struct Edge { - Point point; - Polygon *C; //connection - int C_edge; - List<ConnectionPending>::Element *P; - Edge() { - C = NULL; - C_edge = -1; - P = NULL; - } - }; - - Vector<Edge> edges; - - Vector3 center; - Vector3 entry; - - float distance; - int prev_edge; - bool clockwise; - - NavMesh *owner; - }; - - struct Connection { - - Polygon *A; - int A_edge; - Polygon *B; - int B_edge; - - List<ConnectionPending> pending; - - Connection() { - A = NULL; - B = NULL; - A_edge = -1; - B_edge = -1; - } - }; - - Map<EdgeKey, Connection> connections; - - struct NavMesh { - - Object *owner; - Transform xform; - bool linked; - Ref<NavigationMesh> navmesh; - List<Polygon> polygons; - }; - - _FORCE_INLINE_ Point _get_point(const Vector3 &p_pos) const { - - int x = int(Math::floor(p_pos.x / cell_size)); - int y = int(Math::floor(p_pos.y / cell_size)); - int z = int(Math::floor(p_pos.z / cell_size)); - - Point p; - p.key = 0; - p.x = x; - p.y = y; - p.z = z; - return p; - } - - _FORCE_INLINE_ Vector3 _get_vertex(const Point &p_point) const { - - return Vector3(p_point.x, p_point.y, p_point.z) * cell_size; - } - - void _navmesh_link(int p_id); - void _navmesh_unlink(int p_id); - - float cell_size; - Map<int, NavMesh> navmesh_map; - int last_id; + RID map; Vector3 up; - void _clip_path(Vector<Vector3> &path, Polygon *from_poly, const Vector3 &p_to_point, Polygon *p_to_poly); + real_t cell_size; + real_t edge_connection_margin; protected: static void _bind_methods(); + void _notification(int p_what); public: + RID get_rid() const { + return map; + } + void set_up_vector(const Vector3 &p_up); Vector3 get_up_vector() const; - //API should be as dynamic as possible - int navmesh_add(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner = NULL); - void navmesh_set_transform(int p_id, const Transform &p_xform); - void navmesh_remove(int p_id); + void set_cell_size(float p_cell_size); + float get_cell_size() const { + return cell_size; + } + + void set_edge_connection_margin(float p_edge_connection_margin); + float get_edge_connection_margin() const { + return edge_connection_margin; + } - Vector<Vector3> get_simple_path(const Vector3 &p_start, const Vector3 &p_end, bool p_optimize = true); - Vector3 get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, const bool &p_use_collision = false); - Vector3 get_closest_point(const Vector3 &p_point); - Vector3 get_closest_point_normal(const Vector3 &p_point); - Object *get_closest_point_owner(const Vector3 &p_point); + Vector<Vector3> get_simple_path(const Vector3 &p_start, const Vector3 &p_end, bool p_optimize = true) const; + Vector3 get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision = false) const; + Vector3 get_closest_point(const Vector3 &p_point) const; + Vector3 get_closest_point_normal(const Vector3 &p_point) const; + RID get_closest_point_owner(const Vector3 &p_point) const; Navigation(); + ~Navigation(); }; #endif // NAVIGATION_H diff --git a/scene/3d/navigation_agent.cpp b/scene/3d/navigation_agent.cpp new file mode 100644 index 0000000000..728fc947e9 --- /dev/null +++ b/scene/3d/navigation_agent.cpp @@ -0,0 +1,361 @@ +/*************************************************************************/ +/* navigation_agent.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "navigation_agent.h" + +#include "core/engine.h" +#include "scene/3d/navigation.h" +#include "servers/navigation_server.h" + +void NavigationAgent::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_target_desired_distance", "desired_distance"), &NavigationAgent::set_target_desired_distance); + ClassDB::bind_method(D_METHOD("get_target_desired_distance"), &NavigationAgent::get_target_desired_distance); + + ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationAgent::set_radius); + ClassDB::bind_method(D_METHOD("get_radius"), &NavigationAgent::get_radius); + + ClassDB::bind_method(D_METHOD("set_agent_height_offset", "agent_height_offset"), &NavigationAgent::set_agent_height_offset); + ClassDB::bind_method(D_METHOD("get_agent_height_offset"), &NavigationAgent::get_agent_height_offset); + + ClassDB::bind_method(D_METHOD("set_ignore_y", "ignore"), &NavigationAgent::set_ignore_y); + ClassDB::bind_method(D_METHOD("get_ignore_y"), &NavigationAgent::get_ignore_y); + + ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationAgent::set_navigation_node); + ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationAgent::get_navigation_node); + + ClassDB::bind_method(D_METHOD("set_neighbor_dist", "neighbor_dist"), &NavigationAgent::set_neighbor_dist); + ClassDB::bind_method(D_METHOD("get_neighbor_dist"), &NavigationAgent::get_neighbor_dist); + + ClassDB::bind_method(D_METHOD("set_max_neighbors", "max_neighbors"), &NavigationAgent::set_max_neighbors); + ClassDB::bind_method(D_METHOD("get_max_neighbors"), &NavigationAgent::get_max_neighbors); + + ClassDB::bind_method(D_METHOD("set_time_horizon", "time_horizon"), &NavigationAgent::set_time_horizon); + ClassDB::bind_method(D_METHOD("get_time_horizon"), &NavigationAgent::get_time_horizon); + + ClassDB::bind_method(D_METHOD("set_max_speed", "max_speed"), &NavigationAgent::set_max_speed); + ClassDB::bind_method(D_METHOD("get_max_speed"), &NavigationAgent::get_max_speed); + + ClassDB::bind_method(D_METHOD("set_path_max_distance", "max_speed"), &NavigationAgent::set_path_max_distance); + ClassDB::bind_method(D_METHOD("get_path_max_distance"), &NavigationAgent::get_path_max_distance); + + ClassDB::bind_method(D_METHOD("set_target_location", "location"), &NavigationAgent::set_target_location); + ClassDB::bind_method(D_METHOD("get_target_location"), &NavigationAgent::get_target_location); + ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent::get_next_location); + ClassDB::bind_method(D_METHOD("distance_to_target"), &NavigationAgent::distance_to_target); + ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &NavigationAgent::set_velocity); + ClassDB::bind_method(D_METHOD("get_nav_path"), &NavigationAgent::get_nav_path); + ClassDB::bind_method(D_METHOD("get_nav_path_index"), &NavigationAgent::get_nav_path_index); + ClassDB::bind_method(D_METHOD("is_target_reached"), &NavigationAgent::is_target_reached); + ClassDB::bind_method(D_METHOD("is_target_reachable"), &NavigationAgent::is_target_reachable); + ClassDB::bind_method(D_METHOD("is_navigation_finished"), &NavigationAgent::is_navigation_finished); + ClassDB::bind_method(D_METHOD("get_final_location"), &NavigationAgent::get_final_location); + + ClassDB::bind_method(D_METHOD("_avoidance_done", "new_velocity"), &NavigationAgent::_avoidance_done); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01"), "set_target_desired_distance", "get_target_desired_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.1,100,0.01"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_height_offset", PROPERTY_HINT_RANGE, "-100.0,100,0.01"), "set_agent_height_offset", "get_agent_height_offset"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_dist", PROPERTY_HINT_RANGE, "0.1,10000,0.01"), "set_neighbor_dist", "get_neighbor_dist"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_neighbors", PROPERTY_HINT_RANGE, "1,10000,1"), "set_max_neighbors", "get_max_neighbors"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon", PROPERTY_HINT_RANGE, "0.01,100,0.01"), "set_time_horizon", "get_time_horizon"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,10000,0.01"), "set_max_speed", "get_max_speed"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "0.01,100,0.1"), "set_path_max_distance", "get_path_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_y"), "set_ignore_y", "get_ignore_y"); + + ADD_SIGNAL(MethodInfo("path_changed")); + ADD_SIGNAL(MethodInfo("target_reached")); + ADD_SIGNAL(MethodInfo("navigation_finished")); + ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR3, "safe_velocity"))); +} + +void NavigationAgent::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_READY: { + + agent_parent = Object::cast_to<Spatial>(get_parent()); + + NavigationServer::get_singleton()->agent_set_callback(agent, this, "_avoidance_done"); + + // Search the navigation node and set it + { + Navigation *nav = NULL; + Node *p = get_parent(); + while (p != NULL) { + nav = Object::cast_to<Navigation>(p); + if (nav != NULL) + p = NULL; + else + p = p->get_parent(); + } + + set_navigation(nav); + } + + set_physics_process_internal(true); + } break; + case NOTIFICATION_EXIT_TREE: { + agent_parent = NULL; + set_navigation(NULL); + set_physics_process_internal(false); + } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + if (agent_parent) { + + NavigationServer::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin); + if (!target_reached) { + if (distance_to_target() < target_desired_distance) { + emit_signal("target_reached"); + target_reached = true; + } + } + } + } break; + } +} + +NavigationAgent::NavigationAgent() : + agent_parent(NULL), + navigation(NULL), + agent(RID()), + target_desired_distance(1.0), + navigation_height_offset(0.0), + path_max_distance(3.0), + velocity_submitted(false), + target_reached(false), + navigation_finished(true) { + agent = NavigationServer::get_singleton()->agent_create(); + set_neighbor_dist(50.0); + set_max_neighbors(10); + set_time_horizon(5.0); + set_radius(1.0); + set_max_speed(10.0); + set_ignore_y(true); +} + +NavigationAgent::~NavigationAgent() { + NavigationServer::get_singleton()->free(agent); + agent = RID(); // Pointless +} + +void NavigationAgent::set_navigation(Navigation *p_nav) { + if (navigation == p_nav) + return; // Pointless + + navigation = p_nav; + NavigationServer::get_singleton()->agent_set_map(agent, navigation == NULL ? RID() : navigation->get_rid()); +} + +void NavigationAgent::set_navigation_node(Node *p_nav) { + Navigation *nav = Object::cast_to<Navigation>(p_nav); + ERR_FAIL_COND(nav == NULL); + set_navigation(nav); +} + +Node *NavigationAgent::get_navigation_node() const { + return Object::cast_to<Node>(navigation); +} + +void NavigationAgent::set_target_desired_distance(real_t p_dd) { + target_desired_distance = p_dd; +} + +void NavigationAgent::set_radius(real_t p_radius) { + radius = p_radius; + NavigationServer::get_singleton()->agent_set_radius(agent, radius); +} + +void NavigationAgent::set_agent_height_offset(real_t p_hh) { + navigation_height_offset = p_hh; +} + +void NavigationAgent::set_ignore_y(bool p_ignore_y) { + ignore_y = p_ignore_y; + NavigationServer::get_singleton()->agent_set_ignore_y(agent, ignore_y); +} + +void NavigationAgent::set_neighbor_dist(real_t p_dist) { + neighbor_dist = p_dist; + NavigationServer::get_singleton()->agent_set_neighbor_dist(agent, neighbor_dist); +} + +void NavigationAgent::set_max_neighbors(int p_count) { + max_neighbors = p_count; + NavigationServer::get_singleton()->agent_set_max_neighbors(agent, max_neighbors); +} + +void NavigationAgent::set_time_horizon(real_t p_time) { + time_horizon = p_time; + NavigationServer::get_singleton()->agent_set_time_horizon(agent, time_horizon); +} + +void NavigationAgent::set_max_speed(real_t p_max_speed) { + max_speed = p_max_speed; + NavigationServer::get_singleton()->agent_set_max_speed(agent, max_speed); +} + +void NavigationAgent::set_path_max_distance(real_t p_pmd) { + path_max_distance = p_pmd; +} + +real_t NavigationAgent::get_path_max_distance() { + return path_max_distance; +} + +void NavigationAgent::set_target_location(Vector3 p_location) { + target_location = p_location; + navigation_path.clear(); + target_reached = false; + navigation_finished = false; +} + +Vector3 NavigationAgent::get_target_location() const { + return target_location; +} + +Vector3 NavigationAgent::get_next_location() { + update_navigation(); + if (navigation_path.size() == 0) { + ERR_FAIL_COND_V(agent_parent == NULL, Vector3()); + return agent_parent->get_global_transform().origin; + } else { + return navigation_path[nav_path_index] - Vector3(0, navigation_height_offset, 0); + } +} + +real_t NavigationAgent::distance_to_target() const { + ERR_FAIL_COND_V(agent_parent == NULL, 0.0); + return agent_parent->get_global_transform().origin.distance_to(target_location); +} + +bool NavigationAgent::is_target_reached() const { + return target_reached; +} + +bool NavigationAgent::is_target_reachable() { + return target_desired_distance >= get_final_location().distance_to(target_location); +} + +bool NavigationAgent::is_navigation_finished() { + update_navigation(); + return navigation_finished; +} + +Vector3 NavigationAgent::get_final_location() { + update_navigation(); + if (navigation_path.size() == 0) { + return Vector3(); + } + return navigation_path[navigation_path.size() - 1]; +} + +void NavigationAgent::set_velocity(Vector3 p_velocity) { + target_velocity = p_velocity; + NavigationServer::get_singleton()->agent_set_target_velocity(agent, target_velocity); + NavigationServer::get_singleton()->agent_set_velocity(agent, prev_safe_velocity); + velocity_submitted = true; +} + +void NavigationAgent::_avoidance_done(Vector3 p_new_velocity) { + prev_safe_velocity = p_new_velocity; + + if (!velocity_submitted) { + target_velocity = Vector3(); + return; + } + velocity_submitted = false; + + emit_signal("velocity_computed", p_new_velocity); +} + +String NavigationAgent::get_configuration_warning() const { + if (!Object::cast_to<Spatial>(get_parent())) { + return TTR("The NavigationAgent can be used only under a spatial node."); + } + + return String(); +} + +void NavigationAgent::update_navigation() { + + if (agent_parent == NULL) return; + if (navigation == NULL) return; + if (update_frame_id == Engine::get_singleton()->get_physics_frames()) return; + + update_frame_id = Engine::get_singleton()->get_physics_frames(); + + Vector3 o = agent_parent->get_global_transform().origin; + + bool reload_path = false; + + if (NavigationServer::get_singleton()->agent_is_map_changed(agent)) { + reload_path = true; + } else if (navigation_path.size() == 0) { + reload_path = true; + } else { + // Check if too far from the navigation path + if (nav_path_index > 0) { + Vector3 segment[2]; + segment[0] = navigation_path[nav_path_index - 1]; + segment[1] = navigation_path[nav_path_index]; + segment[0].y -= navigation_height_offset; + segment[1].y -= navigation_height_offset; + Vector3 p = Geometry::get_closest_point_to_segment(o, segment); + if (o.distance_to(p) >= path_max_distance) { + // To faraway, reload path + reload_path = true; + } + } + } + + if (reload_path) { + navigation_path = NavigationServer::get_singleton()->map_get_path(navigation->get_rid(), o, target_location, true); + navigation_finished = false; + nav_path_index = 0; + emit_signal("path_changed"); + } + + if (navigation_path.size() == 0) + return; + + // Check if we can advance the navigation path + if (navigation_finished == false) { + // Advances to the next far away location. + while (o.distance_to(navigation_path[nav_path_index] - Vector3(0, navigation_height_offset, 0)) < target_desired_distance) { + nav_path_index += 1; + if (nav_path_index == navigation_path.size()) { + nav_path_index -= 1; + navigation_finished = true; + emit_signal("navigation_finished"); + break; + } + } + } +} diff --git a/scene/3d/navigation_agent.h b/scene/3d/navigation_agent.h new file mode 100644 index 0000000000..200d5db475 --- /dev/null +++ b/scene/3d/navigation_agent.h @@ -0,0 +1,162 @@ +/*************************************************************************/ +/* navigation_agent.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef NAVIGATION_AGENT_H +#define NAVIGATION_AGENT_H + +#include "core/vector.h" +#include "scene/main/node.h" + +class Spatial; +class Navigation; + +class NavigationAgent : public Node { + GDCLASS(NavigationAgent, Node); + + Spatial *agent_parent; + Navigation *navigation; + + RID agent; + + real_t target_desired_distance; + real_t radius; + real_t navigation_height_offset; + bool ignore_y; + real_t neighbor_dist; + int max_neighbors; + real_t time_horizon; + real_t max_speed; + + real_t path_max_distance; + + Vector3 target_location; + Vector<Vector3> navigation_path; + int nav_path_index; + bool velocity_submitted; + Vector3 prev_safe_velocity; + /// The submitted target velocity + Vector3 target_velocity; + bool target_reached; + bool navigation_finished; + // No initialized on purpose + uint32_t update_frame_id; + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + NavigationAgent(); + virtual ~NavigationAgent(); + + void set_navigation(Navigation *p_nav); + const Navigation *get_navigation() const { + return navigation; + } + + void set_navigation_node(Node *p_nav); + Node *get_navigation_node() const; + + RID get_rid() const { + return agent; + } + + void set_target_desired_distance(real_t p_dd); + real_t get_target_desired_distance() const { + return target_desired_distance; + } + + void set_radius(real_t p_radius); + real_t get_radius() const { + return radius; + } + + void set_agent_height_offset(real_t p_hh); + real_t get_agent_height_offset() const { + return navigation_height_offset; + } + + void set_ignore_y(bool p_ignore_y); + bool get_ignore_y() const { + return ignore_y; + } + + void set_neighbor_dist(real_t p_dist); + real_t get_neighbor_dist() const { + return neighbor_dist; + } + + void set_max_neighbors(int p_count); + int get_max_neighbors() const { + return max_neighbors; + } + + void set_time_horizon(real_t p_time); + real_t get_time_horizon() const { + return time_horizon; + } + + void set_max_speed(real_t p_max_speed); + real_t get_max_speed() const { + return max_speed; + } + + void set_path_max_distance(real_t p_pmd); + real_t get_path_max_distance(); + + void set_target_location(Vector3 p_location); + Vector3 get_target_location() const; + + Vector3 get_next_location(); + + Vector<Vector3> get_nav_path() const { + return navigation_path; + } + + int get_nav_path_index() const { + return nav_path_index; + } + + real_t distance_to_target() const; + bool is_target_reached() const; + bool is_target_reachable(); + bool is_navigation_finished(); + Vector3 get_final_location(); + + void set_velocity(Vector3 p_velocity); + void _avoidance_done(Vector3 p_new_velocity); + + virtual String get_configuration_warning() const; + +private: + void update_navigation(); +}; + +#endif diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp deleted file mode 100644 index aaba91125e..0000000000 --- a/scene/3d/navigation_mesh.cpp +++ /dev/null @@ -1,744 +0,0 @@ -/*************************************************************************/ -/* navigation_mesh.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "navigation_mesh.h" -#include "mesh_instance.h" -#include "navigation.h" - -void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) { - - vertices = PoolVector<Vector3>(); - clear_polygons(); - - for (int i = 0; i < p_mesh->get_surface_count(); i++) { - - if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) - continue; - Array arr = p_mesh->surface_get_arrays(i); - PoolVector<Vector3> varr = arr[Mesh::ARRAY_VERTEX]; - PoolVector<int> iarr = arr[Mesh::ARRAY_INDEX]; - if (varr.size() == 0 || iarr.size() == 0) - continue; - - int from = vertices.size(); - vertices.append_array(varr); - int rlen = iarr.size(); - PoolVector<int>::Read r = iarr.read(); - - for (int j = 0; j < rlen; j += 3) { - Vector<int> vi; - vi.resize(3); - vi.write[0] = r[j + 0] + from; - vi.write[1] = r[j + 1] + from; - vi.write[2] = r[j + 2] + from; - - add_polygon(vi); - } - } -} - -void NavigationMesh::set_sample_partition_type(int p_value) { - ERR_FAIL_COND(p_value >= SAMPLE_PARTITION_MAX); - partition_type = static_cast<SamplePartitionType>(p_value); -} - -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_source_geometry_mode(int p_geometry_mode) { - ERR_FAIL_INDEX(p_geometry_mode, SOURCE_GEOMETRY_MAX); - source_geometry_mode = static_cast<SourceGeometryMode>(p_geometry_mode); - _change_notify(); -} - -int NavigationMesh::get_source_geometry_mode() const { - return source_geometry_mode; -} - -void NavigationMesh::set_source_group_name(StringName p_group_name) { - source_group_name = p_group_name; -} - -StringName NavigationMesh::get_source_group_name() const { - return source_group_name; -} - -void NavigationMesh::set_cell_size(float p_value) { - cell_size = p_value; -} - -float NavigationMesh::get_cell_size() const { - return cell_size; -} - -void NavigationMesh::set_cell_height(float p_value) { - cell_height = p_value; -} - -float NavigationMesh::get_cell_height() const { - return cell_height; -} - -void NavigationMesh::set_agent_height(float p_value) { - agent_height = p_value; -} - -float NavigationMesh::get_agent_height() const { - return agent_height; -} - -void NavigationMesh::set_agent_radius(float p_value) { - agent_radius = p_value; -} - -float NavigationMesh::get_agent_radius() { - return agent_radius; -} - -void NavigationMesh::set_agent_max_climb(float p_value) { - agent_max_climb = p_value; -} - -float NavigationMesh::get_agent_max_climb() const { - return agent_max_climb; -} - -void NavigationMesh::set_agent_max_slope(float p_value) { - agent_max_slope = p_value; -} - -float NavigationMesh::get_agent_max_slope() const { - return agent_max_slope; -} - -void NavigationMesh::set_region_min_size(float p_value) { - region_min_size = p_value; -} - -float NavigationMesh::get_region_min_size() const { - return region_min_size; -} - -void NavigationMesh::set_region_merge_size(float p_value) { - region_merge_size = p_value; -} - -float NavigationMesh::get_region_merge_size() const { - return region_merge_size; -} - -void NavigationMesh::set_edge_max_length(float p_value) { - edge_max_length = p_value; -} - -float NavigationMesh::get_edge_max_length() const { - return edge_max_length; -} - -void NavigationMesh::set_edge_max_error(float p_value) { - edge_max_error = p_value; -} - -float NavigationMesh::get_edge_max_error() const { - return edge_max_error; -} - -void NavigationMesh::set_verts_per_poly(float p_value) { - verts_per_poly = p_value; -} - -float NavigationMesh::get_verts_per_poly() const { - return verts_per_poly; -} - -void NavigationMesh::set_detail_sample_distance(float p_value) { - detail_sample_distance = p_value; -} - -float NavigationMesh::get_detail_sample_distance() const { - return detail_sample_distance; -} - -void NavigationMesh::set_detail_sample_max_error(float p_value) { - detail_sample_max_error = p_value; -} - -float NavigationMesh::get_detail_sample_max_error() const { - return detail_sample_max_error; -} - -void NavigationMesh::set_filter_low_hanging_obstacles(bool p_value) { - filter_low_hanging_obstacles = p_value; -} - -bool NavigationMesh::get_filter_low_hanging_obstacles() const { - return filter_low_hanging_obstacles; -} - -void NavigationMesh::set_filter_ledge_spans(bool p_value) { - filter_ledge_spans = p_value; -} - -bool NavigationMesh::get_filter_ledge_spans() const { - return filter_ledge_spans; -} - -void NavigationMesh::set_filter_walkable_low_height_spans(bool p_value) { - filter_walkable_low_height_spans = p_value; -} - -bool NavigationMesh::get_filter_walkable_low_height_spans() const { - return filter_walkable_low_height_spans; -} - -void NavigationMesh::set_vertices(const PoolVector<Vector3> &p_vertices) { - - vertices = p_vertices; - _change_notify(); -} - -PoolVector<Vector3> NavigationMesh::get_vertices() const { - - return vertices; -} - -void NavigationMesh::_set_polygons(const Array &p_array) { - - polygons.resize(p_array.size()); - for (int i = 0; i < p_array.size(); i++) { - polygons.write[i].indices = p_array[i]; - } - _change_notify(); -} - -Array NavigationMesh::_get_polygons() const { - - Array ret; - ret.resize(polygons.size()); - for (int i = 0; i < ret.size(); i++) { - ret[i] = polygons[i].indices; - } - - return ret; -} - -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 { - - return polygons.size(); -} -Vector<int> NavigationMesh::get_polygon(int p_idx) { - - ERR_FAIL_INDEX_V(p_idx, polygons.size(), Vector<int>()); - return polygons[p_idx].indices; -} -void NavigationMesh::clear_polygons() { - - polygons.clear(); -} - -Ref<Mesh> NavigationMesh::get_debug_mesh() { - - if (debug_mesh.is_valid()) - return debug_mesh; - - PoolVector<Vector3> vertices = get_vertices(); - PoolVector<Vector3>::Read vr = vertices.read(); - List<Face3> faces; - for (int i = 0; i < get_polygon_count(); i++) { - Vector<int> p = get_polygon(i); - - for (int j = 2; j < p.size(); j++) { - Face3 f; - f.vertex[0] = vr[p[0]]; - f.vertex[1] = vr[p[j - 1]]; - f.vertex[2] = vr[p[j]]; - - faces.push_back(f); - } - } - - Map<_EdgeKey, bool> edge_map; - PoolVector<Vector3> tmeshfaces; - tmeshfaces.resize(faces.size() * 3); - - { - PoolVector<Vector3>::Write tw = tmeshfaces.write(); - int tidx = 0; - - for (List<Face3>::Element *E = faces.front(); E; E = E->next()) { - - const Face3 &f = E->get(); - - for (int j = 0; j < 3; j++) { - - tw[tidx++] = f.vertex[j]; - _EdgeKey ek; - ek.from = f.vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); - ek.to = f.vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); - if (ek.from < ek.to) - SWAP(ek.from, ek.to); - - Map<_EdgeKey, bool>::Element *F = edge_map.find(ek); - - if (F) { - - F->get() = false; - - } else { - - edge_map[ek] = true; - } - } - } - } - List<Vector3> lines; - - for (Map<_EdgeKey, bool>::Element *E = edge_map.front(); E; E = E->next()) { - - if (E->get()) { - lines.push_back(E->key().from); - lines.push_back(E->key().to); - } - } - - PoolVector<Vector3> varr; - varr.resize(lines.size()); - { - PoolVector<Vector3>::Write w = varr.write(); - int idx = 0; - for (List<Vector3>::Element *E = lines.front(); E; E = E->next()) { - w[idx++] = E->get(); - } - } - - debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); - - Array arr; - arr.resize(Mesh::ARRAY_MAX); - arr[Mesh::ARRAY_VERTEX] = varr; - - debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, arr); - - return debug_mesh; -} - -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_source_geometry_mode", "mask"), &NavigationMesh::set_source_geometry_mode); - ClassDB::bind_method(D_METHOD("get_source_geometry_mode"), &NavigationMesh::get_source_geometry_mode); - - ClassDB::bind_method(D_METHOD("set_source_group_name", "mask"), &NavigationMesh::set_source_group_name); - ClassDB::bind_method(D_METHOD("get_source_group_name"), &NavigationMesh::get_source_group_name); - - 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); - - ClassDB::bind_method(D_METHOD("set_cell_height", "cell_height"), &NavigationMesh::set_cell_height); - ClassDB::bind_method(D_METHOD("get_cell_height"), &NavigationMesh::get_cell_height); - - ClassDB::bind_method(D_METHOD("set_agent_height", "agent_height"), &NavigationMesh::set_agent_height); - ClassDB::bind_method(D_METHOD("get_agent_height"), &NavigationMesh::get_agent_height); - - ClassDB::bind_method(D_METHOD("set_agent_radius", "agent_radius"), &NavigationMesh::set_agent_radius); - ClassDB::bind_method(D_METHOD("get_agent_radius"), &NavigationMesh::get_agent_radius); - - ClassDB::bind_method(D_METHOD("set_agent_max_climb", "agent_max_climb"), &NavigationMesh::set_agent_max_climb); - ClassDB::bind_method(D_METHOD("get_agent_max_climb"), &NavigationMesh::get_agent_max_climb); - - ClassDB::bind_method(D_METHOD("set_agent_max_slope", "agent_max_slope"), &NavigationMesh::set_agent_max_slope); - ClassDB::bind_method(D_METHOD("get_agent_max_slope"), &NavigationMesh::get_agent_max_slope); - - ClassDB::bind_method(D_METHOD("set_region_min_size", "region_min_size"), &NavigationMesh::set_region_min_size); - ClassDB::bind_method(D_METHOD("get_region_min_size"), &NavigationMesh::get_region_min_size); - - ClassDB::bind_method(D_METHOD("set_region_merge_size", "region_merge_size"), &NavigationMesh::set_region_merge_size); - ClassDB::bind_method(D_METHOD("get_region_merge_size"), &NavigationMesh::get_region_merge_size); - - ClassDB::bind_method(D_METHOD("set_edge_max_length", "edge_max_length"), &NavigationMesh::set_edge_max_length); - ClassDB::bind_method(D_METHOD("get_edge_max_length"), &NavigationMesh::get_edge_max_length); - - ClassDB::bind_method(D_METHOD("set_edge_max_error", "edge_max_error"), &NavigationMesh::set_edge_max_error); - ClassDB::bind_method(D_METHOD("get_edge_max_error"), &NavigationMesh::get_edge_max_error); - - ClassDB::bind_method(D_METHOD("set_verts_per_poly", "verts_per_poly"), &NavigationMesh::set_verts_per_poly); - ClassDB::bind_method(D_METHOD("get_verts_per_poly"), &NavigationMesh::get_verts_per_poly); - - ClassDB::bind_method(D_METHOD("set_detail_sample_distance", "detail_sample_dist"), &NavigationMesh::set_detail_sample_distance); - ClassDB::bind_method(D_METHOD("get_detail_sample_distance"), &NavigationMesh::get_detail_sample_distance); - - ClassDB::bind_method(D_METHOD("set_detail_sample_max_error", "detail_sample_max_error"), &NavigationMesh::set_detail_sample_max_error); - ClassDB::bind_method(D_METHOD("get_detail_sample_max_error"), &NavigationMesh::get_detail_sample_max_error); - - ClassDB::bind_method(D_METHOD("set_filter_low_hanging_obstacles", "filter_low_hanging_obstacles"), &NavigationMesh::set_filter_low_hanging_obstacles); - ClassDB::bind_method(D_METHOD("get_filter_low_hanging_obstacles"), &NavigationMesh::get_filter_low_hanging_obstacles); - - ClassDB::bind_method(D_METHOD("set_filter_ledge_spans", "filter_ledge_spans"), &NavigationMesh::set_filter_ledge_spans); - ClassDB::bind_method(D_METHOD("get_filter_ledge_spans"), &NavigationMesh::get_filter_ledge_spans); - - ClassDB::bind_method(D_METHOD("set_filter_walkable_low_height_spans", "filter_walkable_low_height_spans"), &NavigationMesh::set_filter_walkable_low_height_spans); - ClassDB::bind_method(D_METHOD("get_filter_walkable_low_height_spans"), &NavigationMesh::get_filter_walkable_low_height_spans); - - ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationMesh::set_vertices); - ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationMesh::get_vertices); - - ClassDB::bind_method(D_METHOD("add_polygon", "polygon"), &NavigationMesh::add_polygon); - ClassDB::bind_method(D_METHOD("get_polygon_count"), &NavigationMesh::get_polygon_count); - ClassDB::bind_method(D_METHOD("get_polygon", "idx"), &NavigationMesh::get_polygon); - ClassDB::bind_method(D_METHOD("clear_polygons"), &NavigationMesh::clear_polygons); - - ClassDB::bind_method(D_METHOD("create_from_mesh", "mesh"), &NavigationMesh::create_from_mesh); - - ClassDB::bind_method(D_METHOD("_set_polygons", "polygons"), &NavigationMesh::_set_polygons); - ClassDB::bind_method(D_METHOD("_get_polygons"), &NavigationMesh::_get_polygons); - - BIND_CONSTANT(SAMPLE_PARTITION_WATERSHED); - 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::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::INT, "geometry/source_geometry_mode", PROPERTY_HINT_ENUM, "Navmesh Children, Group With Children, Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "geometry/source_group_name"), "set_source_group_name", "get_source_group_name"); - - 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,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; - } - } - - if (property.name == "geometry/source_group_name") { - if (source_geometry_mode == SOURCE_GEOMETRY_NAVMESH_CHILDREN) { - property.usage = 0; - return; - } - } -} - -NavigationMesh::NavigationMesh() { - cell_size = 0.3f; - cell_height = 0.2f; - agent_height = 2.0f; - agent_radius = 0.6f; - agent_max_climb = 0.9f; - agent_max_slope = 45.0f; - region_min_size = 8.0f; - region_merge_size = 20.0f; - edge_max_length = 12.0f; - edge_max_error = 1.3f; - verts_per_poly = 6.0f; - detail_sample_distance = 6.0f; - detail_sample_max_error = 1.0f; - - partition_type = SAMPLE_PARTITION_WATERSHED; - parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES; - collision_mask = 0xFFFFFFFF; - source_geometry_mode = SOURCE_GEOMETRY_NAVMESH_CHILDREN; - source_group_name = "navmesh"; - filter_low_hanging_obstacles = false; - filter_ledge_spans = false; - filter_walkable_low_height_spans = false; -} - -void NavigationMeshInstance::set_enabled(bool p_enabled) { - - if (enabled == p_enabled) - return; - enabled = p_enabled; - - if (!is_inside_tree()) - return; - - if (!enabled) { - - if (nav_id != -1) { - navigation->navmesh_remove(nav_id); - nav_id = -1; - } - } else { - - if (navigation) { - - if (navmesh.is_valid()) { - - nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this); - } - } - } - - if (debug_view) { - MeshInstance *dm = Object::cast_to<MeshInstance>(debug_view); - if (is_enabled()) { - dm->set_material_override(get_tree()->get_debug_navigation_material()); - } else { - dm->set_material_override(get_tree()->get_debug_navigation_disabled_material()); - } - } - - update_gizmo(); -} - -bool NavigationMeshInstance::is_enabled() const { - - return enabled; -} - -///////////////////////////// - -void NavigationMeshInstance::_notification(int p_what) { - - switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - - Spatial *c = this; - while (c) { - - navigation = Object::cast_to<Navigation>(c); - if (navigation) { - - if (enabled && navmesh.is_valid()) { - - nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this); - } - break; - } - - c = c->get_parent_spatial(); - } - - if (navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) { - - MeshInstance *dm = memnew(MeshInstance); - dm->set_mesh(navmesh->get_debug_mesh()); - if (is_enabled()) { - dm->set_material_override(get_tree()->get_debug_navigation_material()); - } else { - dm->set_material_override(get_tree()->get_debug_navigation_disabled_material()); - } - add_child(dm); - debug_view = dm; - } - - } break; - case NOTIFICATION_TRANSFORM_CHANGED: { - - if (navigation && nav_id != -1) { - navigation->navmesh_set_transform(nav_id, get_relative_transform(navigation)); - } - - } break; - case NOTIFICATION_EXIT_TREE: { - - if (navigation) { - - if (nav_id != -1) { - navigation->navmesh_remove(nav_id); - nav_id = -1; - } - } - - if (debug_view) { - debug_view->queue_delete(); - debug_view = NULL; - } - navigation = NULL; - } break; - } -} - -void NavigationMeshInstance::set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh) { - - if (p_navmesh == navmesh) - return; - - if (navigation && nav_id != -1) { - 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); - } - - if (debug_view && navmesh.is_valid()) { - Object::cast_to<MeshInstance>(debug_view)->set_mesh(navmesh->get_debug_mesh()); - } - - update_gizmo(); - update_configuration_warning(); -} - -Ref<NavigationMesh> NavigationMeshInstance::get_navigation_mesh() const { - - return navmesh; -} - -String NavigationMeshInstance::get_configuration_warning() const { - - if (!is_visible_in_tree() || !is_inside_tree()) - return String(); - - if (!navmesh.is_valid()) { - return TTR("A NavigationMesh resource must be set or created for this node to work."); - } - const Spatial *c = this; - while (c) { - - if (Object::cast_to<Navigation>(c)) - return String(); - - c = Object::cast_to<Spatial>(c->get_parent()); - } - - return TTR("NavigationMeshInstance must be a child or grandchild to a Navigation node. It only provides navigation data."); -} - -void NavigationMeshInstance::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_navigation_mesh", "navmesh"), &NavigationMeshInstance::set_navigation_mesh); - ClassDB::bind_method(D_METHOD("get_navigation_mesh"), &NavigationMeshInstance::get_navigation_mesh); - - ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationMeshInstance::set_enabled); - ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationMeshInstance::is_enabled); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"), "set_navigation_mesh", "get_navigation_mesh"); - 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; - navigation = NULL; - nav_id = -1; - 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 deleted file mode 100644 index f9ab911bea..0000000000 --- a/scene/3d/navigation_mesh.h +++ /dev/null @@ -1,227 +0,0 @@ -/*************************************************************************/ -/* navigation_mesh.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef NAVIGATION_MESH_H -#define NAVIGATION_MESH_H - -#include "scene/3d/spatial.h" -#include "scene/resources/mesh.h" - -class Mesh; - -class NavigationMesh : public Resource { - - GDCLASS(NavigationMesh, Resource); - - PoolVector<Vector3> vertices; - struct Polygon { - Vector<int> indices; - }; - Vector<Polygon> polygons; - Ref<ArrayMesh> debug_mesh; - - struct _EdgeKey { - - Vector3 from; - Vector3 to; - - bool operator<(const _EdgeKey &p_with) const { return from == p_with.from ? to < p_with.to : from < p_with.from; } - }; - -protected: - static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const; - - void _set_polygons(const Array &p_array); - Array _get_polygons() const; - -public: - enum SamplePartitionType { - SAMPLE_PARTITION_WATERSHED = 0, - SAMPLE_PARTITION_MONOTONE, - SAMPLE_PARTITION_LAYERS, - SAMPLE_PARTITION_MAX - }; - - enum ParsedGeometryType { - PARSED_GEOMETRY_MESH_INSTANCES = 0, - PARSED_GEOMETRY_STATIC_COLLIDERS, - PARSED_GEOMETRY_BOTH, - PARSED_GEOMETRY_MAX - }; - - enum SourceGeometryMode { - SOURCE_GEOMETRY_NAVMESH_CHILDREN = 0, - SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN, - SOURCE_GEOMETRY_GROUPS_EXPLICIT, - SOURCE_GEOMETRY_MAX - }; - -protected: - float cell_size; - float cell_height; - float agent_height; - float agent_radius; - float agent_max_climb; - float agent_max_slope; - float region_min_size; - float region_merge_size; - float edge_max_length; - float edge_max_error; - float verts_per_poly; - float detail_sample_distance; - float detail_sample_max_error; - - SamplePartitionType partition_type; - ParsedGeometryType parsed_geometry_type; - uint32_t collision_mask; - - SourceGeometryMode source_geometry_mode; - StringName source_group_name; - - bool filter_low_hanging_obstacles; - bool filter_ledge_spans; - bool filter_walkable_low_height_spans; - -public: - // Recast settings - 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_source_geometry_mode(int p_geometry_mode); - int get_source_geometry_mode() const; - - void set_source_group_name(StringName p_group_name); - StringName get_source_group_name() const; - - void set_cell_size(float p_value); - float get_cell_size() const; - - void set_cell_height(float p_value); - float get_cell_height() const; - - void set_agent_height(float p_value); - float get_agent_height() const; - - void set_agent_radius(float p_value); - float get_agent_radius(); - - void set_agent_max_climb(float p_value); - float get_agent_max_climb() const; - - void set_agent_max_slope(float p_value); - float get_agent_max_slope() const; - - void set_region_min_size(float p_value); - float get_region_min_size() const; - - void set_region_merge_size(float p_value); - float get_region_merge_size() const; - - void set_edge_max_length(float p_value); - float get_edge_max_length() const; - - void set_edge_max_error(float p_value); - float get_edge_max_error() const; - - void set_verts_per_poly(float p_value); - float get_verts_per_poly() const; - - void set_detail_sample_distance(float p_value); - float get_detail_sample_distance() const; - - void set_detail_sample_max_error(float p_value); - float get_detail_sample_max_error() const; - - void set_filter_low_hanging_obstacles(bool p_value); - bool get_filter_low_hanging_obstacles() const; - - void set_filter_ledge_spans(bool p_value); - bool get_filter_ledge_spans() const; - - void set_filter_walkable_low_height_spans(bool p_value); - bool get_filter_walkable_low_height_spans() const; - - void create_from_mesh(const Ref<Mesh> &p_mesh); - - void set_vertices(const PoolVector<Vector3> &p_vertices); - PoolVector<Vector3> get_vertices() const; - - void add_polygon(const Vector<int> &p_polygon); - int get_polygon_count() const; - Vector<int> get_polygon(int p_idx); - void clear_polygons(); - - Ref<Mesh> get_debug_mesh(); - - NavigationMesh(); -}; - -class Navigation; - -class NavigationMeshInstance : public Spatial { - - GDCLASS(NavigationMeshInstance, Spatial); - - bool enabled; - int nav_id; - Navigation *navigation; - Ref<NavigationMesh> navmesh; - - Node *debug_view; - -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); - bool is_enabled() const; - - void set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh); - Ref<NavigationMesh> get_navigation_mesh() const; - - String get_configuration_warning() const; - - NavigationMeshInstance(); - ~NavigationMeshInstance(); -}; - -#endif // NAVIGATION_MESH_H diff --git a/scene/3d/navigation_obstacle.cpp b/scene/3d/navigation_obstacle.cpp new file mode 100644 index 0000000000..befc41eee5 --- /dev/null +++ b/scene/3d/navigation_obstacle.cpp @@ -0,0 +1,163 @@ +/*************************************************************************/ +/* navigation_obstacle.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "navigation_obstacle.h" + +#include "scene/3d/collision_shape.h" +#include "scene/3d/navigation.h" +#include "scene/3d/physics_body.h" +#include "servers/navigation_server.h" + +void NavigationObstacle::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationObstacle::set_navigation_node); + ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationObstacle::get_navigation_node); +} + +void NavigationObstacle::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_READY: { + + update_agent_shape(); + + // Search the navigation node and set it + { + Navigation *nav = NULL; + Node *p = get_parent(); + while (p != NULL) { + nav = Object::cast_to<Navigation>(p); + if (nav != NULL) + p = NULL; + else + p = p->get_parent(); + } + + set_navigation(nav); + } + + set_physics_process_internal(true); + } break; + case NOTIFICATION_EXIT_TREE: { + set_navigation(NULL); + set_physics_process_internal(false); + } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + Spatial *spatial = Object::cast_to<Spatial>(get_parent()); + if (spatial) { + NavigationServer::get_singleton()->agent_set_position(agent, spatial->get_global_transform().origin); + } + + PhysicsBody *rigid = Object::cast_to<PhysicsBody>(get_parent()); + if (rigid) { + + Vector3 v = rigid->get_linear_velocity(); + NavigationServer::get_singleton()->agent_set_velocity(agent, v); + NavigationServer::get_singleton()->agent_set_target_velocity(agent, v); + } + + } break; + } +} + +NavigationObstacle::NavigationObstacle() : + navigation(NULL), + agent(RID()) { + agent = NavigationServer::get_singleton()->agent_create(); +} + +NavigationObstacle::~NavigationObstacle() { + NavigationServer::get_singleton()->free(agent); + agent = RID(); // Pointless +} + +void NavigationObstacle::set_navigation(Navigation *p_nav) { + if (navigation == p_nav) + return; // Pointless + + navigation = p_nav; + NavigationServer::get_singleton()->agent_set_map(agent, navigation == NULL ? RID() : navigation->get_rid()); +} + +void NavigationObstacle::set_navigation_node(Node *p_nav) { + Navigation *nav = Object::cast_to<Navigation>(p_nav); + ERR_FAIL_COND(nav == NULL); + set_navigation(nav); +} + +Node *NavigationObstacle::get_navigation_node() const { + return Object::cast_to<Node>(navigation); +} + +String NavigationObstacle::get_configuration_warning() const { + if (!Object::cast_to<Spatial>(get_parent())) { + + return TTR("The NavigationObstacle only serves to provide collision avoidance to a spatial object."); + } + + return String(); +} + +void NavigationObstacle::update_agent_shape() { + Node *node = get_parent(); + + // Estimate the radius of this physics body + real_t radius = 0.0; + for (int i(0); i < node->get_child_count(); i++) { + // For each collision shape + CollisionShape *cs = Object::cast_to<CollisionShape>(node->get_child(i)); + if (cs) { + // Take the distance between the Body center to the shape center + real_t r = cs->get_transform().origin.length(); + if (cs->get_shape().is_valid()) { + // and add the enclosing shape radius + r += cs->get_shape()->get_enclosing_radius(); + } + Vector3 s = cs->get_global_transform().basis.get_scale(); + r *= MAX(s.x, MAX(s.y, s.z)); + // Takes the biggest radius + radius = MAX(radius, r); + } + } + Spatial *spa = Object::cast_to<Spatial>(node); + if (spa) { + Vector3 s = spa->get_global_transform().basis.get_scale(); + radius *= MAX(s.x, MAX(s.y, s.z)); + } + + if (radius == 0.0) + radius = 1.0; // Never a 0 radius + + // Initialize the Agent as an object + NavigationServer::get_singleton()->agent_set_neighbor_dist(agent, 0.0); + NavigationServer::get_singleton()->agent_set_max_neighbors(agent, 0); + NavigationServer::get_singleton()->agent_set_time_horizon(agent, 0.0); + NavigationServer::get_singleton()->agent_set_radius(agent, radius); + NavigationServer::get_singleton()->agent_set_max_speed(agent, 0.0); +} diff --git a/scene/3d/navigation_obstacle.h b/scene/3d/navigation_obstacle.h new file mode 100644 index 0000000000..7257a43150 --- /dev/null +++ b/scene/3d/navigation_obstacle.h @@ -0,0 +1,71 @@ +/*************************************************************************/ +/* navigation_obstacle.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef NAVIGATION_OBSTACLE_H +#define NAVIGATION_OBSTACLE_H + +#include "scene/main/node.h" + +class Navigation; + +class NavigationObstacle : public Node { + GDCLASS(NavigationObstacle, Node); + + Navigation *navigation; + + RID agent; + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + NavigationObstacle(); + virtual ~NavigationObstacle(); + + void set_navigation(Navigation *p_nav); + const Navigation *get_navigation() const { + return navigation; + } + + void set_navigation_node(Node *p_nav); + Node *get_navigation_node() const; + + RID get_rid() const { + return agent; + } + + virtual String get_configuration_warning() const; + +private: + void update_agent_shape(); +}; + +#endif diff --git a/scene/3d/navigation_region.cpp b/scene/3d/navigation_region.cpp new file mode 100644 index 0000000000..d96d095797 --- /dev/null +++ b/scene/3d/navigation_region.cpp @@ -0,0 +1,258 @@ +/*************************************************************************/ +/* navigation_region.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "navigation_region.h" +#include "core/os/thread.h" +#include "mesh_instance.h" +#include "navigation.h" +#include "servers/navigation_server.h" + +void NavigationRegion::set_enabled(bool p_enabled) { + + if (enabled == p_enabled) + return; + enabled = p_enabled; + + if (!is_inside_tree()) + return; + + if (!enabled) { + + NavigationServer::get_singleton()->region_set_map(region, RID()); + } else { + + if (navigation) { + + NavigationServer::get_singleton()->region_set_map(region, navigation->get_rid()); + } + } + + if (debug_view) { + MeshInstance *dm = Object::cast_to<MeshInstance>(debug_view); + if (is_enabled()) { + dm->set_material_override(get_tree()->get_debug_navigation_material()); + } else { + dm->set_material_override(get_tree()->get_debug_navigation_disabled_material()); + } + } + + update_gizmo(); +} + +bool NavigationRegion::is_enabled() const { + + return enabled; +} + +///////////////////////////// + +void NavigationRegion::_notification(int p_what) { + + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + + Spatial *c = this; + while (c) { + + navigation = Object::cast_to<Navigation>(c); + if (navigation) { + + if (enabled) { + + NavigationServer::get_singleton()->region_set_map(region, navigation->get_rid()); + } + break; + } + + c = c->get_parent_spatial(); + } + + if (navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) { + + MeshInstance *dm = memnew(MeshInstance); + dm->set_mesh(navmesh->get_debug_mesh()); + if (is_enabled()) { + dm->set_material_override(get_tree()->get_debug_navigation_material()); + } else { + dm->set_material_override(get_tree()->get_debug_navigation_disabled_material()); + } + add_child(dm); + debug_view = dm; + } + + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + + NavigationServer::get_singleton()->region_set_transform(region, get_global_transform()); + + } break; + case NOTIFICATION_EXIT_TREE: { + + if (navigation) { + + NavigationServer::get_singleton()->region_set_map(region, RID()); + } + + if (debug_view) { + debug_view->queue_delete(); + debug_view = NULL; + } + navigation = NULL; + } break; + } +} + +void NavigationRegion::set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh) { + + if (p_navmesh == navmesh) + return; + + if (navmesh.is_valid()) { + navmesh->remove_change_receptor(this); + } + + navmesh = p_navmesh; + + if (navmesh.is_valid()) { + navmesh->add_change_receptor(this); + } + + NavigationServer::get_singleton()->region_set_navmesh(region, p_navmesh); + + if (debug_view && navmesh.is_valid()) { + Object::cast_to<MeshInstance>(debug_view)->set_mesh(navmesh->get_debug_mesh()); + } + + emit_signal("navigation_mesh_changed"); + + update_gizmo(); + update_configuration_warning(); +} + +Ref<NavigationMesh> NavigationRegion::get_navigation_mesh() const { + + return navmesh; +} + +struct BakeThreadsArgs { + NavigationRegion *nav_mesh_instance; +}; + +void _bake_navigation_mesh(void *p_user_data) { + BakeThreadsArgs *args = static_cast<BakeThreadsArgs *>(p_user_data); + + if (args->nav_mesh_instance->get_navigation_mesh().is_valid()) { + Ref<NavigationMesh> nav_mesh = args->nav_mesh_instance->get_navigation_mesh()->duplicate(); + + NavigationServer::get_singleton()->region_bake_navmesh(nav_mesh, args->nav_mesh_instance); + args->nav_mesh_instance->call_deferred("_bake_finished", nav_mesh); + memdelete(args); + } else { + + ERR_PRINT("Can't bake the navigation mesh if the `NavigationMesh` resource doesn't exist"); + args->nav_mesh_instance->call_deferred("_bake_finished", Ref<NavigationMesh>()); + memdelete(args); + } +} + +void NavigationRegion::bake_navigation_mesh() { + ERR_FAIL_COND(bake_thread != NULL); + + BakeThreadsArgs *args = memnew(BakeThreadsArgs); + args->nav_mesh_instance = this; + + bake_thread = Thread::create(_bake_navigation_mesh, args); + ERR_FAIL_COND(bake_thread == NULL); +} + +void NavigationRegion::_bake_finished(Ref<NavigationMesh> p_nav_mesh) { + set_navigation_mesh(p_nav_mesh); + bake_thread = NULL; +} + +String NavigationRegion::get_configuration_warning() const { + + if (!is_visible_in_tree() || !is_inside_tree()) + return String(); + + if (!navmesh.is_valid()) { + return TTR("A NavigationMesh resource must be set or created for this node to work."); + } + const Spatial *c = this; + while (c) { + + if (Object::cast_to<Navigation>(c)) + return String(); + + c = Object::cast_to<Spatial>(c->get_parent()); + } + + return TTR("NavigationRegion must be a child or grandchild to a Navigation node. It only provides navigation data."); +} + +void NavigationRegion::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_navigation_mesh", "navmesh"), &NavigationRegion::set_navigation_mesh); + ClassDB::bind_method(D_METHOD("get_navigation_mesh"), &NavigationRegion::get_navigation_mesh); + + ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion::set_enabled); + ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationRegion::is_enabled); + + ClassDB::bind_method(D_METHOD("bake_navigation_mesh"), &NavigationRegion::bake_navigation_mesh); + ClassDB::bind_method(D_METHOD("_bake_finished", "nav_mesh"), &NavigationRegion::_bake_finished); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"), "set_navigation_mesh", "get_navigation_mesh"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); + + ADD_SIGNAL(MethodInfo("navigation_mesh_changed")); + ADD_SIGNAL(MethodInfo("bake_finished")); +} + +void NavigationRegion::_changed_callback(Object *p_changed, const char *p_prop) { + update_gizmo(); + update_configuration_warning(); +} + +NavigationRegion::NavigationRegion() { + + enabled = true; + set_notify_transform(true); + region = NavigationServer::get_singleton()->region_create(); + + navigation = NULL; + debug_view = NULL; + bake_thread = NULL; +} + +NavigationRegion::~NavigationRegion() { + if (navmesh.is_valid()) + navmesh->remove_change_receptor(this); + NavigationServer::get_singleton()->free(region); +} diff --git a/scene/3d/navigation_region.h b/scene/3d/navigation_region.h new file mode 100644 index 0000000000..f215e92c97 --- /dev/null +++ b/scene/3d/navigation_region.h @@ -0,0 +1,75 @@ +/*************************************************************************/ +/* navigation_region.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef NAVIGATION_REGION_H +#define NAVIGATION_REGION_H + +#include "scene/3d/spatial.h" +#include "scene/resources/mesh.h" +#include "scene/resources/navigation_mesh.h" + +class Navigation; + +class NavigationRegion : public Spatial { + + GDCLASS(NavigationRegion, Spatial); + + bool enabled; + RID region; + Ref<NavigationMesh> navmesh; + + Navigation *navigation; + Node *debug_view; + Thread *bake_thread; + +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); + bool is_enabled() const; + + void set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh); + Ref<NavigationMesh> get_navigation_mesh() const; + + /// Bakes the navigation mesh in a dedicated thread; once done, automatically + /// sets the new navigation mesh and emits a signal + void bake_navigation_mesh(); + void _bake_finished(Ref<NavigationMesh> p_nav_mesh); + + String get_configuration_warning() const; + + NavigationRegion(); + ~NavigationRegion(); +}; + +#endif // NAVIGATION_REGION_H diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index add563d991..e502b0c037 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -39,9 +39,9 @@ AABB Particles::get_aabb() const { return AABB(); } -PoolVector<Face3> Particles::get_faces(uint32_t p_usage_flags) const { +Vector<Face3> Particles::get_faces(uint32_t p_usage_flags) const { - return PoolVector<Face3>(); + return Vector<Face3>(); } void Particles::set_emitting(bool p_emitting) { @@ -254,16 +254,16 @@ String Particles::get_configuration_warning() const { meshes_found = true; for (int j = 0; j < draw_passes[i]->get_surface_count(); j++) { anim_material_found = Object::cast_to<ShaderMaterial>(draw_passes[i]->surface_get_material(j).ptr()) != NULL; - SpatialMaterial *spat = Object::cast_to<SpatialMaterial>(draw_passes[i]->surface_get_material(j).ptr()); - anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == SpatialMaterial::BILLBOARD_PARTICLES); + StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(draw_passes[i]->surface_get_material(j).ptr()); + anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES); } if (anim_material_found) break; } } anim_material_found = anim_material_found || Object::cast_to<ShaderMaterial>(get_material_override().ptr()) != NULL; - SpatialMaterial *spat = Object::cast_to<SpatialMaterial>(get_material_override().ptr()); - anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == SpatialMaterial::BILLBOARD_PARTICLES); + StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(get_material_override().ptr()); + anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES); if (!meshes_found) { if (warnings != String()) @@ -282,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 whose Billboard Mode is set to \"Particle Billboard\"."); + warnings += "- " + TTR("Particles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."); } } @@ -386,12 +386,12 @@ void Particles::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount"); ADD_GROUP("Time", ""); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta"); ADD_GROUP("Drawing", ""); diff --git a/scene/3d/particles.h b/scene/3d/particles.h index 69be7da29a..95c6de15ec 100644 --- a/scene/3d/particles.h +++ b/scene/3d/particles.h @@ -78,7 +78,7 @@ protected: public: AABB get_aabb() const; - PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; + Vector<Face3> get_faces(uint32_t p_usage_flags) const; void set_emitting(bool p_emitting); void set_amount(int p_amount); diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp index ac012de1ab..f93485d79f 100644 --- a/scene/3d/path.cpp +++ b/scene/3d/path.cpp @@ -59,13 +59,13 @@ void Path::_curve_changed() { void Path::set_curve(const Ref<Curve3D> &p_curve) { if (curve.is_valid()) { - curve->disconnect("changed", this, "_curve_changed"); + curve->disconnect("changed", callable_mp(this, &Path::_curve_changed)); } curve = p_curve; if (curve.is_valid()) { - curve->connect("changed", this, "_curve_changed"); + curve->connect("changed", callable_mp(this, &Path::_curve_changed)); } _curve_changed(); } @@ -79,7 +79,6 @@ void Path::_bind_methods() { ClassDB::bind_method(D_METHOD("set_curve", "curve"), &Path::set_curve); ClassDB::bind_method(D_METHOD("get_curve"), &Path::get_curve); - ClassDB::bind_method(D_METHOD("_curve_changed"), &Path::_curve_changed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve3D"), "set_curve", "get_curve"); @@ -297,10 +296,10 @@ void PathFollow::_bind_methods() { ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow::set_loop); ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow::has_loop); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); - 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::FLOAT, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater"), "set_offset", "get_offset"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset"), "set_h_offset", "get_h_offset"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset"), "set_v_offset", "get_v_offset"); ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM, "None,Y,XY,XYZ,Oriented"), "set_rotation_mode", "get_rotation_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cubic_interp"), "set_cubic_interpolation", "get_cubic_interpolation"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop"); diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index caeae90238..eba45a5604 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -36,15 +36,14 @@ #include "core/method_bind_ext.gen.inc" #include "core/object.h" #include "core/rid.h" +#include "scene/3d/collision_shape.h" #include "scene/scene_string_names.h" +#include "servers/navigation_server.h" #ifdef TOOLS_ENABLED #include "editor/plugins/spatial_editor_plugin.h" #endif -void PhysicsBody::_notification(int p_what) { -} - Vector3 PhysicsBody::get_linear_velocity() const { return Vector3(); @@ -179,74 +178,17 @@ PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) : collision_mask = 1; } -#ifndef DISABLE_DEPRECATED -void StaticBody::set_friction(real_t p_friction) { - - if (p_friction == 1.0 && physics_material_override.is_null()) { // default value, don't create an override for that - return; - } - - WARN_DEPRECATED_MSG("The method set_friction has been deprecated and will be removed in the future, use physics material instead."); - - ERR_FAIL_COND_MSG(p_friction < 0 || p_friction > 1, "Friction must be between 0 and 1."); - - if (physics_material_override.is_null()) { - physics_material_override.instance(); - set_physics_material_override(physics_material_override); - } - physics_material_override->set_friction(p_friction); -} - -real_t StaticBody::get_friction() const { - - WARN_DEPRECATED_MSG("The method get_friction has been deprecated and will be removed in the future, use physics material instead."); - - if (physics_material_override.is_null()) { - return 1; - } - - return physics_material_override->get_friction(); -} - -void StaticBody::set_bounce(real_t p_bounce) { - - if (p_bounce == 0.0 && physics_material_override.is_null()) { // default value, don't create an override for that - return; - } - - WARN_DEPRECATED_MSG("The method set_bounce has been deprecated and will be removed in the future, use physics material instead."); - - ERR_FAIL_COND_MSG(p_bounce < 0 || p_bounce > 1, "Bounce must be between 0 and 1."); - - if (physics_material_override.is_null()) { - physics_material_override.instance(); - set_physics_material_override(physics_material_override); - } - physics_material_override->set_bounce(p_bounce); -} - -real_t StaticBody::get_bounce() const { - - WARN_DEPRECATED_MSG("The method get_bounce has been deprecated and will be removed in the future, use physics material instead."); - - if (physics_material_override.is_null()) { - return 0; - } - - return physics_material_override->get_bounce(); -} -#endif - void StaticBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { if (physics_material_override.is_valid()) { - if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics")) - physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &StaticBody::_reload_physics_characteristics))) { + physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &StaticBody::_reload_physics_characteristics)); + } } physics_material_override = p_physics_material_override; if (physics_material_override.is_valid()) { - physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &StaticBody::_reload_physics_characteristics)); } _reload_physics_characteristics(); } @@ -283,27 +225,13 @@ void StaticBody::_bind_methods() { ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody::get_constant_linear_velocity); ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody::get_constant_angular_velocity); -#ifndef DISABLE_DEPRECATED - ClassDB::bind_method(D_METHOD("set_friction", "friction"), &StaticBody::set_friction); - ClassDB::bind_method(D_METHOD("get_friction"), &StaticBody::get_friction); - - ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &StaticBody::set_bounce); - ClassDB::bind_method(D_METHOD("get_bounce"), &StaticBody::get_bounce); -#endif // DISABLE_DEPRECATED - ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody::set_physics_material_override); ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody::get_physics_material_override); - ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &StaticBody::_reload_physics_characteristics); - ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody::get_collision_exceptions); ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody::add_collision_exception_with); ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody::remove_collision_exception_with); -#ifndef DISABLE_DEPRECATED - ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_friction", "get_friction"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_bounce", "get_bounce"); -#endif // DISABLE_DEPRECATED ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity"); @@ -393,8 +321,8 @@ void RigidBody::_body_inout(int p_status, ObjectID p_instance, int p_body_shape, //E->get().rc=0; E->get().in_tree = node && node->is_inside_tree(); if (node) { - node->connect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree, make_binds(objid)); - node->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody::_body_enter_tree), make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody::_body_exit_tree), make_binds(objid)); if (E->get().in_tree) { emit_signal(SceneStringNames::get_singleton()->body_entered, node); } @@ -420,8 +348,8 @@ void RigidBody::_body_inout(int p_status, ObjectID p_instance, int p_body_shape, if (E->get().shapes.empty()) { if (node) { - node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree); - node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree); + node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody::_body_enter_tree)); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody::_body_exit_tree)); if (in_tree) emit_signal(SceneStringNames::get_singleton()->body_exited, node); } @@ -619,70 +547,17 @@ real_t RigidBody::get_weight() const { return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8)); } -#ifndef DISABLE_DEPRECATED -void RigidBody::set_friction(real_t p_friction) { - - if (p_friction == 1.0 && physics_material_override.is_null()) { // default value, don't create an override for that - return; - } - - WARN_DEPRECATED_MSG("The method set_friction has been deprecated and will be removed in the future, use physics material instead."); - - ERR_FAIL_COND(p_friction < 0 || p_friction > 1); - - if (physics_material_override.is_null()) { - physics_material_override.instance(); - set_physics_material_override(physics_material_override); - } - physics_material_override->set_friction(p_friction); -} -real_t RigidBody::get_friction() const { - - WARN_DEPRECATED_MSG("The method get_friction has been deprecated and will be removed in the future, use physics material instead."); - - if (physics_material_override.is_null()) { - return 1; - } - - return physics_material_override->get_friction(); -} - -void RigidBody::set_bounce(real_t p_bounce) { - - if (p_bounce == 0.0 && physics_material_override.is_null()) { // default value, don't create an override for that - return; - } - - WARN_DEPRECATED_MSG("The method set_bounce has been deprecated and will be removed in the future, use physics material instead."); - - ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); - - if (physics_material_override.is_null()) { - physics_material_override.instance(); - set_physics_material_override(physics_material_override); - } - physics_material_override->set_bounce(p_bounce); -} -real_t RigidBody::get_bounce() const { - WARN_DEPRECATED_MSG("The method get_bounce has been deprecated and will be removed in the future, use physics material instead."); - if (physics_material_override.is_null()) { - return 0; - } - - return physics_material_override->get_bounce(); -} -#endif // DISABLE_DEPRECATED - void RigidBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { if (physics_material_override.is_valid()) { - if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics")) - physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody::_reload_physics_characteristics))) { + physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody::_reload_physics_characteristics)); + } } physics_material_override = p_physics_material_override; if (physics_material_override.is_valid()) { - physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody::_reload_physics_characteristics)); } _reload_physics_characteristics(); } @@ -862,9 +737,8 @@ void RigidBody::set_contact_monitor(bool p_enabled) { Node *node = Object::cast_to<Node>(obj); if (node) { - - node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree); - node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree); + node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody::_body_enter_tree)); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody::_body_exit_tree)); } } @@ -936,19 +810,9 @@ void RigidBody::_bind_methods() { ClassDB::bind_method(D_METHOD("set_weight", "weight"), &RigidBody::set_weight); ClassDB::bind_method(D_METHOD("get_weight"), &RigidBody::get_weight); -#ifndef DISABLE_DEPRECATED - ClassDB::bind_method(D_METHOD("set_friction", "friction"), &RigidBody::set_friction); - ClassDB::bind_method(D_METHOD("get_friction"), &RigidBody::get_friction); - - ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &RigidBody::set_bounce); - ClassDB::bind_method(D_METHOD("get_bounce"), &RigidBody::get_bounce); -#endif // DISABLE_DEPRECATED - ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody::set_physics_material_override); ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody::get_physics_material_override); - ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &RigidBody::_reload_physics_characteristics); - ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody::set_linear_velocity); ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody::get_linear_velocity); @@ -993,8 +857,6 @@ void RigidBody::_bind_methods() { ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody::is_able_to_sleep); ClassDB::bind_method(D_METHOD("_direct_state_changed"), &RigidBody::_direct_state_changed); - ClassDB::bind_method(D_METHOD("_body_enter_tree"), &RigidBody::_body_enter_tree); - ClassDB::bind_method(D_METHOD("_body_exit_tree"), &RigidBody::_body_exit_tree); ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &RigidBody::set_axis_lock); ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &RigidBody::get_axis_lock); @@ -1004,14 +866,10 @@ void RigidBody::_bind_methods() { BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState"))); ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Rigid,Static,Character,Kinematic"), "set_mode", "get_mode"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", PROPERTY_USAGE_EDITOR), "set_weight", "get_weight"); -#ifndef DISABLE_DEPRECATED - ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_friction", "get_friction"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_bounce", "get_bounce"); -#endif // DISABLE_DEPRECATED + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", PROPERTY_USAGE_EDITOR), "set_weight", "get_weight"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "continuous_cd"), "set_use_continuous_collision_detection", "is_using_continuous_collision_detection"); ADD_PROPERTY(PropertyInfo(Variant::INT, "contacts_reported", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_max_contacts_reported", "get_max_contacts_reported"); @@ -1027,10 +885,10 @@ void RigidBody::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Z); ADD_GROUP("Linear", "linear_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); ADD_GROUP("Angular", "angular_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity"), "set_angular_velocity", "get_angular_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); @@ -1104,6 +962,14 @@ Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_inf return Ref<KinematicCollision>(); } +Vector3 KinematicBody::get_linear_velocity() const { + return linear_velocity; +} + +Vector3 KinematicBody::get_angular_velocity() const { + return angular_velocity; +} + bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only) { Transform gt = get_global_transform(); @@ -1399,6 +1265,8 @@ void KinematicBody::_notification(int p_what) { void KinematicBody::_bind_methods() { + ClassDB::bind_method(D_METHOD("_direct_state_changed"), &KinematicBody::_direct_state_changed); + ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false)); ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true)); ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody::move_and_slide_with_snap, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true)); @@ -1424,7 +1292,18 @@ void KinematicBody::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_y", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Y); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_z", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Z); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); +} + +void KinematicBody::_direct_state_changed(Object *p_state) { +#ifdef DEBUG_ENABLED + PhysicsDirectBodyState *state = Object::cast_to<PhysicsDirectBodyState>(p_state); +#else + PhysicsDirectBodyState *state = (PhysicsDirectBodyState *)p_state; //trust it +#endif + + linear_velocity = state->get_linear_velocity(); + angular_velocity = state->get_angular_velocity(); } KinematicBody::KinematicBody() : @@ -1435,6 +1314,8 @@ KinematicBody::KinematicBody() : on_floor = false; on_ceiling = false; on_wall = false; + + PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); } KinematicBody::~KinematicBody() { @@ -1471,7 +1352,7 @@ Object *KinematicCollision::get_local_shape() const { Object *KinematicCollision::get_collider() const { - if (collision.collider) { + if (collision.collider.is_valid()) { return ObjectDB::get_instance(collision.collider); } @@ -1535,7 +1416,7 @@ void KinematicCollision::_bind_methods() { } KinematicCollision::KinematicCollision() { - collision.collider = 0; + collision.collider_shape = 0; collision.local_shape = 0; owner = NULL; @@ -1562,6 +1443,24 @@ void PhysicalBone::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) PhysicsServer::get_singleton()->body_apply_impulse(get_rid(), p_pos, p_impulse); } +void PhysicalBone::reset_physics_simulation_state() { + if (simulate_physics) { + _start_physics_simulation(); + } else { + _stop_physics_simulation(); + } +} + +void PhysicalBone::reset_to_rest_position() { + if (parent_skeleton) { + if (-1 == bone_id) { + set_global_transform(parent_skeleton->get_global_transform() * body_offset); + } else { + set_global_transform(parent_skeleton->get_global_transform() * parent_skeleton->get_bone_global_pose(bone_id) * body_offset); + } + } +} + bool PhysicalBone::PinJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { if (JointData::_set(p_name, p_value, j)) { return true; @@ -1610,9 +1509,9 @@ bool PhysicalBone::PinJointData::_get(const StringName &p_name, Variant &r_ret) void PhysicalBone::PinJointData::_get_property_list(List<PropertyInfo> *p_list) const { JointData::_get_property_list(p_list); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/damping", PROPERTY_HINT_RANGE, "0.01,8.0,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/impulse_clamp", PROPERTY_HINT_RANGE, "0.0,64.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/damping", PROPERTY_HINT_RANGE, "0.01,8.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/impulse_clamp", PROPERTY_HINT_RANGE, "0.0,64.0,0.01")); } bool PhysicalBone::ConeJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { @@ -1677,11 +1576,11 @@ bool PhysicalBone::ConeJointData::_get(const StringName &p_name, Variant &r_ret) void PhysicalBone::ConeJointData::_get_property_list(List<PropertyInfo> *p_list) const { JointData::_get_property_list(p_list); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/swing_span", PROPERTY_HINT_RANGE, "-180,180,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1,or_lesser,or_greater")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/relaxation", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/swing_span", PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1,or_lesser,or_greater")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/relaxation", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); } bool PhysicalBone::HingeJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { @@ -1754,11 +1653,11 @@ void PhysicalBone::HingeJointData::_get_property_list(List<PropertyInfo> *p_list JointData::_get_property_list(p_list); p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/angular_limit_enabled")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01")); } bool PhysicalBone::SliderJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { @@ -1858,17 +1757,17 @@ bool PhysicalBone::SliderJointData::_get(const StringName &p_name, Variant &r_re void PhysicalBone::SliderJointData::_get_property_list(List<PropertyInfo> *p_list) const { JointData::_get_property_list(p_list); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_upper")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_lower")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_damping", PROPERTY_HINT_RANGE, "0,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/linear_limit_upper")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/linear_limit_lower")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/linear_limit_softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/linear_limit_restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/linear_limit_damping", PROPERTY_HINT_RANGE, "0,16.0,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_damping", PROPERTY_HINT_RANGE, "0,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_damping", PROPERTY_HINT_RANGE, "0,16.0,0.01")); } bool PhysicalBone::SixDOFJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { @@ -2082,26 +1981,26 @@ void PhysicalBone::SixDOFJointData::_get_property_list(List<PropertyInfo> *p_lis const StringName axis_names[] = { "x", "y", "z" }; for (int i = 0; i < 3; ++i) { p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/linear_limit_enabled")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_limit_upper")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_limit_lower")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_limit_upper")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_limit_lower")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01")); p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/linear_spring_enabled")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_spring_stiffness")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_spring_damping")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_equilibrium_point")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_damping", PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_spring_stiffness")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_spring_damping")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_equilibrium_point")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_damping", PROPERTY_HINT_RANGE, "0.01,16,0.01")); p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/angular_limit_enabled")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_damping", PROPERTY_HINT_RANGE, "0.01,16,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/erp")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_damping", PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/erp")); p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/angular_spring_enabled")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_spring_stiffness")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_spring_damping")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_equilibrium_point")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_spring_stiffness")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_spring_damping")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_equilibrium_point")); } } @@ -2150,10 +2049,10 @@ void PhysicalBone::_get_property_list(List<PropertyInfo> *p_list) const { names += parent->get_bone_name(i); } - p_list->push_back(PropertyInfo(Variant::STRING, "bone_name", PROPERTY_HINT_ENUM, names)); + p_list->push_back(PropertyInfo(Variant::STRING_NAME, "bone_name", PROPERTY_HINT_ENUM, names)); } else { - p_list->push_back(PropertyInfo(Variant::STRING, "bone_name")); + p_list->push_back(PropertyInfo(Variant::STRING_NAME, "bone_name")); } if (joint_data) { @@ -2167,7 +2066,7 @@ void PhysicalBone::_notification(int p_what) { parent_skeleton = find_skeleton_parent(get_parent()); update_bone_id(); reset_to_rest_position(); - _reset_physics_simulation_state(); + reset_physics_simulation_state(); if (!joint.is_valid() && joint_data) { _reload_joint(); } @@ -2238,8 +2137,6 @@ void PhysicalBone::_bind_methods() { ClassDB::bind_method(D_METHOD("set_body_offset", "offset"), &PhysicalBone::set_body_offset); ClassDB::bind_method(D_METHOD("get_body_offset"), &PhysicalBone::get_body_offset); - ClassDB::bind_method(D_METHOD("is_static_body"), &PhysicalBone::is_static_body); - ClassDB::bind_method(D_METHOD("get_simulate_physics"), &PhysicalBone::get_simulate_physics); ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone::is_simulating_physics); @@ -2267,11 +2164,11 @@ void PhysicalBone::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "body_offset"), "set_body_offset", "get_body_offset"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_weight", "get_weight"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-10,10,0.01"), "set_gravity_scale", "get_gravity_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_weight", "get_weight"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-10,10,0.01"), "set_gravity_scale", "get_gravity_scale"); BIND_ENUM_CONSTANT(JOINT_TYPE_NONE); BIND_ENUM_CONSTANT(JOINT_TYPE_PIN); @@ -2508,26 +2405,13 @@ const Transform &PhysicalBone::get_joint_offset() const { return joint_offset; } -void PhysicalBone::set_static_body(bool p_static) { - - static_body = p_static; - - set_as_toplevel(!static_body); - - _reset_physics_simulation_state(); -} - -bool PhysicalBone::is_static_body() { - return static_body; -} - void PhysicalBone::set_simulate_physics(bool p_simulate) { if (simulate_physics == p_simulate) { return; } simulate_physics = p_simulate; - _reset_physics_simulation_state(); + reset_physics_simulation_state(); } bool PhysicalBone::get_simulate_physics() { @@ -2535,7 +2419,7 @@ bool PhysicalBone::get_simulate_physics() { } bool PhysicalBone::is_simulating_physics() { - return _internal_simulate_physics && !_internal_static_body; + return _internal_simulate_physics; } void PhysicalBone::set_bone_name(const String &p_name) { @@ -2618,8 +2502,6 @@ PhysicalBone::PhysicalBone() : #endif joint_data(NULL), parent_skeleton(NULL), - static_body(false), - _internal_static_body(false), simulate_physics(false), _internal_simulate_physics(false), bone_id(-1), @@ -2629,8 +2511,7 @@ PhysicalBone::PhysicalBone() : friction(1), gravity_scale(1) { - set_static_body(static_body); - _reset_physics_simulation_state(); + reset_physics_simulation_state(); } PhysicalBone::~PhysicalBone() { @@ -2657,8 +2538,7 @@ void PhysicalBone::update_bone_id() { parent_skeleton->bind_physical_bone_to_bone(bone_id, this); _fix_joint_offset(); - _internal_static_body = !static_body; // Force staticness reset - _reset_staticness_state(); + reset_physics_simulation_state(); } } @@ -2680,49 +2560,6 @@ void PhysicalBone::update_offset() { #endif } -void PhysicalBone::reset_to_rest_position() { - if (parent_skeleton) { - if (-1 == bone_id) { - set_global_transform(parent_skeleton->get_global_transform() * body_offset); - } else { - set_global_transform(parent_skeleton->get_global_transform() * parent_skeleton->get_bone_global_pose(bone_id) * body_offset); - } - } -} - -void PhysicalBone::_reset_physics_simulation_state() { - if (simulate_physics && !static_body) { - _start_physics_simulation(); - } else { - _stop_physics_simulation(); - } - - _reset_staticness_state(); -} - -void PhysicalBone::_reset_staticness_state() { - - if (parent_skeleton && -1 != bone_id) { - if (static_body && simulate_physics) { // With this check I'm sure the position of this body is updated only when it's necessary - - if (_internal_static_body) { - return; - } - - parent_skeleton->bind_child_node_to_bone(bone_id, this); - _internal_static_body = true; - } else { - - if (!_internal_static_body) { - return; - } - - parent_skeleton->unbind_child_node_from_bone(bone_id, this); - _internal_static_body = false; - } - } -} - void PhysicalBone::_start_physics_simulation() { if (_internal_simulate_physics || !parent_skeleton) { return; @@ -2732,17 +2569,27 @@ void PhysicalBone::_start_physics_simulation() { PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); + set_as_toplevel(true); _internal_simulate_physics = true; } void PhysicalBone::_stop_physics_simulation() { - if (!_internal_simulate_physics || !parent_skeleton) { + if (!parent_skeleton) { return; } - PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_STATIC); - PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), 0); - PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), 0); - PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), NULL, ""); - parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false); - _internal_simulate_physics = false; + if (parent_skeleton->get_animate_physical_bones()) { + PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_KINEMATIC); + PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); + PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); + } else { + PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_STATIC); + PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), 0); + PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), 0); + } + if (_internal_simulate_physics) { + PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), NULL, ""); + parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false); + set_as_toplevel(false); + _internal_simulate_physics = false; + } } diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index 05bcbe22f0..5362baf8ee 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -49,7 +49,6 @@ class PhysicsBody : public CollisionObject { protected: static void _bind_methods(); - void _notification(int p_what); PhysicsBody(PhysicsServer::BodyMode p_mode); public: @@ -89,14 +88,6 @@ protected: static void _bind_methods(); public: -#ifndef DISABLE_DEPRECATED - void set_friction(real_t p_friction); - real_t get_friction() const; - - void set_bounce(real_t p_bounce); - real_t get_bounce() const; -#endif - void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); Ref<PhysicsMaterial> get_physics_material_override() const; @@ -205,14 +196,6 @@ public: void set_weight(real_t p_weight); real_t get_weight() const; -#ifndef DISABLE_DEPRECATED - void set_friction(real_t p_friction); - real_t get_friction() const; - - void set_bounce(real_t p_bounce); - real_t get_bounce() const; -#endif - void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); Ref<PhysicsMaterial> get_physics_material_override() const; @@ -296,6 +279,9 @@ public: }; private: + Vector3 linear_velocity; + Vector3 angular_velocity; + uint16_t locked_axis; float margin; @@ -319,7 +305,12 @@ protected: void _notification(int p_what); static void _bind_methods(); + virtual void _direct_state_changed(Object *p_state); + public: + virtual Vector3 get_linear_velocity() const; + virtual Vector3 get_angular_velocity() const; + 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); @@ -562,8 +553,6 @@ private: Skeleton *parent_skeleton; Transform body_offset; Transform body_offset_inverse; - bool static_body; - bool _internal_static_body; bool simulate_physics; bool _internal_simulate_physics; int bone_id; @@ -613,9 +602,6 @@ public: void set_body_offset(const Transform &p_offset); const Transform &get_body_offset() const; - void set_static_body(bool p_static); - bool is_static_body(); - void set_simulate_physics(bool p_simulate); bool get_simulate_physics(); bool is_simulating_physics(); @@ -641,16 +627,15 @@ public: void apply_central_impulse(const Vector3 &p_impulse); void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse); + void reset_physics_simulation_state(); + void reset_to_rest_position(); + PhysicalBone(); ~PhysicalBone(); private: void update_bone_id(); void update_offset(); - void reset_to_rest_position(); - - void _reset_physics_simulation_state(); - void _reset_staticness_state(); void _start_physics_simulation(); void _stop_physics_simulation(); diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp index eacc6bcc0f..0699e366e0 100644 --- a/scene/3d/physics_joint.cpp +++ b/scene/3d/physics_joint.cpp @@ -172,9 +172,9 @@ void PinJoint::_bind_methods() { ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &PinJoint::set_param); ClassDB::bind_method(D_METHOD("get_param", "param"), &PinJoint::get_param); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "params/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_BIAS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "params/damping", PROPERTY_HINT_RANGE, "0.01,8.0,0.01"), "set_param", "get_param", PARAM_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "params/impulse_clamp", PROPERTY_HINT_RANGE, "0.0,64.0,0.01"), "set_param", "get_param", PARAM_IMPULSE_CLAMP); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_BIAS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/damping", PROPERTY_HINT_RANGE, "0.01,8.0,0.01"), "set_param", "get_param", PARAM_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/impulse_clamp", PROPERTY_HINT_RANGE, "0.0,64.0,0.01"), "set_param", "get_param", PARAM_IMPULSE_CLAMP); BIND_ENUM_CONSTANT(PARAM_BIAS); BIND_ENUM_CONSTANT(PARAM_DAMPING); @@ -257,18 +257,18 @@ void HingeJoint::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_lower_limit", "lower_limit"), &HingeJoint::_set_lower_limit); ClassDB::bind_method(D_METHOD("_get_lower_limit"), &HingeJoint::_get_lower_limit); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "params/bias", PROPERTY_HINT_RANGE, "0.00,0.99,0.01"), "set_param", "get_param", PARAM_BIAS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/bias", PROPERTY_HINT_RANGE, "0.00,0.99,0.01"), "set_param", "get_param", PARAM_BIAS); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit/enable"), "set_flag", "get_flag", FLAG_USE_LIMIT); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit/upper", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_upper_limit", "_get_upper_limit"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit/lower", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_lower_limit", "_get_lower_limit"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_LIMIT_BIAS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit/relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_RELAXATION); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/upper", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_upper_limit", "_get_upper_limit"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/lower", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_lower_limit", "_get_lower_limit"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_LIMIT_BIAS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_RELAXATION); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "motor/enable"), "set_flag", "get_flag", FLAG_ENABLE_MOTOR); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "motor/target_velocity", PROPERTY_HINT_RANGE, "-200,200,0.01,or_greater,or_lesser"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "motor/max_impulse", PROPERTY_HINT_RANGE, "0.01,1024,0.01"), "set_param", "get_param", PARAM_MOTOR_MAX_IMPULSE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/target_velocity", PROPERTY_HINT_RANGE, "-200,200,0.01,or_greater,or_lesser"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/max_impulse", PROPERTY_HINT_RANGE, "0.01,1024,0.01"), "set_param", "get_param", PARAM_MOTOR_MAX_IMPULSE); BIND_ENUM_CONSTANT(PARAM_BIAS); BIND_ENUM_CONSTANT(PARAM_LIMIT_UPPER); @@ -392,29 +392,29 @@ void SliderJoint::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_lower_limit_angular", "lower_limit_angular"), &SliderJoint::_set_lower_limit_angular); ClassDB::bind_method(D_METHOD("_get_lower_limit_angular"), &SliderJoint::_get_lower_limit_angular); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit/upper_distance", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_UPPER); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit/lower_distance", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_LOWER); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motion/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motion/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motion/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_ortho/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_ortho/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_ortho/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_DAMPING); - - ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_upper_limit_angular", "_get_upper_limit_angular"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_lower_limit_angular", "_get_lower_limit_angular"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_motion/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_motion/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_motion/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_ortho/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_ortho/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_ortho/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/upper_distance", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_UPPER); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/lower_distance", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_LOWER); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motion/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motion/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motion/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_DAMPING); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_upper_limit_angular", "_get_upper_limit_angular"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_lower_limit_angular", "_get_lower_limit_angular"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motion/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motion/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motion/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_ortho/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_ortho/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_ortho/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_DAMPING); BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_UPPER); BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_LOWER); @@ -541,12 +541,12 @@ void ConeTwistJoint::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_twist_span", "twist_span"), &ConeTwistJoint::_set_twist_span); ClassDB::bind_method(D_METHOD("_get_twist_span"), &ConeTwistJoint::_get_twist_span); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "swing_span", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_swing_span", "_get_swing_span"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1"), "_set_twist_span", "_get_twist_span"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "swing_span", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_swing_span", "_get_swing_span"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1"), "_set_twist_span", "_get_twist_span"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_BIAS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "relaxation", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_RELAXATION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_BIAS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "relaxation", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_RELAXATION); BIND_ENUM_CONSTANT(PARAM_SWING_SPAN); BIND_ENUM_CONSTANT(PARAM_TWIST_SPAN); @@ -711,92 +711,92 @@ void Generic6DOFJoint::_bind_methods() { ClassDB::bind_method(D_METHOD("get_precision"), &Generic6DOFJoint::get_precision); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_LIMIT); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_x/upper_distance"), "set_param_x", "get_param_x", PARAM_LINEAR_UPPER_LIMIT); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_x/lower_distance"), "set_param_x", "get_param_x", PARAM_LINEAR_LOWER_LIMIT); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_x/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_LIMIT_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_x/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_x/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/upper_distance"), "set_param_x", "get_param_x", PARAM_LINEAR_UPPER_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/lower_distance"), "set_param_x", "get_param_x", PARAM_LINEAR_LOWER_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_LIMIT_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_MOTOR); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_x/target_velocity"), "set_param_x", "get_param_x", PARAM_LINEAR_MOTOR_TARGET_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_x/force_limit"), "set_param_x", "get_param_x", PARAM_LINEAR_MOTOR_FORCE_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_x/target_velocity"), "set_param_x", "get_param_x", PARAM_LINEAR_MOTOR_TARGET_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_x/force_limit"), "set_param_x", "get_param_x", PARAM_LINEAR_MOTOR_FORCE_LIMIT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_spring_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_SPRING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_spring_x/stiffness"), "set_param_x", "get_param_x", PARAM_LINEAR_SPRING_STIFFNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_spring_x/damping"), "set_param_x", "get_param_x", PARAM_LINEAR_SPRING_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_spring_x/equilibrium_point"), "set_param_x", "get_param_x", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_x/stiffness"), "set_param_x", "get_param_x", PARAM_LINEAR_SPRING_STIFFNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_x/damping"), "set_param_x", "get_param_x", PARAM_LINEAR_SPRING_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_x/equilibrium_point"), "set_param_x", "get_param_x", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_ANGULAR_LIMIT); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_x/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_x", "_get_angular_hi_limit_x"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_x/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_x", "_get_angular_lo_limit_x"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit_x/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_LIMIT_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit_x/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit_x/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit_x/force_limit"), "set_param_x", "get_param_x", PARAM_ANGULAR_FORCE_LIMIT); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit_x/erp"), "set_param_x", "get_param_x", PARAM_ANGULAR_ERP); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_x/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_x", "_get_angular_hi_limit_x"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_x/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_x", "_get_angular_lo_limit_x"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_LIMIT_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/force_limit"), "set_param_x", "get_param_x", PARAM_ANGULAR_FORCE_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/erp"), "set_param_x", "get_param_x", PARAM_ANGULAR_ERP); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_motor_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_MOTOR); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_motor_x/target_velocity"), "set_param_x", "get_param_x", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_motor_x/force_limit"), "set_param_x", "get_param_x", PARAM_ANGULAR_MOTOR_FORCE_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_x/target_velocity"), "set_param_x", "get_param_x", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_x/force_limit"), "set_param_x", "get_param_x", PARAM_ANGULAR_MOTOR_FORCE_LIMIT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_spring_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_ANGULAR_SPRING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_spring_x/stiffness"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_STIFFNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_spring_x/damping"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_spring_x/equilibrium_point"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_x/stiffness"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_STIFFNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_x/damping"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_x/equilibrium_point"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_LIMIT); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_y/upper_distance"), "set_param_y", "get_param_y", PARAM_LINEAR_UPPER_LIMIT); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_y/lower_distance"), "set_param_y", "get_param_y", PARAM_LINEAR_LOWER_LIMIT); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_y/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_LIMIT_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_y/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_y/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/upper_distance"), "set_param_y", "get_param_y", PARAM_LINEAR_UPPER_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/lower_distance"), "set_param_y", "get_param_y", PARAM_LINEAR_LOWER_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_LIMIT_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_MOTOR); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_y/target_velocity"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_TARGET_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_y/force_limit"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_FORCE_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_y/target_velocity"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_TARGET_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_y/force_limit"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_FORCE_LIMIT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_spring_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_SPRING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_spring_y/stiffness"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_STIFFNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_spring_y/damping"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_spring_y/equilibrium_point"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_y/stiffness"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_STIFFNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_y/damping"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_y/equilibrium_point"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_ANGULAR_LIMIT); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_y/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_y", "_get_angular_hi_limit_y"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_y/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_y", "_get_angular_lo_limit_y"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit_y/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_LIMIT_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit_y/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit_y/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit_y/force_limit"), "set_param_y", "get_param_y", PARAM_ANGULAR_FORCE_LIMIT); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit_y/erp"), "set_param_y", "get_param_y", PARAM_ANGULAR_ERP); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_y/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_y", "_get_angular_hi_limit_y"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_y/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_y", "_get_angular_lo_limit_y"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_LIMIT_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/force_limit"), "set_param_y", "get_param_y", PARAM_ANGULAR_FORCE_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/erp"), "set_param_y", "get_param_y", PARAM_ANGULAR_ERP); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_motor_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_MOTOR); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_motor_y/target_velocity"), "set_param_y", "get_param_y", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_motor_y/force_limit"), "set_param_y", "get_param_y", PARAM_ANGULAR_MOTOR_FORCE_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_y/target_velocity"), "set_param_y", "get_param_y", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_y/force_limit"), "set_param_y", "get_param_y", PARAM_ANGULAR_MOTOR_FORCE_LIMIT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_spring_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_ANGULAR_SPRING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_spring_y/stiffness"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_STIFFNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_spring_y/damping"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_spring_y/equilibrium_point"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_y/stiffness"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_STIFFNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_y/damping"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_y/equilibrium_point"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_LIMIT); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_z/upper_distance"), "set_param_z", "get_param_z", PARAM_LINEAR_UPPER_LIMIT); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_z/lower_distance"), "set_param_z", "get_param_z", PARAM_LINEAR_LOWER_LIMIT); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_z/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_LIMIT_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_z/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_z/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/upper_distance"), "set_param_z", "get_param_z", PARAM_LINEAR_UPPER_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/lower_distance"), "set_param_z", "get_param_z", PARAM_LINEAR_LOWER_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_LIMIT_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_MOTOR); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_z/target_velocity"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_TARGET_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_z/force_limit"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_FORCE_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_z/target_velocity"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_TARGET_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_z/force_limit"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_FORCE_LIMIT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_spring_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_SPRING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_spring_z/stiffness"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_STIFFNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_spring_z/damping"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_spring_z/equilibrium_point"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_z/stiffness"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_STIFFNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_z/damping"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_z/equilibrium_point"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_ANGULAR_LIMIT); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_z/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_z", "_get_angular_hi_limit_z"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_z/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_z", "_get_angular_lo_limit_z"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit_z/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_LIMIT_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit_z/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit_z/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit_z/force_limit"), "set_param_z", "get_param_z", PARAM_ANGULAR_FORCE_LIMIT); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit_z/erp"), "set_param_z", "get_param_z", PARAM_ANGULAR_ERP); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_z/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_z", "_get_angular_hi_limit_z"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_z/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_z", "_get_angular_lo_limit_z"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_LIMIT_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/force_limit"), "set_param_z", "get_param_z", PARAM_ANGULAR_FORCE_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/erp"), "set_param_z", "get_param_z", PARAM_ANGULAR_ERP); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_motor_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_MOTOR); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_motor_z/target_velocity"), "set_param_z", "get_param_z", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_motor_z/force_limit"), "set_param_z", "get_param_z", PARAM_ANGULAR_MOTOR_FORCE_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_z/target_velocity"), "set_param_z", "get_param_z", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_z/force_limit"), "set_param_z", "get_param_z", PARAM_ANGULAR_MOTOR_FORCE_LIMIT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_spring_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_ANGULAR_SPRING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_spring_z/stiffness"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_STIFFNESS); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_spring_z/damping"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_spring_z/equilibrium_point"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_z/stiffness"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_STIFFNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_z/damping"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_z/equilibrium_point"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT); ADD_PROPERTY(PropertyInfo(Variant::INT, "precision", PROPERTY_HINT_RANGE, "1,99999,1"), "set_precision", "get_precision"); diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp index fbe3cd7a3e..be1426f13c 100644 --- a/scene/3d/ray_cast.cpp +++ b/scene/3d/ray_cast.cpp @@ -80,7 +80,7 @@ bool RayCast::is_colliding() const { } Object *RayCast::get_collider() const { - if (against == 0) + if (against.is_null()) return NULL; return ObjectDB::get_instance(against); @@ -186,7 +186,7 @@ void RayCast::_notification(int p_what) { _update_raycast_state(); if (prev_collision_state != collided && get_tree()->is_debugging_collisions_hint()) { if (debug_material.is_valid()) { - Ref<SpatialMaterial> line_material = static_cast<Ref<SpatialMaterial> >(debug_material); + Ref<StandardMaterial3D> line_material = static_cast<Ref<StandardMaterial3D> >(debug_material); line_material->set_albedo(collided ? Color(1.0, 0, 0) : Color(1.0, 0.8, 0.6)); } } @@ -219,7 +219,7 @@ void RayCast::_update_raycast_state() { against_shape = rr.shape; } else { collided = false; - against = 0; + against = ObjectID(); against_shape = 0; } } @@ -333,11 +333,10 @@ void RayCast::_bind_methods() { void RayCast::_create_debug_shape() { if (!debug_material.is_valid()) { - debug_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + debug_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); - Ref<SpatialMaterial> line_material = static_cast<Ref<SpatialMaterial> >(debug_material); - line_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - line_material->set_line_width(3.0); + Ref<StandardMaterial3D> line_material = static_cast<Ref<StandardMaterial3D> >(debug_material); + line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); line_material->set_albedo(Color(1.0, 0.8, 0.6)); } @@ -363,8 +362,7 @@ void RayCast::_update_debug_shape() { return; Ref<ArrayMesh> mesh = mi->get_mesh(); - if (mesh->get_surface_count() > 0) - mesh->surface_remove(0); + mesh->clear_surfaces(); Array a; a.resize(Mesh::ARRAY_MAX); @@ -395,7 +393,7 @@ void RayCast::_clear_debug_shape() { RayCast::RayCast() { enabled = false; - against = 0; + collided = false; against_shape = 0; collision_mask = 1; diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp index 2a5a84741f..3cf8e43ec2 100644 --- a/scene/3d/reflection_probe.cpp +++ b/scene/3d/reflection_probe.cpp @@ -186,9 +186,9 @@ AABB ReflectionProbe::get_aabb() const { aabb.size = origin_offset + extents; return aabb; } -PoolVector<Face3> ReflectionProbe::get_faces(uint32_t p_usage_flags) const { +Vector<Face3> ReflectionProbe::get_faces(uint32_t p_usage_flags) const { - return PoolVector<Face3>(); + return Vector<Face3>(); } void ReflectionProbe::_validate_property(PropertyInfo &property) const { @@ -239,8 +239,8 @@ void ReflectionProbe::_bind_methods() { ClassDB::bind_method(D_METHOD("get_update_mode"), &ReflectionProbe::get_update_mode); ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Once,Always"), "set_update_mode", "get_update_mode"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "intensity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_intensity", "get_intensity"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,16384,0.1,or_greater"), "set_max_distance", "get_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "intensity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_intensity", "get_intensity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,16384,0.1,or_greater"), "set_max_distance", "get_max_distance"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "origin_offset"), "set_origin_offset", "get_origin_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "box_projection"), "set_enable_box_projection", "is_box_projection_enabled"); @@ -250,8 +250,8 @@ void ReflectionProbe::_bind_methods() { ADD_GROUP("Interior", "interior_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior_enable"), "set_as_interior", "is_set_as_interior"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "interior_ambient_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_interior_ambient", "get_interior_ambient"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "interior_ambient_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_interior_ambient_energy", "get_interior_ambient_energy"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "interior_ambient_contrib", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_interior_ambient_probe_contribution", "get_interior_ambient_probe_contribution"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "interior_ambient_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_interior_ambient_energy", "get_interior_ambient_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "interior_ambient_contrib", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_interior_ambient_probe_contribution", "get_interior_ambient_probe_contribution"); BIND_ENUM_CONSTANT(UPDATE_ONCE); BIND_ENUM_CONSTANT(UPDATE_ALWAYS); diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h index 28ca680e9f..57c1b0a320 100644 --- a/scene/3d/reflection_probe.h +++ b/scene/3d/reflection_probe.h @@ -103,7 +103,7 @@ public: UpdateMode get_update_mode() const; virtual AABB get_aabb() const; - virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; + virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const; ReflectionProbe(); ~ReflectionProbe(); diff --git a/scene/3d/remote_transform.cpp b/scene/3d/remote_transform.cpp index 983af7a9ec..9ef43647ba 100644 --- a/scene/3d/remote_transform.cpp +++ b/scene/3d/remote_transform.cpp @@ -31,7 +31,7 @@ #include "remote_transform.h" void RemoteTransform::_update_cache() { - cache = 0; + cache = ObjectID(); if (has_node(remote_node)) { Node *node = get_node(remote_node); if (!node || this == node || node->is_a_parent_of(this) || this->is_a_parent_of(node)) { @@ -47,7 +47,7 @@ void RemoteTransform::_update_remote() { if (!is_inside_tree()) return; - if (!cache) + if (cache.is_null()) return; Spatial *n = Object::cast_to<Spatial>(ObjectDB::get_instance(cache)); @@ -114,7 +114,7 @@ void RemoteTransform::_notification(int p_what) { if (!is_inside_tree()) break; - if (cache) { + if (cache.is_valid()) { _update_remote(); } @@ -219,6 +219,5 @@ RemoteTransform::RemoteTransform() { update_remote_rotation = true; update_remote_scale = true; - cache = 0; set_notify_transform(true); } diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index 17e67c47d1..b2252bcb04 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -30,8 +30,8 @@ #include "skeleton.h" +#include "core/engine.h" #include "core/message_queue.h" - #include "core/project_settings.h" #include "scene/3d/physics_body.h" #include "scene/resources/surface_tool.h" @@ -40,6 +40,7 @@ void SkinReference::_skin_changed() { if (skeleton_node) { skeleton_node->_make_dirty(); } + skeleton_version = 0; } void SkinReference::_bind_methods() { @@ -137,7 +138,7 @@ bool Skeleton::_get(const StringName &p_path, Variant &r_ret) const { else if (what == "bound_children") { Array children; - for (const List<uint32_t>::Element *E = bones[which].nodes_bound.front(); E; E = E->next()) { + for (const List<ObjectID>::Element *E = bones[which].nodes_bound.front(); E; E = E->next()) { Object *obj = ObjectDB::get_instance(E->get()); ERR_CONTINUE(!obj); @@ -301,7 +302,7 @@ void Skeleton::_notification(int p_what) { b.global_pose_override_amount = 0.0; } - for (List<uint32_t>::Element *E = b.nodes_bound.front(); E; E = E->next()) { + for (List<ObjectID>::Element *E = b.nodes_bound.front(); E; E = E->next()) { Object *obj = ObjectDB::get_instance(E->get()); ERR_CONTINUE(!obj); @@ -321,10 +322,49 @@ void Skeleton::_notification(int p_what) { if (E->get()->bind_count != bind_count) { VS::get_singleton()->skeleton_allocate(skeleton, bind_count); E->get()->bind_count = bind_count; + E->get()->skin_bone_indices.resize(bind_count); + E->get()->skin_bone_indices_ptrs = E->get()->skin_bone_indices.ptrw(); + } + + if (E->get()->skeleton_version != version) { + + for (uint32_t i = 0; i < bind_count; i++) { + StringName bind_name = skin->get_bind_name(i); + + if (bind_name != StringName()) { + //bind name used, use this + bool found = false; + for (int j = 0; j < len; j++) { + if (bonesptr[j].name == bind_name) { + E->get()->skin_bone_indices_ptrs[i] = j; + found = true; + break; + } + } + + if (!found) { + ERR_PRINT("Skin bind #" + itos(i) + " contains named bind '" + String(bind_name) + "' but Skeleton has no bone by that name."); + E->get()->skin_bone_indices_ptrs[i] = 0; + } + } else if (skin->get_bind_bone(i) >= 0) { + int bind_index = skin->get_bind_bone(i); + if (bind_index >= len) { + ERR_PRINT("Skin bind #" + itos(i) + " contains bone index bind: " + itos(bind_index) + " , which is greater than the skeleton bone count: " + itos(len) + "."); + E->get()->skin_bone_indices_ptrs[i] = 0; + } else { + E->get()->skin_bone_indices_ptrs[i] = bind_index; + } + } else { + ERR_PRINT("Skin bind #" + itos(i) + " does not contain a name nor a bone index."); + E->get()->skin_bone_indices_ptrs[i] = 0; + } + } + + E->get()->skeleton_version = version; } for (uint32_t i = 0; i < bind_count; i++) { - uint32_t bone_index = skin->get_bind_bone(i); + uint32_t bone_index = E->get()->skin_bone_indices_ptrs[i]; ERR_CONTINUE(bone_index >= (uint32_t)len); vs->skeleton_bone_set_transform(skeleton, i, bonesptr[bone_index].pose_global * skin->get_bind_pose(i)); } @@ -332,6 +372,27 @@ void Skeleton::_notification(int p_what) { dirty = false; } break; + +#ifndef _3D_DISABLED + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + // This is active only if the skeleton animates the physical bones + // and the state of the bone is not active. + if (animate_physical_bones) { + for (int i = 0; i < bones.size(); i += 1) { + if (bones[i].physical_bone) { + if (bones[i].physical_bone->is_simulating_physics() == false) { + bones[i].physical_bone->reset_to_rest_position(); + } + } + } + } + } break; + case NOTIFICATION_READY: { + if (Engine::get_singleton()->is_editor_hint()) { + set_physics_process_internal(true); + } + } break; +#endif } } @@ -366,6 +427,7 @@ void Skeleton::add_bone(const String &p_name) { b.name = p_name; bones.push_back(b); process_order_dirty = true; + version++; _make_dirty(); update_gizmo(); } @@ -483,9 +545,9 @@ void Skeleton::bind_child_node_to_bone(int p_bone, Node *p_node) { ERR_FAIL_NULL(p_node); ERR_FAIL_INDEX(p_bone, bones.size()); - uint32_t id = p_node->get_instance_id(); + ObjectID id = p_node->get_instance_id(); - for (const List<uint32_t>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) { + for (const List<ObjectID>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) { if (E->get() == id) return; // already here @@ -498,14 +560,14 @@ void Skeleton::unbind_child_node_from_bone(int p_bone, Node *p_node) { ERR_FAIL_NULL(p_node); ERR_FAIL_INDEX(p_bone, bones.size()); - uint32_t id = p_node->get_instance_id(); + ObjectID id = p_node->get_instance_id(); bones.write[p_bone].nodes_bound.erase(id); } void Skeleton::get_bound_child_nodes_to_bone(int p_bone, List<Node *> *p_bound) const { ERR_FAIL_INDEX(p_bone, bones.size()); - for (const List<uint32_t>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) { + for (const List<ObjectID>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) { Object *obj = ObjectDB::get_instance(E->get()); ERR_CONTINUE(!obj); @@ -517,7 +579,7 @@ void Skeleton::clear_bones() { bones.clear(); process_order_dirty = true; - + version++; _make_dirty(); } @@ -584,6 +646,27 @@ void Skeleton::localize_rests() { #ifndef _3D_DISABLED +void Skeleton::set_animate_physical_bones(bool p_animate) { + animate_physical_bones = p_animate; + + if (Engine::get_singleton()->is_editor_hint() == false) { + bool sim = false; + for (int i = 0; i < bones.size(); i += 1) { + if (bones[i].physical_bone) { + bones[i].physical_bone->reset_physics_simulation_state(); + if (bones[i].physical_bone->is_simulating_physics()) { + sim = true; + } + } + } + set_physics_process_internal(sim == false && p_animate); + } +} + +bool Skeleton::get_animate_physical_bones() const { + return animate_physical_bones; +} + void Skeleton::bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone) { ERR_FAIL_INDEX(p_bone, bones.size()); ERR_FAIL_COND(bones[p_bone].physical_bone); @@ -653,12 +736,14 @@ void _pb_stop_simulation(Node *p_node) { PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node); if (pb) { pb->set_simulate_physics(false); - pb->set_static_body(false); } } void Skeleton::physical_bones_stop_simulation() { _pb_stop_simulation(this); + if (Engine::get_singleton()->is_editor_hint() == false && animate_physical_bones) { + set_physics_process_internal(true); + } } void _pb_start_simulation(const Skeleton *p_skeleton, Node *p_node, const Vector<int> &p_sim_bones) { @@ -669,24 +754,17 @@ void _pb_start_simulation(const Skeleton *p_skeleton, Node *p_node, const Vector PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node); if (pb) { - bool sim = false; for (int i = p_sim_bones.size() - 1; 0 <= i; --i) { if (p_sim_bones[i] == pb->get_bone_id() || p_skeleton->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) { - sim = true; + pb->set_simulate_physics(true); break; } } - - pb->set_simulate_physics(true); - if (sim) { - pb->set_static_body(false); - } else { - pb->set_static_body(true); - } } } void Skeleton::physical_bones_start_simulation_on(const Array &p_bones) { + set_physics_process_internal(false); Vector<int> sim_bones; if (p_bones.size() <= 0) { @@ -695,7 +773,8 @@ void Skeleton::physical_bones_start_simulation_on(const Array &p_bones) { sim_bones.resize(p_bones.size()); int c = 0; for (int i = sim_bones.size() - 1; 0 <= i; --i) { - if (Variant::STRING == p_bones.get(i).get_type()) { + Variant::Type type = p_bones.get(i).get_type(); + if (Variant::STRING == type || Variant::STRING_NAME == type) { int bone_id = find_bone(p_bones.get(i)); if (bone_id != -1) sim_bones.write[c++] = bone_id; @@ -791,8 +870,10 @@ Ref<SkinReference> Skeleton::register_skin(const Ref<Skin> &p_skin) { skin_bindings.insert(skin_ref.operator->()); - skin->connect("changed", skin_ref.operator->(), "_skin_changed"); - _make_dirty(); + skin->connect_compat("changed", skin_ref.operator->(), "_skin_changed"); + + _make_dirty(); //skin needs to be updated, so update skeleton + return skin_ref; } @@ -836,11 +917,15 @@ void Skeleton::_bind_methods() { #ifndef _3D_DISABLED + ClassDB::bind_method(D_METHOD("set_animate_physical_bones"), &Skeleton::set_animate_physical_bones); + ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton::get_animate_physical_bones); + ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation); ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &Skeleton::physical_bones_start_simulation_on, DEFVAL(Array())); ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton::physical_bones_add_collision_exception); ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton::physical_bones_remove_collision_exception); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "animate_physical_bones"), "set_animate_physical_bones", "get_animate_physical_bones"); #endif // _3D_DISABLED BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON); @@ -848,7 +933,9 @@ void Skeleton::_bind_methods() { Skeleton::Skeleton() { + animate_physical_bones = true; dirty = false; + version = 1; process_order_dirty = true; } diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h index 056f70e22b..76fd96f30a 100644 --- a/scene/3d/skeleton.h +++ b/scene/3d/skeleton.h @@ -51,6 +51,9 @@ class SkinReference : public Reference { RID skeleton; Ref<Skin> skin; uint32_t bind_count = 0; + uint64_t skeleton_version = 0; + Vector<uint32_t> skin_bone_indices; + uint32_t *skin_bone_indices_ptrs; void _skin_changed(); protected: @@ -99,7 +102,7 @@ private: PhysicalBone *cache_parent_physical_bone; #endif // _3D_DISABLED - List<uint32_t> nodes_bound; + List<ObjectID> nodes_bound; Bone() { parent = -1; @@ -115,6 +118,7 @@ private: } }; + bool animate_physical_bones; Vector<Bone> bones; Vector<int> process_order; bool process_order_dirty; @@ -122,6 +126,8 @@ private: void _make_dirty(); bool dirty; + uint64_t version; + // bind helpers Array _get_bound_child_nodes_to_bone(int p_bone) const { @@ -199,6 +205,9 @@ public: #ifndef _3D_DISABLED // Physical bone API + void set_animate_physical_bones(bool p_animate); + bool get_animate_physical_bones() const; + void bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone); void unbind_physical_bone_from_bone(int p_bone); diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp index ef13985bf4..3859a278ef 100644 --- a/scene/3d/soft_body.cpp +++ b/scene/3d/soft_body.cpp @@ -47,7 +47,10 @@ void SoftBodyVisualServerHandler::prepare(RID p_mesh, int p_surface) { mesh = p_mesh; surface = p_surface; - +#ifndef _MSC_VER +#warning Softbody is not working, needs to be redone considering that these functions no longer exist +#endif +#if 0 const uint32_t surface_format = VS::get_singleton()->mesh_surface_get_format(mesh, surface); const int surface_vertex_len = VS::get_singleton()->mesh_surface_get_array_len(mesh, p_surface); const int surface_index_len = VS::get_singleton()->mesh_surface_get_array_index_len(mesh, p_surface); @@ -57,6 +60,7 @@ void SoftBodyVisualServerHandler::prepare(RID p_mesh, int p_surface) { stride = VS::get_singleton()->mesh_surface_make_offsets_from_format(surface_format, surface_vertex_len, surface_index_len, surface_offsets); offset_vertices = surface_offsets[VS::ARRAY_VERTEX]; offset_normal = surface_offsets[VS::ARRAY_NORMAL]; +#endif } void SoftBodyVisualServerHandler::clear() { @@ -69,11 +73,11 @@ void SoftBodyVisualServerHandler::clear() { } void SoftBodyVisualServerHandler::open() { - write_buffer = buffer.write(); + write_buffer = buffer.ptrw(); } void SoftBodyVisualServerHandler::close() { - write_buffer.release(); + //write_buffer.release(); } void SoftBodyVisualServerHandler::commit_changes() { @@ -145,7 +149,7 @@ bool SoftBody::_get(const StringName &p_name, Variant &r_ret) const { if ("pinned_points" == which) { Array arr_ret; const int pinned_points_indices_size = pinned_points.size(); - PoolVector<PinnedPoint>::Read r = pinned_points.read(); + const PinnedPoint *r = pinned_points.ptr(); arr_ret.resize(pinned_points_indices_size); for (int i = 0; i < pinned_points_indices_size; ++i) { @@ -170,7 +174,7 @@ void SoftBody::_get_property_list(List<PropertyInfo> *p_list) const { const int pinned_points_indices_size = pinned_points.size(); - p_list->push_back(PropertyInfo(Variant::POOL_INT_ARRAY, "pinned_points")); + p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "pinned_points")); for (int i = 0; i < pinned_points_indices_size; ++i) { p_list->push_back(PropertyInfo(Variant::INT, "attachments/" + itos(i) + "/point_index")); @@ -184,7 +188,7 @@ bool SoftBody::_set_property_pinned_points_indices(const Array &p_indices) { const int p_indices_size = p_indices.size(); { // Remove the pined points on physics server that will be removed by resize - PoolVector<PinnedPoint>::Read r = pinned_points.read(); + const PinnedPoint *r = pinned_points.ptr(); if (p_indices_size < pinned_points.size()) { for (int i = pinned_points.size() - 1; i >= p_indices_size; --i) { pin_point(r[i].point_index, false); @@ -194,7 +198,7 @@ bool SoftBody::_set_property_pinned_points_indices(const Array &p_indices) { pinned_points.resize(p_indices_size); - PoolVector<PinnedPoint>::Write w = pinned_points.write(); + PinnedPoint *w = pinned_points.ptrw(); int point_index; for (int i = 0; i < p_indices_size; ++i) { point_index = p_indices.get(i); @@ -214,11 +218,11 @@ bool SoftBody::_set_property_pinned_points_attachment(int p_item, const String & } if ("spatial_attachment_path" == p_what) { - PoolVector<PinnedPoint>::Write w = pinned_points.write(); + PinnedPoint *w = pinned_points.ptrw(); pin_point(w[p_item].point_index, true, p_value); _make_cache_dirty(); } else if ("offset" == p_what) { - PoolVector<PinnedPoint>::Write w = pinned_points.write(); + PinnedPoint *w = pinned_points.ptrw(); w[p_item].offset = p_value; } else { return false; @@ -231,7 +235,7 @@ bool SoftBody::_get_property_pinned_points(int p_item, const String &p_what, Var if (pinned_points.size() <= p_item) { return false; } - PoolVector<PinnedPoint>::Read r = pinned_points.read(); + const PinnedPoint *r = pinned_points.ptr(); if ("point_index" == p_what) { r_ret = r[p_item].point_index; @@ -247,7 +251,7 @@ bool SoftBody::_get_property_pinned_points(int p_item, const String &p_what, Var } void SoftBody::_changed_callback(Object *p_changed, const char *p_prop) { - update_physics_server(); + prepare_physics_server(); _reset_points_offsets(); #ifdef TOOLS_ENABLED if (p_changed == this) { @@ -267,7 +271,7 @@ void SoftBody::_notification(int p_what) { RID space = get_world()->get_space(); PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, space); - update_physics_server(); + prepare_physics_server(); } break; case NOTIFICATION_READY: { if (!parent_collision_ignore.is_empty()) @@ -290,21 +294,6 @@ void SoftBody::_notification(int p_what) { set_notify_transform(true); } break; - case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { - - if (!simulation_started) - return; - - _update_cache_pin_points_datas(); - // Submit bone attachment - const int pinned_points_indices_size = pinned_points.size(); - PoolVector<PinnedPoint>::Read r = pinned_points.read(); - for (int i = 0; i < pinned_points_indices_size; ++i) { - if (r[i].spatial_attachment) { - PhysicsServer::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, r[i].spatial_attachment->get_global_transform().xform(r[i].offset)); - } - } - } break; case NOTIFICATION_VISIBILITY_CHANGED: { _update_pickable(); @@ -330,8 +319,6 @@ void SoftBody::_notification(int p_what) { void SoftBody::_bind_methods() { - ClassDB::bind_method(D_METHOD("_draw_soft_mesh"), &SoftBody::_draw_soft_mesh); - ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftBody::set_collision_mask); ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftBody::get_collision_mask); @@ -387,14 +374,14 @@ void SoftBody::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "parent_collision_ignore", PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE, "Parent collision object"), "set_parent_collision_ignore", "get_parent_collision_ignore"); ADD_PROPERTY(PropertyInfo(Variant::INT, "simulation_precision", PROPERTY_HINT_RANGE, "1,100,1"), "set_simulation_precision", "get_simulation_precision"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "total_mass", PROPERTY_HINT_RANGE, "0.01,10000,1"), "set_total_mass", "get_total_mass"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_linear_stiffness", "get_linear_stiffness"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "areaAngular_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_areaAngular_stiffness", "get_areaAngular_stiffness"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_volume_stiffness", "get_volume_stiffness"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "pressure_coefficient"), "set_pressure_coefficient", "get_pressure_coefficient"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "damping_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_damping_coefficient", "get_damping_coefficient"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "drag_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_coefficient", "get_drag_coefficient"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "pose_matching_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_pose_matching_coefficient", "get_pose_matching_coefficient"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_mass", PROPERTY_HINT_RANGE, "0.01,10000,1"), "set_total_mass", "get_total_mass"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_linear_stiffness", "get_linear_stiffness"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "areaAngular_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_areaAngular_stiffness", "get_areaAngular_stiffness"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_volume_stiffness", "get_volume_stiffness"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pressure_coefficient"), "set_pressure_coefficient", "get_pressure_coefficient"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_damping_coefficient", "get_damping_coefficient"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "drag_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_coefficient", "get_drag_coefficient"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pose_matching_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_pose_matching_coefficient", "get_pose_matching_coefficient"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ray_pickable"), "set_ray_pickable", "is_ray_pickable"); } @@ -421,6 +408,21 @@ String SoftBody::get_configuration_warning() const { return warning; } +void SoftBody::_update_physics_server() { + if (!simulation_started) + return; + + _update_cache_pin_points_datas(); + // Submit bone attachment + const int pinned_points_indices_size = pinned_points.size(); + const PinnedPoint *r = pinned_points.ptr(); + for (int i = 0; i < pinned_points_indices_size; ++i) { + if (r[i].spatial_attachment) { + PhysicsServer::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, r[i].spatial_attachment->get_global_transform().xform(r[i].offset)); + } + } +} + void SoftBody::_draw_soft_mesh() { if (get_mesh().is_null()) return; @@ -435,6 +437,8 @@ void SoftBody::_draw_soft_mesh() { call_deferred("set_transform", Transform()); } + _update_physics_server(); + visual_server_handler.open(); PhysicsServer::get_singleton()->soft_body_update_visual_server(physics_rid, &visual_server_handler); visual_server_handler.close(); @@ -442,7 +446,7 @@ void SoftBody::_draw_soft_mesh() { visual_server_handler.commit_changes(); } -void SoftBody::update_physics_server() { +void SoftBody::prepare_physics_server() { if (Engine::get_singleton()->is_editor_hint()) { @@ -458,12 +462,12 @@ void SoftBody::update_physics_server() { become_mesh_owner(); PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()); - VS::get_singleton()->connect("frame_pre_draw", this, "_draw_soft_mesh"); + VS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &SoftBody::_draw_soft_mesh)); } else { PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, NULL); - if (VS::get_singleton()->is_connected("frame_pre_draw", this, "_draw_soft_mesh")) { - VS::get_singleton()->disconnect("frame_pre_draw", this, "_draw_soft_mesh"); + if (VS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &SoftBody::_draw_soft_mesh))) { + VS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &SoftBody::_draw_soft_mesh)); } } } @@ -483,14 +487,15 @@ void SoftBody::become_mesh_owner() { // Get current mesh array and create new mesh array with necessary flag for softbody Array surface_arrays = mesh->surface_get_arrays(0); Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0); + Dictionary surface_lods = mesh->surface_get_lods(0); uint32_t surface_format = mesh->surface_get_format(0); - surface_format &= ~(Mesh::ARRAY_COMPRESS_VERTEX | Mesh::ARRAY_COMPRESS_NORMAL); + surface_format &= ~(Mesh::ARRAY_COMPRESS_NORMAL); surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE; Ref<ArrayMesh> soft_mesh; soft_mesh.instance(); - soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_format); + soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_lods, surface_format); soft_mesh->surface_set_material(0, mesh->surface_get_material(0)); set_mesh(soft_mesh); @@ -552,15 +557,14 @@ const NodePath &SoftBody::get_parent_collision_ignore() const { return parent_collision_ignore; } -void SoftBody::set_pinned_points_indices(PoolVector<SoftBody::PinnedPoint> p_pinned_points_indices) { +void SoftBody::set_pinned_points_indices(Vector<SoftBody::PinnedPoint> p_pinned_points_indices) { pinned_points = p_pinned_points_indices; - PoolVector<PinnedPoint>::Read w = pinned_points.read(); for (int i = pinned_points.size() - 1; 0 <= i; --i) { pin_point(p_pinned_points_indices[i].point_index, true); } } -PoolVector<SoftBody::PinnedPoint> SoftBody::get_pinned_points_indices() { +Vector<SoftBody::PinnedPoint> SoftBody::get_pinned_points_indices() { return pinned_points; } @@ -706,8 +710,6 @@ SoftBody::SoftBody() : ray_pickable(true) { PhysicsServer::get_singleton()->body_attach_object_instance_id(physics_rid, get_instance_id()); - //set_notify_transform(true); - set_physics_process_internal(true); } SoftBody::~SoftBody() { @@ -716,7 +718,7 @@ SoftBody::~SoftBody() { void SoftBody::reset_softbody_pin() { PhysicsServer::get_singleton()->soft_body_remove_all_pinned_points(physics_rid); - PoolVector<PinnedPoint>::Read pps = pinned_points.read(); + const PinnedPoint *pps = pinned_points.ptr(); for (int i = pinned_points.size() - 1; 0 < i; --i) { PhysicsServer::get_singleton()->soft_body_pin_point(physics_rid, pps[i].point_index, true); } @@ -732,7 +734,7 @@ void SoftBody::_update_cache_pin_points_datas() { pinned_points_cache_dirty = false; - PoolVector<PinnedPoint>::Write w = pinned_points.write(); + PinnedPoint *w = pinned_points.ptrw(); for (int i = pinned_points.size() - 1; 0 <= i; --i) { if (!w[i].spatial_attachment_path.is_empty()) { @@ -781,8 +783,8 @@ void SoftBody::_reset_points_offsets() { if (!Engine::get_singleton()->is_editor_hint()) return; - PoolVector<PinnedPoint>::Read r = pinned_points.read(); - PoolVector<PinnedPoint>::Write w = pinned_points.write(); + const PinnedPoint *r = pinned_points.ptr(); + PinnedPoint *w = pinned_points.ptrw(); for (int i = pinned_points.size() - 1; 0 <= i; --i) { if (!r[i].spatial_attachment) @@ -808,13 +810,13 @@ int SoftBody::_get_pinned_point(int p_point_index, SoftBody::PinnedPoint *&r_poi r_point = NULL; return -1; } else { - r_point = const_cast<SoftBody::PinnedPoint *>(&pinned_points.read()[id]); + r_point = const_cast<SoftBody::PinnedPoint *>(&pinned_points.ptr()[id]); return id; } } int SoftBody::_has_pinned_point(int p_point_index) const { - PoolVector<PinnedPoint>::Read r = pinned_points.read(); + const PinnedPoint *r = pinned_points.ptr(); for (int i = pinned_points.size() - 1; 0 <= i; --i) { if (p_point_index == r[i].point_index) { return i; diff --git a/scene/3d/soft_body.h b/scene/3d/soft_body.h index 629c2e42a5..d6c35a5989 100644 --- a/scene/3d/soft_body.h +++ b/scene/3d/soft_body.h @@ -41,12 +41,12 @@ class SoftBodyVisualServerHandler { RID mesh; int surface; - PoolVector<uint8_t> buffer; + Vector<uint8_t> buffer; uint32_t stride; uint32_t offset_vertices; uint32_t offset_normal; - PoolVector<uint8_t>::Write write_buffer; + uint8_t *write_buffer; private: SoftBodyVisualServerHandler(); @@ -87,7 +87,7 @@ private: uint32_t collision_mask; uint32_t collision_layer; NodePath parent_collision_ignore; - PoolVector<PinnedPoint> pinned_points; + Vector<PinnedPoint> pinned_points; bool simulation_started; bool pinned_points_cache_dirty; @@ -116,10 +116,11 @@ protected: virtual String get_configuration_warning() const; protected: + void _update_physics_server(); void _draw_soft_mesh(); public: - void update_physics_server(); + void prepare_physics_server(); void become_mesh_owner(); void set_collision_mask(uint32_t p_mask); @@ -137,8 +138,8 @@ public: void set_parent_collision_ignore(const NodePath &p_parent_collision_ignore); const NodePath &get_parent_collision_ignore() const; - void set_pinned_points_indices(PoolVector<PinnedPoint> p_pinned_points_indices); - PoolVector<PinnedPoint> get_pinned_points_indices(); + void set_pinned_points_indices(Vector<PinnedPoint> p_pinned_points_indices); + Vector<PinnedPoint> get_pinned_points_indices(); void set_simulation_precision(int p_simulation_precision); int get_simulation_precision(); diff --git a/scene/3d/spring_arm.cpp b/scene/3d/spring_arm.cpp index bce0535d64..ce277dae5b 100644 --- a/scene/3d/spring_arm.cpp +++ b/scene/3d/spring_arm.cpp @@ -81,8 +81,8 @@ void SpringArm::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), "set_shape", "get_shape"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "spring_length"), "set_length", "get_length"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin"), "set_margin", "get_margin"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spring_length"), "set_length", "get_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin"), "set_margin", "get_margin"); } float SpringArm::get_length() const { diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index a4c81b864d..fd22076091 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "sprite_3d.h" + #include "core/core_string_names.h" #include "scene/scene_string_names.h" @@ -177,8 +178,6 @@ void SpriteBase3D::_im_update() { _draw(); pending_update = false; - - //texture->draw_rect_region(ci,dst_rect,src_rect,modulate); } void SpriteBase3D::_queue_update() { @@ -197,18 +196,18 @@ AABB SpriteBase3D::get_aabb() const { return aabb; } -PoolVector<Face3> SpriteBase3D::get_faces(uint32_t p_usage_flags) const { +Vector<Face3> SpriteBase3D::get_faces(uint32_t p_usage_flags) const { - return PoolVector<Face3>(); + return Vector<Face3>(); } Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const { if (triangle_mesh.is_valid()) return triangle_mesh; - PoolVector<Vector3> faces; + Vector<Vector3> faces; faces.resize(6); - PoolVector<Vector3>::Write facesw = faces.write(); + Vector3 *facesw = faces.ptrw(); Rect2 final_rect = get_item_rect(); @@ -254,8 +253,6 @@ Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const { facesw[j] = vtx; } - facesw.release(); - triangle_mesh = Ref<TriangleMesh>(memnew(TriangleMesh)); triangle_mesh->create(faces); @@ -286,14 +283,14 @@ SpriteBase3D::AlphaCutMode SpriteBase3D::get_alpha_cut_mode() const { return alpha_cut; } -void SpriteBase3D::set_billboard_mode(SpatialMaterial::BillboardMode p_mode) { +void SpriteBase3D::set_billboard_mode(StandardMaterial3D::BillboardMode p_mode) { ERR_FAIL_INDEX(p_mode, 3); billboard_mode = p_mode; _queue_update(); } -SpatialMaterial::BillboardMode SpriteBase3D::get_billboard_mode() const { +StandardMaterial3D::BillboardMode SpriteBase3D::get_billboard_mode() const { return billboard_mode; } @@ -336,16 +333,13 @@ void SpriteBase3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_item_rect"), &SpriteBase3D::get_item_rect); ClassDB::bind_method(D_METHOD("generate_triangle_mesh"), &SpriteBase3D::generate_triangle_mesh); - ClassDB::bind_method(D_METHOD("_queue_update"), &SpriteBase3D::_queue_update); - ClassDB::bind_method(D_METHOD("_im_update"), &SpriteBase3D::_im_update); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "opacity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_opacity", "get_opacity"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "pixel_size", PROPERTY_HINT_RANGE, "0.0001,128,0.0001"), "set_pixel_size", "get_pixel_size"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "opacity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_opacity", "get_opacity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pixel_size", PROPERTY_HINT_RANGE, "0.0001,128,0.0001"), "set_pixel_size", "get_pixel_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "axis", PROPERTY_HINT_ENUM, "X-Axis,Y-Axis,Z-Axis"), "set_axis", "get_axis"); ADD_GROUP("Flags", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "billboard", PROPERTY_HINT_ENUM, "Disabled,Enabled,Y-Billboard"), "set_billboard_mode", "get_billboard_mode"); @@ -377,7 +371,7 @@ SpriteBase3D::SpriteBase3D() { flags[i] = i == FLAG_TRANSPARENT || i == FLAG_DOUBLE_SIDED; alpha_cut = ALPHA_CUT_DISABLED; - billboard_mode = SpatialMaterial::BILLBOARD_DISABLED; + billboard_mode = StandardMaterial3D::BILLBOARD_DISABLED; axis = Vector3::AXIS_Z; pixel_size = 0.01; modulate = Color(1, 1, 1, 1); @@ -480,10 +474,10 @@ void Sprite3D::_draw() { tangent = Plane(1, 0, 0, 1); } - RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == SpatialMaterial::BILLBOARD_ENABLED, get_billboard_mode() == SpatialMaterial::BILLBOARD_FIXED_Y); + RID mat = StandardMaterial3D::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y); VS::get_singleton()->immediate_set_material(immediate, mat); - VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_TRIANGLE_FAN, texture->get_rid()); + VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_TRIANGLES, texture->get_rid()); int x_axis = ((axis + 1) % 3); int y_axis = ((axis + 2) % 3); @@ -504,15 +498,18 @@ void Sprite3D::_draw() { AABB aabb; - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 6; i++) { + + static const int index[6] = { 0, 1, 2, 0, 2, 3 }; + VS::get_singleton()->immediate_normal(immediate, normal); VS::get_singleton()->immediate_tangent(immediate, tangent); VS::get_singleton()->immediate_color(immediate, color); VS::get_singleton()->immediate_uv(immediate, uvs[i]); Vector3 vtx; - vtx[x_axis] = vertices[i][0]; - vtx[y_axis] = vertices[i][1]; + vtx[x_axis] = vertices[index[i]][0]; + vtx[y_axis] = vertices[index[i]][1]; VS::get_singleton()->immediate_vertex(immediate, vtx); if (i == 0) { aabb.position = vtx; @@ -525,22 +522,25 @@ void Sprite3D::_draw() { VS::get_singleton()->immediate_end(immediate); } -void Sprite3D::set_texture(const Ref<Texture> &p_texture) { +void Sprite3D::_texture_changed() { + _queue_update(); +} + +void Sprite3D::set_texture(const Ref<Texture2D> &p_texture) { if (p_texture == texture) return; if (texture.is_valid()) { - texture->disconnect(CoreStringNames::get_singleton()->changed, this, SceneStringNames::get_singleton()->_queue_update); + texture->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite3D::_texture_changed)); } texture = p_texture; if (texture.is_valid()) { - texture->set_flags(texture->get_flags()); //remove repeat from texture, it looks bad in sprites - texture->connect(CoreStringNames::get_singleton()->changed, this, SceneStringNames::get_singleton()->_queue_update); + texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite3D::_texture_changed)); } _queue_update(); } -Ref<Texture> Sprite3D::get_texture() const { +Ref<Texture2D> Sprite3D::get_texture() const { return texture; } @@ -691,7 +691,7 @@ void Sprite3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hframes", "hframes"), &Sprite3D::set_hframes); ClassDB::bind_method(D_METHOD("get_hframes"), &Sprite3D::get_hframes); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); ADD_GROUP("Animation", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes"); ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes"); @@ -731,7 +731,7 @@ void AnimatedSprite3D::_draw() { return; } - Ref<Texture> texture = frames->get_frame(animation, frame); + Ref<Texture2D> texture = frames->get_frame(animation, frame); if (!texture.is_valid()) return; //no texuture no life Vector2 tsize = texture->get_size(); @@ -808,11 +808,11 @@ void AnimatedSprite3D::_draw() { tangent = Plane(1, 0, 0, -1); } - RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == SpatialMaterial::BILLBOARD_ENABLED, get_billboard_mode() == SpatialMaterial::BILLBOARD_FIXED_Y); + RID mat = StandardMaterial3D::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y); VS::get_singleton()->immediate_set_material(immediate, mat); - VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_TRIANGLE_FAN, texture->get_rid()); + VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_TRIANGLES, texture->get_rid()); int x_axis = ((axis + 1) % 3); int y_axis = ((axis + 2) % 3); @@ -833,15 +833,21 @@ void AnimatedSprite3D::_draw() { AABB aabb; - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 6; i++) { + + static const int indices[6] = { + 0, 1, 2, + 0, 2, 3 + }; + VS::get_singleton()->immediate_normal(immediate, normal); VS::get_singleton()->immediate_tangent(immediate, tangent); VS::get_singleton()->immediate_color(immediate, color); VS::get_singleton()->immediate_uv(immediate, uvs[i]); Vector3 vtx; - vtx[x_axis] = vertices[i][0]; - vtx[y_axis] = vertices[i][1]; + vtx[x_axis] = vertices[indices[i]][0]; + vtx[y_axis] = vertices[indices[i]][1]; VS::get_singleton()->immediate_vertex(immediate, vtx); if (i == 0) { aabb.position = vtx; @@ -946,10 +952,10 @@ void AnimatedSprite3D::_notification(int p_what) { void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) { if (frames.is_valid()) - frames->disconnect("changed", this, "_res_changed"); + frames->disconnect("changed", callable_mp(this, &AnimatedSprite3D::_res_changed)); frames = p_frames; if (frames.is_valid()) - frames->connect("changed", this, "_res_changed"); + frames->connect("changed", callable_mp(this, &AnimatedSprite3D::_res_changed)); if (!frames.is_valid()) { frame = 0; @@ -1003,7 +1009,7 @@ Rect2 AnimatedSprite3D::get_item_rect() const { return Rect2(0, 0, 1, 1); } - Ref<Texture> t; + Ref<Texture2D> t; if (animation) t = frames->get_frame(animation, frame); if (t.is_null()) @@ -1119,12 +1125,10 @@ void AnimatedSprite3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_frame", "frame"), &AnimatedSprite3D::set_frame); ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite3D::get_frame); - ClassDB::bind_method(D_METHOD("_res_changed"), &AnimatedSprite3D::_res_changed); - ADD_SIGNAL(MethodInfo("frame_changed")); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation"); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "animation"), "set_animation", "get_animation"); ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing"); } diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index ddbade147c..082884c83b 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -80,7 +80,7 @@ private: bool flags[FLAG_MAX]; AlphaCutMode alpha_cut; - SpatialMaterial::BillboardMode billboard_mode; + StandardMaterial3D::BillboardMode billboard_mode; bool pending_update; void _im_update(); @@ -131,13 +131,13 @@ public: void set_alpha_cut_mode(AlphaCutMode p_mode); AlphaCutMode get_alpha_cut_mode() const; - void set_billboard_mode(SpatialMaterial::BillboardMode p_mode); - SpatialMaterial::BillboardMode get_billboard_mode() const; + void set_billboard_mode(StandardMaterial3D::BillboardMode p_mode); + StandardMaterial3D::BillboardMode get_billboard_mode() const; virtual Rect2 get_item_rect() const = 0; virtual AABB get_aabb() const; - virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; + virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const; Ref<TriangleMesh> generate_triangle_mesh() const; SpriteBase3D(); @@ -147,7 +147,7 @@ public: class Sprite3D : public SpriteBase3D { GDCLASS(Sprite3D, SpriteBase3D); - Ref<Texture> texture; + Ref<Texture2D> texture; bool region; Rect2 region_rect; @@ -157,6 +157,8 @@ class Sprite3D : public SpriteBase3D { int vframes; int hframes; + void _texture_changed(); + protected: virtual void _draw(); static void _bind_methods(); @@ -164,8 +166,8 @@ protected: virtual void _validate_property(PropertyInfo &property) const; public: - void set_texture(const Ref<Texture> &p_texture); - Ref<Texture> get_texture() const; + void set_texture(const Ref<Texture2D> &p_texture); + Ref<Texture2D> get_texture() const; void set_region(bool p_region); bool is_region() const; diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp index 92b17d5056..c249d844d1 100644 --- a/scene/3d/vehicle_body.cpp +++ b/scene/3d/vehicle_body.cpp @@ -282,24 +282,24 @@ void VehicleWheel::_bind_methods() { ClassDB::bind_method(D_METHOD("get_steering"), &VehicleWheel::get_steering); ADD_GROUP("Per-Wheel Motion", ""); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering"); ADD_GROUP("VehicleBody Motion", ""); 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_"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "wheel_roll_influence"), "set_roll_influence", "get_roll_influence"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "wheel_radius"), "set_radius", "get_radius"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "wheel_rest_length"), "set_suspension_rest_length", "get_suspension_rest_length"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "wheel_friction_slip"), "set_friction_slip", "get_friction_slip"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wheel_roll_influence"), "set_roll_influence", "get_roll_influence"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wheel_radius"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wheel_rest_length"), "set_suspension_rest_length", "get_suspension_rest_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wheel_friction_slip"), "set_friction_slip", "get_friction_slip"); ADD_GROUP("Suspension", "suspension_"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "suspension_travel"), "set_suspension_travel", "get_suspension_travel"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "suspension_stiffness"), "set_suspension_stiffness", "get_suspension_stiffness"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "suspension_max_force"), "set_suspension_max_force", "get_suspension_max_force"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "suspension_travel"), "set_suspension_travel", "get_suspension_travel"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "suspension_stiffness"), "set_suspension_stiffness", "get_suspension_stiffness"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "suspension_max_force"), "set_suspension_max_force", "get_suspension_max_force"); ADD_GROUP("Damping", "damping_"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "damping_compression"), "set_damping_compression", "get_damping_compression"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "damping_relaxation"), "set_damping_relaxation", "get_damping_relaxation"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping_compression"), "set_damping_compression", "get_damping_compression"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping_relaxation"), "set_damping_relaxation", "get_damping_relaxation"); } void VehicleWheel::set_engine_force(float p_engine_force) { @@ -364,9 +364,8 @@ VehicleWheel::VehicleWheel() { steers = false; engine_traction = false; - m_steering = real_t(0.); - //m_engineForce = real_t(0.); + m_engineForce = real_t(0.); m_rotation = real_t(0.); m_deltaRotation = real_t(0.); m_brake = real_t(0.); @@ -975,9 +974,9 @@ void VehicleBody::_bind_methods() { ClassDB::bind_method(D_METHOD("get_steering"), &VehicleBody::get_steering); ADD_GROUP("Motion", ""); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering"); } VehicleBody::VehicleBody() { diff --git a/scene/3d/visibility_notifier.cpp b/scene/3d/visibility_notifier.cpp index 510442dc1c..986607f18d 100644 --- a/scene/3d/visibility_notifier.cpp +++ b/scene/3d/visibility_notifier.cpp @@ -170,7 +170,7 @@ void VisibilityEnabler::_find_nodes(Node *p_node) { if (add) { - p_node->connect(SceneStringNames::get_singleton()->tree_exiting, this, "_node_removed", varray(p_node), CONNECT_ONESHOT); + p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler::_node_removed), varray(p_node), CONNECT_ONESHOT); nodes[p_node] = meta; _change_node_state(p_node, false); } @@ -208,7 +208,7 @@ void VisibilityEnabler::_notification(int p_what) { if (!visible) _change_node_state(E->key(), true); - E->key()->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, "_node_removed"); + E->key()->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler::_node_removed)); } nodes.clear(); @@ -247,7 +247,6 @@ void VisibilityEnabler::_bind_methods() { ClassDB::bind_method(D_METHOD("set_enabler", "enabler", "enabled"), &VisibilityEnabler::set_enabler); ClassDB::bind_method(D_METHOD("is_enabler_enabled", "enabler"), &VisibilityEnabler::is_enabler_enabled); - ClassDB::bind_method(D_METHOD("_node_removed"), &VisibilityEnabler::_node_removed); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_animations"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_ANIMATIONS); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "freeze_bodies"), "set_enabler", "is_enabler_enabled", ENABLER_FREEZE_BODIES); diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index 4574dfac5f..105ce9ca74 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -294,10 +294,11 @@ void GeometryInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("get_aabb"), &GeometryInstance::get_aabb); ADD_GROUP("Geometry", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,SpatialMaterial"), "set_material_override", "get_material_override"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE), "set_material_override", "get_material_override"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_in_baked_light"), "set_flag", "get_flag", FLAG_USE_BAKED_LIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_dynamic_gi"), "set_flag", "get_flag", FLAG_USE_DYNAMIC_GI); ADD_GROUP("LOD", "lod_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_min_distance", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_min_distance", "get_lod_min_distance"); @@ -313,6 +314,7 @@ void GeometryInstance::_bind_methods() { BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_SHADOWS_ONLY); BIND_ENUM_CONSTANT(FLAG_USE_BAKED_LIGHT); + BIND_ENUM_CONSTANT(FLAG_USE_DYNAMIC_GI); 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 f115748952..fee6787c87 100644 --- a/scene/3d/visual_instance.h +++ b/scene/3d/visual_instance.h @@ -63,7 +63,7 @@ public: RID get_instance() const; virtual AABB get_aabb() const = 0; - virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const = 0; + virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const = 0; virtual AABB get_transformed_aabb() const; // helper @@ -87,6 +87,7 @@ class GeometryInstance : public VisualInstance { public: enum Flags { FLAG_USE_BAKED_LIGHT = VS::INSTANCE_FLAG_USE_BAKED_LIGHT, + FLAG_USE_DYNAMIC_GI = VS::INSTANCE_FLAG_USE_DYNAMIC_GI, FLAG_DRAW_NEXT_FRAME_IF_VISIBLE = VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, FLAG_MAX = VS::INSTANCE_FLAG_MAX, }; diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp deleted file mode 100644 index c1ec59d49f..0000000000 --- a/scene/3d/voxel_light_baker.cpp +++ /dev/null @@ -1,2486 +0,0 @@ -/*************************************************************************/ -/* voxel_light_baker.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "voxel_light_baker.h" - -#include "core/os/os.h" -#include "core/os/threaded_array_processor.h" - -#include <stdlib.h> - -#define FINDMINMAX(x0, x1, x2, min, max) \ - min = max = x0; \ - if (x1 < min) min = x1; \ - if (x1 > max) max = x1; \ - if (x2 < min) min = x2; \ - if (x2 > max) max = x2; - -static bool planeBoxOverlap(Vector3 normal, float d, Vector3 maxbox) { - int q; - Vector3 vmin, vmax; - for (q = 0; q <= 2; q++) { - if (normal[q] > 0.0f) { - vmin[q] = -maxbox[q]; - vmax[q] = maxbox[q]; - } else { - vmin[q] = maxbox[q]; - vmax[q] = -maxbox[q]; - } - } - if (normal.dot(vmin) + d > 0.0f) return false; - if (normal.dot(vmax) + d >= 0.0f) return true; - - return false; -} - -/*======================== X-tests ========================*/ -#define AXISTEST_X01(a, b, fa, fb) \ - p0 = a * v0.y - b * v0.z; \ - p2 = a * v2.y - b * v2.z; \ - if (p0 < p2) { \ - min = p0; \ - max = p2; \ - } else { \ - min = p2; \ - max = p0; \ - } \ - rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \ - if (min > rad || max < -rad) return false; - -#define AXISTEST_X2(a, b, fa, fb) \ - p0 = a * v0.y - b * v0.z; \ - p1 = a * v1.y - b * v1.z; \ - if (p0 < p1) { \ - min = p0; \ - max = p1; \ - } else { \ - min = p1; \ - max = p0; \ - } \ - rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \ - if (min > rad || max < -rad) return false; - -/*======================== Y-tests ========================*/ -#define AXISTEST_Y02(a, b, fa, fb) \ - p0 = -a * v0.x + b * v0.z; \ - p2 = -a * v2.x + b * v2.z; \ - if (p0 < p2) { \ - min = p0; \ - max = p2; \ - } else { \ - min = p2; \ - max = p0; \ - } \ - rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \ - if (min > rad || max < -rad) return false; - -#define AXISTEST_Y1(a, b, fa, fb) \ - p0 = -a * v0.x + b * v0.z; \ - p1 = -a * v1.x + b * v1.z; \ - if (p0 < p1) { \ - min = p0; \ - max = p1; \ - } else { \ - min = p1; \ - max = p0; \ - } \ - rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \ - if (min > rad || max < -rad) return false; - -/*======================== Z-tests ========================*/ - -#define AXISTEST_Z12(a, b, fa, fb) \ - p1 = a * v1.x - b * v1.y; \ - p2 = a * v2.x - b * v2.y; \ - if (p2 < p1) { \ - min = p2; \ - max = p1; \ - } else { \ - min = p1; \ - max = p2; \ - } \ - rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \ - if (min > rad || max < -rad) return false; - -#define AXISTEST_Z0(a, b, fa, fb) \ - p0 = a * v0.x - b * v0.y; \ - p1 = a * v1.x - b * v1.y; \ - if (p0 < p1) { \ - min = p0; \ - max = p1; \ - } else { \ - min = p1; \ - max = p0; \ - } \ - rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \ - if (min > rad || max < -rad) return false; - -static bool fast_tri_box_overlap(const Vector3 &boxcenter, const Vector3 boxhalfsize, const Vector3 *triverts) { - - /* use separating axis theorem to test overlap between triangle and box */ - /* need to test for overlap in these directions: */ - /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */ - /* we do not even need to test these) */ - /* 2) normal of the triangle */ - /* 3) crossproduct(edge from tri, {x,y,z}-directin) */ - /* this gives 3x3=9 more tests */ - Vector3 v0, v1, v2; - float min, max, d, p0, p1, p2, rad, fex, fey, fez; - Vector3 normal, e0, e1, e2; - - /* This is the fastest branch on Sun */ - /* move everything so that the boxcenter is in (0,0,0) */ - - v0 = triverts[0] - boxcenter; - v1 = triverts[1] - boxcenter; - v2 = triverts[2] - boxcenter; - - /* compute triangle edges */ - e0 = v1 - v0; /* tri edge 0 */ - e1 = v2 - v1; /* tri edge 1 */ - e2 = v0 - v2; /* tri edge 2 */ - - /* Bullet 3: */ - /* test the 9 tests first (this was faster) */ - fex = Math::abs(e0.x); - fey = Math::abs(e0.y); - fez = Math::abs(e0.z); - AXISTEST_X01(e0.z, e0.y, fez, fey); - AXISTEST_Y02(e0.z, e0.x, fez, fex); - AXISTEST_Z12(e0.y, e0.x, fey, fex); - - fex = Math::abs(e1.x); - fey = Math::abs(e1.y); - fez = Math::abs(e1.z); - AXISTEST_X01(e1.z, e1.y, fez, fey); - AXISTEST_Y02(e1.z, e1.x, fez, fex); - AXISTEST_Z0(e1.y, e1.x, fey, fex); - - fex = Math::abs(e2.x); - fey = Math::abs(e2.y); - fez = Math::abs(e2.z); - AXISTEST_X2(e2.z, e2.y, fez, fey); - AXISTEST_Y1(e2.z, e2.x, fez, fex); - AXISTEST_Z12(e2.y, e2.x, fey, fex); - - /* Bullet 1: */ - /* first test overlap in the {x,y,z}-directions */ - /* find min, max of the triangle each direction, and test for overlap in */ - /* that direction -- this is equivalent to testing a minimal AABB around */ - /* the triangle against the AABB */ - - /* test in X-direction */ - FINDMINMAX(v0.x, v1.x, v2.x, min, max); - if (min > boxhalfsize.x || max < -boxhalfsize.x) return false; - - /* test in Y-direction */ - FINDMINMAX(v0.y, v1.y, v2.y, min, max); - if (min > boxhalfsize.y || max < -boxhalfsize.y) return false; - - /* test in Z-direction */ - FINDMINMAX(v0.z, v1.z, v2.z, min, max); - if (min > boxhalfsize.z || max < -boxhalfsize.z) return false; - - /* Bullet 2: */ - /* test if the box intersects the plane of the triangle */ - /* compute plane equation of triangle: normal*x+d=0 */ - normal = e0.cross(e1); - d = -normal.dot(v0); /* plane eq: normal.x+d=0 */ - 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) { - - if (p_pos.distance_squared_to(p_vtx[0]) < CMP_EPSILON2) { - r_uv = p_uv[0]; - r_normal = p_normal[0]; - return; - } - if (p_pos.distance_squared_to(p_vtx[1]) < CMP_EPSILON2) { - r_uv = p_uv[1]; - r_normal = p_normal[1]; - return; - } - if (p_pos.distance_squared_to(p_vtx[2]) < CMP_EPSILON2) { - r_uv = p_uv[2]; - r_normal = p_normal[2]; - return; - } - - Vector3 v0 = p_vtx[1] - p_vtx[0]; - Vector3 v1 = p_vtx[2] - p_vtx[0]; - Vector3 v2 = p_pos - p_vtx[0]; - - float d00 = v0.dot(v0); - float d01 = v0.dot(v1); - float d11 = v1.dot(v1); - float d20 = v2.dot(v0); - float d21 = v2.dot(v1); - float denom = (d00 * d11 - d01 * d01); - if (denom == 0) { - r_uv = p_uv[0]; - r_normal = p_normal[0]; - return; - } - float v = (d11 * d20 - d01 * d21) / denom; - float w = (d00 * d21 - d01 * d20) / denom; - float u = 1.0f - v - w; - - r_uv = p_uv[0] * u + p_uv[1] * v + p_uv[2] * w; - r_normal = (p_normal[0] * u + p_normal[1] * v + p_normal[2] * w).normalized(); -} - -void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb) { - - if (p_level == cell_subdiv - 1) { - //plot the face by guessing its albedo and emission value - - //find best axis to map to, for scanning values - int closest_axis = 0; - float closest_dot = 0; - - Plane plane = Plane(p_vtx[0], p_vtx[1], p_vtx[2]); - Vector3 normal = plane.normal; - - for (int i = 0; i < 3; i++) { - - Vector3 axis; - axis[i] = 1.0; - float dot = ABS(normal.dot(axis)); - if (i == 0 || dot > closest_dot) { - closest_axis = i; - closest_dot = dot; - } - } - - Vector3 axis; - axis[closest_axis] = 1.0; - Vector3 t1; - t1[(closest_axis + 1) % 3] = 1.0; - Vector3 t2; - t2[(closest_axis + 2) % 3] = 1.0; - - t1 *= p_aabb.size[(closest_axis + 1) % 3] / float(color_scan_cell_width); - t2 *= p_aabb.size[(closest_axis + 2) % 3] / float(color_scan_cell_width); - - Color albedo_accum; - Color emission_accum; - Vector3 normal_accum; - - float alpha = 0.0; - - //map to a grid average in the best axis for this face - for (int i = 0; i < color_scan_cell_width; i++) { - - Vector3 ofs_i = float(i) * t1; - - for (int j = 0; j < color_scan_cell_width; j++) { - - Vector3 ofs_j = float(j) * t2; - - Vector3 from = p_aabb.position + ofs_i + ofs_j; - Vector3 to = from + t1 + t2 + axis * p_aabb.size[closest_axis]; - Vector3 half = (to - from) * 0.5; - - //is in this cell? - if (!fast_tri_box_overlap(from + half, half, p_vtx)) { - continue; //face does not span this cell - } - - //go from -size to +size*2 to avoid skipping collisions - Vector3 ray_from = from + (t1 + t2) * 0.5 - axis * p_aabb.size[closest_axis]; - Vector3 ray_to = ray_from + axis * p_aabb.size[closest_axis] * 2; - - if (normal.dot(ray_from - ray_to) < 0) { - SWAP(ray_from, ray_to); - } - - Vector3 intersection; - - if (!plane.intersects_segment(ray_from, ray_to, &intersection)) { - if (ABS(plane.distance_to(ray_from)) < ABS(plane.distance_to(ray_to))) { - intersection = plane.project(ray_from); - } else { - - intersection = plane.project(ray_to); - } - } - - intersection = Face3(p_vtx[0], p_vtx[1], p_vtx[2]).get_closest_point_to(intersection); - - Vector2 uv; - Vector3 lnormal; - get_uv_and_normal(intersection, p_vtx, p_uv, p_normal, uv, lnormal); - if (lnormal == Vector3()) //just in case normal as nor provided - lnormal = normal; - - int uv_x = CLAMP(int(Math::fposmod(uv.x, 1.0f) * bake_texture_size), 0, bake_texture_size - 1); - int uv_y = CLAMP(int(Math::fposmod(uv.y, 1.0f) * bake_texture_size), 0, bake_texture_size - 1); - - int ofs = uv_y * bake_texture_size + uv_x; - albedo_accum.r += p_material.albedo[ofs].r; - albedo_accum.g += p_material.albedo[ofs].g; - albedo_accum.b += p_material.albedo[ofs].b; - albedo_accum.a += p_material.albedo[ofs].a; - - emission_accum.r += p_material.emission[ofs].r; - emission_accum.g += p_material.emission[ofs].g; - emission_accum.b += p_material.emission[ofs].b; - - normal_accum += lnormal; - - alpha += 1.0; - } - } - - if (alpha == 0) { - //could not in any way get texture information.. so use closest point to center - - Face3 f(p_vtx[0], p_vtx[1], p_vtx[2]); - Vector3 inters = f.get_closest_point_to(p_aabb.position + p_aabb.size * 0.5); - - Vector3 lnormal; - Vector2 uv; - get_uv_and_normal(inters, p_vtx, p_uv, p_normal, uv, normal); - if (lnormal == Vector3()) //just in case normal as nor provided - lnormal = normal; - - int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); - int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); - - int ofs = uv_y * bake_texture_size + uv_x; - - alpha = 1.0 / (color_scan_cell_width * color_scan_cell_width); - - albedo_accum.r = p_material.albedo[ofs].r * alpha; - albedo_accum.g = p_material.albedo[ofs].g * alpha; - albedo_accum.b = p_material.albedo[ofs].b * alpha; - albedo_accum.a = p_material.albedo[ofs].a * alpha; - - emission_accum.r = p_material.emission[ofs].r * alpha; - emission_accum.g = p_material.emission[ofs].g * alpha; - emission_accum.b = p_material.emission[ofs].b * alpha; - - normal_accum = lnormal * alpha; - - } else { - - float accdiv = 1.0 / (color_scan_cell_width * color_scan_cell_width); - alpha *= accdiv; - - albedo_accum.r *= accdiv; - albedo_accum.g *= accdiv; - albedo_accum.b *= accdiv; - albedo_accum.a *= accdiv; - - emission_accum.r *= accdiv; - emission_accum.g *= accdiv; - emission_accum.b *= accdiv; - - normal_accum *= accdiv; - } - - //put this temporarily here, corrected in a later step - bake_cells.write[p_idx].albedo[0] += albedo_accum.r; - bake_cells.write[p_idx].albedo[1] += albedo_accum.g; - bake_cells.write[p_idx].albedo[2] += albedo_accum.b; - bake_cells.write[p_idx].emission[0] += emission_accum.r; - bake_cells.write[p_idx].emission[1] += emission_accum.g; - bake_cells.write[p_idx].emission[2] += emission_accum.b; - bake_cells.write[p_idx].normal[0] += normal_accum.x; - bake_cells.write[p_idx].normal[1] += normal_accum.y; - bake_cells.write[p_idx].normal[2] += normal_accum.z; - bake_cells.write[p_idx].alpha += alpha; - - } else { - //go down - - int half = (1 << (cell_subdiv - 1)) >> (p_level + 1); - for (int i = 0; i < 8; i++) { - - AABB aabb = p_aabb; - aabb.size *= 0.5; - - int nx = p_x; - int ny = p_y; - int nz = p_z; - - if (i & 1) { - aabb.position.x += aabb.size.x; - nx += half; - } - if (i & 2) { - aabb.position.y += aabb.size.y; - ny += half; - } - if (i & 4) { - aabb.position.z += aabb.size.z; - nz += half; - } - //make sure to not plot beyond limits - if (nx < 0 || nx >= axis_cell_size[0] || ny < 0 || ny >= axis_cell_size[1] || nz < 0 || nz >= axis_cell_size[2]) - continue; - - { - AABB test_aabb = aabb; - //test_aabb.grow_by(test_aabb.get_longest_axis_size()*0.05); //grow a bit to avoid numerical error in real-time - Vector3 qsize = test_aabb.size * 0.5; //quarter size, for fast aabb test - - if (!fast_tri_box_overlap(test_aabb.position + qsize, qsize, p_vtx)) { - //if (!Face3(p_vtx[0],p_vtx[1],p_vtx[2]).intersects_aabb2(aabb)) { - //does not fit in child, go on - continue; - } - } - - if (bake_cells[p_idx].children[i] == CHILD_EMPTY) { - //sub cell must be created - - uint32_t child_idx = bake_cells.size(); - bake_cells.write[p_idx].children[i] = child_idx; - bake_cells.resize(bake_cells.size() + 1); - bake_cells.write[child_idx].level = p_level + 1; - } - - _plot_face(bake_cells[p_idx].children[i], p_level + 1, nx, ny, nz, p_vtx, p_normal, p_uv, p_material, aabb); - } - } -} - -Vector<Color> VoxelLightBaker::_get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add) { - - Vector<Color> ret; - - if (p_image.is_null() || p_image->empty()) { - - ret.resize(bake_texture_size * bake_texture_size); - for (int i = 0; i < bake_texture_size * bake_texture_size; i++) { - ret.write[i] = p_color_add; - } - - return ret; - } - p_image = p_image->duplicate(); - - if (p_image->is_compressed()) { - p_image->decompress(); - } - p_image->convert(Image::FORMAT_RGBA8); - p_image->resize(bake_texture_size, bake_texture_size, Image::INTERPOLATE_CUBIC); - - PoolVector<uint8_t>::Read r = p_image->get_data().read(); - ret.resize(bake_texture_size * bake_texture_size); - - for (int i = 0; i < bake_texture_size * bake_texture_size; i++) { - Color c; - c.r = (r[i * 4 + 0] / 255.0) * p_color_mul.r + p_color_add.r; - c.g = (r[i * 4 + 1] / 255.0) * p_color_mul.g + p_color_add.g; - c.b = (r[i * 4 + 2] / 255.0) * p_color_mul.b + p_color_add.b; - - c.a = r[i * 4 + 3] / 255.0; - - ret.write[i] = c; - } - - return ret; -} - -VoxelLightBaker::MaterialCache VoxelLightBaker::_get_material_cache(Ref<Material> p_material) { - - //this way of obtaining materials is inaccurate and also does not support some compressed formats very well - Ref<SpatialMaterial> mat = p_material; - - Ref<Material> material = mat; //hack for now - - if (material_cache.has(material)) { - return material_cache[material]; - } - - MaterialCache mc; - - if (mat.is_valid()) { - - Ref<Texture> albedo_tex = mat->get_texture(SpatialMaterial::TEXTURE_ALBEDO); - - Ref<Image> img_albedo; - if (albedo_tex.is_valid()) { - - img_albedo = albedo_tex->get_data(); - mc.albedo = _get_bake_texture(img_albedo, mat->get_albedo(), Color(0, 0, 0)); // albedo texture, color is multiplicative - } else { - mc.albedo = _get_bake_texture(img_albedo, Color(1, 1, 1), mat->get_albedo()); // no albedo texture, color is additive - } - - Ref<Texture> emission_tex = mat->get_texture(SpatialMaterial::TEXTURE_EMISSION); - - Color emission_col = mat->get_emission(); - float emission_energy = mat->get_emission_energy(); - - Ref<Image> img_emission; - - if (emission_tex.is_valid()) { - - img_emission = emission_tex->get_data(); - } - - if (mat->get_emission_operator() == SpatialMaterial::EMISSION_OP_ADD) { - mc.emission = _get_bake_texture(img_emission, Color(1, 1, 1) * emission_energy, emission_col * emission_energy); - } else { - mc.emission = _get_bake_texture(img_emission, emission_col * emission_energy, Color(0, 0, 0)); - } - - } else { - Ref<Image> empty; - - mc.albedo = _get_bake_texture(empty, Color(0, 0, 0), Color(1, 1, 1)); - mc.emission = _get_bake_texture(empty, Color(0, 0, 0), Color(0, 0, 0)); - } - - material_cache[p_material] = mc; - return mc; -} - -void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material) { - - for (int i = 0; i < p_mesh->get_surface_count(); i++) { - - if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) - continue; //only triangles - - Ref<Material> src_material; - - if (p_override_material.is_valid()) { - src_material = p_override_material; - } else if (i < p_materials.size() && p_materials[i].is_valid()) { - src_material = p_materials[i]; - } else { - src_material = p_mesh->surface_get_material(i); - } - MaterialCache material = _get_material_cache(src_material); - - Array a = p_mesh->surface_get_arrays(i); - - PoolVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX]; - PoolVector<Vector3>::Read vr = vertices.read(); - PoolVector<Vector2> uv = a[Mesh::ARRAY_TEX_UV]; - PoolVector<Vector2>::Read uvr; - PoolVector<Vector3> normals = a[Mesh::ARRAY_NORMAL]; - PoolVector<Vector3>::Read nr; - PoolVector<int> index = a[Mesh::ARRAY_INDEX]; - - bool read_uv = false; - bool read_normals = false; - - if (uv.size()) { - - uvr = uv.read(); - read_uv = true; - } - - if (normals.size()) { - read_normals = true; - nr = normals.read(); - } - - if (index.size()) { - - int facecount = index.size() / 3; - PoolVector<int>::Read ir = index.read(); - - for (int j = 0; j < facecount; j++) { - - Vector3 vtxs[3]; - Vector2 uvs[3]; - Vector3 normal[3]; - - for (int k = 0; k < 3; k++) { - vtxs[k] = p_xform.xform(vr[ir[j * 3 + k]]); - } - - if (read_uv) { - for (int k = 0; k < 3; k++) { - uvs[k] = uvr[ir[j * 3 + k]]; - } - } - - if (read_normals) { - for (int k = 0; k < 3; k++) { - normal[k] = nr[ir[j * 3 + k]]; - } - } - - //test against original bounds - if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs)) - continue; - //plot - _plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds); - } - - } else { - - int facecount = vertices.size() / 3; - - for (int j = 0; j < facecount; j++) { - - Vector3 vtxs[3]; - Vector2 uvs[3]; - Vector3 normal[3]; - - for (int k = 0; k < 3; k++) { - vtxs[k] = p_xform.xform(vr[j * 3 + k]); - } - - if (read_uv) { - for (int k = 0; k < 3; k++) { - uvs[k] = uvr[j * 3 + k]; - } - } - - if (read_normals) { - for (int k = 0; k < 3; k++) { - normal[k] = nr[j * 3 + k]; - } - } - - //test against original bounds - if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs)) - continue; - //plot face - _plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds); - } - } - } - - max_original_cells = bake_cells.size(); -} - -void VoxelLightBaker::_init_light_plot(int p_idx, int p_level, int p_x, int p_y, int p_z, uint32_t p_parent) { - - bake_light.write[p_idx].x = p_x; - bake_light.write[p_idx].y = p_y; - bake_light.write[p_idx].z = p_z; - - if (p_level == cell_subdiv - 1) { - - bake_light.write[p_idx].next_leaf = first_leaf; - first_leaf = p_idx; - } else { - - //go down - int half = (1 << (cell_subdiv - 1)) >> (p_level + 1); - for (int i = 0; i < 8; i++) { - - uint32_t child = bake_cells[p_idx].children[i]; - - if (child == CHILD_EMPTY) - continue; - - int nx = p_x; - int ny = p_y; - int nz = p_z; - - if (i & 1) - nx += half; - if (i & 2) - ny += half; - if (i & 4) - nz += half; - - _init_light_plot(child, p_level + 1, nx, ny, nz, p_idx); - } - } -} - -void VoxelLightBaker::begin_bake_light(BakeQuality p_quality, BakeMode p_bake_mode, float p_propagation, float p_energy) { - _check_init_light(); - propagation = p_propagation; - bake_quality = p_quality; - bake_mode = p_bake_mode; - energy = p_energy; -} - -void VoxelLightBaker::_check_init_light() { - if (bake_light.size() == 0) { - - direct_lights_baked = false; - leaf_voxel_count = 0; - _fixup_plot(0, 0); //pre fixup, so normal, albedo, emission, etc. work for lighting. - bake_light.resize(bake_cells.size()); - print_line("bake light size: " + itos(bake_light.size())); - //zeromem(bake_light.ptrw(), bake_light.size() * sizeof(Light)); - first_leaf = -1; - _init_light_plot(0, 0, 0, 0, 0, CHILD_EMPTY); - } -} - -static float _get_normal_advance(const Vector3 &p_normal) { - - Vector3 normal = p_normal; - Vector3 unorm = normal.abs(); - - if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) { - // x code - unorm = normal.x > 0.0 ? Vector3(1.0, 0.0, 0.0) : Vector3(-1.0, 0.0, 0.0); - } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) { - // y code - unorm = normal.y > 0.0 ? Vector3(0.0, 1.0, 0.0) : Vector3(0.0, -1.0, 0.0); - } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) { - // z code - unorm = normal.z > 0.0 ? Vector3(0.0, 0.0, 1.0) : Vector3(0.0, 0.0, -1.0); - } else { - // oh-no we messed up code - // has to be - unorm = Vector3(1.0, 0.0, 0.0); - } - - return 1.0 / normal.dot(unorm); -} - -static const Vector3 aniso_normal[6] = { - Vector3(-1, 0, 0), - Vector3(1, 0, 0), - Vector3(0, -1, 0), - Vector3(0, 1, 0), - Vector3(0, 0, -1), - Vector3(0, 0, 1) -}; - -uint32_t VoxelLightBaker::_find_cell_at_pos(const Cell *cells, int x, int y, int z) { - - uint32_t cell = 0; - - int ofs_x = 0; - int ofs_y = 0; - int ofs_z = 0; - int size = 1 << (cell_subdiv - 1); - int half = size / 2; - - if (x < 0 || x >= size) - return -1; - if (y < 0 || y >= size) - return -1; - if (z < 0 || z >= size) - return -1; - - for (int i = 0; i < cell_subdiv - 1; i++) { - - const Cell *bc = &cells[cell]; - - int child = 0; - if (x >= ofs_x + half) { - child |= 1; - ofs_x += half; - } - if (y >= ofs_y + half) { - child |= 2; - ofs_y += half; - } - if (z >= ofs_z + half) { - child |= 4; - ofs_z += half; - } - - cell = bc->children[child]; - if (cell == CHILD_EMPTY) - return CHILD_EMPTY; - - half >>= 1; - } - - return cell; -} -void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_energy, bool p_direct) { - - _check_init_light(); - - float max_len = Vector3(axis_cell_size[0], axis_cell_size[1], axis_cell_size[2]).length() * 1.1; - - if (p_direct) - direct_lights_baked = true; - - Vector3 light_axis = p_direction; - Plane clip[3]; - int clip_planes = 0; - - Light *light_data = bake_light.ptrw(); - const Cell *cells = bake_cells.ptr(); - - for (int i = 0; i < 3; i++) { - - if (Math::is_zero_approx(light_axis[i])) - continue; - clip[clip_planes].normal[i] = 1.0; - - if (light_axis[i] < 0) { - - clip[clip_planes].d = axis_cell_size[i] + 1; - } else { - clip[clip_planes].d -= 1.0; - } - - clip_planes++; - } - - float distance_adv = _get_normal_advance(light_axis); - - int success_count = 0; - - Vector3 light_energy = Vector3(p_color.r, p_color.g, p_color.b) * p_energy * p_indirect_energy; - - int idx = first_leaf; - while (idx >= 0) { - - Light *light = &light_data[idx]; - - Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5); - to += -light_axis.sign() * 0.47; //make it more likely to receive a ray - - Vector3 from = to - max_len * light_axis; - - for (int j = 0; j < clip_planes; j++) { - - clip[j].intersects_segment(from, to, &from); - } - - float distance = (to - from).length(); - distance += distance_adv - Math::fmod(distance, distance_adv); //make it reach the center of the box always - from = to - light_axis * distance; - - uint32_t result = 0xFFFFFFFF; - - while (distance > -distance_adv) { //use this to avoid precision errors - - result = _find_cell_at_pos(cells, int(floor(from.x)), int(floor(from.y)), int(floor(from.z))); - if (result != 0xFFFFFFFF) { - break; - } - - from += light_axis * distance_adv; - distance -= distance_adv; - } - - if (result == (uint32_t)idx) { - //cell hit itself! hooray! - - Vector3 normal(cells[idx].normal[0], cells[idx].normal[1], cells[idx].normal[2]); - if (normal == Vector3()) { - for (int i = 0; i < 6; i++) { - light->accum[i][0] += light_energy.x * cells[idx].albedo[0]; - light->accum[i][1] += light_energy.y * cells[idx].albedo[1]; - light->accum[i][2] += light_energy.z * cells[idx].albedo[2]; - } - - } else { - - for (int i = 0; i < 6; i++) { - float s = MAX(0.0, aniso_normal[i].dot(-normal)); - light->accum[i][0] += light_energy.x * cells[idx].albedo[0] * s; - light->accum[i][1] += light_energy.y * cells[idx].albedo[1] * s; - light->accum[i][2] += light_energy.z * cells[idx].albedo[2] * s; - } - } - - if (p_direct) { - for (int i = 0; i < 6; i++) { - float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct - light->direct_accum[i][0] += light_energy.x * s; - light->direct_accum[i][1] += light_energy.y * s; - light->direct_accum[i][2] += light_energy.z * s; - } - } - success_count++; - } - - idx = light_data[idx].next_leaf; - } -} - -void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color, float p_energy, float p_indirect_energy, float p_radius, float p_attenutation, bool p_direct) { - - _check_init_light(); - - if (p_direct) - direct_lights_baked = true; - - Plane clip[3]; - int clip_planes = 0; - - // uint64_t us = OS::get_singleton()->get_ticks_usec(); - - Vector3 light_pos = to_cell_space.xform(p_pos) + Vector3(0.5, 0.5, 0.5); - //Vector3 spot_axis = -light_cache.transform.basis.get_axis(2).normalized(); - - float local_radius = to_cell_space.basis.xform(Vector3(0, 0, 1)).length() * p_radius; - - Light *light_data = bake_light.ptrw(); - const Cell *cells = bake_cells.ptr(); - Vector3 light_energy = Vector3(p_color.r, p_color.g, p_color.b) * p_energy * p_indirect_energy; - - int idx = first_leaf; - while (idx >= 0) { - - Light *light = &light_data[idx]; - - Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5); - to += (light_pos - to).sign() * 0.47; //make it more likely to receive a ray - - Vector3 light_axis = (to - light_pos).normalized(); - float distance_adv = _get_normal_advance(light_axis); - - Vector3 normal(cells[idx].normal[0], cells[idx].normal[1], cells[idx].normal[2]); - - if (normal != Vector3() && normal.dot(-light_axis) < 0.001) { - idx = light_data[idx].next_leaf; - continue; - } - - float att = 1.0; - { - float d = light_pos.distance_to(to); - if (d + distance_adv > local_radius) { - idx = light_data[idx].next_leaf; - continue; // too far away - } - - float dt = CLAMP((d + distance_adv) / local_radius, 0, 1); - att *= powf(1.0 - dt, p_attenutation); - } - - clip_planes = 0; - - for (int c = 0; c < 3; c++) { - - if (Math::is_zero_approx(light_axis[c])) - continue; - clip[clip_planes].normal[c] = 1.0; - - if (light_axis[c] < 0) { - - clip[clip_planes].d = (1 << (cell_subdiv - 1)) + 1; - } else { - clip[clip_planes].d -= 1.0; - } - - clip_planes++; - } - - Vector3 from = light_pos; - - for (int j = 0; j < clip_planes; j++) { - - clip[j].intersects_segment(from, to, &from); - } - - float distance = (to - from).length(); - - distance -= Math::fmod(distance, distance_adv); //make it reach the center of the box always, but this tame make it closer - from = to - light_axis * distance; - to += (light_pos - to).sign() * 0.47; //make it more likely to receive a ray - - uint32_t result = 0xFFFFFFFF; - - while (distance > -distance_adv) { //use this to avoid precision errors - - result = _find_cell_at_pos(cells, int(floor(from.x)), int(floor(from.y)), int(floor(from.z))); - if (result != 0xFFFFFFFF) { - break; - } - - from += light_axis * distance_adv; - distance -= distance_adv; - } - - if (result == (uint32_t)idx) { - //cell hit itself! hooray! - - if (normal == Vector3()) { - for (int i = 0; i < 6; i++) { - light->accum[i][0] += light_energy.x * cells[idx].albedo[0] * att; - light->accum[i][1] += light_energy.y * cells[idx].albedo[1] * att; - light->accum[i][2] += light_energy.z * cells[idx].albedo[2] * att; - } - - } else { - - for (int i = 0; i < 6; i++) { - float s = MAX(0.0, aniso_normal[i].dot(-normal)); - light->accum[i][0] += light_energy.x * cells[idx].albedo[0] * s * att; - light->accum[i][1] += light_energy.y * cells[idx].albedo[1] * s * att; - light->accum[i][2] += light_energy.z * cells[idx].albedo[2] * s * att; - } - } - - if (p_direct) { - for (int i = 0; i < 6; i++) { - float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct - light->direct_accum[i][0] += light_energy.x * s * att; - light->direct_accum[i][1] += light_energy.y * s * att; - light->direct_accum[i][2] += light_energy.z * s * att; - } - } - } - - idx = light_data[idx].next_leaf; - } -} - -void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axis, const Color &p_color, float p_energy, float p_indirect_energy, float p_radius, float p_attenutation, float p_spot_angle, float p_spot_attenuation, bool p_direct) { - - _check_init_light(); - - if (p_direct) - direct_lights_baked = true; - - Plane clip[3]; - int clip_planes = 0; - - // uint64_t us = OS::get_singleton()->get_ticks_usec(); - - Vector3 light_pos = to_cell_space.xform(p_pos) + Vector3(0.5, 0.5, 0.5); - Vector3 spot_axis = to_cell_space.basis.xform(p_axis).normalized(); - - float local_radius = to_cell_space.basis.xform(Vector3(0, 0, 1)).length() * p_radius; - - Light *light_data = bake_light.ptrw(); - const Cell *cells = bake_cells.ptr(); - Vector3 light_energy = Vector3(p_color.r, p_color.g, p_color.b) * p_energy * p_indirect_energy; - - int idx = first_leaf; - while (idx >= 0) { - - Light *light = &light_data[idx]; - - Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5); - - Vector3 light_axis = (to - light_pos).normalized(); - float distance_adv = _get_normal_advance(light_axis); - - Vector3 normal(cells[idx].normal[0], cells[idx].normal[1], cells[idx].normal[2]); - - if (normal != Vector3() && normal.dot(-light_axis) < 0.001) { - idx = light_data[idx].next_leaf; - continue; - } - - float angle = Math::rad2deg(Math::acos(light_axis.dot(-spot_axis))); - if (angle > p_spot_angle) { - idx = light_data[idx].next_leaf; - continue; // too far away - } - - float att = Math::pow(1.0f - angle / p_spot_angle, p_spot_attenuation); - - { - float d = light_pos.distance_to(to); - if (d + distance_adv > local_radius) { - idx = light_data[idx].next_leaf; - continue; // too far away - } - - float dt = CLAMP((d + distance_adv) / local_radius, 0, 1); - att *= powf(1.0 - dt, p_attenutation); - } - - clip_planes = 0; - - for (int c = 0; c < 3; c++) { - - if (Math::is_zero_approx(light_axis[c])) - continue; - clip[clip_planes].normal[c] = 1.0; - - if (light_axis[c] < 0) { - - clip[clip_planes].d = (1 << (cell_subdiv - 1)) + 1; - } else { - clip[clip_planes].d -= 1.0; - } - - clip_planes++; - } - - Vector3 from = light_pos; - - for (int j = 0; j < clip_planes; j++) { - - clip[j].intersects_segment(from, to, &from); - } - - float distance = (to - from).length(); - - distance -= Math::fmod(distance, distance_adv); //make it reach the center of the box always, but this tame make it closer - from = to - light_axis * distance; - - uint32_t result = 0xFFFFFFFF; - - while (distance > -distance_adv) { //use this to avoid precision errors - - result = _find_cell_at_pos(cells, int(floor(from.x)), int(floor(from.y)), int(floor(from.z))); - if (result != 0xFFFFFFFF) { - break; - } - - from += light_axis * distance_adv; - distance -= distance_adv; - } - - if (result == (uint32_t)idx) { - //cell hit itself! hooray! - - if (normal == Vector3()) { - for (int i = 0; i < 6; i++) { - light->accum[i][0] += light_energy.x * cells[idx].albedo[0] * att; - light->accum[i][1] += light_energy.y * cells[idx].albedo[1] * att; - light->accum[i][2] += light_energy.z * cells[idx].albedo[2] * att; - } - - } else { - - for (int i = 0; i < 6; i++) { - float s = MAX(0.0, aniso_normal[i].dot(-normal)); - light->accum[i][0] += light_energy.x * cells[idx].albedo[0] * s * att; - light->accum[i][1] += light_energy.y * cells[idx].albedo[1] * s * att; - light->accum[i][2] += light_energy.z * cells[idx].albedo[2] * s * att; - } - } - - if (p_direct) { - for (int i = 0; i < 6; i++) { - float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct - light->direct_accum[i][0] += light_energy.x * s * att; - light->direct_accum[i][1] += light_energy.y * s * att; - light->direct_accum[i][2] += light_energy.z * s * att; - } - } - } - - idx = light_data[idx].next_leaf; - } -} - -void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) { - - if (p_level == cell_subdiv - 1) { - - leaf_voxel_count++; - float alpha = bake_cells[p_idx].alpha; - - bake_cells.write[p_idx].albedo[0] /= alpha; - bake_cells.write[p_idx].albedo[1] /= alpha; - bake_cells.write[p_idx].albedo[2] /= alpha; - - //transfer emission to light - bake_cells.write[p_idx].emission[0] /= alpha; - bake_cells.write[p_idx].emission[1] /= alpha; - bake_cells.write[p_idx].emission[2] /= alpha; - - bake_cells.write[p_idx].normal[0] /= alpha; - bake_cells.write[p_idx].normal[1] /= alpha; - bake_cells.write[p_idx].normal[2] /= alpha; - - Vector3 n(bake_cells[p_idx].normal[0], bake_cells[p_idx].normal[1], bake_cells[p_idx].normal[2]); - if (n.length() < 0.01) { - //too much fight over normal, zero it - bake_cells.write[p_idx].normal[0] = 0; - bake_cells.write[p_idx].normal[1] = 0; - bake_cells.write[p_idx].normal[2] = 0; - } else { - n.normalize(); - bake_cells.write[p_idx].normal[0] = n.x; - bake_cells.write[p_idx].normal[1] = n.y; - bake_cells.write[p_idx].normal[2] = n.z; - } - - bake_cells.write[p_idx].alpha = 1.0; - - /*if (bake_light.size()) { - for(int i=0;i<6;i++) { - - } - }*/ - - } else { - - //go down - - bake_cells.write[p_idx].emission[0] = 0; - bake_cells.write[p_idx].emission[1] = 0; - bake_cells.write[p_idx].emission[2] = 0; - bake_cells.write[p_idx].normal[0] = 0; - bake_cells.write[p_idx].normal[1] = 0; - bake_cells.write[p_idx].normal[2] = 0; - bake_cells.write[p_idx].albedo[0] = 0; - bake_cells.write[p_idx].albedo[1] = 0; - bake_cells.write[p_idx].albedo[2] = 0; - if (bake_light.size()) { - for (int j = 0; j < 6; j++) { - bake_light.write[p_idx].accum[j][0] = 0; - bake_light.write[p_idx].accum[j][1] = 0; - bake_light.write[p_idx].accum[j][2] = 0; - } - } - - float alpha_average = 0; - int children_found = 0; - - for (int i = 0; i < 8; i++) { - - uint32_t child = bake_cells[p_idx].children[i]; - - if (child == CHILD_EMPTY) - continue; - - _fixup_plot(child, p_level + 1); - alpha_average += bake_cells[child].alpha; - - if (bake_light.size() > 0) { - for (int j = 0; j < 6; j++) { - bake_light.write[p_idx].accum[j][0] += bake_light[child].accum[j][0]; - bake_light.write[p_idx].accum[j][1] += bake_light[child].accum[j][1]; - bake_light.write[p_idx].accum[j][2] += bake_light[child].accum[j][2]; - } - bake_cells.write[p_idx].emission[0] += bake_cells[child].emission[0]; - bake_cells.write[p_idx].emission[1] += bake_cells[child].emission[1]; - bake_cells.write[p_idx].emission[2] += bake_cells[child].emission[2]; - } - - children_found++; - } - - bake_cells.write[p_idx].alpha = alpha_average / 8.0; - if (bake_light.size() && children_found) { - float divisor = Math::lerp(8, children_found, propagation); - for (int j = 0; j < 6; j++) { - bake_light.write[p_idx].accum[j][0] /= divisor; - bake_light.write[p_idx].accum[j][1] /= divisor; - bake_light.write[p_idx].accum[j][2] /= divisor; - } - bake_cells.write[p_idx].emission[0] /= divisor; - bake_cells.write[p_idx].emission[1] /= divisor; - bake_cells.write[p_idx].emission[2] /= divisor; - } - } -} - -//make sure any cell (save for the root) has an empty cell previous to it, so it can be interpolated into - -void VoxelLightBaker::_plot_triangle(Vector2 *vertices, Vector3 *positions, Vector3 *normals, LightMap *pixels, int width, int height) { - - int x[3]; - int y[3]; - - for (int j = 0; j < 3; j++) { - - x[j] = vertices[j].x * width; - y[j] = vertices[j].y * height; - //x[j] = CLAMP(x[j], 0, bt.width - 1); - //y[j] = CLAMP(y[j], 0, bt.height - 1); - } - - // sort the points vertically - if (y[1] > y[2]) { - SWAP(x[1], x[2]); - SWAP(y[1], y[2]); - SWAP(positions[1], positions[2]); - SWAP(normals[1], normals[2]); - } - if (y[0] > y[1]) { - SWAP(x[0], x[1]); - SWAP(y[0], y[1]); - SWAP(positions[0], positions[1]); - SWAP(normals[0], normals[1]); - } - if (y[1] > y[2]) { - SWAP(x[1], x[2]); - SWAP(y[1], y[2]); - SWAP(positions[1], positions[2]); - SWAP(normals[1], normals[2]); - } - - double dx_far = double(x[2] - x[0]) / (y[2] - y[0] + 1); - double dx_upper = double(x[1] - x[0]) / (y[1] - y[0] + 1); - double dx_low = double(x[2] - x[1]) / (y[2] - y[1] + 1); - double xf = x[0]; - double xt = x[0] + dx_upper; // if y[0] == y[1], special case - for (int yi = y[0]; yi <= (y[2] > height - 1 ? height - 1 : y[2]); yi++) { - if (yi >= 0) { - for (int xi = (xf > 0 ? int(xf) : 0); xi <= (xt < width ? xt : width - 1); xi++) { - //pixels[int(x + y * width)] = color; - - Vector2 v0 = Vector2(x[1] - x[0], y[1] - y[0]); - Vector2 v1 = Vector2(x[2] - x[0], y[2] - y[0]); - //vertices[2] - vertices[0]; - Vector2 v2 = Vector2(xi - x[0], yi - y[0]); - float d00 = v0.dot(v0); - float d01 = v0.dot(v1); - float d11 = v1.dot(v1); - float d20 = v2.dot(v0); - float d21 = v2.dot(v1); - float denom = (d00 * d11 - d01 * d01); - Vector3 pos; - Vector3 normal; - if (denom == 0) { - pos = positions[0]; - normal = normals[0]; - } else { - float v = (d11 * d20 - d01 * d21) / denom; - float w = (d00 * d21 - d01 * d20) / denom; - float u = 1.0f - v - w; - pos = positions[0] * u + positions[1] * v + positions[2] * w; - normal = normals[0] * u + normals[1] * v + normals[2] * w; - } - - int ofs = yi * width + xi; - pixels[ofs].normal = normal; - pixels[ofs].pos = pos; - } - - for (int xi = (xf < width ? int(xf) : width - 1); xi >= (xt > 0 ? xt : 0); xi--) { - //pixels[int(x + y * width)] = color; - Vector2 v0 = Vector2(x[1] - x[0], y[1] - y[0]); - Vector2 v1 = Vector2(x[2] - x[0], y[2] - y[0]); - //vertices[2] - vertices[0]; - Vector2 v2 = Vector2(xi - x[0], yi - y[0]); - float d00 = v0.dot(v0); - float d01 = v0.dot(v1); - float d11 = v1.dot(v1); - float d20 = v2.dot(v0); - float d21 = v2.dot(v1); - float denom = (d00 * d11 - d01 * d01); - Vector3 pos; - Vector3 normal; - if (denom == 0) { - pos = positions[0]; - normal = normals[0]; - } else { - float v = (d11 * d20 - d01 * d21) / denom; - float w = (d00 * d21 - d01 * d20) / denom; - float u = 1.0f - v - w; - pos = positions[0] * u + positions[1] * v + positions[2] * w; - normal = normals[0] * u + normals[1] * v + normals[2] * w; - } - - int ofs = yi * width + xi; - pixels[ofs].normal = normal; - pixels[ofs].pos = pos; - } - } - xf += dx_far; - if (yi < y[1]) - xt += dx_upper; - else - xt += dx_low; - } -} - -void VoxelLightBaker::_sample_baked_octree_filtered_and_anisotropic(const Vector3 &p_posf, const Vector3 &p_direction, float p_level, Vector3 &r_color, float &r_alpha) { - - int size = 1 << (cell_subdiv - 1); - - int clamp_v = size - 1; - //first of all, clamp - Vector3 pos; - pos.x = CLAMP(p_posf.x, 0, clamp_v); - pos.y = CLAMP(p_posf.y, 0, clamp_v); - pos.z = CLAMP(p_posf.z, 0, clamp_v); - - float level = (cell_subdiv - 1) - p_level; - - int target_level; - float level_filter; - if (level <= 0.0) { - level_filter = 0; - target_level = 0; - } else { - target_level = Math::ceil(level); - level_filter = target_level - level; - } - - const Cell *cells = bake_cells.ptr(); - const Light *light = bake_light.ptr(); - - Vector3 color[2][8]; - float alpha[2][8]; - zeromem(alpha, sizeof(float) * 2 * 8); - - //find cell at given level first - - for (int c = 0; c < 2; c++) { - - int current_level = MAX(0, target_level - c); - int level_cell_size = (1 << (cell_subdiv - 1)) >> current_level; - - for (int n = 0; n < 8; n++) { - - int x = int(pos.x); - int y = int(pos.y); - int z = int(pos.z); - - if (n & 1) - x += level_cell_size; - if (n & 2) - y += level_cell_size; - if (n & 4) - z += level_cell_size; - - int ofs_x = 0; - int ofs_y = 0; - int ofs_z = 0; - - x = CLAMP(x, 0, clamp_v); - y = CLAMP(y, 0, clamp_v); - z = CLAMP(z, 0, clamp_v); - - int half = size / 2; - uint32_t cell = 0; - for (int i = 0; i < current_level; i++) { - - const Cell *bc = &cells[cell]; - - int child = 0; - if (x >= ofs_x + half) { - child |= 1; - ofs_x += half; - } - if (y >= ofs_y + half) { - child |= 2; - ofs_y += half; - } - if (z >= ofs_z + half) { - child |= 4; - ofs_z += half; - } - - cell = bc->children[child]; - if (cell == CHILD_EMPTY) - break; - - half >>= 1; - } - - if (cell == CHILD_EMPTY) { - alpha[c][n] = 0; - } else { - alpha[c][n] = cells[cell].alpha; - - for (int i = 0; i < 6; i++) { - //anisotropic read light - float amount = p_direction.dot(aniso_normal[i]); - if (amount < 0) - amount = 0; - color[c][n].x += light[cell].accum[i][0] * amount; - color[c][n].y += light[cell].accum[i][1] * amount; - color[c][n].z += light[cell].accum[i][2] * amount; - } - - color[c][n].x += cells[cell].emission[0]; - color[c][n].y += cells[cell].emission[1]; - color[c][n].z += cells[cell].emission[2]; - } - } - } - - float target_level_size = size >> target_level; - Vector3 pos_fract[2]; - - pos_fract[0].x = Math::fmod(pos.x, target_level_size) / target_level_size; - pos_fract[0].y = Math::fmod(pos.y, target_level_size) / target_level_size; - pos_fract[0].z = Math::fmod(pos.z, target_level_size) / target_level_size; - - target_level_size = size >> MAX(0, target_level - 1); - - pos_fract[1].x = Math::fmod(pos.x, target_level_size) / target_level_size; - pos_fract[1].y = Math::fmod(pos.y, target_level_size) / target_level_size; - pos_fract[1].z = Math::fmod(pos.z, target_level_size) / target_level_size; - - float alpha_interp[2]; - Vector3 color_interp[2]; - - for (int i = 0; i < 2; i++) { - - Vector3 color_x00 = color[i][0].linear_interpolate(color[i][1], pos_fract[i].x); - Vector3 color_xy0 = color[i][2].linear_interpolate(color[i][3], pos_fract[i].x); - Vector3 blend_z0 = color_x00.linear_interpolate(color_xy0, pos_fract[i].y); - - Vector3 color_x0z = color[i][4].linear_interpolate(color[i][5], pos_fract[i].x); - Vector3 color_xyz = color[i][6].linear_interpolate(color[i][7], pos_fract[i].x); - Vector3 blend_z1 = color_x0z.linear_interpolate(color_xyz, pos_fract[i].y); - - color_interp[i] = blend_z0.linear_interpolate(blend_z1, pos_fract[i].z); - - float alpha_x00 = Math::lerp(alpha[i][0], alpha[i][1], pos_fract[i].x); - float alpha_xy0 = Math::lerp(alpha[i][2], alpha[i][3], pos_fract[i].x); - float alpha_z0 = Math::lerp(alpha_x00, alpha_xy0, pos_fract[i].y); - - float alpha_x0z = Math::lerp(alpha[i][4], alpha[i][5], pos_fract[i].x); - float alpha_xyz = Math::lerp(alpha[i][6], alpha[i][7], pos_fract[i].x); - float alpha_z1 = Math::lerp(alpha_x0z, alpha_xyz, pos_fract[i].y); - - alpha_interp[i] = Math::lerp(alpha_z0, alpha_z1, pos_fract[i].z); - } - - r_color = color_interp[0].linear_interpolate(color_interp[1], level_filter); - r_alpha = Math::lerp(alpha_interp[0], alpha_interp[1], level_filter); -} - -Vector3 VoxelLightBaker::_voxel_cone_trace(const Vector3 &p_pos, const Vector3 &p_normal, float p_aperture) { - - float bias = 2.5; - float max_distance = (Vector3(1, 1, 1) * (1 << (cell_subdiv - 1))).length(); - - float dist = bias; - float alpha = 0.0; - Vector3 color; - - Vector3 scolor; - float salpha; - - while (dist < max_distance && alpha < 0.95) { - float diameter = MAX(1.0, 2.0 * p_aperture * dist); - _sample_baked_octree_filtered_and_anisotropic(p_pos + dist * p_normal, p_normal, log2(diameter), scolor, salpha); - float a = (1.0 - alpha); - color += scolor * a; - alpha += a * salpha; - dist += diameter * 0.5; - } - - /*if (blend_ambient) { - color.rgb = mix(ambient,color.rgb,min(1.0,alpha/0.95)); - }*/ - - return color; -} - -Vector3 VoxelLightBaker::_compute_pixel_light_at_pos(const Vector3 &p_pos, const Vector3 &p_normal) { - - //find arbitrary tangent and bitangent, then build a matrix - Vector3 v0 = Math::abs(p_normal.z) < 0.999 ? Vector3(0, 0, 1) : Vector3(0, 1, 0); - Vector3 tangent = v0.cross(p_normal).normalized(); - Vector3 bitangent = tangent.cross(p_normal).normalized(); - Basis normal_xform = Basis(tangent, bitangent, p_normal).transposed(); - - const Vector3 *cone_dirs = NULL; - const float *cone_weights = NULL; - int cone_dir_count = 0; - float cone_aperture = 0; - - switch (bake_quality) { - case BAKE_QUALITY_LOW: { - //default quality - static const Vector3 dirs[4] = { - Vector3(Math_SQRT12, 0, Math_SQRT12), - Vector3(0, Math_SQRT12, Math_SQRT12), - Vector3(-Math_SQRT12, 0, Math_SQRT12), - Vector3(0, -Math_SQRT12, Math_SQRT12) - }; - - static const float weights[4] = { 0.25, 0.25, 0.25, 0.25 }; - - cone_dirs = dirs; - cone_dir_count = 4; - cone_aperture = 1.0; // tan(angle) 90 degrees - cone_weights = weights; - } break; - case BAKE_QUALITY_MEDIUM: { - //default quality - static const Vector3 dirs[6] = { - Vector3(0, 0, 1), - Vector3(0.866025, 0, 0.5), - Vector3(0.267617, 0.823639, 0.5), - Vector3(-0.700629, 0.509037, 0.5), - Vector3(-0.700629, -0.509037, 0.5), - Vector3(0.267617, -0.823639, 0.5) - }; - static const float weights[6] = { 0.25f, 0.15f, 0.15f, 0.15f, 0.15f, 0.15f }; - // - cone_dirs = dirs; - cone_dir_count = 6; - cone_aperture = 0.577; // tan(angle) 60 degrees - cone_weights = weights; - } break; - case BAKE_QUALITY_HIGH: { - - //high qualily - static const Vector3 dirs[10] = { - Vector3(0.8781648411741658, 0.0, 0.478358141694643), - Vector3(0.5369754325592234, 0.6794204427701518, 0.5000452447267606), - Vector3(-0.19849436573466497, 0.8429904390140635, 0.49996710542041645), - Vector3(-0.7856196499811189, 0.3639120321329737, 0.5003696617825604), - Vector3(-0.7856196499811189, -0.3639120321329737, 0.5003696617825604), - Vector3(-0.19849436573466497, -0.8429904390140635, 0.49996710542041645), - Vector3(0.5369754325592234, -0.6794204427701518, 0.5000452447267606), - Vector3(-0.4451656858129485, 0.0, 0.8954482185892644), - Vector3(0.19124006749743122, 0.39355745585016605, 0.8991883926788214), - Vector3(0.19124006749743122, -0.39355745585016605, 0.8991883926788214), - }; - static const float weights[10] = { 0.08571f, 0.08571f, 0.08571f, 0.08571f, 0.08571f, 0.08571f, 0.08571f, 0.133333f, 0.133333f, 0.13333f }; - cone_dirs = dirs; - cone_dir_count = 10; - cone_aperture = 0.404; // tan(angle) 45 degrees - cone_weights = weights; - } break; - } - - Vector3 accum; - - for (int i = 0; i < cone_dir_count; i++) { - Vector3 dir = normal_xform.xform(cone_dirs[i]).normalized(); //normal may not completely correct when transformed to cell - accum += _voxel_cone_trace(p_pos, dir, cone_aperture) * cone_weights[i]; - } - - return accum; -} - -_ALWAYS_INLINE_ uint32_t xorshift32(uint32_t *state) { - /* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */ - uint32_t x = *state; - x ^= x << 13; - x ^= x >> 17; - x ^= x << 5; - *state = x; - return x; -} - -Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal) { - - int samples_per_quality[3] = { 48, 128, 512 }; - - int samples = samples_per_quality[bake_quality]; - - //create a basis in Z - Vector3 v0 = Math::abs(p_normal.z) < 0.999 ? Vector3(0, 0, 1) : Vector3(0, 1, 0); - Vector3 tangent = v0.cross(p_normal).normalized(); - Vector3 bitangent = tangent.cross(p_normal).normalized(); - Basis normal_xform = Basis(tangent, bitangent, p_normal).transposed(); - - float bias = 1.5; - int max_level = cell_subdiv - 1; - int size = 1 << max_level; - - Vector3 accum; - float spread = Math::deg2rad(80.0); - - const Light *light = bake_light.ptr(); - const Cell *cells = bake_cells.ptr(); - - uint32_t local_rng_state = rand(); //needs to be fixed again - - for (int i = 0; i < samples; i++) { - - float random_angle1 = (((xorshift32(&local_rng_state) % 65535) / 65535.0) * 2.0 - 1.0) * spread; - Vector3 axis(0, sin(random_angle1), cos(random_angle1)); - float random_angle2 = ((xorshift32(&local_rng_state) % 65535) / 65535.0) * Math_PI * 2.0; - Basis rot(Vector3(0, 0, 1), random_angle2); - axis = rot.xform(axis); - - Vector3 direction = normal_xform.xform(axis).normalized(); - - Vector3 advance = direction * _get_normal_advance(direction); - - Vector3 pos = p_pos /*+ Vector3(0.5, 0.5, 0.5)*/ + advance * bias; - - uint32_t cell = CHILD_EMPTY; - - while (cell == CHILD_EMPTY) { - - int x = int(pos.x); - int y = int(pos.y); - int z = int(pos.z); - - int ofs_x = 0; - int ofs_y = 0; - int ofs_z = 0; - int half = size / 2; - - if (x < 0 || x >= size) - break; - if (y < 0 || y >= size) - break; - if (z < 0 || z >= size) - break; - - //int level_limit = max_level; - - cell = 0; //start from root - for (int j = 0; j < max_level; j++) { - - const Cell *bc = &cells[cell]; - - int child = 0; - if (x >= ofs_x + half) { - child |= 1; - ofs_x += half; - } - if (y >= ofs_y + half) { - child |= 2; - ofs_y += half; - } - if (z >= ofs_z + half) { - child |= 4; - ofs_z += half; - } - - cell = bc->children[child]; - if (unlikely(cell == CHILD_EMPTY)) - break; - - half >>= 1; - } - - pos += advance; - } - - if (unlikely(cell != CHILD_EMPTY)) { - for (int j = 0; j < 6; j++) { - //anisotropic read light - float amount = direction.dot(aniso_normal[j]); - if (amount <= 0) - continue; - accum.x += light[cell].accum[j][0] * amount; - accum.y += light[cell].accum[j][1] * amount; - accum.z += light[cell].accum[j][2] * amount; - } - accum.x += cells[cell].emission[0]; - accum.y += cells[cell].emission[1]; - accum.z += cells[cell].emission[2]; - } - } - - // Make sure we don't reset this thread's RNG state - - return accum / samples; -} - -void VoxelLightBaker::_lightmap_bake_point(uint32_t p_x, LightMap *p_line) { - - LightMap *pixel = &p_line[p_x]; - if (pixel->pos == Vector3()) - return; - switch (bake_mode) { - case BAKE_MODE_CONE_TRACE: { - pixel->light = _compute_pixel_light_at_pos(pixel->pos, pixel->normal) * energy; - } break; - case BAKE_MODE_RAY_TRACE: { - pixel->light = _compute_ray_trace_at_pos(pixel->pos, pixel->normal) * energy; - } break; - } -} - -Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh, float default_texels_per_unit, LightMapData &r_lightmap, bool (*p_bake_time_func)(void *, float, float), void *p_bake_time_ud) { - - //transfer light information to a lightmap - Ref<Mesh> mesh = p_mesh; - - //step 1 - create lightmap - int width; - int height; - Vector<LightMap> lightmap; - Transform xform = to_cell_space * p_xform; - if (mesh->get_lightmap_size_hint() == Size2()) { - double area = 0; - double uv_area = 0; - for (int i = 0; i < mesh->get_surface_count(); i++) { - Array arrays = mesh->surface_get_arrays(i); - PoolVector<Vector3> vertices = arrays[Mesh::ARRAY_VERTEX]; - PoolVector<Vector2> uv2 = arrays[Mesh::ARRAY_TEX_UV2]; - PoolVector<int> indices = arrays[Mesh::ARRAY_INDEX]; - - ERR_FAIL_COND_V(vertices.size() == 0, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(uv2.size() == 0, ERR_INVALID_PARAMETER); - - int vc = vertices.size(); - PoolVector<Vector3>::Read vr = vertices.read(); - PoolVector<Vector2>::Read u2r = uv2.read(); - PoolVector<int>::Read ir; - int ic = 0; - - if (indices.size()) { - ic = indices.size(); - ir = indices.read(); - } - - int faces = ic ? ic / 3 : vc / 3; - for (int j = 0; j < faces; j++) { - Vector3 vertex[3]; - Vector2 uv[3]; - - for (int k = 0; k < 3; k++) { - int idx = ic ? ir[j * 3 + k] : j * 3 + k; - vertex[k] = xform.xform(vr[idx]); - uv[k] = u2r[idx]; - } - - Vector3 p1 = vertex[0]; - Vector3 p2 = vertex[1]; - Vector3 p3 = vertex[2]; - double a = p1.distance_to(p2); - double b = p2.distance_to(p3); - double c = p3.distance_to(p1); - double halfPerimeter = (a + b + c) / 2.0; - area += sqrt(halfPerimeter * (halfPerimeter - a) * (halfPerimeter - b) * (halfPerimeter - c)); - - Vector2 uv_p1 = uv[0]; - Vector2 uv_p2 = uv[1]; - Vector2 uv_p3 = uv[2]; - double uv_a = uv_p1.distance_to(uv_p2); - double uv_b = uv_p2.distance_to(uv_p3); - double uv_c = uv_p3.distance_to(uv_p1); - double uv_halfPerimeter = (uv_a + uv_b + uv_c) / 2.0; - uv_area += sqrt(uv_halfPerimeter * (uv_halfPerimeter - uv_a) * (uv_halfPerimeter - uv_b) * (uv_halfPerimeter - uv_c)); - } - } - - if (uv_area < 0.0001f) { - uv_area = 1.0; - } - - int pixels = (ceil((1.0 / sqrt(uv_area)) * sqrt(area * default_texels_per_unit))); - width = height = CLAMP(pixels, 2, 4096); - } else { - width = mesh->get_lightmap_size_hint().x; - height = mesh->get_lightmap_size_hint().y; - } - - lightmap.resize(width * height); - - //step 2 plot faces to lightmap - for (int i = 0; i < mesh->get_surface_count(); i++) { - Array arrays = mesh->surface_get_arrays(i); - PoolVector<Vector3> vertices = arrays[Mesh::ARRAY_VERTEX]; - PoolVector<Vector3> normals = arrays[Mesh::ARRAY_NORMAL]; - PoolVector<Vector2> uv2 = arrays[Mesh::ARRAY_TEX_UV2]; - PoolVector<int> indices = arrays[Mesh::ARRAY_INDEX]; - - ERR_FAIL_COND_V(vertices.size() == 0, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(normals.size() == 0, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(uv2.size() == 0, ERR_INVALID_PARAMETER); - - int vc = vertices.size(); - PoolVector<Vector3>::Read vr = vertices.read(); - PoolVector<Vector3>::Read nr = normals.read(); - PoolVector<Vector2>::Read u2r = uv2.read(); - PoolVector<int>::Read ir; - int ic = 0; - - if (indices.size()) { - ic = indices.size(); - ir = indices.read(); - } - - int faces = ic ? ic / 3 : vc / 3; - for (int j = 0; j < faces; j++) { - Vector3 vertex[3]; - Vector3 normal[3]; - Vector2 uv[3]; - - for (int k = 0; k < 3; k++) { - int idx = ic ? ir[j * 3 + k] : j * 3 + k; - vertex[k] = xform.xform(vr[idx]); - normal[k] = xform.basis.xform(nr[idx]).normalized(); - uv[k] = u2r[idx]; - } - - _plot_triangle(uv, vertex, normal, lightmap.ptrw(), width, height); - } - } - - //step 3 perform voxel cone trace on lightmap pixels - { - LightMap *lightmap_ptr = lightmap.ptrw(); - uint64_t begin_time = OS::get_singleton()->get_ticks_usec(); - volatile int lines = 0; - - // make sure our OS-level rng is seeded - - for (int i = 0; i < height; i++) { - - thread_process_array(width, this, &VoxelLightBaker::_lightmap_bake_point, &lightmap_ptr[i * width]); - - lines = MAX(lines, i); //for multithread - if (p_bake_time_func) { - uint64_t elapsed = OS::get_singleton()->get_ticks_usec() - begin_time; - float elapsed_sec = double(elapsed) / 1000000.0; - float remaining = lines < 1 ? 0 : (elapsed_sec / lines) * (height - lines - 1); - if (p_bake_time_func(p_bake_time_ud, remaining, lines / float(height))) { - return ERR_SKIP; - } - } - } - - if (bake_mode == BAKE_MODE_RAY_TRACE) { - //blur - //gauss kernel, 7 step sigma 2 - static const float gauss_kernel[4] = { 0.214607f, 0.189879f, 0.131514f, 0.071303f }; - //horizontal pass - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++) { - if (lightmap_ptr[i * width + j].normal == Vector3()) { - continue; //empty - } - float gauss_sum = gauss_kernel[0]; - Vector3 accum = lightmap_ptr[i * width + j].light * gauss_kernel[0]; - for (int k = 1; k < 4; k++) { - int new_x = j + k; - if (new_x >= width || lightmap_ptr[i * width + new_x].normal == Vector3()) - break; - gauss_sum += gauss_kernel[k]; - accum += lightmap_ptr[i * width + new_x].light * gauss_kernel[k]; - } - for (int k = 1; k < 4; k++) { - int new_x = j - k; - if (new_x < 0 || lightmap_ptr[i * width + new_x].normal == Vector3()) - break; - gauss_sum += gauss_kernel[k]; - accum += lightmap_ptr[i * width + new_x].light * gauss_kernel[k]; - } - - lightmap_ptr[i * width + j].pos = accum /= gauss_sum; - } - } - //vertical pass - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++) { - if (lightmap_ptr[i * width + j].normal == Vector3()) - continue; //empty, don't write over it anyway - float gauss_sum = gauss_kernel[0]; - Vector3 accum = lightmap_ptr[i * width + j].pos * gauss_kernel[0]; - for (int k = 1; k < 4; k++) { - int new_y = i + k; - if (new_y >= height || lightmap_ptr[new_y * width + j].normal == Vector3()) - break; - gauss_sum += gauss_kernel[k]; - accum += lightmap_ptr[new_y * width + j].pos * gauss_kernel[k]; - } - for (int k = 1; k < 4; k++) { - int new_y = i - k; - if (new_y < 0 || lightmap_ptr[new_y * width + j].normal == Vector3()) - break; - gauss_sum += gauss_kernel[k]; - accum += lightmap_ptr[new_y * width + j].pos * gauss_kernel[k]; - } - - lightmap_ptr[i * width + j].light = accum /= gauss_sum; - } - } - } - - //add directional light (do this after blur) - { - const Cell *cells = bake_cells.ptr(); - const Light *light = bake_light.ptr(); -#ifdef _OPENMP -#pragma omp parallel -#endif - for (int i = 0; i < height; i++) { -#ifdef _OPENMP -#pragma omp parallel for schedule(dynamic, 1) -#endif - for (int j = 0; j < width; j++) { - - //if (i == 125 && j == 280) { - - LightMap *pixel = &lightmap_ptr[i * width + j]; - if (pixel->pos == Vector3()) - continue; //unused, skipe - - int x = int(pixel->pos.x) - 1; - int y = int(pixel->pos.y) - 1; - int z = int(pixel->pos.z) - 1; - Color accum; - int size = 1 << (cell_subdiv - 1); - - int found = 0; - - for (int k = 0; k < 8; k++) { - - int ofs_x = x; - int ofs_y = y; - int ofs_z = z; - - if (k & 1) - ofs_x++; - if (k & 2) - ofs_y++; - if (k & 4) - ofs_z++; - - if (x < 0 || x >= size) - continue; - if (y < 0 || y >= size) - continue; - if (z < 0 || z >= size) - continue; - - uint32_t cell = _find_cell_at_pos(cells, ofs_x, ofs_y, ofs_z); - - if (cell == CHILD_EMPTY) - continue; - for (int l = 0; l < 6; l++) { - float s = pixel->normal.dot(aniso_normal[l]); - if (s < 0) - s = 0; - accum.r += light[cell].direct_accum[l][0] * s; - accum.g += light[cell].direct_accum[l][1] * s; - accum.b += light[cell].direct_accum[l][2] * s; - } - found++; - } - if (found) { - accum /= found; - pixel->light.x += accum.r; - pixel->light.y += accum.g; - pixel->light.z += accum.b; - } - } - } - } - - { - //fill gaps with neighbour vertices to avoid filter fades to black on edges - - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++) { - if (lightmap_ptr[i * width + j].normal != Vector3()) { - continue; //filled, skip - } - - //this can't be made separatable.. - - int closest_i = -1, closest_j = 1; - float closest_dist = 1e20; - - const int margin = 3; - for (int y = i - margin; y <= i + margin; y++) { - for (int x = j - margin; x <= j + margin; x++) { - - if (x == j && y == i) - continue; - if (x < 0 || x >= width) - continue; - if (y < 0 || y >= height) - continue; - if (lightmap_ptr[y * width + x].normal == Vector3()) - continue; //also ensures that blitted stuff is not reused - - float dist = Vector2(i - y, j - x).length(); - if (dist > closest_dist) - continue; - - closest_dist = dist; - closest_i = y; - closest_j = x; - } - } - - if (closest_i != -1) { - lightmap_ptr[i * width + j].light = lightmap_ptr[closest_i * width + closest_j].light; - } - } - } - } - - { - //fill the lightmap data - r_lightmap.width = width; - r_lightmap.height = height; - r_lightmap.light.resize(lightmap.size() * 3); - PoolVector<float>::Write w = r_lightmap.light.write(); - for (int i = 0; i < lightmap.size(); i++) { - w[i * 3 + 0] = lightmap[i].light.x; - w[i * 3 + 1] = lightmap[i].light.y; - w[i * 3 + 2] = lightmap[i].light.z; - } - } - -#if 0 // Enable for debugging. - { - PoolVector<uint8_t> img; - int ls = lightmap.size(); - img.resize(ls * 3); - { - PoolVector<uint8_t>::Write w = img.write(); - for (int i = 0; i < ls; i++) { - w[i * 3 + 0] = CLAMP(lightmap_ptr[i].light.x * 255, 0, 255); - w[i * 3 + 1] = CLAMP(lightmap_ptr[i].light.y * 255, 0, 255); - w[i * 3 + 2] = CLAMP(lightmap_ptr[i].light.z * 255, 0, 255); - //w[i * 3 + 0] = CLAMP(lightmap_ptr[i].normal.x * 255, 0, 255); - //w[i * 3 + 1] = CLAMP(lightmap_ptr[i].normal.y * 255, 0, 255); - //w[i * 3 + 2] = CLAMP(lightmap_ptr[i].normal.z * 255, 0, 255); - //w[i * 3 + 0] = CLAMP(lightmap_ptr[i].pos.x / (1 << (cell_subdiv - 1)) * 255, 0, 255); - //w[i * 3 + 1] = CLAMP(lightmap_ptr[i].pos.y / (1 << (cell_subdiv - 1)) * 255, 0, 255); - //w[i * 3 + 2] = CLAMP(lightmap_ptr[i].pos.z / (1 << (cell_subdiv - 1)) * 255, 0, 255); - } - } - - Ref<Image> image; - image.instance(); - image->create(width, height, false, Image::FORMAT_RGB8, img); - - String name = p_mesh->get_name(); - if (name == "") { - name = "Mesh" + itos(p_mesh->get_instance_id()); - } - image->save_png(name + ".png"); - } -#endif - } - - return OK; -} - -void VoxelLightBaker::begin_bake(int p_subdiv, const AABB &p_bounds) { - - original_bounds = p_bounds; - cell_subdiv = p_subdiv; - bake_cells.resize(1); - material_cache.clear(); - - //find out the actual real bounds, power of 2, which gets the highest subdivision - po2_bounds = p_bounds; - int longest_axis = po2_bounds.get_longest_axis_index(); - axis_cell_size[longest_axis] = (1 << (cell_subdiv - 1)); - leaf_voxel_count = 0; - - for (int i = 0; i < 3; i++) { - - if (i == longest_axis) - continue; - - axis_cell_size[i] = axis_cell_size[longest_axis]; - float axis_size = po2_bounds.size[longest_axis]; - - //shrink until fit subdiv - while (axis_size / 2.0 >= po2_bounds.size[i]) { - axis_size /= 2.0; - axis_cell_size[i] >>= 1; - } - - po2_bounds.size[i] = po2_bounds.size[longest_axis]; - } - - Transform to_bounds; - to_bounds.basis.scale(Vector3(po2_bounds.size[longest_axis], po2_bounds.size[longest_axis], po2_bounds.size[longest_axis])); - to_bounds.origin = po2_bounds.position; - - Transform to_grid; - to_grid.basis.scale(Vector3(axis_cell_size[longest_axis], axis_cell_size[longest_axis], axis_cell_size[longest_axis])); - - to_cell_space = to_grid * to_bounds.affine_inverse(); - - cell_size = po2_bounds.size[longest_axis] / axis_cell_size[longest_axis]; -} - -void VoxelLightBaker::end_bake() { - _fixup_plot(0, 0); -} - -//create the data for visual server - -PoolVector<int> VoxelLightBaker::create_gi_probe_data() { - - PoolVector<int> data; - - data.resize(16 + (8 + 1 + 1 + 1 + 1) * bake_cells.size()); //4 for header, rest for rest. - - { - PoolVector<int>::Write w = data.write(); - - uint32_t *w32 = (uint32_t *)w.ptr(); - - w32[0] = 0; //version - w32[1] = cell_subdiv; //subdiv - w32[2] = axis_cell_size[0]; - w32[3] = axis_cell_size[1]; - w32[4] = axis_cell_size[2]; - w32[5] = bake_cells.size(); - w32[6] = leaf_voxel_count; - - int ofs = 16; - - for (int i = 0; i < bake_cells.size(); i++) { - - for (int j = 0; j < 8; j++) { - w32[ofs++] = bake_cells[i].children[j]; - } - - { //albedo - uint32_t rgba = uint32_t(CLAMP(bake_cells[i].albedo[0] * 255.0, 0, 255)) << 16; - rgba |= uint32_t(CLAMP(bake_cells[i].albedo[1] * 255.0, 0, 255)) << 8; - rgba |= uint32_t(CLAMP(bake_cells[i].albedo[2] * 255.0, 0, 255)) << 0; - - w32[ofs++] = rgba; - } - { //emission - - Vector3 e(bake_cells[i].emission[0], bake_cells[i].emission[1], bake_cells[i].emission[2]); - float l = e.length(); - if (l > 0) { - e.normalize(); - l = CLAMP(l / 8.0, 0, 1.0); - } - - uint32_t em = uint32_t(CLAMP(e[0] * 255, 0, 255)) << 24; - em |= uint32_t(CLAMP(e[1] * 255, 0, 255)) << 16; - em |= uint32_t(CLAMP(e[2] * 255, 0, 255)) << 8; - em |= uint32_t(CLAMP(l * 255, 0, 255)); - - w32[ofs++] = em; - } - - //w32[ofs++]=bake_cells[i].used_sides; - { //normal - - Vector3 n(bake_cells[i].normal[0], bake_cells[i].normal[1], bake_cells[i].normal[2]); - n = n * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); - uint32_t norm = 0; - - norm |= uint32_t(CLAMP(n.x * 255.0, 0, 255)) << 16; - norm |= uint32_t(CLAMP(n.y * 255.0, 0, 255)) << 8; - norm |= uint32_t(CLAMP(n.z * 255.0, 0, 255)) << 0; - - w32[ofs++] = norm; - } - - { - uint16_t alpha = MIN(uint32_t(bake_cells[i].alpha * 65535.0), 65535); - uint16_t level = bake_cells[i].level; - - w32[ofs++] = (uint32_t(level) << 16) | uint32_t(alpha); - } - } - } - - return data; -} - -void VoxelLightBaker::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx, DebugMode p_mode) { - - if (p_level == cell_subdiv - 1) { - - Vector3 center = p_aabb.position + p_aabb.size * 0.5; - Transform xform; - xform.origin = center; - xform.basis.scale(p_aabb.size * 0.5); - p_multimesh->set_instance_transform(idx, xform); - Color col; - if (p_mode == DEBUG_ALBEDO) { - col = Color(bake_cells[p_idx].albedo[0], bake_cells[p_idx].albedo[1], bake_cells[p_idx].albedo[2]); - } else if (p_mode == DEBUG_LIGHT) { - for (int i = 0; i < 6; i++) { - col.r += bake_light[p_idx].accum[i][0]; - col.g += bake_light[p_idx].accum[i][1]; - col.b += bake_light[p_idx].accum[i][2]; - col.r += bake_light[p_idx].direct_accum[i][0]; - col.g += bake_light[p_idx].direct_accum[i][1]; - col.b += bake_light[p_idx].direct_accum[i][2]; - } - } - //Color col = Color(bake_cells[p_idx].emission[0], bake_cells[p_idx].emission[1], bake_cells[p_idx].emission[2]); - p_multimesh->set_instance_color(idx, col); - - idx++; - - } else { - - for (int i = 0; i < 8; i++) { - - uint32_t child = bake_cells[p_idx].children[i]; - - if (child == CHILD_EMPTY || child >= (uint32_t)max_original_cells) - continue; - - AABB aabb = p_aabb; - aabb.size *= 0.5; - - if (i & 1) - aabb.position.x += aabb.size.x; - if (i & 2) - aabb.position.y += aabb.size.y; - if (i & 4) - aabb.position.z += aabb.size.z; - - _debug_mesh(bake_cells[p_idx].children[i], p_level + 1, aabb, p_multimesh, idx, p_mode); - } - } -} - -Ref<MultiMesh> VoxelLightBaker::create_debug_multimesh(DebugMode p_mode) { - - Ref<MultiMesh> mm; - - ERR_FAIL_COND_V(p_mode == DEBUG_LIGHT && bake_light.size() == 0, mm); - mm.instance(); - - mm->set_transform_format(MultiMesh::TRANSFORM_3D); - mm->set_color_format(MultiMesh::COLOR_8BIT); - mm->set_instance_count(leaf_voxel_count); - - Ref<ArrayMesh> mesh; - mesh.instance(); - - { - Array arr; - arr.resize(Mesh::ARRAY_MAX); - - PoolVector<Vector3> vertices; - PoolVector<Color> colors; -#define ADD_VTX(m_idx) \ - ; \ - vertices.push_back(face_points[m_idx]); \ - colors.push_back(Color(1, 1, 1, 1)); - - for (int i = 0; i < 6; i++) { - - Vector3 face_points[4]; - - for (int j = 0; j < 4; j++) { - - float v[3]; - v[0] = 1.0; - v[1] = 1 - 2 * ((j >> 1) & 1); - v[2] = v[1] * (1 - 2 * (j & 1)); - - for (int k = 0; k < 3; k++) { - - if (i < 3) - face_points[j][(i + k) % 3] = v[k]; - else - face_points[3 - j][(i + k) % 3] = -v[k]; - } - } - - //tri 1 - ADD_VTX(0); - ADD_VTX(1); - ADD_VTX(2); - //tri 2 - ADD_VTX(2); - ADD_VTX(3); - ADD_VTX(0); - } - - arr[Mesh::ARRAY_VERTEX] = vertices; - arr[Mesh::ARRAY_COLOR] = colors; - mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr); - } - - { - Ref<SpatialMaterial> fsm; - fsm.instance(); - fsm->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - fsm->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - fsm->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - fsm->set_albedo(Color(1, 1, 1, 1)); - - mesh->surface_set_material(0, fsm); - } - - mm->set_mesh(mesh); - - int idx = 0; - _debug_mesh(0, 0, po2_bounds, mm, idx, p_mode); - - return mm; -} - -struct VoxelLightBakerOctree { - - enum { - CHILD_EMPTY = 0xFFFFFFFF - }; - - uint16_t light[6][3]; //anisotropic light - float alpha; - uint32_t children[8]; -}; - -PoolVector<uint8_t> VoxelLightBaker::create_capture_octree(int p_subdiv) { - - p_subdiv = MIN(p_subdiv, cell_subdiv); // use the smaller one - - Vector<uint32_t> remap; - int bc = bake_cells.size(); - remap.resize(bc); - Vector<uint32_t> demap; - - int new_size = 0; - for (int i = 0; i < bc; i++) { - uint32_t c = CHILD_EMPTY; - if (bake_cells[i].level < p_subdiv) { - c = new_size; - new_size++; - demap.push_back(i); - } - remap.write[i] = c; - } - - Vector<VoxelLightBakerOctree> octree; - octree.resize(new_size); - - for (int i = 0; i < new_size; i++) { - octree.write[i].alpha = bake_cells[demap[i]].alpha; - for (int j = 0; j < 6; j++) { - for (int k = 0; k < 3; k++) { - float l = bake_light[demap[i]].accum[j][k]; //add anisotropic light - l += bake_cells[demap[i]].emission[k]; //add emission - octree.write[i].light[j][k] = CLAMP(l * 1024, 0, 65535); //give two more bits to octree - } - } - - for (int j = 0; j < 8; j++) { - uint32_t child = bake_cells[demap[i]].children[j]; - octree.write[i].children[j] = child == CHILD_EMPTY ? CHILD_EMPTY : remap[child]; - } - } - - PoolVector<uint8_t> ret; - int ret_bytes = octree.size() * sizeof(VoxelLightBakerOctree); - ret.resize(ret_bytes); - { - PoolVector<uint8_t>::Write w = ret.write(); - copymem(w.ptr(), octree.ptr(), ret_bytes); - } - - return ret; -} - -float VoxelLightBaker::get_cell_size() const { - return cell_size; -} - -Transform VoxelLightBaker::get_to_cell_space_xform() const { - return to_cell_space; -} -VoxelLightBaker::VoxelLightBaker() { - color_scan_cell_width = 4; - bake_texture_size = 128; - propagation = 0.85; - energy = 1.0; -} diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp new file mode 100644 index 0000000000..0257e6e83d --- /dev/null +++ b/scene/3d/voxelizer.cpp @@ -0,0 +1,1224 @@ +/*************************************************************************/ +/* voxelizer.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "voxelizer.h" +#include "core/os/os.h" +#include "core/os/threaded_array_processor.h" + +#include <stdlib.h> + +#define FINDMINMAX(x0, x1, x2, min, max) \ + min = max = x0; \ + if (x1 < min) min = x1; \ + if (x1 > max) max = x1; \ + if (x2 < min) min = x2; \ + if (x2 > max) max = x2; + +static bool planeBoxOverlap(Vector3 normal, float d, Vector3 maxbox) { + int q; + Vector3 vmin, vmax; + for (q = 0; q <= 2; q++) { + if (normal[q] > 0.0f) { + vmin[q] = -maxbox[q]; + vmax[q] = maxbox[q]; + } else { + vmin[q] = maxbox[q]; + vmax[q] = -maxbox[q]; + } + } + if (normal.dot(vmin) + d > 0.0f) return false; + if (normal.dot(vmax) + d >= 0.0f) return true; + + return false; +} + +/*======================== X-tests ========================*/ +#define AXISTEST_X01(a, b, fa, fb) \ + p0 = a * v0.y - b * v0.z; \ + p2 = a * v2.y - b * v2.z; \ + if (p0 < p2) { \ + min = p0; \ + max = p2; \ + } else { \ + min = p2; \ + max = p0; \ + } \ + rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \ + if (min > rad || max < -rad) return false; + +#define AXISTEST_X2(a, b, fa, fb) \ + p0 = a * v0.y - b * v0.z; \ + p1 = a * v1.y - b * v1.z; \ + if (p0 < p1) { \ + min = p0; \ + max = p1; \ + } else { \ + min = p1; \ + max = p0; \ + } \ + rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \ + if (min > rad || max < -rad) return false; + +/*======================== Y-tests ========================*/ +#define AXISTEST_Y02(a, b, fa, fb) \ + p0 = -a * v0.x + b * v0.z; \ + p2 = -a * v2.x + b * v2.z; \ + if (p0 < p2) { \ + min = p0; \ + max = p2; \ + } else { \ + min = p2; \ + max = p0; \ + } \ + rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \ + if (min > rad || max < -rad) return false; + +#define AXISTEST_Y1(a, b, fa, fb) \ + p0 = -a * v0.x + b * v0.z; \ + p1 = -a * v1.x + b * v1.z; \ + if (p0 < p1) { \ + min = p0; \ + max = p1; \ + } else { \ + min = p1; \ + max = p0; \ + } \ + rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \ + if (min > rad || max < -rad) return false; + +/*======================== Z-tests ========================*/ + +#define AXISTEST_Z12(a, b, fa, fb) \ + p1 = a * v1.x - b * v1.y; \ + p2 = a * v2.x - b * v2.y; \ + if (p2 < p1) { \ + min = p2; \ + max = p1; \ + } else { \ + min = p1; \ + max = p2; \ + } \ + rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \ + if (min > rad || max < -rad) return false; + +#define AXISTEST_Z0(a, b, fa, fb) \ + p0 = a * v0.x - b * v0.y; \ + p1 = a * v1.x - b * v1.y; \ + if (p0 < p1) { \ + min = p0; \ + max = p1; \ + } else { \ + min = p1; \ + max = p0; \ + } \ + rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \ + if (min > rad || max < -rad) return false; + +static bool fast_tri_box_overlap(const Vector3 &boxcenter, const Vector3 boxhalfsize, const Vector3 *triverts) { + + /* use separating axis theorem to test overlap between triangle and box */ + /* need to test for overlap in these directions: */ + /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */ + /* we do not even need to test these) */ + /* 2) normal of the triangle */ + /* 3) crossproduct(edge from tri, {x,y,z}-directin) */ + /* this gives 3x3=9 more tests */ + Vector3 v0, v1, v2; + float min, max, d, p0, p1, p2, rad, fex, fey, fez; + Vector3 normal, e0, e1, e2; + + /* This is the fastest branch on Sun */ + /* move everything so that the boxcenter is in (0,0,0) */ + + v0 = triverts[0] - boxcenter; + v1 = triverts[1] - boxcenter; + v2 = triverts[2] - boxcenter; + + /* compute triangle edges */ + e0 = v1 - v0; /* tri edge 0 */ + e1 = v2 - v1; /* tri edge 1 */ + e2 = v0 - v2; /* tri edge 2 */ + + /* Bullet 3: */ + /* test the 9 tests first (this was faster) */ + fex = Math::abs(e0.x); + fey = Math::abs(e0.y); + fez = Math::abs(e0.z); + AXISTEST_X01(e0.z, e0.y, fez, fey); + AXISTEST_Y02(e0.z, e0.x, fez, fex); + AXISTEST_Z12(e0.y, e0.x, fey, fex); + + fex = Math::abs(e1.x); + fey = Math::abs(e1.y); + fez = Math::abs(e1.z); + AXISTEST_X01(e1.z, e1.y, fez, fey); + AXISTEST_Y02(e1.z, e1.x, fez, fex); + AXISTEST_Z0(e1.y, e1.x, fey, fex); + + fex = Math::abs(e2.x); + fey = Math::abs(e2.y); + fez = Math::abs(e2.z); + AXISTEST_X2(e2.z, e2.y, fez, fey); + AXISTEST_Y1(e2.z, e2.x, fez, fex); + AXISTEST_Z12(e2.y, e2.x, fey, fex); + + /* Bullet 1: */ + /* first test overlap in the {x,y,z}-directions */ + /* find min, max of the triangle each direction, and test for overlap in */ + /* that direction -- this is equivalent to testing a minimal AABB around */ + /* the triangle against the AABB */ + + /* test in X-direction */ + FINDMINMAX(v0.x, v1.x, v2.x, min, max); + if (min > boxhalfsize.x || max < -boxhalfsize.x) return false; + + /* test in Y-direction */ + FINDMINMAX(v0.y, v1.y, v2.y, min, max); + if (min > boxhalfsize.y || max < -boxhalfsize.y) return false; + + /* test in Z-direction */ + FINDMINMAX(v0.z, v1.z, v2.z, min, max); + if (min > boxhalfsize.z || max < -boxhalfsize.z) return false; + + /* Bullet 2: */ + /* test if the box intersects the plane of the triangle */ + /* compute plane equation of triangle: normal*x+d=0 */ + normal = e0.cross(e1); + d = -normal.dot(v0); /* plane eq: normal.x+d=0 */ + 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) { + + if (p_pos.distance_squared_to(p_vtx[0]) < CMP_EPSILON2) { + r_uv = p_uv[0]; + r_normal = p_normal[0]; + return; + } + if (p_pos.distance_squared_to(p_vtx[1]) < CMP_EPSILON2) { + r_uv = p_uv[1]; + r_normal = p_normal[1]; + return; + } + if (p_pos.distance_squared_to(p_vtx[2]) < CMP_EPSILON2) { + r_uv = p_uv[2]; + r_normal = p_normal[2]; + return; + } + + Vector3 v0 = p_vtx[1] - p_vtx[0]; + Vector3 v1 = p_vtx[2] - p_vtx[0]; + Vector3 v2 = p_pos - p_vtx[0]; + + float d00 = v0.dot(v0); + float d01 = v0.dot(v1); + float d11 = v1.dot(v1); + float d20 = v2.dot(v0); + float d21 = v2.dot(v1); + float denom = (d00 * d11 - d01 * d01); + if (denom == 0) { + r_uv = p_uv[0]; + r_normal = p_normal[0]; + return; + } + float v = (d11 * d20 - d01 * d21) / denom; + float w = (d00 * d21 - d01 * d20) / denom; + float u = 1.0f - v - w; + + r_uv = p_uv[0] * u + p_uv[1] * v + p_uv[2] * w; + r_normal = (p_normal[0] * u + p_normal[1] * v + p_normal[2] * w).normalized(); +} + +void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb) { + + if (p_level == cell_subdiv) { + //plot the face by guessing its albedo and emission value + + //find best axis to map to, for scanning values + int closest_axis = 0; + float closest_dot = 0; + + Plane plane = Plane(p_vtx[0], p_vtx[1], p_vtx[2]); + Vector3 normal = plane.normal; + + for (int i = 0; i < 3; i++) { + + Vector3 axis; + axis[i] = 1.0; + float dot = ABS(normal.dot(axis)); + if (i == 0 || dot > closest_dot) { + closest_axis = i; + closest_dot = dot; + } + } + + Vector3 axis; + axis[closest_axis] = 1.0; + Vector3 t1; + t1[(closest_axis + 1) % 3] = 1.0; + Vector3 t2; + t2[(closest_axis + 2) % 3] = 1.0; + + t1 *= p_aabb.size[(closest_axis + 1) % 3] / float(color_scan_cell_width); + t2 *= p_aabb.size[(closest_axis + 2) % 3] / float(color_scan_cell_width); + + Color albedo_accum; + Color emission_accum; + Vector3 normal_accum; + + float alpha = 0.0; + + //map to a grid average in the best axis for this face + for (int i = 0; i < color_scan_cell_width; i++) { + + Vector3 ofs_i = float(i) * t1; + + for (int j = 0; j < color_scan_cell_width; j++) { + + Vector3 ofs_j = float(j) * t2; + + Vector3 from = p_aabb.position + ofs_i + ofs_j; + Vector3 to = from + t1 + t2 + axis * p_aabb.size[closest_axis]; + Vector3 half = (to - from) * 0.5; + + //is in this cell? + if (!fast_tri_box_overlap(from + half, half, p_vtx)) { + continue; //face does not span this cell + } + + //go from -size to +size*2 to avoid skipping collisions + Vector3 ray_from = from + (t1 + t2) * 0.5 - axis * p_aabb.size[closest_axis]; + Vector3 ray_to = ray_from + axis * p_aabb.size[closest_axis] * 2; + + if (normal.dot(ray_from - ray_to) < 0) { + SWAP(ray_from, ray_to); + } + + Vector3 intersection; + + if (!plane.intersects_segment(ray_from, ray_to, &intersection)) { + if (ABS(plane.distance_to(ray_from)) < ABS(plane.distance_to(ray_to))) { + intersection = plane.project(ray_from); + } else { + + intersection = plane.project(ray_to); + } + } + + intersection = Face3(p_vtx[0], p_vtx[1], p_vtx[2]).get_closest_point_to(intersection); + + Vector2 uv; + Vector3 lnormal; + get_uv_and_normal(intersection, p_vtx, p_uv, p_normal, uv, lnormal); + if (lnormal == Vector3()) //just in case normal as nor provided + lnormal = normal; + + int uv_x = CLAMP(int(Math::fposmod(uv.x, 1.0f) * bake_texture_size), 0, bake_texture_size - 1); + int uv_y = CLAMP(int(Math::fposmod(uv.y, 1.0f) * bake_texture_size), 0, bake_texture_size - 1); + + int ofs = uv_y * bake_texture_size + uv_x; + albedo_accum.r += p_material.albedo[ofs].r; + albedo_accum.g += p_material.albedo[ofs].g; + albedo_accum.b += p_material.albedo[ofs].b; + albedo_accum.a += p_material.albedo[ofs].a; + + emission_accum.r += p_material.emission[ofs].r; + emission_accum.g += p_material.emission[ofs].g; + emission_accum.b += p_material.emission[ofs].b; + + normal_accum += lnormal; + + alpha += 1.0; + } + } + + if (alpha == 0) { + //could not in any way get texture information.. so use closest point to center + + Face3 f(p_vtx[0], p_vtx[1], p_vtx[2]); + Vector3 inters = f.get_closest_point_to(p_aabb.position + p_aabb.size * 0.5); + + Vector3 lnormal; + Vector2 uv; + get_uv_and_normal(inters, p_vtx, p_uv, p_normal, uv, normal); + if (lnormal == Vector3()) //just in case normal as nor provided + lnormal = normal; + + int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); + int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); + + int ofs = uv_y * bake_texture_size + uv_x; + + alpha = 1.0 / (color_scan_cell_width * color_scan_cell_width); + + albedo_accum.r = p_material.albedo[ofs].r * alpha; + albedo_accum.g = p_material.albedo[ofs].g * alpha; + albedo_accum.b = p_material.albedo[ofs].b * alpha; + albedo_accum.a = p_material.albedo[ofs].a * alpha; + + emission_accum.r = p_material.emission[ofs].r * alpha; + emission_accum.g = p_material.emission[ofs].g * alpha; + emission_accum.b = p_material.emission[ofs].b * alpha; + + normal_accum = lnormal * alpha; + + } else { + + float accdiv = 1.0 / (color_scan_cell_width * color_scan_cell_width); + alpha *= accdiv; + + albedo_accum.r *= accdiv; + albedo_accum.g *= accdiv; + albedo_accum.b *= accdiv; + albedo_accum.a *= accdiv; + + emission_accum.r *= accdiv; + emission_accum.g *= accdiv; + emission_accum.b *= accdiv; + + normal_accum *= accdiv; + } + + //put this temporarily here, corrected in a later step + bake_cells.write[p_idx].albedo[0] += albedo_accum.r; + bake_cells.write[p_idx].albedo[1] += albedo_accum.g; + bake_cells.write[p_idx].albedo[2] += albedo_accum.b; + bake_cells.write[p_idx].emission[0] += emission_accum.r; + bake_cells.write[p_idx].emission[1] += emission_accum.g; + bake_cells.write[p_idx].emission[2] += emission_accum.b; + bake_cells.write[p_idx].normal[0] += normal_accum.x; + bake_cells.write[p_idx].normal[1] += normal_accum.y; + bake_cells.write[p_idx].normal[2] += normal_accum.z; + bake_cells.write[p_idx].alpha += alpha; + + } else { + //go down + + int half = (1 << cell_subdiv) >> (p_level + 1); + for (int i = 0; i < 8; i++) { + + AABB aabb = p_aabb; + aabb.size *= 0.5; + + int nx = p_x; + int ny = p_y; + int nz = p_z; + + if (i & 1) { + aabb.position.x += aabb.size.x; + nx += half; + } + if (i & 2) { + aabb.position.y += aabb.size.y; + ny += half; + } + if (i & 4) { + aabb.position.z += aabb.size.z; + nz += half; + } + //make sure to not plot beyond limits + if (nx < 0 || nx >= axis_cell_size[0] || ny < 0 || ny >= axis_cell_size[1] || nz < 0 || nz >= axis_cell_size[2]) + continue; + + { + AABB test_aabb = aabb; + //test_aabb.grow_by(test_aabb.get_longest_axis_size()*0.05); //grow a bit to avoid numerical error in real-time + Vector3 qsize = test_aabb.size * 0.5; //quarter size, for fast aabb test + + if (!fast_tri_box_overlap(test_aabb.position + qsize, qsize, p_vtx)) { + //if (!Face3(p_vtx[0],p_vtx[1],p_vtx[2]).intersects_aabb2(aabb)) { + //does not fit in child, go on + continue; + } + } + + if (bake_cells[p_idx].children[i] == CHILD_EMPTY) { + //sub cell must be created + + uint32_t child_idx = bake_cells.size(); + bake_cells.write[p_idx].children[i] = child_idx; + bake_cells.resize(bake_cells.size() + 1); + bake_cells.write[child_idx].level = p_level + 1; + bake_cells.write[child_idx].x = nx / half; + bake_cells.write[child_idx].y = ny / half; + bake_cells.write[child_idx].z = nz / half; + } + + _plot_face(bake_cells[p_idx].children[i], p_level + 1, nx, ny, nz, p_vtx, p_normal, p_uv, p_material, aabb); + } + } +} + +Vector<Color> Voxelizer::_get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add) { + + Vector<Color> ret; + + if (p_image.is_null() || p_image->empty()) { + + ret.resize(bake_texture_size * bake_texture_size); + for (int i = 0; i < bake_texture_size * bake_texture_size; i++) { + ret.write[i] = p_color_add; + } + + return ret; + } + p_image = p_image->duplicate(); + + if (p_image->is_compressed()) { + p_image->decompress(); + } + p_image->convert(Image::FORMAT_RGBA8); + p_image->resize(bake_texture_size, bake_texture_size, Image::INTERPOLATE_CUBIC); + + const uint8_t *r = p_image->get_data().ptr(); + ret.resize(bake_texture_size * bake_texture_size); + + for (int i = 0; i < bake_texture_size * bake_texture_size; i++) { + Color c; + c.r = (r[i * 4 + 0] / 255.0) * p_color_mul.r + p_color_add.r; + c.g = (r[i * 4 + 1] / 255.0) * p_color_mul.g + p_color_add.g; + c.b = (r[i * 4 + 2] / 255.0) * p_color_mul.b + p_color_add.b; + + c.a = r[i * 4 + 3] / 255.0; + + ret.write[i] = c; + } + + return ret; +} + +Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material) { + + //this way of obtaining materials is inaccurate and also does not support some compressed formats very well + Ref<StandardMaterial3D> mat = p_material; + + Ref<Material> material = mat; //hack for now + + if (material_cache.has(material)) { + return material_cache[material]; + } + + MaterialCache mc; + + if (mat.is_valid()) { + + Ref<Texture2D> albedo_tex = mat->get_texture(StandardMaterial3D::TEXTURE_ALBEDO); + + Ref<Image> img_albedo; + if (albedo_tex.is_valid()) { + + img_albedo = albedo_tex->get_data(); + mc.albedo = _get_bake_texture(img_albedo, mat->get_albedo(), Color(0, 0, 0)); // albedo texture, color is multiplicative + } else { + mc.albedo = _get_bake_texture(img_albedo, Color(1, 1, 1), mat->get_albedo()); // no albedo texture, color is additive + } + + Ref<Texture2D> emission_tex = mat->get_texture(StandardMaterial3D::TEXTURE_EMISSION); + + Color emission_col = mat->get_emission(); + float emission_energy = mat->get_emission_energy(); + + Ref<Image> img_emission; + + if (emission_tex.is_valid()) { + + img_emission = emission_tex->get_data(); + } + + if (mat->get_emission_operator() == StandardMaterial3D::EMISSION_OP_ADD) { + mc.emission = _get_bake_texture(img_emission, Color(1, 1, 1) * emission_energy, emission_col * emission_energy); + } else { + mc.emission = _get_bake_texture(img_emission, emission_col * emission_energy, Color(0, 0, 0)); + } + + } else { + Ref<Image> empty; + + mc.albedo = _get_bake_texture(empty, Color(0, 0, 0), Color(1, 1, 1)); + mc.emission = _get_bake_texture(empty, Color(0, 0, 0), Color(0, 0, 0)); + } + + material_cache[p_material] = mc; + return mc; +} + +void Voxelizer::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material) { + + for (int i = 0; i < p_mesh->get_surface_count(); i++) { + + if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) + continue; //only triangles + + Ref<Material> src_material; + + if (p_override_material.is_valid()) { + src_material = p_override_material; + } else if (i < p_materials.size() && p_materials[i].is_valid()) { + src_material = p_materials[i]; + } else { + src_material = p_mesh->surface_get_material(i); + } + MaterialCache material = _get_material_cache(src_material); + + Array a = p_mesh->surface_get_arrays(i); + + Vector<Vector3> vertices = a[Mesh::ARRAY_VERTEX]; + const Vector3 *vr = vertices.ptr(); + Vector<Vector2> uv = a[Mesh::ARRAY_TEX_UV]; + const Vector2 *uvr; + Vector<Vector3> normals = a[Mesh::ARRAY_NORMAL]; + const Vector3 *nr; + Vector<int> index = a[Mesh::ARRAY_INDEX]; + + bool read_uv = false; + bool read_normals = false; + + if (uv.size()) { + + uvr = uv.ptr(); + read_uv = true; + } + + if (normals.size()) { + read_normals = true; + nr = normals.ptr(); + } + + if (index.size()) { + + int facecount = index.size() / 3; + const int *ir = index.ptr(); + + for (int j = 0; j < facecount; j++) { + + Vector3 vtxs[3]; + Vector2 uvs[3]; + Vector3 normal[3]; + + for (int k = 0; k < 3; k++) { + vtxs[k] = p_xform.xform(vr[ir[j * 3 + k]]); + } + + if (read_uv) { + for (int k = 0; k < 3; k++) { + uvs[k] = uvr[ir[j * 3 + k]]; + } + } + + if (read_normals) { + for (int k = 0; k < 3; k++) { + normal[k] = nr[ir[j * 3 + k]]; + } + } + + //test against original bounds + if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs)) + continue; + //plot + _plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds); + } + + } else { + + int facecount = vertices.size() / 3; + + for (int j = 0; j < facecount; j++) { + + Vector3 vtxs[3]; + Vector2 uvs[3]; + Vector3 normal[3]; + + for (int k = 0; k < 3; k++) { + vtxs[k] = p_xform.xform(vr[j * 3 + k]); + } + + if (read_uv) { + for (int k = 0; k < 3; k++) { + uvs[k] = uvr[j * 3 + k]; + } + } + + if (read_normals) { + for (int k = 0; k < 3; k++) { + normal[k] = nr[j * 3 + k]; + } + } + + //test against original bounds + if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs)) + continue; + //plot face + _plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds); + } + } + } + + max_original_cells = bake_cells.size(); +} + +void Voxelizer::_sort() { + + // cells need to be sorted by level and coordinates + // it is important that level has more priority (for compute), and that Z has the least, + // given it may aid older implementations plot using GPU + + Vector<CellSort> sorted_cells; + uint32_t cell_count = bake_cells.size(); + sorted_cells.resize(cell_count); + { + + CellSort *sort_cellsp = sorted_cells.ptrw(); + const Cell *bake_cellsp = bake_cells.ptr(); + + for (uint32_t i = 0; i < cell_count; i++) { + sort_cellsp[i].x = bake_cellsp[i].x; + sort_cellsp[i].y = bake_cellsp[i].y; + sort_cellsp[i].z = bake_cellsp[i].z; + sort_cellsp[i].level = bake_cellsp[i].level; + sort_cellsp[i].index = i; + } + } + + sorted_cells.sort(); + + //verify just in case, index 0 must be level 0 + ERR_FAIL_COND(sorted_cells[0].level != 0); + + Vector<Cell> new_bake_cells; + new_bake_cells.resize(cell_count); + Vector<uint32_t> reverse_map; + + { + reverse_map.resize(cell_count); + const CellSort *sort_cellsp = sorted_cells.ptr(); + uint32_t *reverse_mapp = reverse_map.ptrw(); + + for (uint32_t i = 0; i < cell_count; i++) { + reverse_mapp[sort_cellsp[i].index] = i; + } + } + + { + + const CellSort *sort_cellsp = sorted_cells.ptr(); + const Cell *bake_cellsp = bake_cells.ptr(); + const uint32_t *reverse_mapp = reverse_map.ptr(); + Cell *new_bake_cellsp = new_bake_cells.ptrw(); + + for (uint32_t i = 0; i < cell_count; i++) { + //copy to new cell + new_bake_cellsp[i] = bake_cellsp[sort_cellsp[i].index]; + //remap children + for (uint32_t j = 0; j < 8; j++) { + if (new_bake_cellsp[i].children[j] != CHILD_EMPTY) { + new_bake_cellsp[i].children[j] = reverse_mapp[new_bake_cellsp[i].children[j]]; + } + } + } + } + + bake_cells = new_bake_cells; + sorted = true; +} + +void Voxelizer::_fixup_plot(int p_idx, int p_level) { + + if (p_level == cell_subdiv) { + + leaf_voxel_count++; + float alpha = bake_cells[p_idx].alpha; + + bake_cells.write[p_idx].albedo[0] /= alpha; + bake_cells.write[p_idx].albedo[1] /= alpha; + bake_cells.write[p_idx].albedo[2] /= alpha; + + //transfer emission to light + bake_cells.write[p_idx].emission[0] /= alpha; + bake_cells.write[p_idx].emission[1] /= alpha; + bake_cells.write[p_idx].emission[2] /= alpha; + + bake_cells.write[p_idx].normal[0] /= alpha; + bake_cells.write[p_idx].normal[1] /= alpha; + bake_cells.write[p_idx].normal[2] /= alpha; + + Vector3 n(bake_cells[p_idx].normal[0], bake_cells[p_idx].normal[1], bake_cells[p_idx].normal[2]); + if (n.length() < 0.01) { + //too much fight over normal, zero it + bake_cells.write[p_idx].normal[0] = 0; + bake_cells.write[p_idx].normal[1] = 0; + bake_cells.write[p_idx].normal[2] = 0; + } else { + n.normalize(); + bake_cells.write[p_idx].normal[0] = n.x; + bake_cells.write[p_idx].normal[1] = n.y; + bake_cells.write[p_idx].normal[2] = n.z; + } + + bake_cells.write[p_idx].alpha = 1.0; + + /*if (bake_light.size()) { + for(int i=0;i<6;i++) { + + } + }*/ + + } else { + + //go down + + bake_cells.write[p_idx].emission[0] = 0; + bake_cells.write[p_idx].emission[1] = 0; + bake_cells.write[p_idx].emission[2] = 0; + bake_cells.write[p_idx].normal[0] = 0; + bake_cells.write[p_idx].normal[1] = 0; + bake_cells.write[p_idx].normal[2] = 0; + bake_cells.write[p_idx].albedo[0] = 0; + bake_cells.write[p_idx].albedo[1] = 0; + bake_cells.write[p_idx].albedo[2] = 0; + + float alpha_average = 0; + int children_found = 0; + + for (int i = 0; i < 8; i++) { + + uint32_t child = bake_cells[p_idx].children[i]; + + if (child == CHILD_EMPTY) + continue; + + _fixup_plot(child, p_level + 1); + alpha_average += bake_cells[child].alpha; + + children_found++; + } + + bake_cells.write[p_idx].alpha = alpha_average / 8.0; + } +} + +void Voxelizer::begin_bake(int p_subdiv, const AABB &p_bounds) { + + sorted = false; + original_bounds = p_bounds; + cell_subdiv = p_subdiv; + bake_cells.resize(1); + material_cache.clear(); + + print_line("subdiv: " + itos(p_subdiv)); + //find out the actual real bounds, power of 2, which gets the highest subdivision + po2_bounds = p_bounds; + int longest_axis = po2_bounds.get_longest_axis_index(); + axis_cell_size[longest_axis] = 1 << cell_subdiv; + leaf_voxel_count = 0; + + for (int i = 0; i < 3; i++) { + + if (i == longest_axis) + continue; + + axis_cell_size[i] = axis_cell_size[longest_axis]; + float axis_size = po2_bounds.size[longest_axis]; + + //shrink until fit subdiv + while (axis_size / 2.0 >= po2_bounds.size[i]) { + axis_size /= 2.0; + axis_cell_size[i] >>= 1; + } + + po2_bounds.size[i] = po2_bounds.size[longest_axis]; + } + + Transform to_bounds; + to_bounds.basis.scale(Vector3(po2_bounds.size[longest_axis], po2_bounds.size[longest_axis], po2_bounds.size[longest_axis])); + to_bounds.origin = po2_bounds.position; + + Transform to_grid; + to_grid.basis.scale(Vector3(axis_cell_size[longest_axis], axis_cell_size[longest_axis], axis_cell_size[longest_axis])); + + to_cell_space = to_grid * to_bounds.affine_inverse(); + + cell_size = po2_bounds.size[longest_axis] / axis_cell_size[longest_axis]; +} + +void Voxelizer::end_bake() { + if (!sorted) { + _sort(); + } + _fixup_plot(0, 0); +} + +//create the data for visual server + +int Voxelizer::get_gi_probe_octree_depth() const { + return cell_subdiv; +} +Vector3i Voxelizer::get_giprobe_octree_size() const { + return Vector3i(axis_cell_size[0], axis_cell_size[1], axis_cell_size[2]); +} +int Voxelizer::get_giprobe_cell_count() const { + return bake_cells.size(); +} + +Vector<uint8_t> Voxelizer::get_giprobe_octree_cells() const { + Vector<uint8_t> data; + data.resize((8 * 4) * bake_cells.size()); //8 uint32t values + { + uint8_t *w = data.ptrw(); + uint32_t *children_cells = (uint32_t *)w; + const Cell *cells = bake_cells.ptr(); + + uint32_t cell_count = bake_cells.size(); + + for (uint32_t i = 0; i < cell_count; i++) { + + for (uint32_t j = 0; j < 8; j++) { + children_cells[i * 8 + j] = cells[i].children[j]; + } + } + } + + return data; +} +Vector<uint8_t> Voxelizer::get_giprobe_data_cells() const { + Vector<uint8_t> data; + data.resize((4 * 4) * bake_cells.size()); //8 uint32t values + { + uint8_t *w = data.ptrw(); + uint32_t *dataptr = (uint32_t *)w; + const Cell *cells = bake_cells.ptr(); + + uint32_t cell_count = bake_cells.size(); + + for (uint32_t i = 0; i < cell_count; i++) { + + { //position + + uint32_t x = cells[i].x; + uint32_t y = cells[i].y; + uint32_t z = cells[i].z; + + uint32_t position = x; + position |= y << 11; + position |= z << 21; + + dataptr[i * 4 + 0] = position; + } + + { //albedo + alpha + uint32_t rgba = uint32_t(CLAMP(cells[i].alpha * 255.0, 0, 255)) << 24; //a + rgba |= uint32_t(CLAMP(cells[i].albedo[2] * 255.0, 0, 255)) << 16; //b + rgba |= uint32_t(CLAMP(cells[i].albedo[1] * 255.0, 0, 255)) << 8; //g + rgba |= uint32_t(CLAMP(cells[i].albedo[0] * 255.0, 0, 255)); //r + + dataptr[i * 4 + 1] = rgba; + } + + { //emission, as rgbe9995 + Color emission = Color(cells[i].emission[0], cells[i].emission[1], cells[i].emission[2]); + dataptr[i * 4 + 2] = emission.to_rgbe9995(); + } + + { //normal + + Vector3 n(bake_cells[i].normal[0], bake_cells[i].normal[1], bake_cells[i].normal[2]); + n.normalize(); + + uint32_t normal = uint32_t(uint8_t(int8_t(CLAMP(n.x * 127.0, -128, 127)))); + normal |= uint32_t(uint8_t(int8_t(CLAMP(n.y * 127.0, -128, 127)))) << 8; + normal |= uint32_t(uint8_t(int8_t(CLAMP(n.z * 127.0, -128, 127)))) << 16; + + dataptr[i * 4 + 3] = normal; + } + } + } + + return data; +} + +Vector<int> Voxelizer::get_giprobe_level_cell_count() const { + uint32_t cell_count = bake_cells.size(); + const Cell *cells = bake_cells.ptr(); + Vector<int> level_count; + level_count.resize(cell_subdiv + 1); //remember, always x+1 levels for x subdivisions + { + int *w = level_count.ptrw(); + for (int i = 0; i < cell_subdiv + 1; i++) { + w[i] = 0; + } + + for (uint32_t i = 0; i < cell_count; i++) { + w[cells[i].level]++; + } + } + + return level_count; +} + +// euclidean distance computation based on: +// https://prideout.net/blog/distance_fields/ + +#define square(m_s) ((m_s) * (m_s)) +#define INF 1e20 + +/* dt of 1d function using squared distance */ +static void edt(float *f, int stride, int n) { + + float *d = (float *)alloca(sizeof(float) * n + sizeof(int) * n + sizeof(float) * (n + 1)); + int *v = (int *)&(d[n]); + float *z = (float *)&v[n]; + + int k = 0; + v[0] = 0; + z[0] = -INF; + z[1] = +INF; + for (int q = 1; q <= n - 1; q++) { + float s = ((f[q * stride] + square(q)) - (f[v[k] * stride] + square(v[k]))) / (2 * q - 2 * v[k]); + while (s <= z[k]) { + k--; + s = ((f[q * stride] + square(q)) - (f[v[k] * stride] + square(v[k]))) / (2 * q - 2 * v[k]); + } + k++; + v[k] = q; + + z[k] = s; + z[k + 1] = +INF; + } + + k = 0; + for (int q = 0; q <= n - 1; q++) { + while (z[k + 1] < q) + k++; + d[q] = square(q - v[k]) + f[v[k] * stride]; + } + + for (int i = 0; i < n; i++) { + f[i * stride] = d[i]; + } +} + +#undef square + +Vector<uint8_t> Voxelizer::get_sdf_3d_image() const { + + Vector3i octree_size = get_giprobe_octree_size(); + + uint32_t float_count = octree_size.x * octree_size.y * octree_size.z; + float *work_memory = memnew_arr(float, float_count); + for (uint32_t i = 0; i < float_count; i++) { + work_memory[i] = INF; + } + + uint32_t y_mult = octree_size.x; + uint32_t z_mult = y_mult * octree_size.y; + + //plot solid cells + { + const Cell *cells = bake_cells.ptr(); + uint32_t cell_count = bake_cells.size(); + + for (uint32_t i = 0; i < cell_count; i++) { + + if (cells[i].level < (cell_subdiv - 1)) { + continue; //do not care about this level + } + + work_memory[cells[i].x + cells[i].y * y_mult + cells[i].z * z_mult] = 0; + } + } + + //process in each direction + + //xy->z + + for (int i = 0; i < octree_size.x; i++) { + for (int j = 0; j < octree_size.y; j++) { + edt(&work_memory[i + j * y_mult], z_mult, octree_size.z); + } + } + + //xz->y + + for (int i = 0; i < octree_size.x; i++) { + for (int j = 0; j < octree_size.z; j++) { + edt(&work_memory[i + j * z_mult], y_mult, octree_size.y); + } + } + + //yz->x + for (int i = 0; i < octree_size.y; i++) { + for (int j = 0; j < octree_size.z; j++) { + edt(&work_memory[i * y_mult + j * z_mult], 1, octree_size.x); + } + } + + Vector<uint8_t> image3d; + image3d.resize(float_count); + { + uint8_t *w = image3d.ptrw(); + for (uint32_t i = 0; i < float_count; i++) { + uint32_t d = uint32_t(Math::sqrt(work_memory[i])); + if (d == 0) { + w[i] = 0; + } else { + w[i] = MIN(d, 254) + 1; + } + } + } + + return image3d; +} + +#undef INF + +void Voxelizer::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx) { + + if (p_level == cell_subdiv - 1) { + + Vector3 center = p_aabb.position + p_aabb.size * 0.5; + Transform xform; + xform.origin = center; + xform.basis.scale(p_aabb.size * 0.5); + p_multimesh->set_instance_transform(idx, xform); + Color col; + col = Color(bake_cells[p_idx].albedo[0], bake_cells[p_idx].albedo[1], bake_cells[p_idx].albedo[2]); + //Color col = Color(bake_cells[p_idx].emission[0], bake_cells[p_idx].emission[1], bake_cells[p_idx].emission[2]); + p_multimesh->set_instance_color(idx, col); + + idx++; + + } else { + + for (int i = 0; i < 8; i++) { + + uint32_t child = bake_cells[p_idx].children[i]; + + if (child == CHILD_EMPTY || child >= (uint32_t)max_original_cells) + continue; + + AABB aabb = p_aabb; + aabb.size *= 0.5; + + if (i & 1) + aabb.position.x += aabb.size.x; + if (i & 2) + aabb.position.y += aabb.size.y; + if (i & 4) + aabb.position.z += aabb.size.z; + + _debug_mesh(bake_cells[p_idx].children[i], p_level + 1, aabb, p_multimesh, idx); + } + } +} + +Ref<MultiMesh> Voxelizer::create_debug_multimesh() { + + Ref<MultiMesh> mm; + + mm.instance(); + + mm->set_transform_format(MultiMesh::TRANSFORM_3D); + mm->set_use_colors(true); + mm->set_instance_count(leaf_voxel_count); + + Ref<ArrayMesh> mesh; + mesh.instance(); + + { + Array arr; + arr.resize(Mesh::ARRAY_MAX); + + Vector<Vector3> vertices; + Vector<Color> colors; +#define ADD_VTX(m_idx) \ + vertices.push_back(face_points[m_idx]); \ + colors.push_back(Color(1, 1, 1, 1)); + + for (int i = 0; i < 6; i++) { + + Vector3 face_points[4]; + + for (int j = 0; j < 4; j++) { + + float v[3]; + v[0] = 1.0; + v[1] = 1 - 2 * ((j >> 1) & 1); + v[2] = v[1] * (1 - 2 * (j & 1)); + + for (int k = 0; k < 3; k++) { + + if (i < 3) + face_points[j][(i + k) % 3] = v[k]; + else + face_points[3 - j][(i + k) % 3] = -v[k]; + } + } + + //tri 1 + ADD_VTX(0); + ADD_VTX(1); + ADD_VTX(2); + //tri 2 + ADD_VTX(2); + ADD_VTX(3); + ADD_VTX(0); + } + + arr[Mesh::ARRAY_VERTEX] = vertices; + arr[Mesh::ARRAY_COLOR] = colors; + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr); + } + + { + Ref<StandardMaterial3D> fsm; + fsm.instance(); + fsm->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); + fsm->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + fsm->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); + fsm->set_albedo(Color(1, 1, 1, 1)); + + mesh->surface_set_material(0, fsm); + } + + mm->set_mesh(mesh); + + int idx = 0; + _debug_mesh(0, 0, po2_bounds, mm, idx); + + return mm; +} + +Transform Voxelizer::get_to_cell_space_xform() const { + return to_cell_space; +} +Voxelizer::Voxelizer() { + sorted = false; + color_scan_cell_width = 4; + bake_texture_size = 128; +} diff --git a/scene/3d/voxel_light_baker.h b/scene/3d/voxelizer.h index 7e78a19830..1d50f1cd18 100644 --- a/scene/3d/voxel_light_baker.h +++ b/scene/3d/voxelizer.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* voxel_light_baker.h */ +/* voxelizer.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -31,27 +31,11 @@ #ifndef VOXEL_LIGHT_BAKER_H #define VOXEL_LIGHT_BAKER_H +#include "core/math/vector3i.h" #include "scene/3d/mesh_instance.h" #include "scene/resources/multimesh.h" -class VoxelLightBaker { -public: - enum DebugMode { - DEBUG_ALBEDO, - DEBUG_LIGHT - }; - - enum BakeQuality { - BAKE_QUALITY_LOW, - BAKE_QUALITY_MEDIUM, - BAKE_QUALITY_HIGH - }; - - enum BakeMode { - BAKE_MODE_CONE_TRACE, - BAKE_MODE_RAY_TRACE, - }; - +class Voxelizer { private: enum { CHILD_EMPTY = 0xFFFFFFFF @@ -66,7 +50,10 @@ private: float normal[3]; uint32_t used_sides; float alpha; //used for upsampling - int level; + uint16_t x; + uint16_t y; + uint16_t z; + uint16_t level; Cell() { for (int i = 0; i < 8; i++) { @@ -80,6 +67,7 @@ private: } alpha = 0; used_sides = 0; + x = y = z = 0; level = 0; } }; @@ -87,27 +75,24 @@ private: Vector<Cell> bake_cells; int cell_subdiv; - struct Light { - int x, y, z; - float accum[6][3]; //rgb anisotropic - float direct_accum[6][3]; //for direct bake - int next_leaf; - Light() { - x = y = z = 0; - for (int i = 0; i < 6; i++) { - for (int j = 0; j < 3; j++) { - accum[i][j] = 0; - direct_accum[i][j] = 0; - } - } - next_leaf = 0; + struct CellSort { + union { + struct { + uint64_t z : 16; + uint64_t y : 16; + uint64_t x : 16; + uint64_t level : 16; + }; + uint64_t key; + }; + + int32_t index; + + _FORCE_INLINE_ bool operator<(const CellSort &p_cell_sort) const { + return key < p_cell_sort.key; } }; - int first_leaf; - - Vector<Light> bake_light; - struct MaterialCache { //128x128 textures Vector<Color> albedo; @@ -115,9 +100,6 @@ private: }; Map<Ref<Material>, MaterialCache> material_cache; - int leaf_voxel_count; - bool direct_lights_baked; - AABB original_bounds; AABB po2_bounds; int axis_cell_size[3]; @@ -127,65 +109,37 @@ private: int color_scan_cell_width; int bake_texture_size; float cell_size; - float propagation; - float energy; - - BakeQuality bake_quality; - BakeMode bake_mode; int max_original_cells; - - void _init_light_plot(int p_idx, int p_level, int p_x, int p_y, int p_z, uint32_t p_parent); + int leaf_voxel_count; Vector<Color> _get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add); MaterialCache _get_material_cache(Ref<Material> p_material); void _plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb); void _fixup_plot(int p_idx, int p_level); - void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx, DebugMode p_mode); - void _check_init_light(); - - uint32_t _find_cell_at_pos(const Cell *cells, int x, int y, int z); + void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx); - struct LightMap { - Vector3 light; - Vector3 pos; - Vector3 normal; - }; - - void _plot_triangle(Vector2 *vertices, Vector3 *positions, Vector3 *normals, LightMap *pixels, int width, int height); - - _FORCE_INLINE_ void _sample_baked_octree_filtered_and_anisotropic(const Vector3 &p_posf, const Vector3 &p_direction, float p_level, Vector3 &r_color, float &r_alpha); - _FORCE_INLINE_ Vector3 _voxel_cone_trace(const Vector3 &p_pos, const Vector3 &p_normal, float p_aperture); - _FORCE_INLINE_ Vector3 _compute_pixel_light_at_pos(const Vector3 &p_pos, const Vector3 &p_normal); - _FORCE_INLINE_ Vector3 _compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal); - - void _lightmap_bake_point(uint32_t p_x, LightMap *p_line); + bool sorted; + void _sort(); public: void begin_bake(int p_subdiv, const AABB &p_bounds); void plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material); - void begin_bake_light(BakeQuality p_quality = BAKE_QUALITY_MEDIUM, BakeMode p_bake_mode = BAKE_MODE_CONE_TRACE, float p_propagation = 0.85, float p_energy = 1); - void plot_light_directional(const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_energy, bool p_direct); - void plot_light_omni(const Vector3 &p_pos, const Color &p_color, float p_energy, float p_indirect_energy, float p_radius, float p_attenutation, bool p_direct); - void plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axis, const Color &p_color, float p_energy, float p_indirect_energy, float p_radius, float p_attenutation, float p_spot_angle, float p_spot_attenuation, bool p_direct); void end_bake(); - struct LightMapData { - int width; - int height; - PoolVector<float> light; - }; - - Error make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh, float default_texels_per_unit, LightMapData &r_lightmap, bool (*p_bake_time_func)(void *, float, float) = NULL, void *p_bake_time_ud = NULL); + int get_gi_probe_octree_depth() const; + Vector3i get_giprobe_octree_size() const; + int get_giprobe_cell_count() const; + Vector<uint8_t> get_giprobe_octree_cells() const; + Vector<uint8_t> get_giprobe_data_cells() const; + Vector<int> get_giprobe_level_cell_count() const; + Vector<uint8_t> get_sdf_3d_image() const; - PoolVector<int> create_gi_probe_data(); - Ref<MultiMesh> create_debug_multimesh(DebugMode p_mode = DEBUG_ALBEDO); - PoolVector<uint8_t> create_capture_octree(int p_subdiv); + Ref<MultiMesh> create_debug_multimesh(); - float get_cell_size() const; Transform get_to_cell_space_xform() const; - VoxelLightBaker(); + Voxelizer(); }; #endif // VOXEL_LIGHT_BAKER_H diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp index c8d7382e81..83a7243906 100644 --- a/scene/3d/world_environment.cpp +++ b/scene/3d/world_environment.cpp @@ -43,12 +43,25 @@ void WorldEnvironment::_notification(int p_what) { add_to_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); } + if (camera_effects.is_valid()) { + if (get_viewport()->find_world()->get_camera_effects().is_valid()) { + WARN_PRINT("World already has a camera effects (Another WorldEnvironment?), overriding."); + } + get_viewport()->find_world()->set_camera_effects(camera_effects); + add_to_group("_world_camera_effects_" + itos(get_viewport()->find_world()->get_scenario().get_id())); + } + } else if (p_what == Spatial::NOTIFICATION_EXIT_WORLD || p_what == Spatial::NOTIFICATION_EXIT_TREE) { if (environment.is_valid() && get_viewport()->find_world()->get_environment() == environment) { get_viewport()->find_world()->set_environment(Ref<Environment>()); remove_from_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); } + + if (camera_effects.is_valid() && get_viewport()->find_world()->get_camera_effects() == camera_effects) { + get_viewport()->find_world()->set_camera_effects(Ref<CameraEffects>()); + remove_from_group("_world_camera_effects_" + itos(get_viewport()->find_world()->get_scenario().get_id())); + } } } @@ -77,13 +90,38 @@ Ref<Environment> WorldEnvironment::get_environment() const { return environment; } +void WorldEnvironment::set_camera_effects(const Ref<CameraEffects> &p_camera_effects) { + + if (is_inside_tree() && camera_effects.is_valid() && get_viewport()->find_world()->get_camera_effects() == camera_effects) { + get_viewport()->find_world()->set_camera_effects(Ref<CameraEffects>()); + remove_from_group("_world_camera_effects_" + itos(get_viewport()->find_world()->get_scenario().get_id())); + //clean up + } + + camera_effects = p_camera_effects; + if (is_inside_tree() && camera_effects.is_valid()) { + if (get_viewport()->find_world()->get_camera_effects().is_valid()) { + WARN_PRINT("World already has an camera_effects (Another WorldEnvironment?), overriding."); + } + get_viewport()->find_world()->set_camera_effects(camera_effects); + add_to_group("_world_camera_effects_" + itos(get_viewport()->find_world()->get_scenario().get_id())); + } + + update_configuration_warning(); +} + +Ref<CameraEffects> WorldEnvironment::get_camera_effects() const { + + return camera_effects; +} + String WorldEnvironment::get_configuration_warning() const { if (!environment.is_valid()) { return TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect."); } - if (/*!is_visible_in_tree() ||*/ !is_inside_tree()) + if (!is_inside_tree()) return String(); List<Node *> nodes; @@ -93,11 +131,6 @@ String WorldEnvironment::get_configuration_warning() const { return TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."); } - // Commenting this warning for now, I think it makes no sense. If anyone can figure out what its supposed to do, feedback welcome. Else it should be deprecated. - //if (environment.is_valid() && get_viewport() && !get_viewport()->get_camera() && environment->get_background() != Environment::BG_CANVAS) { - // return TTR("This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set this environment's Background Mode to Canvas (for 2D scenes)."); - //} - return String(); } @@ -106,6 +139,10 @@ void WorldEnvironment::_bind_methods() { ClassDB::bind_method(D_METHOD("set_environment", "env"), &WorldEnvironment::set_environment); ClassDB::bind_method(D_METHOD("get_environment"), &WorldEnvironment::get_environment); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment"); + + ClassDB::bind_method(D_METHOD("set_camera_effects", "env"), &WorldEnvironment::set_camera_effects); + ClassDB::bind_method(D_METHOD("get_camera_effects"), &WorldEnvironment::get_camera_effects); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_camera_effects", "get_camera_effects"); } WorldEnvironment::WorldEnvironment() { diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h index 6e89fe8517..0c590bfc07 100644 --- a/scene/3d/world_environment.h +++ b/scene/3d/world_environment.h @@ -38,6 +38,7 @@ class WorldEnvironment : public Node { GDCLASS(WorldEnvironment, Node); Ref<Environment> environment; + Ref<CameraEffects> camera_effects; protected: void _notification(int p_what); @@ -47,6 +48,9 @@ public: void set_environment(const Ref<Environment> &p_environment); Ref<Environment> get_environment() const; + void set_camera_effects(const Ref<CameraEffects> &p_camera_effects); + Ref<CameraEffects> get_camera_effects() const; + String get_configuration_warning() const; WorldEnvironment(); |