diff options
Diffstat (limited to 'servers/physics_3d/collision_solver_3d_sw.cpp')
-rw-r--r-- | servers/physics_3d/collision_solver_3d_sw.cpp | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/servers/physics_3d/collision_solver_3d_sw.cpp b/servers/physics_3d/collision_solver_3d_sw.cpp index dcecac1c73..e7b79e8450 100644 --- a/servers/physics_3d/collision_solver_3d_sw.cpp +++ b/servers/physics_3d/collision_solver_3d_sw.cpp @@ -89,6 +89,49 @@ bool CollisionSolver3DSW::solve_static_plane(const Shape3DSW *p_shape_A, const T return found; } +bool CollisionSolver3DSW::solve_separation_ray(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin) { + const SeparationRayShape3DSW *ray = static_cast<const SeparationRayShape3DSW *>(p_shape_A); + + Vector3 from = p_transform_A.origin; + Vector3 to = from + p_transform_A.basis.get_axis(2) * (ray->get_length() + p_margin); + Vector3 support_A = to; + + Transform3D ai = p_transform_B.affine_inverse(); + + from = ai.xform(from); + to = ai.xform(to); + + Vector3 p, n; + if (!p_shape_B->intersect_segment(from, to, p, n)) { + return false; + } + + // Discard contacts when the ray is fully contained inside the shape. + if (n == Vector3()) { + return false; + } + + // Discard contacts in the wrong direction. + if (n.dot(from - to) < CMP_EPSILON) { + return false; + } + + Vector3 support_B = p_transform_B.xform(p); + if (ray->get_slide_on_slope()) { + Vector3 global_n = ai.basis.xform_inv(n).normalized(); + support_B = support_A + (support_B - support_A).length() * global_n; + } + + if (p_result_callback) { + if (p_swap_result) { + p_result_callback(support_B, 0, support_A, 0, p_userdata); + } else { + p_result_callback(support_A, 0, support_B, 0, p_userdata); + } + } + return true; +} + struct _SoftBodyContactCollisionInfo { int node_index = 0; CollisionSolver3DSW::CallbackResult result_callback = nullptr; @@ -318,6 +361,9 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo if (type_B == PhysicsServer3D::SHAPE_PLANE) { return false; } + if (type_B == PhysicsServer3D::SHAPE_SEPARATION_RAY) { + return false; + } if (type_B == PhysicsServer3D::SHAPE_SOFT_BODY) { return false; } @@ -328,6 +374,17 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo return solve_static_plane(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false); } + } else if (type_A == PhysicsServer3D::SHAPE_SEPARATION_RAY) { + if (type_B == PhysicsServer3D::SHAPE_SEPARATION_RAY) { + return false; + } + + if (swap) { + return solve_separation_ray(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true, p_margin_B); + } else { + return solve_separation_ray(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false, p_margin_A); + } + } else if (type_B == PhysicsServer3D::SHAPE_SOFT_BODY) { if (type_A == PhysicsServer3D::SHAPE_SOFT_BODY) { // Soft Body / Soft Body not supported. |