jolt_custom_ray_shape.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /**************************************************************************/
  2. /* jolt_custom_ray_shape.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "jolt_custom_ray_shape.h"
  31. #include "../spaces/jolt_query_collectors.h"
  32. #include "Jolt/Physics/Collision/CastResult.h"
  33. #include "Jolt/Physics/Collision/RayCast.h"
  34. #include "Jolt/Physics/Collision/TransformedShape.h"
  35. #ifdef JPH_DEBUG_RENDERER
  36. #include "Jolt/Renderer/DebugRenderer.h"
  37. #endif
  38. namespace {
  39. class JoltCustomRayShapeSupport final : public JPH::ConvexShape::Support {
  40. public:
  41. explicit JoltCustomRayShapeSupport(float p_length) :
  42. length(p_length) {}
  43. virtual JPH::Vec3 GetSupport(JPH::Vec3Arg p_direction) const override {
  44. if (p_direction.GetZ() > 0.0f) {
  45. return JPH::Vec3(0.0f, 0.0f, length);
  46. } else {
  47. return JPH::Vec3::sZero();
  48. }
  49. }
  50. virtual float GetConvexRadius() const override { return 0.0f; }
  51. private:
  52. float length = 0.0f;
  53. };
  54. static_assert(sizeof(JoltCustomRayShapeSupport) <= sizeof(JPH::ConvexShape::SupportBuffer), "Size of SeparationRayShape3D support is larger than size of support buffer.");
  55. JPH::Shape *construct_ray() {
  56. return new JoltCustomRayShape();
  57. }
  58. void collide_ray_vs_shape(const JPH::Shape *p_shape1, const JPH::Shape *p_shape2, JPH::Vec3Arg p_scale1, JPH::Vec3Arg p_scale2, JPH::Mat44Arg p_center_of_mass_transform1, JPH::Mat44Arg p_center_of_mass_transform2, const JPH::SubShapeIDCreator &p_sub_shape_id_creator1, const JPH::SubShapeIDCreator &p_sub_shape_id_creator2, const JPH::CollideShapeSettings &p_collide_shape_settings, JPH::CollideShapeCollector &p_collector, const JPH::ShapeFilter &p_shape_filter) {
  59. ERR_FAIL_COND(p_shape1->GetSubType() != JoltCustomShapeSubType::RAY);
  60. const JoltCustomRayShape *shape1 = static_cast<const JoltCustomRayShape *>(p_shape1);
  61. const float margin = p_collide_shape_settings.mMaxSeparationDistance;
  62. const float ray_length = shape1->length;
  63. const float ray_length_padded = ray_length + margin;
  64. const JPH::Mat44 transform1 = p_center_of_mass_transform1 * JPH::Mat44::sScale(p_scale1);
  65. const JPH::Mat44 transform2 = p_center_of_mass_transform2 * JPH::Mat44::sScale(p_scale2);
  66. const JPH::Mat44 transform_inv2 = transform2.Inversed();
  67. const JPH::Vec3 ray_start = transform1.GetTranslation();
  68. const JPH::Vec3 ray_direction = transform1.GetAxisZ();
  69. const JPH::Vec3 ray_vector = ray_direction * ray_length;
  70. const JPH::Vec3 ray_vector_padded = ray_direction * ray_length_padded;
  71. const JPH::Vec3 ray_start2 = transform_inv2 * ray_start;
  72. const JPH::Vec3 ray_direction2 = transform_inv2.Multiply3x3(ray_direction);
  73. const JPH::Vec3 ray_vector_padded2 = transform_inv2.Multiply3x3(ray_vector_padded);
  74. const JPH::RayCast ray_cast(ray_start2, ray_vector_padded2);
  75. JPH::RayCastSettings ray_cast_settings;
  76. ray_cast_settings.mTreatConvexAsSolid = false;
  77. ray_cast_settings.mBackFaceModeTriangles = p_collide_shape_settings.mBackFaceMode;
  78. JoltQueryCollectorClosest<JPH::CastRayCollector> ray_collector;
  79. p_shape2->CastRay(ray_cast, ray_cast_settings, p_sub_shape_id_creator2, ray_collector);
  80. if (!ray_collector.had_hit()) {
  81. return;
  82. }
  83. const JPH::RayCastResult &hit = ray_collector.get_hit();
  84. const float hit_distance = ray_length_padded * hit.mFraction;
  85. const float hit_depth = ray_length - hit_distance;
  86. if (-hit_depth >= p_collector.GetEarlyOutFraction()) {
  87. return;
  88. }
  89. // Since `hit.mSubShapeID2` could represent a path not only from `p_shape2` but also any
  90. // compound shape that it's contained within, we need to split this path into something that
  91. // `p_shape2` can actually understand.
  92. JPH::SubShapeID local_sub_shape_id2;
  93. hit.mSubShapeID2.PopID(p_sub_shape_id_creator2.GetNumBitsWritten(), local_sub_shape_id2);
  94. const JPH::Vec3 hit_point2 = ray_cast.GetPointOnRay(hit.mFraction);
  95. const JPH::Vec3 hit_point_on_1 = ray_start + ray_vector;
  96. const JPH::Vec3 hit_point_on_2 = transform2 * hit_point2;
  97. JPH::Vec3 hit_normal2 = JPH::Vec3::sZero();
  98. if (shape1->slide_on_slope) {
  99. hit_normal2 = p_shape2->GetSurfaceNormal(local_sub_shape_id2, hit_point2);
  100. // If we got a back-face normal we need to flip it.
  101. if (hit_normal2.Dot(ray_direction2) > 0) {
  102. hit_normal2 = -hit_normal2;
  103. }
  104. } else {
  105. hit_normal2 = -ray_direction2;
  106. }
  107. const JPH::Vec3 hit_normal = transform2.Multiply3x3(hit_normal2);
  108. JPH::CollideShapeResult result(hit_point_on_1, hit_point_on_2, -hit_normal, hit_depth, p_sub_shape_id_creator1.GetID(), hit.mSubShapeID2, JPH::TransformedShape::sGetBodyID(p_collector.GetContext()));
  109. if (p_collide_shape_settings.mCollectFacesMode == JPH::ECollectFacesMode::CollectFaces) {
  110. p_shape2->GetSupportingFace(local_sub_shape_id2, ray_direction2, p_scale2, p_center_of_mass_transform2, result.mShape2Face);
  111. }
  112. p_collector.AddHit(result);
  113. }
  114. void collide_noop(const JPH::Shape *p_shape1, const JPH::Shape *p_shape2, JPH::Vec3Arg p_scale1, JPH::Vec3Arg p_scale2, JPH::Mat44Arg p_center_of_mass_transform1, JPH::Mat44Arg p_center_of_mass_transform2, const JPH::SubShapeIDCreator &p_sub_shape_id_creator1, const JPH::SubShapeIDCreator &p_sub_shape_id_creator2, const JPH::CollideShapeSettings &p_collide_shape_settings, JPH::CollideShapeCollector &p_collector, const JPH::ShapeFilter &p_shape_filter) {
  115. }
  116. void cast_noop(const JPH::ShapeCast &p_shape_cast, const JPH::ShapeCastSettings &p_shape_cast_settings, const JPH::Shape *p_shape, JPH::Vec3Arg p_scale, const JPH::ShapeFilter &p_shape_filter, JPH::Mat44Arg p_center_of_mass_transform2, const JPH::SubShapeIDCreator &p_sub_shape_id_creator1, const JPH::SubShapeIDCreator &p_sub_shape_id_creator2, JPH::CastShapeCollector &p_collector) {
  117. }
  118. } // namespace
  119. JPH::ShapeSettings::ShapeResult JoltCustomRayShapeSettings::Create() const {
  120. if (mCachedResult.IsEmpty()) {
  121. new JoltCustomRayShape(*this, mCachedResult);
  122. }
  123. return mCachedResult;
  124. }
  125. void JoltCustomRayShape::register_type() {
  126. JPH::ShapeFunctions &shape_functions = JPH::ShapeFunctions::sGet(JoltCustomShapeSubType::RAY);
  127. shape_functions.mConstruct = construct_ray;
  128. shape_functions.mColor = JPH::Color::sDarkRed;
  129. static constexpr JPH::EShapeSubType concrete_sub_types[] = {
  130. JPH::EShapeSubType::Sphere,
  131. JPH::EShapeSubType::Box,
  132. JPH::EShapeSubType::Triangle,
  133. JPH::EShapeSubType::Capsule,
  134. JPH::EShapeSubType::TaperedCapsule,
  135. JPH::EShapeSubType::Cylinder,
  136. JPH::EShapeSubType::ConvexHull,
  137. JPH::EShapeSubType::Mesh,
  138. JPH::EShapeSubType::HeightField,
  139. JPH::EShapeSubType::Plane,
  140. JPH::EShapeSubType::TaperedCylinder
  141. };
  142. for (const JPH::EShapeSubType concrete_sub_type : concrete_sub_types) {
  143. JPH::CollisionDispatch::sRegisterCollideShape(JoltCustomShapeSubType::RAY, concrete_sub_type, collide_ray_vs_shape);
  144. JPH::CollisionDispatch::sRegisterCollideShape(concrete_sub_type, JoltCustomShapeSubType::RAY, JPH::CollisionDispatch::sReversedCollideShape);
  145. }
  146. JPH::CollisionDispatch::sRegisterCollideShape(JoltCustomShapeSubType::RAY, JoltCustomShapeSubType::RAY, collide_noop);
  147. for (const JPH::EShapeSubType sub_type : JPH::sAllSubShapeTypes) {
  148. JPH::CollisionDispatch::sRegisterCastShape(JoltCustomShapeSubType::RAY, sub_type, cast_noop);
  149. JPH::CollisionDispatch::sRegisterCastShape(sub_type, JoltCustomShapeSubType::RAY, cast_noop);
  150. }
  151. }
  152. JPH::AABox JoltCustomRayShape::GetLocalBounds() const {
  153. const float radius = GetInnerRadius();
  154. return JPH::AABox(JPH::Vec3(-radius, -radius, 0.0f), JPH::Vec3(radius, radius, length));
  155. }
  156. float JoltCustomRayShape::GetInnerRadius() const {
  157. // There is no sensible value here, since this shape is infinitely thin, so we pick something
  158. // that's hopefully small enough to effectively be zero, but big enough to not cause any
  159. // numerical issues.
  160. return 0.0001f;
  161. }
  162. JPH::MassProperties JoltCustomRayShape::GetMassProperties() const {
  163. JPH::MassProperties mass_properties;
  164. // Since this shape has no volume we can't really give it a correct set of mass properties, so
  165. // instead we just give it some arbitrary ones.
  166. mass_properties.mMass = 1.0f;
  167. mass_properties.mInertia = JPH::Mat44::sIdentity();
  168. return mass_properties;
  169. }
  170. #ifdef JPH_DEBUG_RENDERER
  171. void JoltCustomRayShape::Draw(JPH::DebugRenderer *p_renderer, JPH::RMat44Arg p_center_of_mass_transform, JPH::Vec3Arg p_scale, JPH::ColorArg p_color, bool p_use_material_colors, bool p_draw_wireframe) const {
  172. p_renderer->DrawArrow(p_center_of_mass_transform.GetTranslation(), p_center_of_mass_transform * JPH::Vec3(0, 0, length * p_scale.GetZ()), p_use_material_colors ? GetMaterial()->GetDebugColor() : p_color, 0.1f);
  173. }
  174. #endif
  175. const JPH::ConvexShape::Support *JoltCustomRayShape::GetSupportFunction(JPH::ConvexShape::ESupportMode p_mode, JPH::ConvexShape::SupportBuffer &p_buffer, JPH::Vec3Arg p_scale) const {
  176. return new (&p_buffer) JoltCustomRayShapeSupport(p_scale.GetZ() * length);
  177. }