Unity
Blender

BlenderからUnityのHumanoid互換でfbxをエクスポートする

BlenderでUnity向けにウェイト付きメッシュを作る方法。
Rigify使わない。

  • Blender2.79
  • Unity5.6.3p1

更新

  • 20180624。RのVertexGroupを作るスクリプト
  • 20180531。Shoulderを入れることにした。左右対称のVertexGroupは後付けでもよいぽい
  • 20180527。Neckを入れることにした
  • 20180527。編集リクエスト採用
  • 20180301。WeightPaintのところまで

UnityのHumanoidの必須15ボーンと追加のChest, Neck, Shoulder

これから作るモデルの作業計画。
下図の実線の丸印がHumanoidで必須とされるボーンで、点線の丸印はなくてもいいボーン。

なくてもいいけどFinalIKでの利用時にShoulderがあった方がよさげらしいです。
ChestShoulderNeckを入れることにした。

humanoid.png
(最近のUnityに更新)

  • Hips(腰)

    • UpperLeg.L
    • LowerLeg.L
    • Foot.L
    • UpperLeg.R
    • LowerLeg.R
    • Foot.R
  • Spine(腹)

  • Chest(胸 Option。入れておく方が良いのではないかということで)

    • Shoulder.L(Option。入れておく方が良いのではないかということで)
    • UpperArm.L
    • LowerArm.L
    • Hand.L
    • Shoulder.R(Option。入れておく方が良いのではないかということで)
    • UpperArm.R
    • LowerArm.R
    • Hand.R
  • Neck(Option。入れておく方が良いのではないかということで)

  • Head

Nestしすぎるとうまく表示できなかったので木構造あきらめ

BlenderでSkeletonを作成する手順

手前(Y軸マイナス)向きに作成する(向かって右が左半身になります)。

オプション。単位設定

Metric.png

メートル単位系で倍率1に設定した。
これはやらなくてもいいのだけど、後続のスクリーンショットでcm等の単位が入っているのはこの設定のためです。

新規シーンにArmatureを作る

  • Object mode
  • CameraとLampとCubeがあるので全部削除
  • Add - Armature - SingleBone

Armatureの表示設定

  • Meshに埋もれても見えるようにArmature propertyのX-rayをOn
  • ついでにボーン名が表示されるようにnamesをOn

Armature_Display.png

Armatureを編集

  • Object mode
  • Armatureを選択
  • Edit mode

胴体(Hips-Spine-Chest-Neck-Head。全部上向き)

身長160cmとして、Blenderの1を1mとみなす

  • 最初のボーンにHipsと名付ける
    bone_name.png

  • Hipsのヘッドを0.8の高さに移動しテイルを0.9にする(下のHead=80cm, Tail=90cm)
    Head_Tail.png

  • Hipsのテイルを選択。子ボーンを生やす[Eキー]。Spineと名付けて上に伸ばす。Spineのテイルを20cmくらい上

  • Spineのテイルを選択。子ボーンを生やす。Chestと名付けて上に伸ばす。Chestのテイルを20cmくらい上

  • Chestのテイルを選択。子ボーンをはやす。Neckと名付けて上に伸ばす。Neckのテイルを10cmくらい上

  • Neckのテイルを選択。子ボーンを生やす。Headと名付けて上に伸ばす。Headのテイルを30cmくらい上

腕(Shoulder - UpperArm - LowerArm - Hand。Chestのテイルから水平に伸ばす。左右対称)

  • ToolShelf[3DViewでTキー] - Options - X-Axis MirrorをOn
    x-axis-mirror.png
    EditModeにするとこれが出てくる。

  • 分岐点の親になるChestのテイルを選択

  • 左右対称に子ボーンを生やす[Shift+Eキー]。Shoulder.LとShoulder.Rと名付ける。

  • Shoulder.Lのテイルを10cm横に伸ばす
    (X-Axis-MirrorでShoulder.RもX軸対称に移動する。しなければ、X-Axis-Mirrorの設定とShoulderの名前を確認する)

  • Shoulder.Lのテイルを選択。子ボーンをはやす[Eキー]。UpperArm.LとUpperArm.Rと名付ける。UpperArm.Lのテイルを30cmくらい横に移動。

  • UpperArm.Lのテイルを選択。子ボーンを生やす[Eキー]。LowerArm.LとLowerArm.Rと名付ける。LowerArm.Lのテイルを20cmくらい横に移動。

  • LowerArm.Lのテイルを選択。子ボーンを生やす。Hand.LとHand.Rと名付ける。Hand.Lのテイルを10cmくらい横に移動。

足(UpperLeg - LowerLeg - Foot。Hipsの子供だが少し離れたところから始める。下向き)

  • 分岐点の親になるHipsのテイルを選択
  • 左右対称に子ボーンを生やす[Shift+Eキー]。UpperLeg.LとUpperLeg.Rと名付ける。両方Connectedを外す。
  • UpperLeg.Rのヘッドを横に10cmくらい移動する。UpperLeg.Lのテイルを下に40cmくらい移動する。
    connected.png
    Connectedをオフにしてヘッドを移動すると親のボーンとの間に点線が表示される。

  • UpperLeg.Lのテイルを選択。子ボーンを生やす[Eキー]。LowerLeg.LとLowerLeg.Rと名付ける。LowerLeg.Lのテイルを30cmくらい下に移動する。

  • LowerLeg.Lのテイルを選択。子ボーンを生やす。Foot.LとFoot.Rと名付ける。Foot.Lのテイルを10cmくらい下に移動し、前にも10cmくらい移動する。

foot.png

スケルトン完成

Skeleton.png

Fbxエクスポート

さっそくfbxにエクスポートしてUnityで読み込んでみる。
fbx_export.png

UnityでImport

Animation TypeをHumanoidに変えてApply。
unity_humanoid.png

インポートできた。
Humanoidとしてインポートできる条件はArmatureが条件に沿っていればよくて、メッシュは関係無いとわかった。

BlenderでMeshを作る

せっかくなので全身が一つにつながったボーンウェイト
の効果があるモデルを作る。

  • objectモード
  • AddPlane。Bodyと名付ける。
  • Bodyを選択してEditモードにする。
  • 4つの頂点を移動してこの状態にする。Y軸は全部0
    first.png

  • Mirror ModifierとArmature Modifierを追加する
    modifier.png

  • Mirror: Clipping: x軸の反対側に行けないようにする

  • Armature: Object: Armatureを設定

  • MirrorしてからArmatureするこの順番で

  • Eを駆使してボックスマンを更に退化させた平面マンを作った。
    pera.png

ウェイトを1で済ますために関節を挟むように頂点を配置した

BlenderでBoneWeightをつける

手順

Weightが見えやすいようにBodyのWire描画をオンにする。

wire.png

WireとDrawAllEdgeをチェックする。EditorモードでなくてもWire描画が見える。

  • ObjectモードでArmatureを選択してPoseモードにする
  • Bodyを選択してWeightPaintモードにする
  • Hipsを選択する(VertexGroup Hipsを描画する状態になる)

weight_paint.png

  • 筆の太さを変える。[Fキー]
  • 左ドラッグで塗るf

vertex_group.png

塗るとすぐにVertexGroupに選択中のボーン名で新しいグループが作成されて、対称の頂点がVertexGroupに登録される(赤が1.0)。

Hips_weight.png

Hipsをすべて塗った。

Blenderのボーンウェイトの持ち方

頂点のボーンウェイトは、ボーン名のVertexGroupに格納されます。

頂点を選択します。

select_vertex.png

ボーンと同じ名前のVertexGroupを作ってAssignします。Weight値がボーンウェイトになります。

bone_weight.png

選択した頂点の属しているVertexGroupとWeight値は、3Dビュー右側(NキーでOn/Off)に表示されます(VertexGroupに属していないときは非表示)。

vertex_weights.png

以下の手順でボーンウェイトを設定していきます。ウェイトペイントでVertexGroupを操作することができます。

続き

Hips, Spine, Chest, Neck, Headと左右ボーンが無いところを塗りました。

SpineVertexGroup.png

左右対称ボーンのウェイトペイント

だめな例。

Shoulder.Lを選択して塗ってみたところ、VertexGroup.Lだけが現れて両方の肩がShouler.Lに結び付けられてしまった。これじゃない。

L_only.png

おもむろにVertexGroup Shouler.Rを作ると・・・

both.png

希望したとおりになった。後からRのVertexGroupを追加するだけでよいことが判明。

ということで、左半身だけ先にWeightPaintしてあとからRのVertexGroupを作ることにする。

Shoulder-UpperArm-LowerArm-Hand作業完了。

arm_hand.png

UpperLeg-LowerLeg-Foot作業完了。

legs.png

完成

complete.png

WeightPaintが終わってからEで厚みを付けたのであった。

unity.png

モデリングが完全に終わってからボーンを作ってWeight付けするんじゃなくて、
最初にスケルトンがある手順を模索している。

Tips

WeightPaintモードでボーンを選択できない場合

  • objectモード
  • Armatureを選択
  • Poseモード
  • meshを選択
  • WeightPaintモード

とする。WeightPaintのときはArmatureをあらかじめポーズモードにしておく

ミラーリングされた部分にWeightを塗る

準備ができていないと両方にウェイトがついてしまう。

ng_mirrorweight.png

left_right_vertexgroup.png

  • 左右両方のVertexGroupを作る必要がある。WeightPaintの後からでもよいが先に作っておいた方がわかりやすいかもしれない
  • WeightPaint Mode時に先に UpperArm.RとUpperArm.Lというような名称で頂点グループ二つがあることが重要。
  • MirrorModifier使用時は、ミラーする前の実体がある方に塗る

失敗したWeigtPaintをクリアする

  • VertexGroupを削除する
  • 部分的にやり直すには、Editモードで頂点を選択して、該当するVertexGroupを選択して、選択頂点のRemoveボタンを押して、頂点をVertexGroupから削除する。

ポーズを全クリアする

  • pose mode で全ボーンを選択[Aキー]。回転クリア[Alt+R]。移動クリア[Alt+G]

裏表が反対に

  • bodyをedit mode で全頂点を選択[Aキー]。向き再計算[Ctrl+N]

アクティブなオブジェクトに対して、RのVertexGroupを作るスクリプト

import bpy

def get_right_name(name):
    if name.endswith('_L'):
        return name[0:-2]+'_R'
    if name.endswith('.L'):
        return name[0:-2]+'.R'

def execute(o):
    print(o)
    groups=[x.name for x in o.vertex_groups]
    for x in groups:
        right_name=get_right_name(x)
        if right_name:
            right=o.vertex_groups.get(right_name)
            if not right:
                print(right_name)
                o.vertex_groups.new(right_name)

o=bpy.context.active_object
execute(o)

最初の記事の残骸

あとでメンテする。

painted.png

unity.png

Unityでメッシュが寝た状態でヒエラルキーに不要なスケールと回転が入っているのを修正する

何度もモデル修正してfbxを上書きしているとAvatarがおかしくなる。
再インポートした際に、Avatarは上書きしない仕様のようだ。
新しいスケルトンを反映するには、
AvtarのConfig画面に入って下の方のPose - Reset
をする。

で、Humanoidのモーションを当ててみたらそれなりに動いたのだけど
まだ綺麗じゃないところがある。

直したいところ1。
transform.png

直したいところ2。
preview.png

スケールに関してはBlenderがfbxに出力するときにメートルとcmの変換がかかるらしい。
スクリーンショットの Scale: 1.0 <-> と左右の矢印のあるボックスの設定を変えてエクスポートしたら1になった。

export_option.png

残りの問題はBlenderが右手系のZ-UpでUnityが左手系のY-Upであることから来るX軸の-90度回転だ。

  • Mesh Objectにカウンターで90, 0, 0の回転。その状態で立って見えるように中身を回転(ローカル座標でY-UP)
  • Armature Objectにカウンターで90, 0, 0の回転。その状態で立って見えるように中味を回転(ローカル座標でY-UP)
  • SetParent無し

としたらうまくいった。
なるほど。
自動でHumanoid仕様のスケルトンを作ったり、回転を調整してからfbxエクスポートを呼び出して終わったらUndoするヘルパーを作ったらよさげ。

Blenderの補助スクリプト

作った。

https://gist.github.com/ousttrue/e5ae25958b8ccc1f212538b9fa8d2db4

addon.png

まだ、ちゃんとテストされてないので使うときはシーンをバックアップしておくなどご注意

Add Unity Humanoid

新規にArmatureを作成してUnity Humanoidに沿ったボーンを作る(危険度小)

  • ObjectMode

Add X-Mirror VertexGroup

X-MirrorでWeightPaintする時のために、事前に末尾にL, Rのついたボーン名のVertexGroupを作成する(危険度小)

  • ObjectMode。選択中のMeshObject

Fix Rotation

Unityにfbxエクスポートするときのためにモデルに逆回転を加える(危険度中)

  • ObjectMode。選択中のMeshObject
  • 既存シーンに変更を加える
  • Armatureをmodifier適用して、SetParentしてない場合しか試していない。

あと、モーションの挙動をチェックしておく必要があるな・・・