#■ はじめに
Houdini 18.5からKineFXが追加されましたが、このKineFXによりFBXが大幅に扱いやすくなりました。以前はobjファイルでHoudiniと他のDCCツールとのやり取りを行っていましたが、現在のバージョンであればFBXでの運用がよさそうです。ただ、HoudiniでFBXのモデル情報にアクセスする情報があまりないようでしたので、基本的なアクセスや編集の方法をまとめてみました。
FBXの読み込みと書き出し
FBXの読み書きは多くの情報がネットでありますので、とくに迷うことはないかと思いますが、「FBX Character Import」ノードなどで読み込むことができます。objファイルと異なり、FBXに含まれる単位情報も利用できるため、インポート時にモデルのサイズがおかしくなることはありません。
FBXの書き出しは「ROP FBX Character Output」などで行います。「ROP FBX Character Output」ノードでは出力時にジオメトリ情報とレストポーズが必須となり、アニメーション情報は任意となります。
#■ マテリアルへのアクセス
FBXのマテリアル情報はPrimitivesのアトリビュートの「material_override」に格納されています。これをWrangleノードなどでjson形式でデコードすることでマテリアル情報にアクセスすることができます。
注意点としては、「material_override」に格納されている文字列はjson形式とはやや異なるフォーマットで、「"」であるべき箇所が「'」となっているため、置換を行う必要があります。また、WrangleではなくPythonでアクセスする場合は、最後の要素の後の「,」も削除する必要があります。
#■ マテリアルの割り当て
Kine FXでFBXをインポートしたモデルのマテリアルは、「FBX Character Import」などノード内のマテリアルネットワーク(名前はmatnet1)に対してPrimitivesのアトリビュートの「material_override」の情報で書き換えることで各マテリアルの情報を切り替えています。しかし、Labs Map Bakerなどを使用する際に、テクスチャごとに異なるマテリアルで分けたい場合があります。そのような複数のマテリアルを割り当てたい場合は、新たに割り当てる必要があります。
下記のコードはPythonでテクスチャごとにマテリアルを割り当てる例になります。
import os, json
node = hou.pwd()
geo = node.geometry()
contextNode = hou.node("/mat")
shopExists = geo.findPrimAttrib("shop_materialpath")
matOverrideExists = geo.findPrimAttrib("material_override")
nodeType = hou.nodeType(hou.vopNodeTypeCategory(), "principledshader::2.0")
mats = nodeType.instances()
matPaths = []
for mat in mats:
matPaths.append(mat.path())
for prim in geo.iterPrims():
matOverride = prim.attribValue('material_override')
if not matOverride:
continue
matOverride = matOverride[:-2]+'}'
matOverride = json.loads(matOverride.replace("\'", "\""))
texPath = matOverride['basecolor_texture']
fileName = os.path.basename(texPath)
texName = os.path.splitext(fileName)[0]
matPath = "/mat/" + texName
prim.setAttribValue(matOverrideExists, "{}")
if matPath not in matPaths:
mat = contextNode.createNode("principledshader::2.0", texName)
mat.parm("basecolor_useTexture").set(1)
mat.parm("basecolor_texture").set(texPath)
prim.setAttribValue(shopExists, mat.path())
matPaths.append(mat.path())
else:
prim.setAttribValue(shopExists, matPath)
#■ ボーンの編集
ボーンは「FBX Character Import」などでインポートした場合、「Points」にボーンの情報が格納され、「Vertices」で親子関係が定義されます。
また、モデルのボーンの移動や回転を試したい場合は、「Rig Pose」ノードでボーンの姿勢を変更し、「Bone Deform」でスキニング結果を確認することができます。
ボーンのライン化
ボーンの親子関係の構造は、一見PolyLineで繋がって作られているように見えますが、実際には1つ1つのラインは独立しています。そのため、連続したラインとして編集したい場合は、一度プリミティブを削除してPolyLineで繋げることで編集しやすい構造になります。
手始めにプリミティブはDeleteノードで削除しますが、この時に「Points」にあるボーン情報を維持させるために「Keep Points」にチェックを入れます。
次に連続したラインとして扱えるようPolyLineでプリミティブを再構築します。下図のWrangleはボーン名の末尾に親子関係を示す連番がある場合の構築例ですが、新しく追加したアトリビュートの「no」は次のソートの説明で使用します。
「Vertices」に格納されているボーン情報ですが、親子関係順に格納されているとは限りません。Sortノードなどで親子順に並び替えると、ラインを編集するノードで問題が発生しにくくなります。下図の例では、1つ前のWrangleで追加した「no」のアトリビュートを使って並び替えを行っています。
ボーン数の制限
Klabさんの公演で紹介されていましたが、「Capture Correct」ノードでボーンの最大数を設定することができます。スマホなどの低スペック用にリダクションする場合などに使用します。下図のように「Limit Regions」にチェックを入れ、「Maximum Regions」で最大数を設定します。
MayaのTransformはJointへ変換される
これは現在のKine FXでFBXを出力した場合の制約と考えてよいかと思いますが、MayaのTransformはHoudiniからの出力時にJointに強制的に変換されてしまいます(MotionBuilder上ではNullがSkeleton Nodeに変換されます)。Kine FXでFBXの読み込みと書き出しを行うだけでも、以前の情報が全く同じ状態では維持されないことに注意する必要があります。
#■ ウェイトへのアクセス
スキニング用のボーンのウェイト情報は「Points」の「boneCapture」アトリビュートとして格納されています。「boneCapture regn」がボーンのインデックス、「boneCapture w」がウェイト値に該当します。
これらの情報ですが、そのままではアクセスすることができず、「Capture Attribute Unpack」ノードでアンパックすることでアトリビュートにアクセスできるようになります。
また、アンパックすることで「Detail」に「boneCapture_pCaptData」と「boneCapture_pCaptPath」の2つのアトリビュートが追加されます。「boneCapture_regn」で使用されるボーンの配列インデックスは「boneCapture_pCapPath」のリストのインデックスで構成されています。
「boneCapture」の編集後は「Capture Attribute Pack」ノードでパックし直します。なお、foreach内でアンパックした場合は、foreachから抜けると自動的にパックされるようです。
#■ ブレンドシェイプへのアクセス
ブレンドシェイプは「Primitives」にパックされた形で格納されています。まず、編集しやすいよう他のメッシュなどのデータと分離します。「@blendshape_name」が空であればそのデータはブレンドシェイプではありませんので、Splitノードなどで分離しておきます。
次にforeachで要素をPrimitivesに指定し、Unpack後に各ブレンドシェイプにアクセスできるようになります。下図ではUnpackノードとPackノードの中で必要な処理を行います。
なお、ウィエト(boneCapture)と違い、Packノードの後にいくつかやっておく処理があります。
- GroupCreateノードで「_3d_hidden_primitives」の名前でグルーピングする
- VisibilityノードでPrimitivesを非表示にする
- Unpack/PackノードによるPrimitivesのアトリビュート(name/blendshape_channel/blendshape_name/shop_materialpath)が失われてしまうので復旧させる