回答編集履歴
2
念のため角度算出過程にProjectOnPlaneを追加
answer
CHANGED
@@ -97,16 +97,20 @@
|
|
97
97
|
this.joint.connectedBody.transform.InverseTransformDirection(
|
98
98
|
this.transform.TransformDirection(this.joint.axis));
|
99
99
|
this.polarAxis =
|
100
|
+
Vector3.ProjectOnPlane(
|
100
|
-
|
101
|
+
this.joint.connectedBody.transform.InverseTransformDirection(
|
101
|
-
|
102
|
+
this.transform.TransformDirection(this.joint.secondaryAxis)),
|
103
|
+
this.pole);
|
102
104
|
}
|
103
105
|
|
104
106
|
// また、現在のsecondaryAxisの向きをconnectedBodyの座標系に変換して
|
105
107
|
// polarAxisの向きと比較することで角度の変化を算出するプロパティを用意しておく
|
106
108
|
private float Azimuth => Vector3.SignedAngle(
|
107
109
|
this.polarAxis,
|
110
|
+
Vector3.ProjectOnPlane(
|
108
|
-
|
111
|
+
this.joint.connectedBody.transform.InverseTransformDirection(
|
109
|
-
|
112
|
+
this.transform.TransformDirection(this.joint.secondaryAxis)),
|
113
|
+
this.pole),
|
110
114
|
this.pole);
|
111
115
|
|
112
116
|
// そしてロック状態を操作するためのプロパティを作る
|
1
ロック時にリミットを更新する案を追記
answer
CHANGED
@@ -69,4 +69,117 @@
|
|
69
69
|
|
70
70
|
すみませんが、そもそも`swapBodies`がどういう役割を持つのかよく分からないです。リファレンスの説明から想像すると「オブジェクトAにジョイントをアタッチしてオブジェクトBと接続した状態で`swapBodies`をオンにすると、オブジェクトBにジョイントをアタッチしてオブジェクトAと接続した状態と同じ挙動をする」といった感じでしょうかね?
|
71
71
|
|
72
|
-
実際のところは何をやっているのかを追おうとしても、こういった物理シミュレーション関連はほとんどがネイティブコードになっていて([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`の関係を入れ替える過程のどこかに初期姿勢を再設定する部分があるのかもしれません。
|
72
|
+
実際のところは何をやっているのかを追おうとしても、こういった物理シミュレーション関連はほとんどがネイティブコードになっていて([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`の関係を入れ替える過程のどこかに初期姿勢を再設定する部分があるのかもしれません。
|
73
|
+
|
74
|
+
##ロック時にリミットを更新する案
|
75
|
+
|
76
|
+
実験用のスクリプトを下記のように変更しました。
|
77
|
+
|
78
|
+
```C#
|
79
|
+
using UnityEngine;
|
80
|
+
using UnityEngine.UI;
|
81
|
+
|
82
|
+
[RequireComponent(typeof(ConfigurableJoint), typeof(Rigidbody))]
|
83
|
+
public class JointController : MonoBehaviour
|
84
|
+
{
|
85
|
+
[SerializeField] private Text stateText;
|
86
|
+
[SerializeField] private float torqueMagnitude = 20.0f;
|
87
|
+
private ConfigurableJoint joint;
|
88
|
+
private new Rigidbody rigidbody;
|
89
|
+
private bool isLocked;
|
90
|
+
private Vector3 polarAxis;
|
91
|
+
private Vector3 pole;
|
92
|
+
|
93
|
+
// axisとsecondaryAxisを接続相手の座標系に変換して保存するメソッドを作っておく
|
94
|
+
private void ResetPolarAxis()
|
95
|
+
{
|
96
|
+
this.pole =
|
97
|
+
this.joint.connectedBody.transform.InverseTransformDirection(
|
98
|
+
this.transform.TransformDirection(this.joint.axis));
|
99
|
+
this.polarAxis =
|
100
|
+
this.joint.connectedBody.transform.InverseTransformDirection(
|
101
|
+
this.transform.TransformDirection(this.joint.secondaryAxis));
|
102
|
+
}
|
103
|
+
|
104
|
+
// また、現在のsecondaryAxisの向きをconnectedBodyの座標系に変換して
|
105
|
+
// polarAxisの向きと比較することで角度の変化を算出するプロパティを用意しておく
|
106
|
+
private float Azimuth => Vector3.SignedAngle(
|
107
|
+
this.polarAxis,
|
108
|
+
this.joint.connectedBody.transform.InverseTransformDirection(
|
109
|
+
this.transform.TransformDirection(this.joint.secondaryAxis)),
|
110
|
+
this.pole);
|
111
|
+
|
112
|
+
// そしてロック状態を操作するためのプロパティを作る
|
113
|
+
private bool IsLocked
|
114
|
+
{
|
115
|
+
get => this.isLocked;
|
116
|
+
set
|
117
|
+
{
|
118
|
+
if (value == this.isLocked)
|
119
|
+
{
|
120
|
+
return;
|
121
|
+
}
|
122
|
+
|
123
|
+
this.isLocked = value;
|
124
|
+
if (value)
|
125
|
+
{
|
126
|
+
// まずロック時点のリミットを保存しておき...
|
127
|
+
var oldHighLimit = this.joint.highAngularXLimit;
|
128
|
+
var oldLowLimit = this.joint.lowAngularXLimit;
|
129
|
+
|
130
|
+
// ロック時点の基準方向からの回転角を取得しておく
|
131
|
+
var azimuth = this.Azimuth;
|
132
|
+
|
133
|
+
// そして回転をロック、基準方向を更新し...
|
134
|
+
this.joint.angularXMotion = ConfigurableJointMotion.Locked;
|
135
|
+
this.joint.swapBodies = !this.joint.swapBodies;
|
136
|
+
this.joint.swapBodies = !this.joint.swapBodies;
|
137
|
+
this.ResetPolarAxis();
|
138
|
+
|
139
|
+
// ロック時点の回転角を使ってリミットを修正する
|
140
|
+
var newHighLimit = oldHighLimit;
|
141
|
+
newHighLimit.limit += azimuth;
|
142
|
+
var newLowLimit = oldLowLimit;
|
143
|
+
newLowLimit.limit += azimuth;
|
144
|
+
this.joint.highAngularXLimit = newHighLimit;
|
145
|
+
this.joint.lowAngularXLimit = newLowLimit;
|
146
|
+
|
147
|
+
// 参考情報としてリミットをコンソールに出力する
|
148
|
+
Debug.Log($"High Limit: {oldHighLimit.limit} -> {newHighLimit.limit}, Low Limit: {oldLowLimit.limit} -> {newLowLimit.limit}");
|
149
|
+
}
|
150
|
+
else
|
151
|
+
{
|
152
|
+
this.joint.angularXMotion = ConfigurableJointMotion.Limited;
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
157
|
+
private void Start()
|
158
|
+
{
|
159
|
+
this.joint = this.GetComponent<ConfigurableJoint>();
|
160
|
+
this.rigidbody = this.GetComponent<Rigidbody>();
|
161
|
+
|
162
|
+
// Start時点でResetPolarAxisを実行して、初期基準方向を覚えておく
|
163
|
+
this.ResetPolarAxis();
|
164
|
+
}
|
165
|
+
|
166
|
+
private void Update()
|
167
|
+
{
|
168
|
+
if (Input.GetKeyDown(KeyCode.Space))
|
169
|
+
{
|
170
|
+
this.IsLocked = !this.IsLocked;
|
171
|
+
}
|
172
|
+
|
173
|
+
this.stateText.text = this.joint.angularXMotion.ToString();
|
174
|
+
}
|
175
|
+
|
176
|
+
private void FixedUpdate()
|
177
|
+
{
|
178
|
+
this.rigidbody.AddRelativeTorque(this.joint.axis * (this.torqueMagnitude * Input.GetAxis("Vertical")));
|
179
|
+
}
|
180
|
+
}
|
181
|
+
```
|
182
|
+
|
183
|
+
動かした様子も撮影してみたものの、この図ではちょっと分かりにくかったかもしれません。すみません...
|
184
|
+
|
185
|
+

|