summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SConstruct2
-rw-r--r--editor/import/scene_importer_mesh.cpp2
-rw-r--r--editor/scene_tree_dock.cpp4
-rw-r--r--main/main.cpp2
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp2
-rw-r--r--platform/android/detect.py13
-rw-r--r--platform/android/export/export.cpp33
-rw-r--r--platform/android/java/app/res/drawable/splash_drawable.xml2
-rw-r--r--platform/linuxbsd/joypad_linux.cpp10
-rw-r--r--scene/2d/audio_stream_player_2d.cpp3
-rw-r--r--scene/3d/audio_stream_player_3d.cpp3
-rw-r--r--scene/3d/mesh_instance_3d.cpp1
-rw-r--r--servers/physics_2d/space_2d_sw.cpp84
-rw-r--r--servers/physics_3d/space_3d_sw.cpp95
14 files changed, 172 insertions, 84 deletions
diff --git a/SConstruct b/SConstruct
index 000c918808..90cc99dd47 100644
--- a/SConstruct
+++ b/SConstruct
@@ -617,7 +617,7 @@ if selected_platform in platform_list:
if env["minizip"]:
env.Append(CPPDEFINES=["MINIZIP_ENABLED"])
- editor_module_list = ["regex"]
+ editor_module_list = ["freetype", "regex"]
if env["tools"] and not env.module_check_dependencies("tools", editor_module_list):
print(
"Build option 'module_"
diff --git a/editor/import/scene_importer_mesh.cpp b/editor/import/scene_importer_mesh.cpp
index 78a7cd84f1..46eb4e4fdc 100644
--- a/editor/import/scene_importer_mesh.cpp
+++ b/editor/import/scene_importer_mesh.cpp
@@ -444,7 +444,7 @@ void EditorSceneImporterMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &EditorSceneImporterMesh::set_blend_shape_mode);
ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &EditorSceneImporterMesh::get_blend_shape_mode);
- ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material"), &EditorSceneImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String()));
+ ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material", "name"), &EditorSceneImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String()));
ClassDB::bind_method(D_METHOD("get_surface_count"), &EditorSceneImporterMesh::get_surface_count);
ClassDB::bind_method(D_METHOD("get_surface_primitive_type", "surface_idx"), &EditorSceneImporterMesh::get_surface_primitive_type);
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index c1edeeeb0e..0ba67d05dd 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -2921,7 +2921,7 @@ void SceneTreeDock::_create_remap_for_node(Node *p_node, Map<RES, RES> &r_remap)
if (v.is_ref()) {
RES res = v;
if (res.is_valid()) {
- if (res->get_path() == "" && !r_remap.has(res)) {
+ if ((res->get_path() == "" || res->get_path().find("::") > -1) && !r_remap.has(res)) {
_create_remap_for_resource(res, r_remap);
}
}
@@ -2948,7 +2948,7 @@ void SceneTreeDock::_create_remap_for_resource(RES p_resource, Map<RES, RES> &r_
if (v.is_ref()) {
RES res = v;
if (res.is_valid()) {
- if (res->get_path() == "" && !r_remap.has(res)) {
+ if ((res->get_path() == "" || res->get_path().find("::") > -1) && !r_remap.has(res)) {
_create_remap_for_resource(res, r_remap);
}
}
diff --git a/main/main.cpp b/main/main.cpp
index 9489774dce..b437d2e4f3 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1602,7 +1602,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
MAIN_PRINT("Main: Setup Logo");
-#ifdef JAVASCRIPT_ENABLED
+#if defined(JAVASCRIPT_ENABLED) || defined(ANDROID_ENABLED)
bool show_logo = false;
#else
bool show_logo = true;
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp
index 5e3d6213d3..912c9a174e 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.cpp
+++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp
@@ -163,7 +163,7 @@ void GDScriptLanguageProtocol::_bind_methods() {
ClassDB::bind_method(D_METHOD("initialized", "params"), &GDScriptLanguageProtocol::initialized);
ClassDB::bind_method(D_METHOD("on_client_connected"), &GDScriptLanguageProtocol::on_client_connected);
ClassDB::bind_method(D_METHOD("on_client_disconnected"), &GDScriptLanguageProtocol::on_client_disconnected);
- ClassDB::bind_method(D_METHOD("notify_client", "method", "params"), &GDScriptLanguageProtocol::notify_client, DEFVAL(Variant()), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("notify_client", "method", "params", "client_id"), &GDScriptLanguageProtocol::notify_client, DEFVAL(Variant()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("is_smart_resolve_enabled"), &GDScriptLanguageProtocol::is_smart_resolve_enabled);
ClassDB::bind_method(D_METHOD("get_text_document"), &GDScriptLanguageProtocol::get_text_document);
ClassDB::bind_method(D_METHOD("get_workspace"), &GDScriptLanguageProtocol::get_workspace);
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 98d4a21e26..5f0fcc9b77 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -13,7 +13,7 @@ def get_name():
def can_build():
- return ("ANDROID_NDK_ROOT" in os.environ) or ("ANDROID_SDK_ROOT" in os.environ) or ("ANDROID_HOME" in os.environ)
+ return ("ANDROID_SDK_ROOT" in os.environ) or ("ANDROID_HOME" in os.environ)
def get_platform(platform):
@@ -43,15 +43,12 @@ def get_android_sdk_root():
# Return the ANDROID_NDK_ROOT environment variable.
-# If the env variable is already defined, we use it with the expectation that
-# the user knows what they're doing (e.g: testing a new NDK version).
-# Otherwise, we generate one for this build using the ANDROID_SDK_ROOT env
+# We generate one for this build using the ANDROID_SDK_ROOT env
# variable and the project ndk version.
+# If the env variable is already defined, we override it with
+# our own to match what the project expects.
def get_android_ndk_root():
- if "ANDROID_NDK_ROOT" in os.environ:
- return os.environ.get("ANDROID_NDK_ROOT", 0)
- else:
- return get_android_sdk_root() + "/ndk/" + get_project_ndk_version()
+ return get_android_sdk_root() + "/ndk/" + get_project_ndk_version()
def get_flags():
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index e0aa8dc524..f16ab888d6 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -202,6 +202,19 @@ static const char *android_perms[] = {
static const char *SPLASH_IMAGE_EXPORT_PATH = "res/drawable/splash.png";
static const char *SPLASH_BG_COLOR_PATH = "res/drawable/splash_bg_color.png";
+static const char *SPLASH_CONFIG_PATH = "res://android/build/res/drawable/splash_drawable.xml";
+
+const String SPLASH_CONFIG_XML_CONTENT = R"SPLASH(<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/splash_bg_color" />
+ <item>
+ <bitmap
+ android:gravity="%s"
+ android:filter="%s"
+ android:src="@drawable/splash" />
+ </item>
+</layer-list>
+)SPLASH";
struct LauncherIcon {
const char *export_path;
@@ -1473,8 +1486,9 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
}
- void load_splash_refs(Ref<Image> &splash_image, Ref<Image> &splash_bg_color_image) {
- // TODO: Figure out how to handle remaining boot splash parameters (e.g: fullsize, filter)
+ String load_splash_refs(Ref<Image> &splash_image, Ref<Image> &splash_bg_color_image) {
+ bool scale_splash = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize");
+ bool apply_filter = ProjectSettings::get_singleton()->get("application/boot_splash/use_filter");
String project_splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
if (!project_splash_path.is_empty()) {
@@ -1506,6 +1520,10 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
splash_bg_color_image.instance();
splash_bg_color_image->create(splash_image->get_width(), splash_image->get_height(), false, splash_image->get_format());
splash_bg_color_image->fill(bg_color);
+
+ String gravity = scale_splash ? "fill" : "center";
+ String processed_splash_config_xml = vformat(SPLASH_CONFIG_XML_CONTENT, gravity, bool_to_string(apply_filter));
+ return processed_splash_config_xml;
}
void load_icon_refs(const Ref<EditorExportPreset> &p_preset, Ref<Image> &icon, Ref<Image> &foreground, Ref<Image> &background) {
@@ -1549,11 +1567,18 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
void _copy_icons_to_gradle_project(const Ref<EditorExportPreset> &p_preset,
+ const String &processed_splash_config_xml,
const Ref<Image> &splash_image,
const Ref<Image> &splash_bg_color_image,
const Ref<Image> &main_image,
const Ref<Image> &foreground,
const Ref<Image> &background) {
+ // Store the splash configuration
+ if (!processed_splash_config_xml.is_empty()) {
+ print_verbose("Storing processed splash configuration: " + String("\n") + processed_splash_config_xml);
+ store_string_at_path(SPLASH_CONFIG_PATH, processed_splash_config_xml);
+ }
+
// Store the splash image
if (splash_image.is_valid() && !splash_image->is_empty()) {
print_verbose("Storing splash image in " + String(SPLASH_IMAGE_EXPORT_PATH));
@@ -2391,7 +2416,7 @@ public:
Ref<Image> splash_image;
Ref<Image> splash_bg_color_image;
- load_splash_refs(splash_image, splash_bg_color_image);
+ String processed_splash_config_xml = load_splash_refs(splash_image, splash_bg_color_image);
Ref<Image> main_image;
Ref<Image> foreground;
@@ -2452,7 +2477,7 @@ public:
EditorNode::add_io_error("Unable to overwrite res://android/build/res/*.xml files with project name");
}
// Copies the project icon files into the appropriate Gradle project directory.
- _copy_icons_to_gradle_project(p_preset, splash_image, splash_bg_color_image, main_image, foreground, background);
+ _copy_icons_to_gradle_project(p_preset, processed_splash_config_xml, splash_image, splash_bg_color_image, main_image, foreground, background);
// Write an AndroidManifest.xml file into the Gradle project directory.
_write_tmp_manifest(p_preset, p_give_internet, p_debug);
diff --git a/platform/android/java/app/res/drawable/splash_drawable.xml b/platform/android/java/app/res/drawable/splash_drawable.xml
index 2794a40817..30627b998c 100644
--- a/platform/android/java/app/res/drawable/splash_drawable.xml
+++ b/platform/android/java/app/res/drawable/splash_drawable.xml
@@ -6,7 +6,7 @@
<item>
<bitmap
android:gravity="center"
+ android:filter="false"
android:src="@drawable/splash" />
</item>
-
</layer-list>
diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp
index d1115b146b..9d2a768fb3 100644
--- a/platform/linuxbsd/joypad_linux.cpp
+++ b/platform/linuxbsd/joypad_linux.cpp
@@ -105,11 +105,13 @@ void JoypadLinux::run_joypad_thread() {
udev *_udev = udev_new();
if (!_udev) {
use_udev = false;
- ERR_FAIL_MSG("Failed getting an udev context, falling back to parsing /dev/input.");
+ ERR_PRINT("Failed getting an udev context, falling back to parsing /dev/input.");
+ monitor_joypads();
+ } else {
+ enumerate_joypads(_udev);
+ monitor_joypads(_udev);
+ udev_unref(_udev);
}
- enumerate_joypads(_udev);
- monitor_joypads(_udev);
- udev_unref(_udev);
} else {
monitor_joypads();
}
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index d6f35cc99d..79624bf3bf 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -311,7 +311,6 @@ void AudioStreamPlayer2D::play(float p_from_pos) {
}
if (stream_playback.is_valid()) {
- active = true;
setplay = p_from_pos;
output_ready = false;
set_physics_process_internal(true);
@@ -334,7 +333,7 @@ void AudioStreamPlayer2D::stop() {
bool AudioStreamPlayer2D::is_playing() const {
if (stream_playback.is_valid()) {
- return active; // && stream_playback->is_playing();
+ return active || setplay >= 0;
}
return false;
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 65d0703139..dd77221a3f 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -683,7 +683,6 @@ void AudioStreamPlayer3D::play(float p_from_pos) {
}
if (stream_playback.is_valid()) {
- active = true;
setplay = p_from_pos;
output_ready = false;
set_physics_process_internal(true);
@@ -706,7 +705,7 @@ void AudioStreamPlayer3D::stop() {
bool AudioStreamPlayer3D::is_playing() const {
if (stream_playback.is_valid()) {
- return active; // && stream_playback->is_playing();
+ return active || setplay >= 0;
}
return false;
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index 7b3a0820f1..b997c64b29 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -319,6 +319,7 @@ Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
}
void MeshInstance3D::_mesh_changed() {
+ ERR_FAIL_COND(mesh.is_null());
materials.resize(mesh->get_surface_count());
}
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index 05136e2501..9cbc01d1d3 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -376,6 +376,7 @@ struct _RestCallbackData2D {
Vector2 best_normal;
real_t best_len;
Vector2 valid_dir;
+ real_t valid_depth;
real_t min_allowed_depth;
};
@@ -385,22 +386,24 @@ static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B,
Vector2 contact_rel = p_point_B - p_point_A;
real_t len = contact_rel.length();
- if (len == 0) {
+ if (len < rd->min_allowed_depth) {
return;
}
- Vector2 normal = contact_rel / len;
-
- if (rd->valid_dir != Vector2() && rd->valid_dir.dot(normal) > -CMP_EPSILON) {
+ if (len <= rd->best_len) {
return;
}
- if (len < rd->min_allowed_depth) {
- return;
- }
+ Vector2 normal = contact_rel / len;
- if (len <= rd->best_len) {
- return;
+ if (rd->valid_dir != Vector2()) {
+ if (len > rd->valid_depth) {
+ return;
+ }
+
+ if (rd->valid_dir.dot(normal) > -CMP_EPSILON) {
+ return;
+ }
}
rd->best_len = len;
@@ -739,10 +742,13 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
ExcludedShapeSW excluded_shape_pairs[max_excluded_shape_pairs];
int excluded_shape_pair_count = 0;
- real_t separation_margin = MIN(p_margin, MAX(0.0, p_motion.length() - CMP_EPSILON)); //don't separate by more than the intended motion
+ real_t motion_length = p_motion.length();
+ Vector2 motion_normal = p_motion / motion_length;
Transform2D body_transform = p_from;
+ bool recovered = false;
+
{
//STEP 1, FREE BODY IF STUCK
@@ -819,7 +825,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
bool did_collide = false;
Shape2DSW *against_shape = col_obj->get_shape(shape_idx);
- if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, separation_margin)) {
+ if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, p_margin)) {
did_collide = cbk.passed > current_passed; //more passed, so collision actually existed
}
@@ -845,11 +851,20 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
}
Vector2 recover_motion;
-
for (int i = 0; i < cbk.amount; i++) {
Vector2 a = sr[i * 2 + 0];
Vector2 b = sr[i * 2 + 1];
- recover_motion += (b - a) / cbk.amount;
+
+ // Compute plane on b towards a.
+ Vector2 n = (a - b).normalized();
+ real_t d = n.dot(b);
+
+ // Compute depth on recovered motion.
+ real_t depth = n.dot(a + recover_motion) - d;
+ if (depth > 0.0) {
+ // Only recover if there is penetration.
+ recover_motion -= n * depth * 0.4;
+ }
}
if (recover_motion == Vector2()) {
@@ -857,6 +872,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
break;
}
+ recovered = true;
+
body_transform.elements[2] += recover_motion;
body_aabb.position += recover_motion;
@@ -929,7 +946,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
//test initial overlap
if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, nullptr, 0)) {
if (col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) {
- continue;
+ Vector2 direction = col_obj_shape_xform.get_axis(1).normalized();
+ if (motion_normal.dot(direction) < 0) {
+ continue;
+ }
}
stuck = true;
@@ -939,13 +959,12 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
//just do kinematic solving
real_t low = 0;
real_t hi = 1;
- Vector2 mnormal = p_motion.normalized();
for (int k = 0; k < 8; k++) { //steps should be customizable..
real_t ofs = (low + hi) * 0.5;
- Vector2 sep = mnormal; //important optimization for this to work fast enough
+ Vector2 sep = motion_normal; //important optimization for this to work fast enough
bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * ofs, against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, &sep, 0);
if (collided) {
@@ -966,7 +985,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
cbk.valid_depth = 10e20;
- Vector2 sep = mnormal; //important optimization for this to work fast enough
+ Vector2 sep = motion_normal; //important optimization for this to work fast enough
bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(col_shape_idx), col_obj_shape_xform, Vector2(), PhysicsServer2DSW::_shape_col_cbk, &cbk, &sep, 0);
if (!collided || cbk.amount == 0) {
continue;
@@ -997,11 +1016,12 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
}
bool collided = false;
- if (safe >= 1) {
- best_shape = -1; //no best shape with cast, reset to -1
- }
- if (safe < 1) {
+ if (recovered || (safe < 1)) {
+ if (safe >= 1) {
+ best_shape = -1; //no best shape with cast, reset to -1
+ }
+
//it collided, let's get the rest info in unsafe advance
Transform2D ugt = body_transform;
ugt.elements[2] += p_motion * unsafe;
@@ -1010,9 +1030,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
rcd.best_len = 0;
rcd.best_object = nullptr;
rcd.best_shape = 0;
- rcd.min_allowed_depth = test_motion_min_contact_depth;
- //optimization
+ // Allowed depth can't be lower than motion length, in order to handle contacts at low speed.
+ rcd.min_allowed_depth = MIN(motion_length, test_motion_min_contact_depth);
+
int from_shape = best_shape != -1 ? best_shape : 0;
int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count();
@@ -1060,8 +1081,25 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
rcd.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
+
+ real_t owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx);
+ rcd.valid_depth = MAX(owc_margin, p_margin); //user specified, but never less than actual margin or it won't work
+
+ if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) {
+ const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
+ if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_RIGID) {
+ //fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction
+ Vector2 lv = b->get_linear_velocity();
+ //compute displacement from linear velocity
+ Vector2 motion = lv * PhysicsDirectBodyState2DSW::singleton->step;
+ real_t motion_len = motion.length();
+ motion.normalize();
+ rcd.valid_depth += motion_len * MAX(motion.dot(-rcd.valid_dir), 0.0);
+ }
+ }
} else {
rcd.valid_dir = Vector2();
+ rcd.valid_depth = 0;
}
rcd.object = col_obj;
diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp
index 40537c7001..dd5754b9ac 100644
--- a/servers/physics_3d/space_3d_sw.cpp
+++ b/servers/physics_3d/space_3d_sw.cpp
@@ -384,6 +384,8 @@ bool PhysicsDirectSpaceState3DSW::collide_shape(RID p_shape, const Transform &p_
struct _RestCallbackData {
const CollisionObject3DSW *object;
const CollisionObject3DSW *best_object;
+ int local_shape;
+ int best_local_shape;
int shape;
int best_shape;
Vector3 best_contact;
@@ -409,6 +411,7 @@ static void _rest_cbk_result(const Vector3 &p_point_A, const Vector3 &p_point_B,
rd->best_normal = contact_rel / len;
rd->best_object = rd->object;
rd->best_shape = rd->shape;
+ rd->best_local_shape = rd->local_shape;
}
bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
@@ -739,8 +742,13 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
body_aabb = p_from.xform(p_body->get_inv_transform().xform(body_aabb));
body_aabb = body_aabb.grow(p_margin);
+ real_t motion_length = p_motion.length();
+ Vector3 motion_normal = p_motion / motion_length;
+
Transform body_transform = p_from;
+ bool recovered = false;
+
{
//STEP 1, FREE BODY IF STUCK
@@ -791,7 +799,17 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
for (int i = 0; i < cbk.amount; i++) {
Vector3 a = sr[i * 2 + 0];
Vector3 b = sr[i * 2 + 1];
- recover_motion += (b - a) / cbk.amount;
+
+ // Compute plane on b towards a.
+ Vector3 n = (a - b).normalized();
+ real_t d = n.dot(b);
+
+ // Compute depth on recovered motion.
+ real_t depth = n.dot(a + recover_motion) - d;
+ if (depth > 0.0) {
+ // Only recover if there is penetration.
+ recover_motion -= n * depth * 0.4;
+ }
}
if (recover_motion == Vector3()) {
@@ -799,6 +817,8 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
break;
}
+ recovered = true;
+
body_transform.origin += recover_motion;
body_aabb.position += recover_motion;
@@ -848,14 +868,14 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
//test initial overlap, does it collide if going all the way?
Vector3 point_A, point_B;
- Vector3 sep_axis = p_motion.normalized();
+ Vector3 sep_axis = motion_normal;
Transform col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
//test initial overlap, does it collide if going all the way?
if (CollisionSolver3DSW::solve_distance(&mshape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, motion_aabb, &sep_axis)) {
continue;
}
- sep_axis = p_motion.normalized();
+ sep_axis = motion_normal;
if (!CollisionSolver3DSW::solve_distance(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, motion_aabb, &sep_axis)) {
stuck = true;
@@ -865,13 +885,12 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
//just do kinematic solving
real_t low = 0;
real_t hi = 1;
- Vector3 mnormal = p_motion.normalized();
for (int k = 0; k < 8; k++) { //steps should be customizable..
real_t ofs = (low + hi) * 0.5;
- Vector3 sep = mnormal; //important optimization for this to work fast enough
+ Vector3 sep = motion_normal; //important optimization for this to work fast enough
mshape.motion = body_shape_xform_inv.basis.xform(p_motion * ofs);
@@ -912,16 +931,11 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
}
bool collided = false;
- if (safe >= 1) {
- //not collided
- collided = false;
- if (r_result) {
- r_result->motion = p_motion;
- r_result->remainder = Vector3();
- r_result->motion += (body_transform.get_origin() - p_from.get_origin());
+ if (recovered || (safe < 1)) {
+ if (safe >= 1) {
+ best_shape = -1; //no best shape with cast, reset to -1
}
- } else {
//it collided, let's get the rest info in unsafe advance
Transform ugt = body_transform;
ugt.origin += p_motion * unsafe;
@@ -930,25 +944,40 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
rcd.best_len = 0;
rcd.best_object = nullptr;
rcd.best_shape = 0;
- rcd.min_allowed_depth = test_motion_min_contact_depth;
- Transform body_shape_xform = ugt * p_body->get_shape_transform(best_shape);
- Shape3DSW *body_shape = p_body->get_shape(best_shape);
+ // Allowed depth can't be lower than motion length, in order to handle contacts at low speed.
+ rcd.min_allowed_depth = MIN(motion_length, test_motion_min_contact_depth);
- body_aabb.position += p_motion * unsafe;
+ int from_shape = best_shape != -1 ? best_shape : 0;
+ int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count();
- int amount = _cull_aabb_for_body(p_body, body_aabb);
+ for (int j = from_shape; j < to_shape; j++) {
+ if (p_body->is_shape_set_as_disabled(j)) {
+ continue;
+ }
- for (int i = 0; i < amount; i++) {
- const CollisionObject3DSW *col_obj = intersection_query_results[i];
- int shape_idx = intersection_query_subindex_results[i];
+ Transform body_shape_xform = ugt * p_body->get_shape_transform(j);
+ Shape3DSW *body_shape = p_body->get_shape(j);
- rcd.object = col_obj;
- rcd.shape = shape_idx;
- bool sc = CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_margin);
- if (!sc) {
+ if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer3D::SHAPE_RAY) {
continue;
}
+
+ body_aabb.position += p_motion * unsafe;
+
+ int amount = _cull_aabb_for_body(p_body, body_aabb);
+
+ for (int i = 0; i < amount; i++) {
+ const CollisionObject3DSW *col_obj = intersection_query_results[i];
+ int shape_idx = intersection_query_subindex_results[i];
+
+ rcd.object = col_obj;
+ rcd.shape = shape_idx;
+ bool sc = CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_margin);
+ if (!sc) {
+ continue;
+ }
+ }
}
if (rcd.best_len != 0) {
@@ -956,7 +985,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
r_result->collider = rcd.best_object->get_self();
r_result->collider_id = rcd.best_object->get_instance_id();
r_result->collider_shape = rcd.best_shape;
- r_result->collision_local_shape = best_shape;
+ r_result->collision_local_shape = rcd.best_local_shape;
r_result->collision_normal = rcd.best_normal;
r_result->collision_point = rcd.best_contact;
//r_result->collider_metadata = rcd.best_object->get_shape_metadata(rcd.best_shape);
@@ -972,17 +1001,15 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
}
collided = true;
- } else {
- if (r_result) {
- r_result->motion = p_motion;
- r_result->remainder = Vector3();
- r_result->motion += (body_transform.get_origin() - p_from.get_origin());
- }
-
- collided = false;
}
}
+ if (!collided && r_result) {
+ r_result->motion = p_motion;
+ r_result->remainder = Vector3();
+ r_result->motion += (body_transform.get_origin() - p_from.get_origin());
+ }
+
return collided;
}