Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/jolt_physics/shapes/jolt_custom_ray_shape.cpp
10278 views
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
31
#include "jolt_custom_ray_shape.h"
32
33
#include "../spaces/jolt_query_collectors.h"
34
35
#include "Jolt/Physics/Collision/CastResult.h"
36
#include "Jolt/Physics/Collision/RayCast.h"
37
#include "Jolt/Physics/Collision/TransformedShape.h"
38
39
#ifdef JPH_DEBUG_RENDERER
40
#include "Jolt/Renderer/DebugRenderer.h"
41
#endif
42
43
namespace {
44
45
class JoltCustomRayShapeSupport final : public JPH::ConvexShape::Support {
46
public:
47
explicit JoltCustomRayShapeSupport(float p_length) :
48
length(p_length) {}
49
50
virtual JPH::Vec3 GetSupport(JPH::Vec3Arg p_direction) const override {
51
if (p_direction.GetZ() > 0.0f) {
52
return JPH::Vec3(0.0f, 0.0f, length);
53
} else {
54
return JPH::Vec3::sZero();
55
}
56
}
57
58
virtual float GetConvexRadius() const override { return 0.0f; }
59
60
private:
61
float length = 0.0f;
62
};
63
64
static_assert(sizeof(JoltCustomRayShapeSupport) <= sizeof(JPH::ConvexShape::SupportBuffer), "Size of SeparationRayShape3D support is larger than size of support buffer.");
65
66
JPH::Shape *construct_ray() {
67
return new JoltCustomRayShape();
68
}
69
70
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) {
71
ERR_FAIL_COND(p_shape1->GetSubType() != JoltCustomShapeSubType::RAY);
72
73
const JoltCustomRayShape *shape1 = static_cast<const JoltCustomRayShape *>(p_shape1);
74
75
const float margin = p_collide_shape_settings.mMaxSeparationDistance;
76
const float ray_length = shape1->length;
77
const float ray_length_padded = ray_length + margin;
78
79
const JPH::Mat44 transform1 = p_center_of_mass_transform1 * JPH::Mat44::sScale(p_scale1);
80
const JPH::Mat44 transform2 = p_center_of_mass_transform2 * JPH::Mat44::sScale(p_scale2);
81
const JPH::Mat44 transform_inv2 = transform2.Inversed();
82
83
const JPH::Vec3 ray_start = transform1.GetTranslation();
84
const JPH::Vec3 ray_direction = transform1.GetAxisZ();
85
const JPH::Vec3 ray_vector = ray_direction * ray_length;
86
const JPH::Vec3 ray_vector_padded = ray_direction * ray_length_padded;
87
88
const JPH::Vec3 ray_start2 = transform_inv2 * ray_start;
89
const JPH::Vec3 ray_direction2 = transform_inv2.Multiply3x3(ray_direction);
90
const JPH::Vec3 ray_vector_padded2 = transform_inv2.Multiply3x3(ray_vector_padded);
91
92
const JPH::RayCast ray_cast(ray_start2, ray_vector_padded2);
93
94
JPH::RayCastSettings ray_cast_settings;
95
ray_cast_settings.mTreatConvexAsSolid = false;
96
ray_cast_settings.mBackFaceModeTriangles = p_collide_shape_settings.mBackFaceMode;
97
98
JoltQueryCollectorClosest<JPH::CastRayCollector> ray_collector;
99
100
p_shape2->CastRay(ray_cast, ray_cast_settings, p_sub_shape_id_creator2, ray_collector);
101
102
if (!ray_collector.had_hit()) {
103
return;
104
}
105
106
const JPH::RayCastResult &hit = ray_collector.get_hit();
107
108
const float hit_distance = ray_length_padded * hit.mFraction;
109
const float hit_depth = ray_length - hit_distance;
110
111
if (-hit_depth >= p_collector.GetEarlyOutFraction()) {
112
return;
113
}
114
115
// Since `hit.mSubShapeID2` could represent a path not only from `p_shape2` but also any
116
// compound shape that it's contained within, we need to split this path into something that
117
// `p_shape2` can actually understand.
118
JPH::SubShapeID local_sub_shape_id2;
119
hit.mSubShapeID2.PopID(p_sub_shape_id_creator2.GetNumBitsWritten(), local_sub_shape_id2);
120
121
const JPH::Vec3 hit_point2 = ray_cast.GetPointOnRay(hit.mFraction);
122
123
const JPH::Vec3 hit_point_on_1 = ray_start + ray_vector;
124
const JPH::Vec3 hit_point_on_2 = transform2 * hit_point2;
125
126
JPH::Vec3 hit_normal2 = JPH::Vec3::sZero();
127
128
if (shape1->slide_on_slope) {
129
hit_normal2 = p_shape2->GetSurfaceNormal(local_sub_shape_id2, hit_point2);
130
131
// If we got a back-face normal we need to flip it.
132
if (hit_normal2.Dot(ray_direction2) > 0) {
133
hit_normal2 = -hit_normal2;
134
}
135
} else {
136
hit_normal2 = -ray_direction2;
137
}
138
139
const JPH::Vec3 hit_normal = transform2.Multiply3x3(hit_normal2);
140
141
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()));
142
143
if (p_collide_shape_settings.mCollectFacesMode == JPH::ECollectFacesMode::CollectFaces) {
144
p_shape2->GetSupportingFace(local_sub_shape_id2, ray_direction2, p_scale2, p_center_of_mass_transform2, result.mShape2Face);
145
}
146
147
p_collector.AddHit(result);
148
}
149
150
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) {
151
}
152
153
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) {
154
}
155
156
} // namespace
157
158
JPH::ShapeSettings::ShapeResult JoltCustomRayShapeSettings::Create() const {
159
if (mCachedResult.IsEmpty()) {
160
new JoltCustomRayShape(*this, mCachedResult);
161
}
162
163
return mCachedResult;
164
}
165
166
void JoltCustomRayShape::register_type() {
167
JPH::ShapeFunctions &shape_functions = JPH::ShapeFunctions::sGet(JoltCustomShapeSubType::RAY);
168
169
shape_functions.mConstruct = construct_ray;
170
shape_functions.mColor = JPH::Color::sDarkRed;
171
172
static constexpr JPH::EShapeSubType concrete_sub_types[] = {
173
JPH::EShapeSubType::Sphere,
174
JPH::EShapeSubType::Box,
175
JPH::EShapeSubType::Triangle,
176
JPH::EShapeSubType::Capsule,
177
JPH::EShapeSubType::TaperedCapsule,
178
JPH::EShapeSubType::Cylinder,
179
JPH::EShapeSubType::ConvexHull,
180
JPH::EShapeSubType::Mesh,
181
JPH::EShapeSubType::HeightField,
182
JPH::EShapeSubType::Plane,
183
JPH::EShapeSubType::TaperedCylinder
184
};
185
186
for (const JPH::EShapeSubType concrete_sub_type : concrete_sub_types) {
187
JPH::CollisionDispatch::sRegisterCollideShape(JoltCustomShapeSubType::RAY, concrete_sub_type, collide_ray_vs_shape);
188
JPH::CollisionDispatch::sRegisterCollideShape(concrete_sub_type, JoltCustomShapeSubType::RAY, JPH::CollisionDispatch::sReversedCollideShape);
189
}
190
191
JPH::CollisionDispatch::sRegisterCollideShape(JoltCustomShapeSubType::RAY, JoltCustomShapeSubType::RAY, collide_noop);
192
193
for (const JPH::EShapeSubType sub_type : JPH::sAllSubShapeTypes) {
194
JPH::CollisionDispatch::sRegisterCastShape(JoltCustomShapeSubType::RAY, sub_type, cast_noop);
195
JPH::CollisionDispatch::sRegisterCastShape(sub_type, JoltCustomShapeSubType::RAY, cast_noop);
196
}
197
}
198
199
JPH::AABox JoltCustomRayShape::GetLocalBounds() const {
200
const float radius = GetInnerRadius();
201
return JPH::AABox(JPH::Vec3(-radius, -radius, 0.0f), JPH::Vec3(radius, radius, length));
202
}
203
204
float JoltCustomRayShape::GetInnerRadius() const {
205
// There is no sensible value here, since this shape is infinitely thin, so we pick something
206
// that's hopefully small enough to effectively be zero, but big enough to not cause any
207
// numerical issues.
208
return 0.0001f;
209
}
210
211
JPH::MassProperties JoltCustomRayShape::GetMassProperties() const {
212
JPH::MassProperties mass_properties;
213
214
// Since this shape has no volume we can't really give it a correct set of mass properties, so
215
// instead we just give it some arbitrary ones.
216
mass_properties.mMass = 1.0f;
217
mass_properties.mInertia = JPH::Mat44::sIdentity();
218
219
return mass_properties;
220
}
221
222
#ifdef JPH_DEBUG_RENDERER
223
224
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 {
225
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);
226
}
227
228
#endif
229
230
const JPH::ConvexShape::Support *JoltCustomRayShape::GetSupportFunction(JPH::ConvexShape::ESupportMode p_mode, JPH::ConvexShape::SupportBuffer &p_buffer, JPH::Vec3Arg p_scale) const {
231
return new (&p_buffer) JoltCustomRayShapeSupport(p_scale.GetZ() * length);
232
}
233
234