はじめに
Houdini 20.5にてレシピの追加とともにhou.NodeクラスにasDataメソッドが追加されました。
業務で使った経験も踏まえ簡単にまとめてみました。
環境
- Houdini 20.5.598
asDataメソッドについて
これは端的に言うとノードのパラメータ、フラグ、子ノード、ユーザーデータおよび接続状態をJSON形式の辞書型で出力するものになっておりレシピで内部的に使われているものになります。
選択ノードのasDataを実行すると以下のような結果になります。
"asData"という語句が含まれたメソッドはいくつかありますが今回はそのうちのasDataとchildrenAsDataについて扱っていきます。
childrenAsDataは名前の通りその子ノードをJSON形式で出力するものになります。
次の項からこれらが出力するDataの違いについて見ていきます。
パラメータ関連の場合
Sphere SOPを作成し各種パラメータを変更した上でSpare Parameterを二つ追加しました。
{
"type": "sphere",
"parms": {
"type": "polymesh",
"rad": [0.5, 0.5, 0.5],
"t": [0.5, 0.5, 0.5],
"r": [0.5, 0.5, 0.5],
"spare_str": "Hello Worlf",
"spare_vec": [10.0, 10.0, 10.0]
},
"parmtemplates": [
{
"insert_after": "triangularpoles",
"parmtemplates": {
"spare_str": {
"type": "string",
"label": "Spare String",
"tags": {
"script_callback_language": "python"
},
"menu_type": "normal"
},
"spare_vec": {
"type": "float_vector3",
"label": "Spare Vector",
"tags": {
"script_callback_language": "python"
},
"min_value": -1.0,
"max_value": 1.0
}
}
}
]
}
{
"sphere1": {
"type": "sphere",
"position": [0, 0],
"flags": {
"display": true,
"render": true
},
"parms": {
"type": "polymesh",
"rad": [0.5, 0.5, 0.5],
"spare_str": "Hello Worlf",
"spare_vec": [10.0, 10.0, 10.0]
},
"parmtemplates": [
{
"insert_after": "triangularpoles",
"parmtemplates": {
"spare_str": {
"type": "string",
"label": "Spare String",
"tags": {
"script_callback_language": "python"
},
"menu_type": "normal"
},
"spare_vec": {
"type": "float_vector3",
"label": "Spare Vector",
"tags": {
"script_callback_language": "python"
},
"min_value": -1.0,
"max_value": 1.0
}
}
}
]
}
}
普段HOMを触っている方であればHOMと似たような構造なのがすぐにわかると思います。
フラグ、ユーザーデータ関連の場合
Sphere SOPを作成しByPassフラグをオン、Renderフラグをオフ、Templateフラグをオン、ユーザーデータに{ "user_data": "This is User Data!" }を設定、コメントに"This is Comment!"と入力しました。
{
"type": "sphere",
"comment": "This is Comment!",
"user_data": {
"user_data": "This is User Data!"
}
}
{
"sphere1": {
"type": "sphere",
"position": [0, 0],
"flags": {
"bypass": true,
"display": true,
"displaycomment": true,
"render": true,
"template": true
},
"comment": "This is Comment!",
"user_data": {
"user_data": "This is User Data!"
}
}
}
他ノード接続している場合
下図のようなネットワークを作成しswitch1を選択しました。
{
"type": "switch"
}
{
"switch1": {
"type": "switch",
"inputs": [
{
"from": "attribcopy1",
"from_index": 0,
"to_index": 0
},
{
"from": "box2",
"from_index": 0,
"to_index": 1
},
{
"from": "box3",
"from_index": 0,
"to_index": 2
}
],
"position": [3.59, -6.15],
"flags": {
"display": true,
"render": true
}
},
"box1": {
"type": "box",
"inputs": [
{
"from": "sphere1",
"from_index": 0,
"to_index": 0
}
],
"position": [-0.15, -3.18],
"parms": {
"type": "polymesh",
"divrate": [2, 2, 2]
}
},
"box2": {
"type": "box",
"position": [2.18, -3.18],
"parms": {
"type": "polymesh",
"divrate": [2, 2, 2]
}
},
"box3": {
"type": "box",
"position": [4.85, -3.18],
"parms": {
"type": "polymesh",
"divrate": [2, 2, 2]
}
},
"sphere1": {
"type": "sphere",
"position": [-0.15, -1.83],
"parms": {
"type": "polymesh",
"rad": [0.5, 0.5, 0.5]
}
},
"attribcopy1": {
"type": "attribcopy",
"inputs": [
{
"from": "box1",
"from_index": 0,
"to_index": 0
},
{
"from": "box2",
"from_index": 0,
"to_index": 1
}
],
"position": [-0.16, -4.53]
}
}
ネストしている場合
下図のようにSubnet SOPを作成し内部にネットワークを組みました。
{
"type": "subnet",
"user_data": {
"wirestyle": "rounded"
}
}
{
"subnet1": {
"type": "subnet",
"inputs": [
{
"from": "sphere1",
"from_index": 0,
"to_index": 0
}
],
"position": [4.47, -4.79],
"flags": {
"display": true,
"render": true
},
"user_data": {
"wirestyle": "rounded"
},
"children": {
"output0": {
"type": "output",
"inputs": [
{
"from": "merge1",
"from_index": 0,
"to_index": 0
}
],
"position": [0, 1.31],
"flags": {
"display": true,
"render": true
},
"parms": {
"outputidx": 0
}
},
"box1": {
"type": "box",
"position": [1.91, 4.18],
"parms": {
"type": "polymesh",
"divrate": [2, 2, 2]
}
},
"merge1": {
"type": "merge",
"inputs": [
{
"from": "1",
"from_index": 0,
"to_index": 0
},
{
"from": "box1",
"from_index": 0,
"to_index": 1
}
],
"position": [0, 2.65]
},
"1": {
"type": "SubnetIndirectInput",
"position": [0, 6]
}
}
},
"sphere1": {
"type": "sphere",
"position": [4.47, -3.15],
"parms": {
"type": "polymesh",
"rad": [0.5, 0.5, 0.5]
}
}
}
このようにノードに格納されるデータであればasData()メソッドを用いて取得することができますがフラグ、接続情報や位置情報まで含めて取得する必要がある場合はその親ノードのchildrenAsData()メソッドを使う必要があります。
まとめると以下になります。
キーと値のペアがなかった場合はデフォルト値になります。
{
$ノード名: {
"type": $タイプ名,
"parms": {$パラメータ値},
"parmtemplates": [
{$パラメータのテンプレート}
],
"inputs": [
{
"from": $入力ノード名,
"from_index": $入力ノードの何番目の出力か,
"to_index": $何番目の入力か
}
],
"position": [$位置],
"user_data": {$ユーザーデータ},
"children": {
{$子ノード}
},
"flags": {$フラグの状態},
"comment": {$コメント}
}
}
setChildrenFromDataメソッド
データを書き出すメソッドがあれば読み込むメソッドもあり、子ネットワークを辞書から構築するsetChildrenFromData等がそれにあたります。
新規に二つのGeometryオブジェクトノードを作成しJSONファイル経由でノードネットワークの受け渡しを行ってみます。
それぞれのノードにスペアパラメータを追加し下図のようにコールバックを仕込みます。
- 保存側
import json
import hou
node: hou.ObjNode = kwargs["node"]
json_file: str = node.parm("json_file").evalAsString()
data: dict = node.childrenAsData()
with open(json_file, "wt") as f:
json.load(data, f)
- 読込側
import json
import hou
node: hou.ObjNode = kwargs["node"]
json_file: str = node.parm("json_file").evalAsString()
with open(json_file, "rt") as f:
data = json.load(f)
node.setChildrenFromData(data)
適当なネットワークを作成し保存と読み込みを行うと問題なくネットワークが再現できているのがわかるかと思います。
| 保存したネットワーク | 読み込んだネットワーク |
|---|---|
![]() |
![]() |
おわりに
この機能を用いれば
- 他ソフトでHoudiniのネットワークをJSONで書き出しそれをHoudiniで読み込む
- テンプレートとしてJSONファイルをgitで管理
- webアプリケーションとの連携
等いろいろなことに応用できそうです。
みなさんも思い思いの使い方をしてみてください。

