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

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

* Blender2.79
* Unity5.6.3p1

* [Blender2.83でUnity向けヒューマノイドを Weight Paint する](https://qiita.com/ousttrue/items/ecb442122af6966dcefd)

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

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

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

![humanoid.png](https://qiita-image-store.s3.amazonaws.com/0/59664/2f940988-991f-3936-3baf-8ad88e85f6ba.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](https://qiita-image-store.s3.amazonaws.com/0/59664/ec6d3ad1-02a2-b4d6-40d2-585139639feb.png)

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

### 新規シーンにArmatureを作る

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

### Armatureの表示設定
* Meshに埋もれても見えるようにArmature propertyのX-rayをOn
* ついでにボーン名が表示されるようにnamesをOn
 
![Armature_Display.png](https://qiita-image-store.s3.amazonaws.com/0/59664/bdb94eb4-c1da-2f89-49d4-72736f5d971d.png)

### Armatureを編集

* Object mode
* Armatureを選択
* Edit mode

#### 胴体(Hips-Spine-Chest-Neck-Head。全部上向き)
身長160cmとして、Blenderの1を1mとみなす

* 最初のボーンにHipsと名付ける
![bone_name.png](https://qiita-image-store.s3.amazonaws.com/0/59664/28f45561-e222-f64a-c9c2-f44b2cb7a487.png)

* Hipsのヘッドを0.8の高さに移動しテイルを0.9にする(下のHead=80cm, Tail=90cm)
![Head_Tail.png](https://qiita-image-store.s3.amazonaws.com/0/59664/a8e7a3cb-74d4-f0f7-c845-b3af46270656.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](https://qiita-image-store.s3.amazonaws.com/0/59664/ad488914-a67d-0060-0b06-3742c46be649.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](https://qiita-image-store.s3.amazonaws.com/0/59664/8653a1ee-1aed-d101-c729-a21fbbc897ed.png)
Connectedをオフにしてヘッドを移動すると親のボーンとの間に点線が表示される。 

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

![foot.png](https://qiita-image-store.s3.amazonaws.com/0/59664/32bcea51-0813-3ff4-cc1f-6a97af57cc69.png)

#### スケルトン完成
![Skeleton.png](https://qiita-image-store.s3.amazonaws.com/0/59664/db486170-ffcc-0865-4977-2685777a92b0.png)

### Fbxエクスポート
さっそくfbxにエクスポートしてUnityで読み込んでみる。
![fbx_export.png](https://qiita-image-store.s3.amazonaws.com/0/59664/81ba8170-1e3b-5599-1d09-cf451ecadd28.png)

## UnityでImport
Animation TypeをHumanoidに変えてApply。
![unity_humanoid.png](https://qiita-image-store.s3.amazonaws.com/0/59664/51102616-c2a6-dcfb-1880-c689650ff928.png)

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

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

* objectモード
* AddPlane。Bodyと名付ける。
* Bodyを選択してEditモードにする。
* 4つの頂点を移動してこの状態にする。Y軸は全部0
![first.png](https://qiita-image-store.s3.amazonaws.com/0/59664/4dd6f992-6147-86c0-e206-cfd72d910186.png)

* Mirror ModifierとArmature Modifierを追加する
![modifier.png](https://qiita-image-store.s3.amazonaws.com/0/59664/53937099-85d4-44ba-85b9-315052c80178.png)

* Mirror: Clipping: x軸の反対側に行けないようにする
* Armature: Object: Armatureを設定
* MirrorしてからArmatureするこの順番で

* Eを駆使してボックスマンを更に退化させた平面マンを作った。
![pera.png](https://qiita-image-store.s3.amazonaws.com/0/59664/fa304b6e-6d70-e75b-1ad0-55a068a2191e.png)


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

## BlenderでBoneWeightをつける

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

![wire.png](https://qiita-image-store.s3.amazonaws.com/0/59664/d237d9d2-d23e-b25f-a0fa-38a329a8be5a.png)

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

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

![weight_paint.png](https://qiita-image-store.s3.amazonaws.com/0/59664/c9b04d92-b85d-f8ae-28d0-5937c2f67756.png)

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

![vertex_group.png](https://qiita-image-store.s3.amazonaws.com/0/59664/0c295542-4738-0f80-1aa3-0bb38f2f5b7e.png)

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

![Hips_weight.png](https://qiita-image-store.s3.amazonaws.com/0/59664/3e509371-ff0f-ebcb-8452-9b991b526595.png)

Hipsをすべて塗った。

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

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

頂点を選択します。

![select_vertex.png](https://qiita-image-store.s3.amazonaws.com/0/59664/ffc01e96-b061-612c-1bdb-1ca31bf926fc.png)

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

![bone_weight.png](https://qiita-image-store.s3.amazonaws.com/0/59664/23100077-8c95-284e-dc53-9bb735041770.png)

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

![vertex_weights.png](https://qiita-image-store.s3.amazonaws.com/0/59664/649760f3-44b0-6a3f-d649-1eeb5deb81b0.png)

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

### 続き

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

![SpineVertexGroup.png](https://qiita-image-store.s3.amazonaws.com/0/59664/6eafca95-aa60-5480-5bdb-995da324c994.png)

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

だめな例。

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

![L_only.png](https://qiita-image-store.s3.amazonaws.com/0/59664/a5de4f00-9b59-578d-88c9-83a04f62abba.png)

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

![both.png](https://qiita-image-store.s3.amazonaws.com/0/59664/6b599d5c-ea47-9a05-77a2-0d03e83c5087.png)

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

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

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

![arm_hand.png](https://qiita-image-store.s3.amazonaws.com/0/59664/f00cf1f2-028a-cb9f-3445-2d4a2eb3397c.png)

UpperLeg-LowerLeg-Foot作業完了。

![legs.png](https://qiita-image-store.s3.amazonaws.com/0/59664/64c802d9-ff57-a963-0053-0c7c4f3c86e5.png)

### 完成
![complete.png](https://qiita-image-store.s3.amazonaws.com/0/59664/0e110e19-f7ba-8831-89d4-0f83499d5bc9.png)

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

![unity.png](https://qiita-image-store.s3.amazonaws.com/0/59664/426b462c-433e-9eeb-0ba2-189c20d1e728.png)

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

## Tips
### WeightPaintモードでボーンを選択できない場合
* objectモード
* Armatureを選択
* Poseモード
* meshを選択
* WeightPaintモード

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

### ミラーリングされた部分にWeightを塗る
準備ができていないと両方にウェイトがついてしまう。

![ng_mirrorweight.png](https://qiita-image-store.s3.amazonaws.com/0/59664/c34dea6f-71c2-dfcf-9c85-48b19cdabf52.png)

![left_right_vertexgroup.png](https://qiita-image-store.s3.amazonaws.com/0/59664/bd93474b-51fc-e8dc-5f02-382f23311964.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を作るスクリプト

```python
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](https://qiita-image-store.s3.amazonaws.com/0/59664/e27686f4-2419-6ece-4212-dd2f9a7593af.png)

![unity.png](https://qiita-image-store.s3.amazonaws.com/0/59664/1c2c851f-4207-c520-257d-7349c9f8d1e3.png)

### Unityでメッシュが寝た状態でヒエラルキーに不要なスケールと回転が入っているのを修正する
何度もモデル修正してfbxを上書きしているとAvatarがおかしくなる。
再インポートした際に、Avatarは上書きしない仕様のようだ。
新しいスケルトンを反映するには、
AvtarのConfig画面に入って下の方のPose - Reset
をする。

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

直したいところ１。
![transform.png](https://qiita-image-store.s3.amazonaws.com/0/59664/bfc30d99-be5c-850c-98f2-b38573c3be12.png)

直したいところ２。
![preview.png](https://qiita-image-store.s3.amazonaws.com/0/59664/d45b17f0-658b-1df0-da82-353a54974f67.png)

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

![export_option.png](https://qiita-image-store.s3.amazonaws.com/0/59664/4a6d1612-9b88-b40f-5168-1c9ebb2a2306.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](https://qiita-image-store.s3.amazonaws.com/0/59664/f99c5af3-7a89-4540-5113-f5fb65b9fa16.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してない場合しか試していない。

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