HOUDINIでSkin weightのクリーンアップ。

この記事は[Houdini Apprentice Advent Calendar 2020](https://qiita.com/advent-calendar/2020/happrentice)の4日目の記事です。

houdini18.5からKineFXが登場したことで、
今後はキャラクターモデルの分野でもhoudiniの活用度がますます増えていくと思いますが、
そんな中、ふと普段MayaでやっているSkinWeightのクリーンアップ作業を
Houdiniでも再現できないかなと思い、挑戦してみました。

#■　Skin weightのクリーンアップ
Skin weightのクリーンアップは、
特にゲーム用のアセットなどで、ゲームエンジンの制限やデータ容量の削減などのために
端数を丸めたり、インフルエンスの最大数を制限するといった作業ですが、

昨今のハードウェアの進化を考えると、今は実用性よりは
アーティストがデータをきれいに保ちたいという作業に変わってきているかもしれません。

さて今回は、
![99_weightBefore.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923088/e53342e4-b478-3c52-360d-7451d28a5a16.png)
このようなウェイト値(@boneCapture_data)と、ボーンのID（@boneCapture_index）情報を、

![99_weightAfter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923088/613d5850-e9d6-4418-de7b-e356d25cd984.png)
このようなきれいな数字に整形していきたいと思います。

#■　ダウンロード
[ここからダウンロード](https://drive.google.com/file/d/1FLf_4fhVY5CLrTH9R-pQLxl9trFNL_Mp/view?usp=sharing)
HDA化までには至っておりません。hipncファイルになります。
（Houdini apprentice 18.5.351)

#■　全体図
![00_all.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923088/009b001e-0b1d-14b3-f2bc-97eb14794da5.png)
モデルデータの入力と出力にはKineFXのfbxcharacterimportとrop_fbxcharacteroutputを使いました。
（rop_fbxcharacteroutputのおかげで、Apprenticeでも骨付きのfbxファイルが書き出せるようです。:heart_eyes:）

処理はまずcapture attribute unpackノードで、ウェイト情報を編集可能なattributeに戻し、
各Wrangleノードのスクリプトでウェイト情報の@boneCapture_data、@boneCapture_indexを操作していき、
最後にcapture attribute packしなおす形にしました。

#■　reduce_Influence 最大Influence数の削減
![01_reduceInfluence.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923088/1cdd3741-0fd1-2a3c-87e5-d7fabbaa95a2.png)
頂点が影響されるボーンの数。ゲーム用のアセットでは4以下に設定されることが多いです。
のぞみのInfluence数より多い場合、一番小さいウェイトの値から順番に削除していきます。
Influence数の設定はMax Influenceスライダーで。

#■　normalize_ weight ウェイトの正規化
![02_normalize.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923088/50b2bfe8-c0db-b28a-daa8-b8ea75135296.png)
ウェイトの値の合計が1.0になるようにスケールをかけます。
上記reduce_Influenceノードではウェイトの値の削除のみを行いましたので、
ウェイトの合計が1.0に満たない状態になりましたが、
このノードを通って合計が1.0になります。

#■　round_weight 端数の削減
![03_roundWeight.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923088/cad82716-65fb-2944-b0ec-bff30b214d38.png)
少数を丸めます。Accuracyスライターで、何位まで丸めるか決められます。
スライターには自由に数字を入力できてしまいますが、
0.1, 0.01, 0.001などで、端数を取り、
0.5, 0.05, 0.005などで、5刻みのウェイトになる計算です。
また、ウェイト値の合計が1.0であることを前提に計算しています。

#■　Add(Swap)_sourceWgt_to_targetWgt ウェイトの移動、交換
![04_addWeight.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923088/5c20704b-e50f-fac5-08ae-e26204e87206.png)
SourceBoneのウェイトの値をTargetBoneのウェイトに加算し、SourceBone自身のウェイトは0になります。
これは例えば、上腕（upperarm）と、上腕のねじれ（upperarm_twist）のようなヘルパーボーンがあって、
LODやもろ事情などで、upperarm_twistのボーンを削減するようなときに役に立ちます。
もしくは、指のボーンをなくして、handのみにしたい場合などでしょうか。
ボーンの削減前に、削減後振るはずのボーンにウェイトを移動（加算）しておくので、
ボーンを消した後もウェイトが破綻しません。

交換(swap)はMayaではウェイトを振り間違えた時に使っていました。
twist_01とtwist_02を反対に振ってしまった場合などですね。

#■　delete_unsued_bone_attribute 未使用ボーンの削減
![05_unusedBone.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923088/d123eccb-6648-9613-c03e-cc81df76c4d4.png)
ここだけ少し長いコードになってしまいましたが、
Influenceの削減や、ウェイトの移動などを行ったことで、
参照しなくなったボーンをCapture Attributeから削減しています。

#■　おわり
あとはノードの組み合わせを増やしたり減らしたりして、
必要に応じてツール化もできるのが、Houdiniの魅力かなと思います。

私はまだまだHoudiniの初心者なので、
もし不具合なところや、より良いやり方があればぜひご教示いただければ嬉しいです。
以上になります。