Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/jolt_physics/joints/jolt_cone_twist_joint_3d.cpp
10278 views
1
/**************************************************************************/
2
/* jolt_cone_twist_joint_3d.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_cone_twist_joint_3d.h"
32
33
#include "../misc/jolt_type_conversions.h"
34
#include "../objects/jolt_body_3d.h"
35
#include "../spaces/jolt_space_3d.h"
36
37
#include "Jolt/Physics/Constraints/SwingTwistConstraint.h"
38
39
namespace {
40
41
constexpr double CONE_TWIST_DEFAULT_BIAS = 0.3;
42
constexpr double CONE_TWIST_DEFAULT_SOFTNESS = 0.8;
43
constexpr double CONE_TWIST_DEFAULT_RELAXATION = 1.0;
44
45
} // namespace
46
47
JPH::Constraint *JoltConeTwistJoint3D::_build_swing_twist(JPH::Body *p_jolt_body_a, JPH::Body *p_jolt_body_b, const Transform3D &p_shifted_ref_a, const Transform3D &p_shifted_ref_b, float p_swing_limit_span, float p_twist_limit_span) const {
48
JPH::SwingTwistConstraintSettings constraint_settings;
49
50
const bool twist_span_valid = p_twist_limit_span >= 0 && p_twist_limit_span <= JPH::JPH_PI;
51
const bool swing_span_valid = p_swing_limit_span >= 0 && p_swing_limit_span <= JPH::JPH_PI;
52
53
if (twist_limit_enabled && twist_span_valid) {
54
constraint_settings.mTwistMinAngle = -p_twist_limit_span;
55
constraint_settings.mTwistMaxAngle = p_twist_limit_span;
56
} else {
57
constraint_settings.mTwistMinAngle = -JPH::JPH_PI;
58
constraint_settings.mTwistMaxAngle = JPH::JPH_PI;
59
}
60
61
if (swing_limit_enabled && swing_span_valid) {
62
constraint_settings.mNormalHalfConeAngle = p_swing_limit_span;
63
constraint_settings.mPlaneHalfConeAngle = p_swing_limit_span;
64
} else {
65
constraint_settings.mNormalHalfConeAngle = JPH::JPH_PI;
66
constraint_settings.mPlaneHalfConeAngle = JPH::JPH_PI;
67
68
if (!swing_span_valid) {
69
constraint_settings.mTwistMinAngle = -JPH::JPH_PI;
70
constraint_settings.mTwistMaxAngle = JPH::JPH_PI;
71
}
72
}
73
74
constraint_settings.mSpace = JPH::EConstraintSpace::LocalToBodyCOM;
75
constraint_settings.mPosition1 = to_jolt_r(p_shifted_ref_a.origin);
76
constraint_settings.mTwistAxis1 = to_jolt(p_shifted_ref_a.basis.get_column(Vector3::AXIS_X));
77
constraint_settings.mPlaneAxis1 = to_jolt(p_shifted_ref_a.basis.get_column(Vector3::AXIS_Z));
78
constraint_settings.mPosition2 = to_jolt_r(p_shifted_ref_b.origin);
79
constraint_settings.mTwistAxis2 = to_jolt(p_shifted_ref_b.basis.get_column(Vector3::AXIS_X));
80
constraint_settings.mPlaneAxis2 = to_jolt(p_shifted_ref_b.basis.get_column(Vector3::AXIS_Z));
81
constraint_settings.mSwingType = JPH::ESwingType::Pyramid;
82
83
if (p_jolt_body_a == nullptr) {
84
return constraint_settings.Create(JPH::Body::sFixedToWorld, *p_jolt_body_b);
85
} else if (p_jolt_body_b == nullptr) {
86
return constraint_settings.Create(*p_jolt_body_a, JPH::Body::sFixedToWorld);
87
} else {
88
return constraint_settings.Create(*p_jolt_body_a, *p_jolt_body_b);
89
}
90
}
91
92
void JoltConeTwistJoint3D::_update_swing_motor_state() {
93
if (JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr())) {
94
constraint->SetSwingMotorState(swing_motor_enabled ? JPH::EMotorState::Velocity : JPH::EMotorState::Off);
95
}
96
}
97
98
void JoltConeTwistJoint3D::_update_twist_motor_state() {
99
if (JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr())) {
100
constraint->SetTwistMotorState(twist_motor_enabled ? JPH::EMotorState::Velocity : JPH::EMotorState::Off);
101
}
102
}
103
104
void JoltConeTwistJoint3D::_update_motor_velocity() {
105
if (JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr())) {
106
// We flip the direction since Jolt is CCW but Godot is CW.
107
constraint->SetTargetAngularVelocityCS({ (float)-twist_motor_target_speed, (float)-swing_motor_target_speed_y, (float)-swing_motor_target_speed_z });
108
}
109
}
110
111
void JoltConeTwistJoint3D::_update_swing_motor_limit() {
112
if (JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr())) {
113
JPH::MotorSettings &motor_settings = constraint->GetSwingMotorSettings();
114
motor_settings.mMinTorqueLimit = (float)-swing_motor_max_torque;
115
motor_settings.mMaxTorqueLimit = (float)swing_motor_max_torque;
116
}
117
}
118
119
void JoltConeTwistJoint3D::_update_twist_motor_limit() {
120
if (JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr())) {
121
JPH::MotorSettings &motor_settings = constraint->GetTwistMotorSettings();
122
motor_settings.mMinTorqueLimit = (float)-twist_motor_max_torque;
123
motor_settings.mMaxTorqueLimit = (float)twist_motor_max_torque;
124
}
125
}
126
127
void JoltConeTwistJoint3D::_limits_changed() {
128
rebuild();
129
_wake_up_bodies();
130
}
131
132
void JoltConeTwistJoint3D::_swing_motor_state_changed() {
133
_update_swing_motor_state();
134
_wake_up_bodies();
135
}
136
137
void JoltConeTwistJoint3D::_twist_motor_state_changed() {
138
_update_twist_motor_state();
139
_wake_up_bodies();
140
}
141
142
void JoltConeTwistJoint3D::_motor_velocity_changed() {
143
_update_motor_velocity();
144
_wake_up_bodies();
145
}
146
147
void JoltConeTwistJoint3D::_swing_motor_limit_changed() {
148
_update_swing_motor_limit();
149
_wake_up_bodies();
150
}
151
152
void JoltConeTwistJoint3D::_twist_motor_limit_changed() {
153
_update_twist_motor_limit();
154
_wake_up_bodies();
155
}
156
157
JoltConeTwistJoint3D::JoltConeTwistJoint3D(const JoltJoint3D &p_old_joint, JoltBody3D *p_body_a, JoltBody3D *p_body_b, const Transform3D &p_local_ref_a, const Transform3D &p_local_ref_b) :
158
JoltJoint3D(p_old_joint, p_body_a, p_body_b, p_local_ref_a, p_local_ref_b) {
159
rebuild();
160
}
161
162
double JoltConeTwistJoint3D::get_param(PhysicsServer3D::ConeTwistJointParam p_param) const {
163
switch (p_param) {
164
case PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN: {
165
return swing_limit_span;
166
}
167
case PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN: {
168
return twist_limit_span;
169
}
170
case PhysicsServer3D::CONE_TWIST_JOINT_BIAS: {
171
return CONE_TWIST_DEFAULT_BIAS;
172
}
173
case PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS: {
174
return CONE_TWIST_DEFAULT_SOFTNESS;
175
}
176
case PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION: {
177
return CONE_TWIST_DEFAULT_RELAXATION;
178
}
179
default: {
180
ERR_FAIL_V_MSG(0.0, vformat("Unhandled cone twist joint parameter: '%d'. This should not happen. Please report this.", p_param));
181
}
182
}
183
}
184
185
void JoltConeTwistJoint3D::set_param(PhysicsServer3D::ConeTwistJointParam p_param, double p_value) {
186
switch (p_param) {
187
case PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN: {
188
swing_limit_span = p_value;
189
_limits_changed();
190
} break;
191
case PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN: {
192
twist_limit_span = p_value;
193
_limits_changed();
194
} break;
195
case PhysicsServer3D::CONE_TWIST_JOINT_BIAS: {
196
if (!Math::is_equal_approx(p_value, CONE_TWIST_DEFAULT_BIAS)) {
197
WARN_PRINT(vformat("Cone twist joint bias is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
198
}
199
} break;
200
case PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS: {
201
if (!Math::is_equal_approx(p_value, CONE_TWIST_DEFAULT_SOFTNESS)) {
202
WARN_PRINT(vformat("Cone twist joint softness is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
203
}
204
} break;
205
case PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION: {
206
if (!Math::is_equal_approx(p_value, CONE_TWIST_DEFAULT_RELAXATION)) {
207
WARN_PRINT(vformat("Cone twist joint relaxation is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
208
}
209
} break;
210
default: {
211
ERR_FAIL_MSG(vformat("Unhandled cone twist joint parameter: '%d'. This should not happen. Please report this.", p_param));
212
} break;
213
}
214
}
215
216
double JoltConeTwistJoint3D::get_jolt_param(JoltParameter p_param) const {
217
switch (p_param) {
218
case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_TARGET_VELOCITY_Y: {
219
return swing_motor_target_speed_y;
220
}
221
case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_TARGET_VELOCITY_Z: {
222
return swing_motor_target_speed_z;
223
}
224
case JoltPhysicsServer3D::CONE_TWIST_JOINT_TWIST_MOTOR_TARGET_VELOCITY: {
225
return twist_motor_target_speed;
226
}
227
case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_MAX_TORQUE: {
228
return swing_motor_max_torque;
229
}
230
case JoltPhysicsServer3D::CONE_TWIST_JOINT_TWIST_MOTOR_MAX_TORQUE: {
231
return twist_motor_max_torque;
232
}
233
default: {
234
ERR_FAIL_V_MSG(0.0, vformat("Unhandled parameter: '%d'. This should not happen. Please report this.", p_param));
235
}
236
}
237
}
238
239
void JoltConeTwistJoint3D::set_jolt_param(JoltParameter p_param, double p_value) {
240
switch (p_param) {
241
case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_TARGET_VELOCITY_Y: {
242
swing_motor_target_speed_y = p_value;
243
_motor_velocity_changed();
244
} break;
245
case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_TARGET_VELOCITY_Z: {
246
swing_motor_target_speed_z = p_value;
247
_motor_velocity_changed();
248
} break;
249
case JoltPhysicsServer3D::CONE_TWIST_JOINT_TWIST_MOTOR_TARGET_VELOCITY: {
250
twist_motor_target_speed = p_value;
251
_motor_velocity_changed();
252
} break;
253
case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_MAX_TORQUE: {
254
swing_motor_max_torque = p_value;
255
_swing_motor_limit_changed();
256
} break;
257
case JoltPhysicsServer3D::CONE_TWIST_JOINT_TWIST_MOTOR_MAX_TORQUE: {
258
twist_motor_max_torque = p_value;
259
_twist_motor_limit_changed();
260
} break;
261
default: {
262
ERR_FAIL_MSG(vformat("Unhandled parameter: '%d'. This should not happen. Please report this.", p_param));
263
} break;
264
}
265
}
266
267
bool JoltConeTwistJoint3D::get_jolt_flag(JoltFlag p_flag) const {
268
switch (p_flag) {
269
case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_USE_SWING_LIMIT: {
270
return swing_limit_enabled;
271
}
272
case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_USE_TWIST_LIMIT: {
273
return twist_limit_enabled;
274
}
275
case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_ENABLE_SWING_MOTOR: {
276
return swing_motor_enabled;
277
}
278
case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_ENABLE_TWIST_MOTOR: {
279
return twist_motor_enabled;
280
}
281
default: {
282
ERR_FAIL_V_MSG(false, vformat("Unhandled flag: '%d'. This should not happen. Please report this.", p_flag));
283
}
284
}
285
}
286
287
void JoltConeTwistJoint3D::set_jolt_flag(JoltFlag p_flag, bool p_enabled) {
288
switch (p_flag) {
289
case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_USE_SWING_LIMIT: {
290
swing_limit_enabled = p_enabled;
291
_limits_changed();
292
} break;
293
case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_USE_TWIST_LIMIT: {
294
twist_limit_enabled = p_enabled;
295
_limits_changed();
296
} break;
297
case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_ENABLE_SWING_MOTOR: {
298
swing_motor_enabled = p_enabled;
299
_swing_motor_state_changed();
300
} break;
301
case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_ENABLE_TWIST_MOTOR: {
302
twist_motor_enabled = p_enabled;
303
_twist_motor_state_changed();
304
} break;
305
default: {
306
ERR_FAIL_MSG(vformat("Unhandled flag: '%d'. This should not happen. Please report this.", p_flag));
307
} break;
308
}
309
}
310
311
float JoltConeTwistJoint3D::get_applied_force() const {
312
JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr());
313
ERR_FAIL_NULL_V(constraint, 0.0f);
314
315
JoltSpace3D *space = get_space();
316
ERR_FAIL_NULL_V(space, 0.0f);
317
318
const float last_step = space->get_last_step();
319
if (unlikely(last_step == 0.0f)) {
320
return 0.0f;
321
}
322
323
return constraint->GetTotalLambdaPosition().Length() / last_step;
324
}
325
326
float JoltConeTwistJoint3D::get_applied_torque() const {
327
JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr());
328
ERR_FAIL_NULL_V(constraint, 0.0f);
329
330
JoltSpace3D *space = get_space();
331
ERR_FAIL_NULL_V(space, 0.0f);
332
333
const float last_step = space->get_last_step();
334
if (unlikely(last_step == 0.0f)) {
335
return 0.0f;
336
}
337
338
const JPH::Vec3 swing_twist_lambda = JPH::Vec3(constraint->GetTotalLambdaTwist(), constraint->GetTotalLambdaSwingY(), constraint->GetTotalLambdaSwingZ());
339
340
// Note that the motor lambda is in a different space than the swing twist lambda, and since the two forces can cancel each other it is
341
// technically incorrect to just add them. The bodies themselves have moved, so we can't transform one into the space of the other anymore.
342
const float total_lambda = swing_twist_lambda.Length() + constraint->GetTotalLambdaMotor().Length();
343
344
return total_lambda / last_step;
345
}
346
347
void JoltConeTwistJoint3D::rebuild() {
348
destroy();
349
350
JoltSpace3D *space = get_space();
351
if (space == nullptr) {
352
return;
353
}
354
355
JPH::Body *jolt_body_a = body_a != nullptr ? body_a->get_jolt_body() : nullptr;
356
JPH::Body *jolt_body_b = body_b != nullptr ? body_b->get_jolt_body() : nullptr;
357
ERR_FAIL_COND(jolt_body_a == nullptr && jolt_body_b == nullptr);
358
359
Transform3D shifted_ref_a;
360
Transform3D shifted_ref_b;
361
362
_shift_reference_frames(Vector3(), Vector3(), shifted_ref_a, shifted_ref_b);
363
364
jolt_ref = _build_swing_twist(jolt_body_a, jolt_body_b, shifted_ref_a, shifted_ref_b, (float)swing_limit_span, (float)twist_limit_span);
365
366
space->add_joint(this);
367
368
_update_enabled();
369
_update_iterations();
370
_update_swing_motor_state();
371
_update_twist_motor_state();
372
_update_motor_velocity();
373
_update_swing_motor_limit();
374
_update_twist_motor_limit();
375
}
376
377