回答編集履歴

2

念のため角度算出過程にProjectOnPlaneを追加

2020/12/10 20:57

投稿

Bongo
Bongo

スコア10811

test CHANGED
@@ -196,25 +196,33 @@
196
196
 
197
197
  this.polarAxis =
198
198
 
199
+ Vector3.ProjectOnPlane(
200
+
201
+ this.joint.connectedBody.transform.InverseTransformDirection(
202
+
203
+ this.transform.TransformDirection(this.joint.secondaryAxis)),
204
+
205
+ this.pole);
206
+
207
+ }
208
+
209
+
210
+
211
+ // また、現在のsecondaryAxisの向きをconnectedBodyの座標系に変換して
212
+
213
+ // polarAxisの向きと比較することで角度の変化を算出するプロパティを用意しておく
214
+
215
+ private float Azimuth => Vector3.SignedAngle(
216
+
217
+ this.polarAxis,
218
+
219
+ Vector3.ProjectOnPlane(
220
+
199
221
  this.joint.connectedBody.transform.InverseTransformDirection(
200
222
 
201
- this.transform.TransformDirection(this.joint.secondaryAxis));
202
-
203
- }
204
-
205
-
206
-
207
- // また、現在のsecondaryAxisの向きをconnectedBodyの座標系に変換して
208
-
209
- // polarAxisの向きと比較することで角度の変化を算出するプロパティを用意しておく
210
-
211
- private float Azimuth => Vector3.SignedAngle(
212
-
213
- this.polarAxis,
214
-
215
- this.joint.connectedBody.transform.InverseTransformDirection(
216
-
217
- this.transform.TransformDirection(this.joint.secondaryAxis)),
223
+ this.transform.TransformDirection(this.joint.secondaryAxis)),
224
+
225
+ this.pole),
218
226
 
219
227
  this.pole);
220
228
 

1

ロック時にリミットを更新する案を追記

2020/12/10 20:57

投稿

Bongo
Bongo

スコア10811

test CHANGED
@@ -141,3 +141,229 @@
141
141
 
142
142
 
143
143
  実際のところは何をやっているのかを追おうとしても、こういった物理シミュレーション関連はほとんどがネイティブコードになっていて([UnityCsReference/Dynamics.bindings.cs at master · Unity-Technologies/UnityCsReference · GitHub](https://github.com/Unity-Technologies/UnityCsReference/blob/master/Modules/Physics/ScriptBindings/Dynamics.bindings.cs))手詰まりになり、結局謎のままでした。まあともかく、この両`Rigidbody`の関係を入れ替える過程のどこかに初期姿勢を再設定する部分があるのかもしれません。
144
+
145
+
146
+
147
+ ##ロック時にリミットを更新する案
148
+
149
+
150
+
151
+ 実験用のスクリプトを下記のように変更しました。
152
+
153
+
154
+
155
+ ```C#
156
+
157
+ using UnityEngine;
158
+
159
+ using UnityEngine.UI;
160
+
161
+
162
+
163
+ [RequireComponent(typeof(ConfigurableJoint), typeof(Rigidbody))]
164
+
165
+ public class JointController : MonoBehaviour
166
+
167
+ {
168
+
169
+ [SerializeField] private Text stateText;
170
+
171
+ [SerializeField] private float torqueMagnitude = 20.0f;
172
+
173
+ private ConfigurableJoint joint;
174
+
175
+ private new Rigidbody rigidbody;
176
+
177
+ private bool isLocked;
178
+
179
+ private Vector3 polarAxis;
180
+
181
+ private Vector3 pole;
182
+
183
+
184
+
185
+ // axisとsecondaryAxisを接続相手の座標系に変換して保存するメソッドを作っておく
186
+
187
+ private void ResetPolarAxis()
188
+
189
+ {
190
+
191
+ this.pole =
192
+
193
+ this.joint.connectedBody.transform.InverseTransformDirection(
194
+
195
+ this.transform.TransformDirection(this.joint.axis));
196
+
197
+ this.polarAxis =
198
+
199
+ this.joint.connectedBody.transform.InverseTransformDirection(
200
+
201
+ this.transform.TransformDirection(this.joint.secondaryAxis));
202
+
203
+ }
204
+
205
+
206
+
207
+ // また、現在のsecondaryAxisの向きをconnectedBodyの座標系に変換して
208
+
209
+ // polarAxisの向きと比較することで角度の変化を算出するプロパティを用意しておく
210
+
211
+ private float Azimuth => Vector3.SignedAngle(
212
+
213
+ this.polarAxis,
214
+
215
+ this.joint.connectedBody.transform.InverseTransformDirection(
216
+
217
+ this.transform.TransformDirection(this.joint.secondaryAxis)),
218
+
219
+ this.pole);
220
+
221
+
222
+
223
+ // そしてロック状態を操作するためのプロパティを作る
224
+
225
+ private bool IsLocked
226
+
227
+ {
228
+
229
+ get => this.isLocked;
230
+
231
+ set
232
+
233
+ {
234
+
235
+ if (value == this.isLocked)
236
+
237
+ {
238
+
239
+ return;
240
+
241
+ }
242
+
243
+
244
+
245
+ this.isLocked = value;
246
+
247
+ if (value)
248
+
249
+ {
250
+
251
+ // まずロック時点のリミットを保存しておき...
252
+
253
+ var oldHighLimit = this.joint.highAngularXLimit;
254
+
255
+ var oldLowLimit = this.joint.lowAngularXLimit;
256
+
257
+
258
+
259
+ // ロック時点の基準方向からの回転角を取得しておく
260
+
261
+ var azimuth = this.Azimuth;
262
+
263
+
264
+
265
+ // そして回転をロック、基準方向を更新し...
266
+
267
+ this.joint.angularXMotion = ConfigurableJointMotion.Locked;
268
+
269
+ this.joint.swapBodies = !this.joint.swapBodies;
270
+
271
+ this.joint.swapBodies = !this.joint.swapBodies;
272
+
273
+ this.ResetPolarAxis();
274
+
275
+
276
+
277
+ // ロック時点の回転角を使ってリミットを修正する
278
+
279
+ var newHighLimit = oldHighLimit;
280
+
281
+ newHighLimit.limit += azimuth;
282
+
283
+ var newLowLimit = oldLowLimit;
284
+
285
+ newLowLimit.limit += azimuth;
286
+
287
+ this.joint.highAngularXLimit = newHighLimit;
288
+
289
+ this.joint.lowAngularXLimit = newLowLimit;
290
+
291
+
292
+
293
+ // 参考情報としてリミットをコンソールに出力する
294
+
295
+ Debug.Log($"High Limit: {oldHighLimit.limit} -> {newHighLimit.limit}, Low Limit: {oldLowLimit.limit} -> {newLowLimit.limit}");
296
+
297
+ }
298
+
299
+ else
300
+
301
+ {
302
+
303
+ this.joint.angularXMotion = ConfigurableJointMotion.Limited;
304
+
305
+ }
306
+
307
+ }
308
+
309
+ }
310
+
311
+
312
+
313
+ private void Start()
314
+
315
+ {
316
+
317
+ this.joint = this.GetComponent<ConfigurableJoint>();
318
+
319
+ this.rigidbody = this.GetComponent<Rigidbody>();
320
+
321
+
322
+
323
+ // Start時点でResetPolarAxisを実行して、初期基準方向を覚えておく
324
+
325
+ this.ResetPolarAxis();
326
+
327
+ }
328
+
329
+
330
+
331
+ private void Update()
332
+
333
+ {
334
+
335
+ if (Input.GetKeyDown(KeyCode.Space))
336
+
337
+ {
338
+
339
+ this.IsLocked = !this.IsLocked;
340
+
341
+ }
342
+
343
+
344
+
345
+ this.stateText.text = this.joint.angularXMotion.ToString();
346
+
347
+ }
348
+
349
+
350
+
351
+ private void FixedUpdate()
352
+
353
+ {
354
+
355
+ this.rigidbody.AddRelativeTorque(this.joint.axis * (this.torqueMagnitude * Input.GetAxis("Vertical")));
356
+
357
+ }
358
+
359
+ }
360
+
361
+ ```
362
+
363
+
364
+
365
+ 動かした様子も撮影してみたものの、この図ではちょっと分かりにくかったかもしれません。すみません...
366
+
367
+
368
+
369
+ ![図3](92865ad4f1fb8ae0bf02361898334efc.gif)