【Unity】SetHumanPoseを使うとなぜか吹っ飛んでしまう時の対策
概要
HumanPoseHandlerを使っていたら、なぜか遥か彼方へ飛んでいってしまう…
みたいなことに遭遇していました
今回ようやく原因と一部対処方法が分かったので書いておきます
検証環境
Unity2019.4.22f1
発生条件
把握してる範囲だと2パターンあります
Aパターン
- HumanPoseHandler生成時の第2引数 root に不正な Pos/Rot/Scale 値がある
- SetHumanPose をする
Bパターン
- HumanPoseHandlerを生成する
- Animator が Attach されている Transform の Pos/Rot/Scale を変える
(Editor操作を含む) - SetHumanPose をする
対処方法
Bは対処方法がないので触らない…ということになってしまいます…
Aはキャラが原点にいないせいでHumanPoseHandler生成時に発生します
こっちのほうは対処法を見つけたのでコードを載せます
private HumanPoseHandler CreateHumanPoseHandler(Animator animator) { if (animator == null) { return null; } var position = animator.transform.position; var rotation = animator.transform.rotation; var scale = animator.transform.localScale; animator.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity); animator.transform.localScale = Vector3.one; var humanPoseHandler = new HumanPoseHandler(animator.avatar, animator.transform); var hipBone = animator.GetBoneTransform(HumanBodyBones.Hips); hipBone.rotation = rotation; hipBone.position = position + hipBone.up * hipBone.position.y * scale.y; hipBone.localScale = scale; return humanPoseHandler; }
日本語にすると
- animatorのあるTransformをキャッシュ
- 全部初期値
(Position : Vector.zero / Rotation: Quaternion.identity / Scale: Vector.one) に戻す - HumanPoseHandlerの生成
- HipBoneにキャッシュ分を反映する
4つ目は恐らく HumanPose.bodyPosition/ HumanPose.bodyRotation でもよいですが
Scaleを反映させる術がなさそう?だったのでhipboneにしています
position + hipBone.up * hipBone.position.y * scale.y
この部分はUnityによくある体が半分くらい床に埋まってしまうやつの対策です
hipBoneのYだけ考慮したかったので up と掛け算しつつ、
元のscaleも計算に入れてつじつま合わせをしています
推測
おそらく animator.transform を基準にSetHumanPoseの計算をしており、
これが初期値でないと毎フレームoffsetとして加算されてしまうようです
他に試したこと
Hipの親をHumanPoseHandlerの第2引数にする
ちゃんとroot boneが用意されているモデルを使って試しました
吹っ飛ばなくなる…がMuscleが反映されませんでした
ということはanimator.transformを渡すのが必須のようですね…
HumanPose.bodyPosition/bodyRotation で反映する
途中までこっちで確認していましたが、やや計算誤差がありそうです
まとめ
調べてもあまり同じようなことで悩んでる人がいなさそう…?
だったので記事にしておきました
とりあえずanimator.transformを操作しなければ
一旦これで対策できそうなのでなんとかなってよかったです
なにかあれば Twitter までご連絡ください~