会社のサイトのトップで three.js で動いている棒人間のマスコットを、もっと生き生きと動かしたくて、Pixal3D で 3D にし、Mixamo で骨と既成の動きを付ける技術検証をしました。前回は、Mixamo の自動の骨入れで歩く・走るは生き生きしたものの、腕を上げると脇の面が裂け、自動の重み(どの骨がどの面を動かすか)だけでは足りないと分かりました。

第2回は、その重みを Blender で直していった話です。直すと消える崩れはありました。ただ、直しを積むほど別の所が崩れ、最後は Mixamo の自動のままの版に、最小の直しだけを足すところまで戻りました。それでも、深い姿勢の崩れは残りました。

結論

  • 脇の裂けと首の下のギザギザは、腕の付け根で胴の面から腕の重みを外し、胴にかかる鎖骨の重みを背骨(Spine2)へ移すと消えました。
  • 歩くと腕がお腹にめり込むのは、Mixamo の Character Arm-Space が既定の 50 のままだったためでした。87 で落とし直すと、腕はお腹の外を振りました。動きごとに 50 に戻ります。
  • 動きのキーを抑える直しは足の裏が地面から浮くので捨て、借りた動きは書き換えないことにしました。
  • 胴・腕・脚・手の重みを広く直すと、胸がポンチョのように上がる、股がふくらむ、手が潰れる、と崩れが隣へ移りました。自動のままの版に3つの直しだけを足すと、待機は良くなりましたが、動きが激しいときや体を縮めたときには崩れが残りました。

試した環境

  • Blender 5.2。背景実行の Python で、Mixamo から落とした FBX(骨と重み入り)を直しました。
  • 動き: Mixamo の待機・歩く・走る・跳ぶ・喜ぶ・考える・手を振る
  • 見た目は、three.js の確認ページで動きの時刻を止めて、直す前と後を並べて見ました。

前提として、動きを自作しないために借りているので、動きのキーは書き換えず、形と重みだけで合わせることにしました。

なお、Mixamo の FBX を Blender で読むと UV の継ぎ目で頂点が割れているので、どの直しでも最初に重なった頂点を繋ぎました(同じ現象はUV の継ぎ目で頂点が割れる件に書きました)。

脇の裂けと、首の下のギザギザ

腕の付け根で、胴の面から腕の重みを外す

脇が裂けるのは、腕の付け根の近くにある胴の面まで腕の骨が受け持っているからです。そこで、腕の骨の軸に沿った距離と、軸からの半径で点を分け、付け根の近くで軸から離れた点(胴の面)にかかる腕の重みを、胴の骨へ戻しました。前腕と手は Mixamo の重みのままです。

これで扇のような裂けは消えました。代わりに、喜ぶ動きで首の下にギザギザが残りました。

腕の付け根の重みを直した喜ぶ動き。脇の裂けは消え、首の下にギザギザが残る

ここで、モデルそのものが壊れているのではないかと疑い、Blender で調べました。殻は1つ、面どうしの食い込みは 0、閉じていない辺は 31 本でした。形の壊れではなく、骨の効き方の問題だと判断しました。

鎖骨の重みを背骨へ移す

首の下のギザギザは、鎖骨の骨(Shoulder)が胴の上端を持ち上げて、頭に食い込ませていたのが原因でした。胴の面にかかる鎖骨の重みを Spine2 に移すと、ギザギザは消えました。動きの側の鎖骨の回転はそのままです。

胴にかかる鎖骨の重みを背骨へ移した喜ぶ動き。首の下のギザギザが消えた

お腹の折れと、胴の重みの付け方

次に、跳ぶ動きでお腹が折れました。Mixamo の自動の重みは、胴を背骨の骨ごとの帯に分けていて、背骨を曲げるたびに帯の境でお腹が折れます。

胴の付け方は、何度か変えていきました。

  1. 背骨の4本(Hips・Spine・Spine1・Spine2)に、高さに沿ってなだらかに配った。段は消えたが、大きく丸まると皺が残った。
  2. 4本に均等に配った。胴は曲がらずに向きだけ変わり、卵形が保たれた。
  3. ところが喜ぶ動きで、首の付け根まで胴が一緒に回り、肩が頭の横まで盛り上がった。胴の上の端だけ Spine2、下の端だけ Hips に寄せ、中ほどを均等にすると収まった。

胴の重みを背骨の4本に均等に配った跳ぶ動き。卵形の胴が保たれる

重みを広くぼかすだけの直しも試しましたが、継ぎ目の線が薄くなるだけで、背骨が大きく曲がる所のお腹の折れは消えませんでした。

形を作り直して、目を粒にする

Pixal3D の面には、細かい角ばり、胴のわきの溝、足首の輪じわがありました。マスコットは形が単純なので、ボクセルで作り直してならすことにしました。高さの 1/150 のボクセルで作り直し、ならしを 20 回かけると消えました。1/260 の細かさで作り直すと、元のでこぼこごと写って変わりませんでした。細かいほうが良いとは限らない、という所で迷いやすいと思います。

ボクセルの細かさを変えて作り直した形の比べ。細かすぎると元のでこぼこが残る

作り直した面には重みが無いので、元の面から Blender の Data Transfer(最も近い面の補間)で写しました。

目は、色の画像を UV ごと写すとにじみました。そこで、元のモデルの色の画像で黒い所に当たる頂点から目の位置と大きさを出し、黒い平たい粒の形を作って Head の骨に付けました。色の画像が要らなくなり、Draco で縮めた GLB は 9.3MB から 0.64MB になりました。静止した見た目が整ったのは、この形の直しと目の粒からです。

Blender の Python で一つ詰まりやすいのが、modifier の適用です。適用すると形が作り直され、それより前に取った頂点グループの持ち手が古くなって、重みの書き換えが黙って効かなくなります(書き換えた数が 0 件と出ます)。適用の後に取り直します。

bpy.ops.object.modifier_apply(modifier='smooth')
# 適用で形が作り直されるので、頂点グループの持ち手を取り直す
groups = {g.name: g for g in mesh.vertex_groups}
names = {g.index: g.name for g in mesh.vertex_groups}

動きを抑える案を捨てた

跳ぶときの崩れを減らすために、動きのほうを抑える直しも試しました。首・背骨を 4 割、膝と腿を半分に抑えると、表面は滑らかになりましたが、足の裏が地面から浮き、歩きが変になりました。動きを自作しないために借りているのに、動きそのものを変えるとかえって不自然になります。ここで、借りた動きのキーは書き換えないと決めました。

腕のめり込みは Character Arm-Space で外す

歩くと、振った腕がお腹にめり込んで見えました。Mixamo の Character Arm-Space(腕と体の間隔)が既定の 50 のままだったのが原因で、87 にして落とし直すと、腕はお腹の外を振りました。Mixamo の側で落とすときの調整なので、動きのキーを手で書き換えることにはなりません。

気をつける点が2つあります。動きごとに既定の 50 に戻るので、落とすたびに上げ直します。つまみを引くと 0 になることがあるので、数値の欄に 87 と打ちます。

股下と首

跳ぶときの股下の折れは、脚の付け根のなじませを長めにし、腿と脛を1本のホースのように曲げる(膝の前後に幅を取って重みを移す)と減りました。

待機で首が少し伸びて見える所は、頭の回る支点が頭の玉のいちばん下にあることが元でした。支点が下にあると、頭が回るたびに玉が体からずれ、継ぎ目が首のように伸びます。支点を玉の中ほどへ上げると待機は少し良くなりましたが、喜ぶ動きで頭が浮いて継ぎ目が伸びたので、採りませんでした。首の伸びは残りました。

体型を変えてみる

首が無く脚が短いことが首と腰の崩れの元に見えたので、体型を Mixamo の動きに寄せる案も試しました。Codex に細い首・長い脚と腕の絵を描かせると、マスコットらしい可愛さが失われ、見た目として受け入れられませんでした。

Mixamo の骨格に寄せて、細い首と長い脚と腕で描き直したマスコットの案

そこで、可愛い比率は保ったまま、今の太さで首を足し、脚を少し長くした体型を描かせ、それを全体に丸くした物を選びました。Pixal3D で 3D にした後は、高さの 1/160 のボクセルで作り直し、ならしを 20 回かけ、左半分を右へ写して左右をそろえました。腕の付け根は、腕の軸に沿って断面が急に太くなる所を付け根とみなし、その周りを強くならしました。体積を保つほうのならし(Laplacian)は、表面がでこぼこになったので使いませんでした。

首を足して丸くした体型を、作り直しと左右そろえで整えた形

広く直すと、崩れが隣へ移った

この体型で骨を入れ、重みを広く直しました。胴は背骨の真ん中の骨1本に付けて、曲がらずに向きだけ変わるようにしました。腕は胴から出ている筒の部分だけを腕の骨に、手は指の骨を使わず手の骨1本に、脚の付け根は狭い範囲だけを脚の骨に付けました。ところが、直した所の隣で次々と崩れが出ました。

  • 腕の範囲を広く取ると、腕を上げたとき胸の上の面がポンチョのように一緒に持ち上がった。
  • 付け根から先まで太さで切ると、手袋のような手は筒より太いので手が胴に残り、刃物のように潰れた。
  • 脚の付け根を広げると、お腹の下の段は消えたが、跳ぶときに股に変なふくらみが出た。
  • 脚の筒だけを腿の骨に付けると、着地と歩きで腿の付け根が刃物のように薄く尖った。跳ぶと腿が薄い板になる版もあった。

自動のままと、重みを広く直した版の喜ぶ動きの比べ

お腹の下にも、別の物が生えたようなお椀形の膨らみが見えました。お腹だけを直すと、今度は腿の付け根に段ができ、お腹も直りませんでした。直しを積んだ版と自動のままの版を並べると、自動のままの版はお腹の膨らみがおかしいだけで、動きはかなり自然でした。お腹の膨らみをなだめる前のほうが、跳んだときの股もむしろ自然でした。

直しを積むと崩れが移った流れ

図の「別の所が崩れる」は、上の箇条のポンチョ・股・手・腿の段です。直すたびにここへ戻り、直しを積むほど全体が不自然になりました。重みの直しはどれも局所的なので、ある所の継ぎ目を動かすと、崩れが隣へ移るのだと見ています。

自動のままの版に、最小の直しだけを足す

そこで、自動のままの版を土台に戻り、崩れの原因を確かめてから、最小の直しだけを足しました。Mixamo の自動の重みを骨ごとに色分けすると、原因は2つでした。

  • 胴が2つの固い塊に割られている。胸から上は Spine2、お腹から下は Hips で、あいだの Spine・Spine1 は細い帯にしか効いていない。背骨が少し曲がるだけで、境目でお腹が折れる。
  • 胸の両わきを肩の骨(LeftShoulder・RightShoulder)が受け持っていて、腕を動かすと胸の脇が持ち上がる。

加えて形の側にも理由がありました。高さごとに胴の幅を測ると、胴は洋梨形で、お腹の下が胸より横に約 15% 張り出し、前にも張り出していました。動くと、その張り出しが別の部品に見えます。

足した直しは次の3つです。

  1. 胴の重みのうち、脚の重みが無い所だけを、Hips → Spine → Spine1 → Spine2 へ高さに沿ってなだらかに受け渡す。
  2. 胴の面にかかる肩の骨の重みを Spine2 に移す。
  3. お腹の下の帯を、胴の軸のほうへ 14% すぼめる。重みはそのまま。

着地の姿勢で、自動のままと最小の直しを足した版を並べた比べ

かなり良くなりましたが、お腹はまだ出っ張っていました。動かして見ると、ほぼ動かない待機ではきれいに見えるのに、動きが激しいときや、跳んで体を縮めたときには、お腹が分離して見え、目に見えて崩れていきました。この方式(一枚の面に骨を入れて借りた動きを当てる)の重みの直しは、ここで止めました。

まとめ

  • 脇の裂けは腕の付け根の重み、首の下のギザギザは鎖骨の重み、腕のめり込みは Character Arm-Space(87。動きごとに 50 に戻る)で外せた。
  • 動きのキーを抑えると足が浮くので、借りた動きは書き換えずに直す。
  • 重みを広く直すと、崩れは消えずに隣へ移った。自動のままの版に最小の直しを足すのが、いちばんましだった。
  • それでも、待機は良いのに、深い姿勢(跳んで縮める・着地)では崩れが残った。重みをいじる前に、なぜ崩れるのかを確かめる必要があった。

確かめていないこと

  • 待機の首の伸びを、動きを変えずに消す方法(頭と胴を別の形に分ける、首の継ぎ目を頭の玉の内側に隠す、など)。

おわりに

第2回で分かったのは、重みの直しは局所的で、直しを積んでも崩れが移るだけだということです。次回は、深い姿勢でなぜ崩れるのかを、断面と伸びた面の数で確かめ、体積を保つ混ぜ方や補正の形も試します。

※ Mixamo の Character Arm-Space の既定値や振る舞い、Blender の Python の振る舞いは執筆時点の情報で、いまは変わっている可能性があります。