Houdini 19.5 Solaris

カスタムレイアウトブラシ

Layout LOPの挙動をカスタマイズして利用可能なレイアウトブラシデジタルアセットの作成方法。

On this page

概要

Layout LOPノードには、ポイントインスタンスモデル(例えば、木、茂み、岩、建物)をシーン内にインタラクティブに配置可能なブラシモードがあります。 このノードがマウスイベントからどのようにインスタンスを生成するべきなのかは、 ブラシアセット 側で制御します。 SOPネットワークで独自の挙動が定義された独自のブラシアセットを作成することができます。

このブラシの挙動はコンパイルSOPブロックで定義されているので、カーブやポリゴンの操作ノード、ばら撒きノード、WrangleによるVEXコードを含む(コンパイル可能な)SOPのフルパワーを活かすことができます。

ブラシアセットにパラメータインターフェスを加えることができます。 このインターフェースは、ブラシがアクティブな時にLayout UI内に表示されます。 これによって、あなたの使い勝手に合わせてブラシの挙動をカスタマイズすることができます。

ブラシを実装する前に、おそらく以下のテーマを理解している必要があります:

  • コンパイルブロック。ブラシの実装は、(親のLayoutノードから高パフォーマンスでその実装を呼び出せるように)コンパイルブロックの中で行ないます。コンパイルブロック内で使用可能なSOPノードには制限事項があり、SOPノードがクックするエクスプレッションにも制限事項があります。

  • WrangleノードとVEXスニペット。たいていの場合、何かしらの挙動を実装する最も簡単な方法は、Attribute Wrangleを使用してアトリビュートを読み込んで、値を計算し、新しいアトリビュートを書き出すことです。とはいえ、これにはVEXスニペットビルトインのVEX関数に関してある程度の知識が必要になります。

用語

Stroke(ストローク)

ユーザがマウスボタンを押したままマウスを動かしてマウスボタンを離すことです。

Invocation(呼び出し)

ブラシSOPネットワーク内のコンパイルブロックを1回実行することです。 そのコンパイルブロックは、 ストローク 中に何回も呼び出されます。

Tracking Points(トラッキングポイント)

ストローク 中にマウスカーソルからステージ平面/サーフェス上に投影して生成されたポイントのことです。

Model(モデル)

このドキュメントでは、ポイント上にインスタンス化できるUSDモデルのことを Model(モデル) と呼んでいます。 これは、通常ではブラシデジタルアセットノードを指した アセット という単語と混乱を避けるためにそう呼ぶようにしています。

Working Set(ワーキングセット)

ブラシは実質的にLayoutノード用プラグインであり、Layoutステートでマウスクリックやマウスドラッグなどの解釈のされ方をカスタマイズすることができます。 そのLayoutインターフェースの一部として、ユーザは、インスタンス化したいUSDモデルの“Working Set(ワーキングセット)”を構築します。

ブラッシネットワーク内では、このワーキングセットは6番目の入力( Working Set )のポイント一式と各ポイントにマッチした境界ボックスパックプリミティブで表現されます。 各ポイントのポイント番号は、ポイント上にインスタンス化されるモデルの番号に呼応し、他のPointアトリビュートには境界ボックスなどのモデルに関する基本情報を格納します。

ワーキングセット内の様々なモデルをインスタンス化する方法/インスタンス化するかどうかは、ブラシ側で決めます(以下のワーキングセットの使い方を参照)。

新しいカスタムブラシの作り方

To...Do this

新しくブラシアセットを作成する

LayoutノードUI内の Brushes セクションのギアメニューにある New Brush オプションをクリックします。

これは、新しくデジタルアセットを作成するためのダイアログが開きます。 アセットのネームスペース、名前、保存場所を指定することができます。 詳細は、新しくデジタルアセットを作成する方法を参照してください。

このボタンを使って新しくブラシアセットを作成すると、ブラシの実装が簡単にできるように定型ノード、ステッキーノート、定型Pythonコードがそのアセットに取り込まれます。 さらに、その新しいアセットは、Layoutノードで新規ブラシとして自動的に発見されるようにセットアップされます。

ブラシアセットを編集する

ブラシアセットの内部ネットワーク、パラメータインターフェース、ブラシアセットのPythonスクリプトを編集するには、Layout LOPステートのオペレーションツールバーにある“Debug Brush”ボタンを押して、ビューポート内でサンプルストロークを描画することを強く推奨します。 これは、Layout LOPステートに最も似せようとしたSOPネットワークを作成します。 そうすることで、反復処理が大幅に高速化されデバッグが容易になります。 Layout LOP内部のブラシを編集したいのであれば、そのブラシアイコンを右クリックして Edit Network を選択します。

Tip

Layoutノードは、layout_brushというセクション名を含んだアセットを検索して、利用可能なブラシのリストを構築します。 何かしらの理由で、テンプレートのコピーからではなくゼロからブラシアセットを作成したいのであれば、アセットの Extra Files タブにこの名前のセクションを追加することを忘れないでください。

SOPネットワークの中

  • ブラシは、6本の入力と2本の出力を持ったSOPアセットです。ブラシは、新規ポイントを作成したり、既存ポイントを修正/削除することができます。

  • ブラシの中のネットワークには、ユーザがマウスを動かす度に何回も呼び出されるコンパイルブロックが存在します。

  • このコンパイルブロックの入力には、親のLayout LOPからの現行ステートとユーザが実行した内容に関する情報が格納されます。

  • このコンパイルブロックは、ユーザがストロークを開始する前にマウスを動かしただけでも呼び出されます。これによって、ガイドとプレビューを表示させることができます。

    Switch Ifノードは、特定のマウス操作固有の挙動(例えば、ユーザがマウスをドラッグしている時にポイントのみを出力)を制御するのに役立ちます。

  • トランスフォームを表現するレイアウトブラシの規則は、Scatter and Align SOPなどの多くの一般的なSOPから出力されるのと同じでpscaleorientのアトリビュートで表現されています。

    Note

    他のインスタンス系アトリビュートを追加すると、 現在とこれまでの編集されたすべてのポイントpscaleorientのすべてのアトリビュートが上書きされておかしな挙動を招く可能性があります。

  • 独自のPointアトリビュートを出力すると、その編集されたすべてのポイントの結果のインスタンス上にPrimitiveアトリビュートが作成されます。アトリビュートが増えるとパフォーマンスが悪くなってしまうので、あまり大量のアトリビュートを取り込まないように注意してください。

  • ワーキングセットのモデルをポイント上にインスタンス化するために、以下の事を行ないます:

    • ポイントのasset_indexアトリビュートに、インスタンス化したいモデルに呼応した6番目の入力( Working Set )のポイントのポイント番号を設定します。

  • (“New Points”入力または“Existing Points”入力のどれかからの)ポイントを修正するには、以下の事を行ないます:

    • ポイントの位置を設定するには、vector3タイプのP Pointアトリビュートを設定します。

    • ポイント上にインスタンス化されるモデルの向きとスケールを設定するには、その回転とスケールをmatrix3タイプのtransform Pointアトリビュートにエンコードする必要があります。

      Transform SOPを使用すれば、簡単にtransformアトリビュートを設定/編集することができます。 Transofrm SOPをネットワークに追加し、そのノードの Rotate パラメータと Scale パラメータに必要な値を設定し、 Attributes パラメータをtransformに設定してトランスフォームをそのアトリビュートに書き出します。

    • 修正したポイントを1番目の出力に送ります。

      既存のポイントを修正した場合、そのポイントは削除され、それと同じ新しいポイントが次の呼び出し時に1番目の入力( New Points )に追加されます。 そのため、ストロークで編集した既存のポイントは、そのストロークの“New Points”の一部になります。

    Note

    インスタンスをスケール/回転させるには、標準のorientvector4アトリビュートとpscalefloatアトリビュートで エンコードしなければなりません 。 他のインスタンス系アトリビュートを使用すると、スケール/回転が上書きされて不当な効果を招く可能性があります。

  • 既存のポイントを修正しなかった場合、それらのポイントを出力に送らないでください(出力は常に現在のストロークで作成された新しい一連の“New Points”を表現します)。ブラシが既存のポイントに影響を与えなかった場合、その2番目の入力をどこかにまったく接続する必要はありません。

  • 既存のポイントを削除するには、そのポイント上に整数delete Pointアトリビュートを作成し、その値を1に設定します。次に、そのポイントを1番目の出力にマージします。

    現在のストローク(1番目の入力( New Points ))からポイントを削除するには、単にそのポイントを出力に送らなければよいだけです。

入力

ラベル

説明

1. New Points

現在のストローク 中に前回の呼び出しで追加されたすべてのポイント。

これらのポイントを残したいのであれば(つまり、これらのポイント上にモデルをインスタンス化したいのであれば)、これらのポイントを1番目の出力に接続してください。出力に送られなかった1番目の入力のポイントは破棄されます。

2. Existing Points

ブラシで前回のオペレーションで作成されたすべてのポイント。 これらのポイントは、現在シーンに確定されているポイントインスタンスです。

SOPネットワークでは、Pointアトリビュートを変更することで、これらのポイントを修正することができます。 SOPネットワークで2番目の入力( Existing Points )のポイントのアトリビュートを修正すると、親のLayoutノードは、実際に“既存のポイント”のリストのポイントを削除して、(その修正さえた)ポイントを1番目の入力( New Points )に追加します。

既存のポイントを 削除 するには、削除したいポイント上に整数deletePointアトリビュートを作成し、その値を1に設定して、それらのポイントを1番目の出力にマージします。

3. Static Geometry

これは、ユーザがLayoutノードに接続した“コリジョン”ジオメトリです。たいていの場合、アセットの配置先にしたい“地面”ジオメトリを指定します。

追加でポイントを作成する時にこれを使用すると良いでしょう。 例えば、これをScatterの入力として使用することで、地面ジオメトリ上に新しくポイントをばら撒くことができます。 これを次の入力にマージすることで、静的ジオメトリと既存アセットの両方に新しくポイントをばら撒くことができます。

4. Asset Geometry

このノードで作成されたすべてのインスタンスのジオメトリ(つまり、既存のポイント上にインスタンス化されたモデルの出力)。

追加でポイントを作成する際にこれを使用すると良いでしょう。 例えば、これをScatterの入力として使用することで、既存のアセット上に新しくポイントをばら撒くことができます。 これを前の入力にマージすることで、静的ジオメトリと既存アセットの両方に新しくポイントをばら撒くことができます。

5. Stroke

ポリラインプリミティブが格納されます。このポイントは、マウス光線と現行シーンの交点を表現しています。

この入力には、現在の状態に関する情報(例えば、ユーザが⇧ Shiftキーを押しているかどうか)をエンコードしたグローバル(Detail)アトリビュートも含まれています。 それらのアトリビュートを使用することで、ユーザは修飾キーを使ってブラシの挙動を可変させたりカスタマイズすることができます。

  • ストロークは、Layoutノードの入力ジオメトリ、既存のインスタンス、地面に自動的に投影/交差されます(ユーザは、Layoutノードを使用する際に静的ジオメトリ、インスタンス、または両方(デフォルト)のどちらと交差させるのか選択することができます)。

  • 親のLayoutノードは、ユーザがクリックまたはドラッグしている場合にのみスロトークにポイントを追加します。ユーザが単にマウスを動かしている時は、新しくポイントが追加されず、ストロークの最後のポイントのアトリビュートが更新されます。

  • ユーザがドラッグしている間でも、そのマウスポインタからの光線がどこにも当たらなかった場合、親のLayoutノードは、直近の有効なポイントのコピーをストロークに追加します。

ストロークで利用可能なアトリビュートのリストは、以下のストロークのアトリビュートを参照してください。

6. Working Set

Layoutノードのワーキングセット内の各アイテム(インスタンス化されるモデル)を独立ポイントとそのポイントに関連付けられた境界ボックスパックプリミティブとしてエンコードします。

モデルをインスタンス化するには、新しいポイントのasset_indexアトリビュートに、これらのポイントのどれかのポイント番号を設定します。

これらのポイントで利用可能な他のアトリビュートのリストは、以下のワーキングセットのアトリビュートを参照してください。

出力

ラベル

説明

1. Output Points

Invocation(呼び出し)の度に、ここには、インスタンス先となる一連のポイントが格納されます。 ここで出力されたポイントは、次の呼び出し時の1番目の入力( New Points )として渡されます。 これは、SOPでのfor loopsのマージと同様です。

2. Guides

インスタンス出力に対して描画されるガイドジオメトリ。 これによって、ユーザは視覚的なフィードバックが得られます。 例えば、ブラシがマウスポインタから特定の半径内にモデルをばら撒くと、そのばら撒き領域の限界を示したリングのガイドを描画することができます。

ブラシアセットのPythonモジュール内に、onDrawGuides(draw_handle, guide_geo)関数を実装することができます。 Layoutノードは、ビューアハンドルとhou.Geometryオブジェクトを引数としてこの関数をコールして、2番目の出力のガイドジオメトリを表現します。 そして、hou.AdvancedDrawableオブジェクトを使用して、通常のジオメトリで利用できないスタイル(例えば、破線、太いライン、白熱)でガイドを描画することができます。

アセットのPythonモジュール内にonDrawGuides関数が存在しなかった場合、2番目の出力のジオメトリがガイドジオメトリとして直接表示されます。

ストローク入力のアトリビュート

グローバル(Detail)アトリビュート

名前

タイプ

説明

mouse_drag

int

マウスボタンが押されたままかどうか(Trueなら1、Falseなら0)。

mouse_start

int

これがドラッグの開始かどうか(Trueなら1、Falseなら0)。

mouse_locate

int

ユーザがドラッグせずにマウスを動かしているかどうか(Trueなら1、Falseなら0)。

mouse_pick

int

ユーザがクックしたかどうか(Trueなら1、Falseなら0)。

mouse_changed

int

これがドラッグの終了かどうか(Trueなら1、Falseなら0)。

is_left_button_down

int

が押されているかどうか(Trueなら1、Falseなら0)。

is_middle_button_down

int

が押されているかどうか(Trueなら1、Falseなら0)。

is_right_button_down

int

が押されているかどうか(Trueなら1、Falseなら0)。

is_caps_lock

int

Caps Lockキーが押されているかどうか(Trueなら1、Falseなら0)。

is_ctrl_key

int

⌃ Ctrlキー(Macの場合はcommandキー)が押されているかどうか(Trueなら1、Falseなら0)。

is_shift_key

int

⇧ Shiftキーが押されているかどうか(Trueなら1、Falseなら0)。

is_alt_key

int

Altキー(Macの場合はoptionキー)が押されているかどうか(Trueなら1、Falseなら0)。

seed

int

クリック/ストロークの度に変わる番号が格納されますが、ストローク中は同じ値のままです。 これは、ストローク中は値が変わらないランダム値のシードとして使用するのに役立ちます。

screen_to_world_xform

matrix

スクリーン空間からワールド空間にマップする変換マトリックス。 これは、スクリーン空間で動作するブラシを実装する時に役立ちます。

up

vector3

Layout LOPのステージ入力上のupベクトルメタデータを示したベクトル。

ストロークポリライン上のPointアトリビュート

5番目の入力のポリラインは、ユーザによるインタラクティブなストロークを表現しています。 このポリライン上の各ポイントは、ストロークに沿って取得されたサンプルを意味しています。 各ポイントには、サンプリングされた交差に関するデータが格納されたアトリビュートがいくつかあります。

ユーザがビューポート内でストロークを“描画”すると、Layoutノードは光線をスクリーン“に”送信して、ポインタが3D空間内の何に当たっているのか調べます。

デフォルトでは、Layoutノードは、既存のインスタンス、静的ジオメトリ(たいていの場合は“地面”)、XZグランド平面に最も近い交点を調べます。 (Layoutノードを使用する際にユーザ側で静的ジオメトリまたは既存インスタンスとの交点を調べないようにするオプションを設定することができます。)

光線がどこにも交差しなかった場合、それでもネットワークは呼び出されますが、Stroke入力の新しいポイントは単に前の有効なポイントのコピーになるだけです。

名前

タイプ

説明

P

vector3

3D空間の(交差した)位置。

N

vector3

交差したポイントでの法線。

ray_orig

vector3

(マウスポインタのスクリーン座標から算出された)3D空間の交差光線の原点。 これは、スクリーン空間で動作するブラシを作成するのに役立ちます。

ray_dir

vector3

3D空間の交差光線の方向(カメラ投影に準拠してマウスポインタがスクリーンに“向かった”方向)。

mouse_x

int

マウスポインタの水平位置(スクリーンピクセル)。

mouse_y

int

マウスポインタの垂直位置(スクリーンピクセル)。

hit_instance

int

マウスポインタがインスタンスモデル上にあった場合、この値には、2番目の入力( Existing Points )のインスタンスのポイント番号が入ります。

例えば、このアトリビュートの値をチェックして、そのポイントを出力しないようにすることで、ドラッグしたインスタンスを削除するブラシを作成することができます。

または、既存のインスタンスを押したり寄せたりするブラシを作成することもできます。 ストロークをインスタンス上で開始すると、そのストロークの開始ポイントに続くポイントを使用して、そのインスタンスのポイントを移動させることができます。

tablet_angle

float

ストロークをタブレットまたは同様のデバイスを使用して作成した場合のそのタブレットペンの角度。

tablet_pressure

int

ストロークをタブレットまたは同様のデバイスを使用して作成した場合のタブレットペンの筆圧。

ワーキングセットの入力Pointアトリビュート

6番目の入力( Working Set )の各ポイントは、Layoutノードのワーキングセット内の現在のアイテムに呼応しています。

id

int

ポイント番号と同じ。これは、1番目の出力のポイント上に呼応したモデルをインスタンス化するために、そのポイントのasset_indexアトリビュートに設定すべき値です。

bbox_dim

vector

このポイントに呼応したモデルの境界ボックスのサイズ。

bbox_center

vector

境界ボックスの中心。

この境界ボックス系アトリビュートは、インスタンスを配置する時に交差しないようにインスタンスの間隔を空けたり、占有領域や境界ボックスガイドを表示するのに役立ちます。

Note

各ポイントは、同じインデックスのアセット境界ボックスをパックプリミティブとして持っています。

詳細は、ワーキングセットの使い方を参照してください。

マルチストロークなブラシ

  • 通常では、1回のストロークが終了した時のマウスのUpイベントでそのブラシのコンパイルブロックのポイント出力が“確定”されて、Layoutノードのポイントインスタンスデータに統合されます。

  • 必要に応じて、ユーザが複数のストロークを1オペレーションとして作成できるようにブラシを実装することができます。

    例えば、クリック/ドラッグの度にユーザが開始点と繋げてフェンスを閉じない限り(または、ユーザがEnterを押してフェンスを開いたままで抜けない限り)フェンス内に新しいコーナーが作成されるフェンス描画ブラシを実装することができます。

    マルチストローク操作を使用することで、ユーザは矩形を描画することもできます。その場合、1回のストロークで矩形の一辺の長さを定義し、次のドラッグでその一辺に隣接する辺を引っ張り出してその長さを定義します。

  • 現在のオペレーションを現在のストロークの後に続けたいことを親のLayoutノードに伝えるために、1番目の出力にend_stroke Detailアトリビュートを追加して値を0に設定します。

    Layoutノードは、そのアトリビュートが存在することを確認したら、現在のオペレーションをアクティブなままにします。 すると、以降のストロークは、“Existing Points”と同じリストにポイントの追加を継続するようになります。

  • 次に、現在のオペレーションを終了することを親のLayoutノードに伝えるために、1番目の出力yのそのend_stroke Detailアトリビュートの値を1に設定します。

    フェンスの作成を例にすると、Attribute Createノードを作成してend_stroke整数Detailアトリビュートを作成し、そのノードを1番目の出力に接続することになります。 そしてエクスプレッションやAttribute Wrangleノードを使用して、もし現在のストロークが開始点または1回目のストロークの近くにあればそのアトリビュート値を1に、そうでないなら0に設定します。

    Layoutノードは、end_strokeが存在することを確認し、その値が1に設定されていれば、出力を確定します。

  • ユーザはEnter`を押すことでいつでもストロークを終了して現在のオペレーションを確定することができます。

  • マルチストロークなブラシを実装するのは非常に複雑ですが、いくつか役に立つテクニックがあります。

    • 一連のSwitch Ifノードを使用して個々のブランチを切り替えることで、異なるイベントタイプを制御することができます。

    • Invocation(呼び出し)とストロークの間で情報を渡す必要がある場合は、1番目の出力に独自のDetailアトリビュートを設定すると良いでしょう。オペレーションが確定しない限り、その1番目の出力からそのDetailアトリビュートが1番目の入力( New Points )にコピーされるようになります。

      矩形の描画の例では、Detailアトリビュートを使用することで、現在のストロークがオペレーションの 1回目 それとも 2回目 のどちらのストロークなのか追跡することができます。

オペレーションの確定

ユーザがオペレーションを終了した時:

  • Layoutノードは、出力ジオメトリに追加されたすべてのDetaiアトリビュートをクリアします。

    出力ジオメトリ上に作成したDetailアトリビュートは、次の反復の1番目の入力( New Points )のDetailアトリビュートとして利用可能です。 これらのDetailアトリビュートを使用して反復(または、マルチストロークなブラシのストローク)間で情報を渡しても、その情報はオペレーション間では渡りません。

  • Layoutノードは、ブラシから生成されたすべてのプリミティブも念のためにクリアします。

    ポイントクラウドのマージが頻繁に行われるので、プリミティブが呼び出されると、そのプリミティブのマージによってすぐに指数関数的に重くなりHoudiniがロックアップしてしまいます。

パラメータインターフェース

ブラシ用にパラメータインターフェスをデザインすることができます。 そして、そのブラシのコンパイルブロック内でchエクスプレッションを使用してパラメータの値を読み込んで、その値を使ってそのブラシの挙動を変更することができます。

例えば、ユーザがドラッグした時にブラシがばら撒くポイント数を制御することができるDensityパラメータ(内部名がdensity)をブラシアセット上に追加したとします。 そのブラシのコンパイルブロック内で、例えば、Scatter SOPForce Total Count パラメータにch("../density")のエクスプレッションを使用することで、そのDensityパラメータの値をコピーすることができます。

ブラシがLayoutノード内でアクティブになっている時、そのLayoutノードのインターフェースは、パラメータエディタで表示されるものと同じブラシパラメータを表示します。

スクロールホイール

ユーザがスクロールホイールを使ってブラシの挙動を変更できる方法が2つあります。

  • ブラシのパラメータインターフェースに内部名がscrollで始まるパラメータがあれば、ユーザがマウスホイールをスクロールするとそのパラメータ値が増減します(2個以上のパラメータがscrollで始まっている場合、Layoutノードはそれらすべてのパラメータを変更します)。

  • アセットのPythonモジュール内にonMouseWheelEvent(kwargs)関数を実装すれば、ユーザがマウスホイールをスクロールすると、Layoutノードステートがその関数をコールします。

ブラシのサイズを変更する方法

ブラシの半径(または同等のアトリビュート)のサイズ変更の規則は、Attribute Paint SOPやVellumブラシと同様で⌃ Ctrl + ⇧ Shift + です。

ブラシでこれを有効にするには、影響を与えたいパラメータ(s)に対してdrag_resizeタグを追加します。

Edit Last Strokeを無視する方法

デフォルトでは、パラメータを変更すると、ブラシの最後の呼び出しが再適用されます。 これは、たいていのパラメータでは望ましいですが、場合によっては、フォルダなどの整理整頓系パラメータがあったり、ブラシモードを制御するメニューパラメータであっても最後のストロークに変更を加えたくないものもあります。

特定のパラメータ変更によるブラシの呼び出しを無効にするには、そうしたいパラメータに対してlayout_ignoreタグを追加します。

ワーキングセットの使い方

ブラシ作成者のあなたは、ユーザが選んだモデルのワーキングセットの使い方を決めることができます。 ワーキングセット内のアイテムの順番に意味を持たせるのかどうか選択することができます。

  • ワーキングセットのよくある使われる方は、(例えば、シーン内にアイテムをばら撒く時に)ワーキングセットからランダムにアイテムを選択することです。

  • ブラシは、ワーキングセットの順番を利用することができます。例えば、ワーキングセット内の1番目のアイテムをシーンに投入し、そのアイテムを中心に2番目のアイテムのインスタンスをおおまかに円状にばら撒いて、さらにそのインスタンスを中心に3番目のアイテムを円状にばら撒くといったブラシを作成することができます(これは、周辺に岩、枯れ枝などの小さな生態系をもった木々を散乱させるのに役立ちます)。

    アイテムをランダムに配置するブラシの他の例を挙げると、アイテムの順番を利用して、ワーキングセット内の順番が先のアイテムほど確率が高くなるように、各アイテムが選択される確率に影響を与えることができます。

  • 現在のところ、ブラシがワーキングセットの順番に意味をもたせているかどうかをブラシ利用者に自動的に伝える方法がありません。そのため、ブラシのドキュメントにそのことを記載するか、または、ブラシのパラメータインターフェースで制御できるようにする必要があります。

  • 生成されたポイント上に上手くランダムにワーキングセットを配置する方法は、ワーキングセット入力にConnectivity SOPを接続し、ピースアトリビュート名をasset_indexに設定してから、Attrib From Pieces SOPを使用してポイントにピースを割り当てます。

Pythonコールバック

デジタルアセットには、Pythonソースコードを格納するために使用できるセクションが用意されています。 これは、アセットの様々なコールバックで利用できるように共有された便利関数を格納するのに役立つことが多いです。 さらには、もしあればアセットのインタラクティブステートの実装の格納先としても役立ちます。

ブラシアセットに対して、親のLayoutノードはそのアセット内のいくつかの関数をチェックします。

To...Do this

アセットのPythonモジュールを編集する

  1. ブラシアセットのインスタンスを右クリックして、 Edit Type Properties を選択します。

  2. Edit Operator Type Properties ウィンドウ内の Scripts タブをクリックします。

  3. 左側にあるPythonModuleがまだ選択されていなければ、それをクリックします。

  4. 右側では、そのPythonモジュールの内容を編集することができます。

現在のところ、Layoutノードステートは、ブラシアセットのPythonモジュール内に以下の関数が存在すれば、その関数を使用します。

registerGadgets()

Layoutノードステートからコールされて、ガイドに必須のhou.GeometryDrawableオブジェクトを生成します。

名前とhou.drawableGeometryTypeを含んだタプルのリストを返してください。

def registerGadgets():
    return [("line_gadget", hou.drawableGeometryType.Line), ("face_gadget", hou.drawableGeometryType.Face)]

onDrawGuides(kwargs)

Layoutノードステートが再描画を要求された時にこれがコールされます。いくつか重要なkwargsを以下に載せます:

gadgets

文字列とregisterGadgetsで登録されたhou.GeometryDrawableガジェットとのマップ。

draw_handle

ビューハンドル。gadgets引数内のhou.GeometryDrawableガジェットのdraw()メソッドにこれを渡します。

guide_geo

ブラシSOPネットワークのGUIDE_OUT出力に送信されるジオメトリを含んだhou.Geometryオブジェクト。

Note

この引数にNoneを指定することができます。そのため、あなたの関数側で、このNoneをチェックして適切に処理してください。

このオブジェクトを使用することで、ブラシからガイドに情報を渡すことができます。 例えば、テキストDrawableを使用すれば、あなたのブラシが追加したDetailアトリビュートを表示することができます。

def onDrawGuides(kwargs):
    draw_handle = kwargs['draw_handle']
    guide_geo = kwargs['guide_geo']
    line_gadget = kwargs['gadgets']['line_gadget']
    face_gadget = kwargs['gadgets']['face_gadget']

    line_gadget.setGeometry(guide_geo)
    line_gadget.show(True)
    line_gadget.draw(draw_handle)

    face_gadget.setGeometry(guide_geo)
    face_gadget.show(True)
    face_gadget.draw(draw_handle)

onMouseWheelEvent(kwargs)

ユーザがマウスホイールをスクロールした時にコールされます。

def onMouseWheelEvent(self, kwargs):
    # Get the UI device object
    device = kwargs["ui_event"].device()
    scroll_amount = device.mouseWheel()

現在のところ、このAPIは垂直以外の軸のスクロールに対応していません。

返される数値に関する情報は、hou.UIEventDevice.mouseWheelのヘルプを参照してください。

hudTemplate()

これは、このブラシ固有のHUD Infoテンプレート行を指定することができます。 Layoutノードは、これらの行をHUD Infoパネルに挿入します。

この関数は、(トップレベルのテンプレート辞書 ではなくて ) テンプレート行オブジェクトのリスト を返します。 テンプレートフォーマットに関する情報は、HUD Infoパネルを参照してください。

def hudTemplate():
    return [
        {"key": "G", "label": "Change brush shape"},
        {"key": "mousewheel", "label": "Change brush radius"},
        {"key": "LMB", "label": "Scatter instances"},
        {"key": "Shift + LMB", "label": "Smooth instance orientations"},
    ]

hudUpdate()

この関数は、ブラシの変更、または、layout.utils.requestHUDUpdate関数を介して更新が発動された事が発端で、LayoutノードステートがHUDを更新する必要になった時にコールされます。

これは、モデルなどの何かが変更された時にHUD内の値を更新するのに役立ちます。 Fillブラシは、この関数を使用して、アクティブになっているFillモードに応じて異なる情報を表示しています。

def hudTemplate():
    return [{
        'id': 'info',
        'label': ''
    }]

def hudUpdate():
    # パラメータコールバックスクリプトでlayout.utils.requestHUDUpdate()をコールすることで、
    # この関数を発動させることができます。
    # 何のモードがアクティブになっているのか評価して、そのモードに応じて'info'ラベルを更新します。
    import layout.utils
    node = layout.utils.currentBrushNode()
    mode = node.evalParm("mode")

    if mode == 0:
        label = 'Define grid'
    elif mode == 1:
        label = 'Define disk radius'
    elif mode == 2:
        label = 'Draw scatter region'
    else:
        raise ValueError("Invalid brush mode.")

    return  {'info': {'label': label, 'key': 'LMB'}}

radialMenu(kwargs)

これは、ブラシ固有のRadialメニューの内容を指定することができます。

この関数は、スクリプトを使ってRadialメニューを生成する時に指定する種類の辞書を返します。 その構造体と利用可能なキーに関する情報は、そのページを参照してください。

Layoutノードは、1個のキー:nodeを含んだ辞書を渡します。この値はブラシアセットのインスタンスです。 この設定されたパラメータ値は、メニューのスクリプトアクション内で使用することができます。

def radialMenu(kwargs):
    node = kwargs["node"]

    entries = {}
    entries['n'] = {
        'type':'script_action',
        'label':'Reset Radius',
        'script': lambda: node.setParm("radius", 1.0)
    }
    entries['e'] = {
        'type':'script_action',
        'label':'Embiggen Instances',
        'script': lambda: node.setParm("instance_scale", node.evalParm("instance_scale") + 1.0)
    }
    entries['s'] = {
        'type':'script_action',
        'label':'Disembiggen Instances',
        'script': lambda: node.setParm("instance_scale", node.evalParm("instance_scale") - 1.0)
    }
    return entries

スクリーン空間で動作するブラシの作り方

スクリーン空間で動作するブラシの作成を簡単にするために、5番目の入力( Stroke )にscreen_to_world_xform Detailアトリビュートが用意されます。 このトランスフォーム行列は次の計算結果に相当します: viewport.windowToViewportTransform() * viewport.viewportToNDCTransform() * viewport.ndcToCameraTransform() * viewport.cameraToModelTransform() * viewport.modelToGeometryTransform()

これが意味していること言葉で説明すると、ワールド空間のポイントをスクリーン空間にマッピングしています。 しかし、適切なスクリーン空間の位置を取得するには、その結果のベクトルを'w'コンポーネントで除算して非同次化する必要があります。 非同次化すると、xとyのコンポーネントは、スクリーン座標を示し、zコンポーネントは-1から1までのNDC座標の深度(-1がニアクリップ、1がファークリップに相当)を示します。

DeleteブラシやNudgeブラシなどの既存のスクリーン空間ブラシは単にコピーしてから必要に応じて変更することを強く推奨します。

Tipsとメモ

  • 2個以上のアイテムを持つワーキングセットからアセットの割り当てを制御するには、そのワーキングセットをConnectivity SOPに接続して、Pieceアトリビュート名をasset_indexに設定してから、そのConnectivity SOPをAttrib From Pieces SOPの2番目の入力に接続します(インスタンス先のポイントを1番目の入力に接続します)。

  • Wrangleの入力内のポイントの数を取得するには、VEXスニペット内でnpoints(input_num)を使用します。これはWrangleで動作するものの、すべての入力をクックするので、コンパイルSOPsでは通常Spare入力を使用して、そのSpare入力に対してnpointsをコールする必要があります。例えば、npoints(-1)です。コンパイルSOPsを参照してください。

  • コンパイルブロックの外側で、“セットアップ”を実施するノードを作成してから、もう1つCompile Block Startノードをそのコンパイルブロックに“追加引数”として追加して、その“外側”のノードをそのCompile Block Startノードに接続することができます。これらのノードは 1回だけ クックされ、その静的な結果をそのブロック入力からブロック内で利用可能になります。

    例えば、何か複雑なガイドジオメトリをセットアップしたい時に、Invocation中はトランスフォームのみが変わり、ジオメトリ自体が変わらないのであれば、コンパイルブロックの外側でそのジオメトリを作成して、それをコンパイルブロックに接続すれば、Invocationの度にジオメトリが再生成されなく済みます。

Solaris

USD

ジオメトリ

  • SOPをUSDに取り込む方法

    HoudiniがSOPジオメトリをUSDに変換する方法、その工程を制御する方法の詳細。

  • Component Builder

    Component Builderツールは、マテリアル、バリアント、ペイロード、レイヤーをサポートし、SOPからUSDモデルを作成するためのネットワークスニペットを配置します。

レイアウト

  • Editノード

    ビューア内でインタラクティブにPrimsをトランスフォームさせます。物理衝突を使用して、プロップを現実的に配置することができます。

  • Layoutノード

    インスタンス化されたUSDアセットをシーンに取り込むツールが備わっています。個々にコンポーネントを配置したり、カスタマイズ可能なブラシを使って色々な方法でコンポーネントをペイント/スキャッターしたり、既存のインスタンスを編集することができます。

  • カスタムレイアウトブラシ

    Layout LOPの挙動をカスタマイズして利用可能なレイアウトブラシデジタルアセットの作成方法。

シェーディング

  • シェーダフレームワーク

    シェーダノードのUSDプリミティブへの変換を含む、Solarisシェーディングフレームについて説明しています。

  • SolarisでのMaterialXの使い方

    HoudiniにはMaterialXシェーダノードに呼応させたVOPノードが用意されています。これらのノードを使用してシェーダネットワークを構築したり、既存のMaterialXシェーダをインポートすることで、(HoudiniのUSDレンダラーの)KarmaでMaterialXシェーダノードを利用することができます。

  • UDIM

    テクスチャ空間の異なるタイルを、それぞれ別の解像度で、異なるテクスチャファイルにエンコードすることができます。その後、kaiju.exrといったテクスチャファイル名を指定すると、Houdiniがロード時にそのトークンを特定のタイルアドレスに置き換えてくれます。

Karmaレンダリング

チュートリアル