回答編集履歴
6
マッスル番号が見つからなかった場合の値が「max」であるべきところが「min」になっている...実際の動作では使われることがない値だが、一応修正
test
CHANGED
@@ -116,11 +116,11 @@
|
|
116
116
|
|
117
117
|
? new Vector3(
|
118
118
|
|
119
|
-
muscleIndexX >= 0 ? HumanTrait.GetMuscleDefaultMax(muscleIndexX) : limit.m
|
119
|
+
muscleIndexX >= 0 ? HumanTrait.GetMuscleDefaultMax(muscleIndexX) : limit.max.x,
|
120
|
-
|
120
|
+
|
121
|
-
muscleIndexY >= 0 ? HumanTrait.GetMuscleDefaultMax(muscleIndexY) : limit.m
|
121
|
+
muscleIndexY >= 0 ? HumanTrait.GetMuscleDefaultMax(muscleIndexY) : limit.max.y,
|
122
|
-
|
122
|
+
|
123
|
-
muscleIndexZ >= 0 ? HumanTrait.GetMuscleDefaultMax(muscleIndexZ) : limit.m
|
123
|
+
muscleIndexZ >= 0 ? HumanTrait.GetMuscleDefaultMax(muscleIndexZ) : limit.max.z)
|
124
124
|
|
125
125
|
: limit.max;
|
126
126
|
|
5
実行時のマッスル可動範囲取得の案を追記
test
CHANGED
@@ -201,3 +201,201 @@
|
|
201
201
|
エディタスクリプトでは何とかなりそうでしたが、実際の実行時に[Avatar](https://docs.unity3d.com/ja/current/ScriptReference/Avatar.html)からHumanDescriptionを取り出すのはやっかいそうです。探した限りではそれらしきクラス・メソッドは見つからず、ModelImporterがどのようにHumanDescriptionを作っているかの詳細も公開されていないようで、もっと詳しく調査・解析する必要がありそうです(もしかすると不可能かもしれません)。
|
202
202
|
|
203
203
|
逆に、実行時にHumanDescriptionをもとにAvatarを作ることは[AvatarBuilder](https://docs.unity3d.com/ja/current/ScriptReference/AvatarBuilder.html)を使えば可能らしいんですがね...
|
204
|
+
|
205
|
+
|
206
|
+
|
207
|
+
#追記
|
208
|
+
|
209
|
+
UnityEditorに頼らず実行時に値を取得する方法はないものか調べてみたものの、結局AvatarからのHumanDescription取得は困難そうでしたのであきらめました。
|
210
|
+
|
211
|
+
代案として、モデルのマッスルを最大・最小まで動かし、部位の回転を調べることでマッスル可動範囲の上限・下限を求められないかと思い、ちょっと試してみました。
|
212
|
+
|
213
|
+
|
214
|
+
|
215
|
+
モデルに対して特定のマッスル値を持つポーズを取らせるのは、[HumanPoseHandler](https://docs.unity3d.com/ja/current/ScriptReference/HumanPoseHandler.html)を使えば可能なようです。そこで、各マッスルを1つずつ動かして、回転が起こった部位の角度変化を見てみました。
|
216
|
+
|
217
|
+
下記スクリプトをモデルにアタッチして実行したところ...
|
218
|
+
|
219
|
+
```C#
|
220
|
+
|
221
|
+
using System.Linq;
|
222
|
+
|
223
|
+
using UnityEngine;
|
224
|
+
|
225
|
+
|
226
|
+
|
227
|
+
[RequireComponent(typeof(Animator))]
|
228
|
+
|
229
|
+
public class MuscleRangeInvestigator : MonoBehaviour
|
230
|
+
|
231
|
+
{
|
232
|
+
|
233
|
+
private void Start()
|
234
|
+
|
235
|
+
{
|
236
|
+
|
237
|
+
var animator = this.GetComponent<Animator>();
|
238
|
+
|
239
|
+
var avatar = animator.avatar;
|
240
|
+
|
241
|
+
Debug.Log($"Muscle ranges of {avatar.name}:");
|
242
|
+
|
243
|
+
|
244
|
+
|
245
|
+
// マッスル名一覧を取得
|
246
|
+
|
247
|
+
var muscleNames = HumanTrait.MuscleName;
|
248
|
+
|
249
|
+
var muscleCount = HumanTrait.MuscleCount;
|
250
|
+
|
251
|
+
|
252
|
+
|
253
|
+
// アバターと紐付いたポーズハンドラーを作成
|
254
|
+
|
255
|
+
var poseHandler = new HumanPoseHandler(avatar, this.transform);
|
256
|
+
|
257
|
+
|
258
|
+
|
259
|
+
// 現在のポーズを覚えておく
|
260
|
+
|
261
|
+
// 後で姿勢を復元する際に、リターゲッティング処理の都合上姿勢がずれる可能性が
|
262
|
+
|
263
|
+
// あるらしいので、ポーズを覚える前に親・位置・回転をそれぞれ覚えておき
|
264
|
+
|
265
|
+
// 親子関係を一旦解除、位置・回転もゼロにする
|
266
|
+
|
267
|
+
var initialLocalPosition = this.transform.localPosition;
|
268
|
+
|
269
|
+
var initialLocalRotation = this.transform.localRotation;
|
270
|
+
|
271
|
+
var initialParent = this.transform.parent;
|
272
|
+
|
273
|
+
this.transform.SetParent(null);
|
274
|
+
|
275
|
+
this.transform.localPosition = Vector3.zero;
|
276
|
+
|
277
|
+
this.transform.localRotation = Quaternion.identity;
|
278
|
+
|
279
|
+
var initialPose = new HumanPose();
|
280
|
+
|
281
|
+
poseHandler.GetHumanPose(ref initialPose);
|
282
|
+
|
283
|
+
|
284
|
+
|
285
|
+
// マッスル値をいじって実験するためのポーズを作る
|
286
|
+
|
287
|
+
var pose = new HumanPose
|
288
|
+
|
289
|
+
{
|
290
|
+
|
291
|
+
bodyPosition = Vector3.zero,
|
292
|
+
|
293
|
+
bodyRotation = Quaternion.identity,
|
294
|
+
|
295
|
+
muscles = new float[initialPose.muscles.Length]
|
296
|
+
|
297
|
+
};
|
298
|
+
|
299
|
+
|
300
|
+
|
301
|
+
// モデルルート以下の全Transformを配列化
|
302
|
+
|
303
|
+
var transforms = this.GetComponentsInChildren<Transform>();
|
304
|
+
|
305
|
+
|
306
|
+
|
307
|
+
// ゼロ姿勢(膝や腕を半曲げにした、あの姿勢)をセット
|
308
|
+
|
309
|
+
poseHandler.SetHumanPose(ref pose);
|
310
|
+
|
311
|
+
|
312
|
+
|
313
|
+
// ゼロ姿勢でのローカル回転を覚えておく
|
314
|
+
|
315
|
+
var zeroTransforms = transforms.Select(t => (Transform: t, Rotation: t.localRotation)).ToArray();
|
316
|
+
|
317
|
+
|
318
|
+
|
319
|
+
// 全マッスルについて...
|
320
|
+
|
321
|
+
for (var i = 0; i < muscleCount; i++)
|
322
|
+
|
323
|
+
{
|
324
|
+
|
325
|
+
// まずi番目マッスルを1にし、姿勢を適用
|
326
|
+
|
327
|
+
pose.muscles[i] = 1.0f;
|
328
|
+
|
329
|
+
poseHandler.SetHumanPose(ref pose);
|
330
|
+
|
331
|
+
|
332
|
+
|
333
|
+
// 回転が発生したTransformを抜き出し、おそらくそれらのうち
|
334
|
+
|
335
|
+
// 最大の角度変化量を可動角度上限として採用すればいいと思う...?
|
336
|
+
|
337
|
+
var max = zeroTransforms.Where(t => t.Rotation != t.Transform.localRotation)
|
338
|
+
|
339
|
+
.Select(t => Quaternion.Angle(t.Transform.localRotation, t.Rotation))
|
340
|
+
|
341
|
+
.OrderByDescending(a => a).FirstOrDefault();
|
342
|
+
|
343
|
+
|
344
|
+
|
345
|
+
// 引き続きi番目マッスルを-1にし、姿勢を適用
|
346
|
+
|
347
|
+
pose.muscles[i] = -1.0f;
|
348
|
+
|
349
|
+
poseHandler.SetHumanPose(ref pose);
|
350
|
+
|
351
|
+
|
352
|
+
|
353
|
+
// 同じく最大の角度変化量を求め、符号を反転して可動角度下限として採用...?
|
354
|
+
|
355
|
+
var min = -zeroTransforms.Where(t => t.Rotation != t.Transform.localRotation)
|
356
|
+
|
357
|
+
.Select(t => Quaternion.Angle(t.Transform.localRotation, t.Rotation))
|
358
|
+
|
359
|
+
.OrderByDescending(a => a).FirstOrDefault();
|
360
|
+
|
361
|
+
|
362
|
+
|
363
|
+
// コンソールに結果を表示
|
364
|
+
|
365
|
+
Debug.Log($"\t{muscleNames[i]}: {min:F1}~{max:F1}");
|
366
|
+
|
367
|
+
|
368
|
+
|
369
|
+
// i番目マッスルを0に戻す
|
370
|
+
|
371
|
+
pose.muscles[i] = 0.0f;
|
372
|
+
|
373
|
+
}
|
374
|
+
|
375
|
+
|
376
|
+
|
377
|
+
// 姿勢を元に戻して終わり
|
378
|
+
|
379
|
+
poseHandler.SetHumanPose(ref initialPose);
|
380
|
+
|
381
|
+
this.transform.SetParent(initialParent);
|
382
|
+
|
383
|
+
this.transform.localPosition = initialLocalPosition;
|
384
|
+
|
385
|
+
this.transform.localRotation = initialLocalRotation;
|
386
|
+
|
387
|
+
}
|
388
|
+
|
389
|
+
}
|
390
|
+
|
391
|
+
```
|
392
|
+
|
393
|
+
下図のように、どうやらそれらしい値が得られました。ですが少々ごまかしがありまして、表示される値を小数点以下第1位で丸めています。実際の値はインスペクタ上の値とぴったり一致はしませんでした。おそらく計算誤差によるものでしょう...
|
394
|
+
|
395
|
+
![EthanAvatar](57b06e494b36de8fca8e01b46a19ca32.png)
|
396
|
+
|
397
|
+
※おまけ
|
398
|
+
|
399
|
+
各マッスルを動かしているときにそれぞれどのような姿勢になっているか見てみたところ、下図のようにEthanとユニティちゃんが体操する姿を撮影できました。ちょうどインスペクタ上の各マッスルのプレビュースライダーを操作したときと同様の動きをしていることがお分かりいただけるでしょうか?
|
400
|
+
|
401
|
+
![体操](12a240f964e9e0721e4311ef200a48df.gif)
|
4
明らかに顎や目のデフォルト値がおかしい...リファレンスのサンプルコードは誤っている?おそらく正しいと思われる形に変更、スクリーンショット差し替え
test
CHANGED
@@ -92,21 +92,37 @@
|
|
92
92
|
|
93
93
|
var muscleIndexZ = HumanTrait.MuscleFromBone(boneIndex, 2);
|
94
94
|
|
95
|
+
|
96
|
+
|
97
|
+
// デフォルト値を使うよう設定されている場合は、limit内のmin・maxは無視するらしい?
|
98
|
+
|
95
99
|
var limit = humanBone.limit;
|
96
100
|
|
97
|
-
|
98
|
-
|
99
|
-
// デフォルト値を使うよう設定されている場合は、limit内のmin・maxは無視するらしい?
|
100
|
-
|
101
101
|
var useDefault = limit.useDefaultValues;
|
102
102
|
|
103
|
+
var min = useDefault
|
104
|
+
|
105
|
+
? new Vector3(
|
106
|
+
|
103
|
-
|
107
|
+
muscleIndexX >= 0 ? HumanTrait.GetMuscleDefaultMin(muscleIndexX) : limit.min.x,
|
108
|
+
|
104
|
-
|
109
|
+
muscleIndexY >= 0 ? HumanTrait.GetMuscleDefaultMin(muscleIndexY) : limit.min.y,
|
110
|
+
|
111
|
+
muscleIndexZ >= 0 ? HumanTrait.GetMuscleDefaultMin(muscleIndexZ) : limit.min.z)
|
112
|
+
|
113
|
+
: limit.min;
|
114
|
+
|
115
|
+
var max = useDefault
|
116
|
+
|
117
|
+
? new Vector3(
|
118
|
+
|
105
|
-
|
119
|
+
muscleIndexX >= 0 ? HumanTrait.GetMuscleDefaultMax(muscleIndexX) : limit.min.x,
|
106
|
-
|
107
|
-
|
120
|
+
|
108
|
-
|
109
|
-
|
121
|
+
muscleIndexY >= 0 ? HumanTrait.GetMuscleDefaultMax(muscleIndexY) : limit.min.y,
|
122
|
+
|
123
|
+
muscleIndexZ >= 0 ? HumanTrait.GetMuscleDefaultMax(muscleIndexZ) : limit.min.z)
|
124
|
+
|
125
|
+
: limit.max;
|
110
126
|
|
111
127
|
|
112
128
|
|
@@ -116,13 +132,13 @@
|
|
116
132
|
|
117
133
|
var minMaxColor = useDefault ? "<color=black>" : "<color=blue>";
|
118
134
|
|
119
|
-
|
120
|
-
|
121
135
|
if (muscleIndexX >= 0)
|
122
136
|
|
123
137
|
{
|
124
138
|
|
139
|
+
Debug.Log(
|
140
|
+
|
125
|
-
|
141
|
+
$"\t\t{HumanTrait.MuscleName[muscleIndexX]}: {minMaxColor}{min.x}~{max.x}</color>");
|
126
142
|
|
127
143
|
}
|
128
144
|
|
@@ -132,7 +148,9 @@
|
|
132
148
|
|
133
149
|
{
|
134
150
|
|
151
|
+
Debug.Log(
|
152
|
+
|
135
|
-
|
153
|
+
$"\t\t{HumanTrait.MuscleName[muscleIndexY]}: {minMaxColor}{min.y}~{max.y}</color>");
|
136
154
|
|
137
155
|
}
|
138
156
|
|
@@ -142,7 +160,9 @@
|
|
142
160
|
|
143
161
|
{
|
144
162
|
|
163
|
+
Debug.Log(
|
164
|
+
|
145
|
-
|
165
|
+
$"\t\t{HumanTrait.MuscleName[muscleIndexZ]}: {minMaxColor}{min.z}~{max.z}</color>");
|
146
166
|
|
147
167
|
}
|
148
168
|
|
@@ -176,7 +196,7 @@
|
|
176
196
|
|
177
197
|
プロジェクトビュー内でモデルファイルを選択し「Utility」→「Print HumanDescription」を実行すると、下図のような出力結果が得られました。
|
178
198
|
|
179
|
-
![Ethan](
|
199
|
+
![Ethan](436cb658c8995acbc2c02aef90984845.png)
|
180
200
|
|
181
201
|
エディタスクリプトでは何とかなりそうでしたが、実際の実行時に[Avatar](https://docs.unity3d.com/ja/current/ScriptReference/Avatar.html)からHumanDescriptionを取り出すのはやっかいそうです。探した限りではそれらしきクラス・メソッドは見つからず、ModelImporterがどのようにHumanDescriptionを作っているかの詳細も公開されていないようで、もっと詳しく調査・解析する必要がありそうです(もしかすると不可能かもしれません)。
|
182
202
|
|
3
微修正、ボーンインデックス探索ループにbreak追加
test
CHANGED
@@ -65,6 +65,8 @@
|
|
65
65
|
{
|
66
66
|
|
67
67
|
boneIndex = j;
|
68
|
+
|
69
|
+
break;
|
68
70
|
|
69
71
|
}
|
70
72
|
|
2
デフォルト値取得の誤りを訂正、実行結果スクリーンショットを差し替え
test
CHANGED
@@ -44,23 +44,63 @@
|
|
44
44
|
|
45
45
|
Debug.Log("\tPer-Muscle Settings:");
|
46
46
|
|
47
|
-
for (var
|
47
|
+
foreach (var humanBone in humanDescription.human)
|
48
48
|
|
49
49
|
{
|
50
50
|
|
51
|
-
var human
|
51
|
+
var humanName = humanBone.humanName;
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
// ボーン名一覧を見て、対応するボーン番号を見つける
|
56
|
+
|
57
|
+
var boneIndex = -1;
|
58
|
+
|
59
|
+
for (var j = 0; j < HumanTrait.BoneCount; j++)
|
60
|
+
|
61
|
+
{
|
62
|
+
|
63
|
+
if (HumanTrait.BoneName[j] == humanName)
|
64
|
+
|
65
|
+
{
|
66
|
+
|
67
|
+
boneIndex = j;
|
68
|
+
|
69
|
+
}
|
70
|
+
|
71
|
+
}
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
if (boneIndex < 0)
|
76
|
+
|
77
|
+
{
|
78
|
+
|
79
|
+
continue;
|
80
|
+
|
81
|
+
}
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
// ボーンインデックスの各軸に対応するマッスル番号を見つける
|
86
|
+
|
87
|
+
var muscleIndexX = HumanTrait.MuscleFromBone(boneIndex, 0);
|
88
|
+
|
89
|
+
var muscleIndexY = HumanTrait.MuscleFromBone(boneIndex, 1);
|
90
|
+
|
91
|
+
var muscleIndexZ = HumanTrait.MuscleFromBone(boneIndex, 2);
|
52
92
|
|
53
93
|
var limit = humanBone.limit;
|
54
94
|
|
55
|
-
|
95
|
+
|
56
96
|
|
57
97
|
// デフォルト値を使うよう設定されている場合は、limit内のmin・maxは無視するらしい?
|
58
98
|
|
59
99
|
var useDefault = limit.useDefaultValues;
|
60
100
|
|
61
|
-
var defaultMin = HumanTrait.GetMuscleDefaultMin(
|
101
|
+
var defaultMin = HumanTrait.GetMuscleDefaultMin(boneIndex);
|
62
102
|
|
63
|
-
var defaultMax = HumanTrait.GetMuscleDefaultMax(
|
103
|
+
var defaultMax = HumanTrait.GetMuscleDefaultMax(boneIndex);
|
64
104
|
|
65
105
|
var min = useDefault ? new Vector3(defaultMin, defaultMin, defaultMin) : limit.min;
|
66
106
|
|
@@ -74,17 +114,35 @@
|
|
74
114
|
|
75
115
|
var minMaxColor = useDefault ? "<color=black>" : "<color=blue>";
|
76
116
|
|
77
|
-
|
78
117
|
|
79
|
-
// 多分xがTwist Left-Right、yがLeft-Right、zがFront-Backだと思いますが
|
80
118
|
|
81
|
-
|
119
|
+
if (muscleIndexX >= 0)
|
82
120
|
|
83
|
-
|
121
|
+
{
|
84
122
|
|
85
|
-
Debug.Log($"\t\t{
|
123
|
+
Debug.Log($"\t\t{HumanTrait.MuscleName[muscleIndexX]}: {minMaxColor}{min.x}~{max.x}</color>");
|
86
124
|
|
125
|
+
}
|
126
|
+
|
127
|
+
|
128
|
+
|
129
|
+
if (muscleIndexY >= 0)
|
130
|
+
|
131
|
+
{
|
132
|
+
|
87
|
-
Debug.Log($"\t\t{
|
133
|
+
Debug.Log($"\t\t{HumanTrait.MuscleName[muscleIndexY]}: {minMaxColor}{min.y}~{max.y}</color>");
|
134
|
+
|
135
|
+
}
|
136
|
+
|
137
|
+
|
138
|
+
|
139
|
+
if (muscleIndexZ >= 0)
|
140
|
+
|
141
|
+
{
|
142
|
+
|
143
|
+
Debug.Log($"\t\t{HumanTrait.MuscleName[muscleIndexZ]}: {minMaxColor}{min.z}~{max.z}</color>");
|
144
|
+
|
145
|
+
}
|
88
146
|
|
89
147
|
}
|
90
148
|
|
@@ -116,11 +174,7 @@
|
|
116
174
|
|
117
175
|
プロジェクトビュー内でモデルファイルを選択し「Utility」→「Print HumanDescription」を実行すると、下図のような出力結果が得られました。
|
118
176
|
|
119
|
-
インスペクタ上では、部位によって設定項目名が「Down-Up」「In-Out」だったり「Stretch」「Twist In-Out」だったりとバラバラですが、手抜きして全部「Front-Back」「Left-Right」「Twist Left-Right」としています。すみません...
|
120
|
-
|
121
|
-
ちゃんと対応づけるには、部位ごとにどの値を動かすとHumanDescriptionのどの値が変化するかを確認してやる必要がありそうです。
|
122
|
-
|
123
|
-
![Ethan](5c2
|
177
|
+
![Ethan](127dce58c4d9e702344e8bce71272afe.png)
|
124
178
|
|
125
179
|
エディタスクリプトでは何とかなりそうでしたが、実際の実行時に[Avatar](https://docs.unity3d.com/ja/current/ScriptReference/Avatar.html)からHumanDescriptionを取り出すのはやっかいそうです。探した限りではそれらしきクラス・メソッドは見つからず、ModelImporterがどのようにHumanDescriptionを作っているかの詳細も公開されていないようで、もっと詳しく調査・解析する必要がありそうです(もしかすると不可能かもしれません)。
|
126
180
|
|
1
一部項目名が違うことについて弁解
test
CHANGED
@@ -116,8 +116,12 @@
|
|
116
116
|
|
117
117
|
プロジェクトビュー内でモデルファイルを選択し「Utility」→「Print HumanDescription」を実行すると、下図のような出力結果が得られました。
|
118
118
|
|
119
|
+
インスペクタ上では、部位によって設定項目名が「Down-Up」「In-Out」だったり「Stretch」「Twist In-Out」だったりとバラバラですが、手抜きして全部「Front-Back」「Left-Right」「Twist Left-Right」としています。すみません...
|
120
|
+
|
121
|
+
ちゃんと対応づけるには、部位ごとにどの値を動かすとHumanDescriptionのどの値が変化するかを確認してやる必要がありそうです。
|
122
|
+
|
119
123
|
![Ethan](5c28434208e8e21b723d527f258e5725.png)
|
120
124
|
|
121
|
-
で
|
125
|
+
エディタスクリプトでは何とかなりそうでしたが、実際の実行時に[Avatar](https://docs.unity3d.com/ja/current/ScriptReference/Avatar.html)からHumanDescriptionを取り出すのはやっかいそうです。探した限りではそれらしきクラス・メソッドは見つからず、ModelImporterがどのようにHumanDescriptionを作っているかの詳細も公開されていないようで、もっと詳しく調査・解析する必要がありそうです(もしかすると不可能かもしれません)。
|
122
126
|
|
123
127
|
逆に、実行時にHumanDescriptionをもとにAvatarを作ることは[AvatarBuilder](https://docs.unity3d.com/ja/current/ScriptReference/AvatarBuilder.html)を使えば可能らしいんですがね...
|