On this page |
概要 ¶
Copy to Pointsを使用する際に、各コピーのジオメトリにバリエーションを加えたい時があります。 ターゲットポイント上のPointアトリビュートを使ってFor-Eachループ内のコピー生成に影響を与えることで、バリエーションを加えることができます。 詳細は、コピーにバリエーションを加える方法を参照してください。
このチュートリアルでは、ランダムな星のボールを作成します。このエフェクトを実装するには:
-
星形を示したアトリビュートが付いたターゲットポイントを作成します。
-
For-Eachループ内で、球のポイント上にプロシージャルな星形をコピーします。
-
pointエクスプレッションを使って、そのターゲットポイント上のアトリビュートに基づいて、その星形を可変させます。
ソースポイントの作成 ¶
-
シェルフの Create タブにある Sphere を⌃ Ctrlクリックして、球を原点に追加します。
Createツールを⌃ Ctrlクリックすることで、即座にオブジェクトを原点に作成することができます。 ⌃ Ctrlを使わずにアイコンをクリックすると、Houdiniは、あなたがその新しいオブジェクトの位置を指定するまで待ちます。
-
オペレータコントロールツールバー(3Dビューの上にあります)で、 Primitive Type を Polygon に、 Uniform Scale を
0.6
に設定します。 -
ネットワークエディタで、
sphere_object
ノードの名前のところをクリックして、その名前をstarball
に変更します。 -
その
starball
ノードをダブルクリックして、そのジオメトリネットワークの中に入ります。 -
Attribute Createノードを作成し、そのノードを
sphere
ノードに接続します。 -
Attribute Createノードのパラメータエディタで:
-
Name を
divisions
に設定します。 -
Class を“Point”に設定します。
-
Type を“Integer”に設定します。
-
1番目の Value フィールドに以下のエクスプレッションを設定します:
int(rand($PT) * 6) * 2 + 8
これによって、球のポイント上に
divisions
Pointアトリビュートが作成されます。 このAttribute Createノードの$PT
は現行ポイント番号です。このポイント番号をrand関数のシード値として使用することで、ポイント毎に異なる乱数を生成することができます。rand()
の結果(0以上1未満)を6倍にして整数化することで、0から5までのランダムな整数を生成することができます。 さらにそれを2倍にすることで、0から10までの偶数の分割数を常に取得することができます。最低限の星の形のポイント数は8個なので、そこに8を追加して、8から18までの数を取得しています。
-
Tip
Geometry Spreadsheetを使用することで、ノード内のすべてのポイントのアトリビュート値を調べることができます。 ネットワークエディタ内のジオメトリノードを右クリックして、 Spreadsheet を選択します。
プロシージャルな星を作成する ¶
-
まだ
starball
ジオメトリネットワークの中にいたまま、Circleノードを作成します。 -
circle
ノードのパラメータエディタで、 Primitive Type を Polygon に、 Radius を0.2, 0.2
に設定します。
ポリゴンの円を星形に変換するために、1つおきのポイントを含んだグループを作成し、そのグループをトランスフォームさせます。
-
Group by Rangeノードを追加し、それを
circle
ノードに接続します。-
Group を
even
に設定します。 -
Group Type を“Points”に設定します。
-
“Range Filter”を Select 1 of 2 に設定します。
-
-
Transformノードを追加し、それを
grouprange
に接続します。-
1つおきにポイントをトランスフォームさせたいので Group を
even
に設定します。 -
Uniform Scale を
0.5
に設定します。
-
-
transform
ノードのディスプレイフラグをクリックします。circle
ノードを選択して、その Divisions フィールドに色々な値を入れてみることで、そのフィールドが星の形状にどのように影響するのかを確認することができます。 これは星のポイントで起こり得る表示の問題も対処することができます。
ポイントへのコピー ¶
-
Copy to Pointsノードを作成します。
transform
ノード(星の形状)を1番目の入力に接続します。attribcreate
(コピー先の球ポイント)を2番目の入力に接続します。 -
copytopoints
ノードのディスプレイフラグをクリックします。ビューポートでは、そのノードは単に現在の星のジオメトリをそのまま各ポイント上にコピーしているのがわかります。 これがよく行なわれる使い方です。 とはいえ、このチュートリアルでは、球に作成された
divisions
Pointアトリビュートを使って、それぞれの星の分割数を制御したいと思います。 そのため、For-Eachループを使用します。
For-Eachループの追加 ¶
-
⇥ TabメニューからFor-Each Pointを作成します。
Houdiniは、自動的に
foreach_begin
とforeach_end
のノードのペアを作成します。 -
そのBeginノードとEndノードの間にノードを接続していくので、それらのノード間に空きスペースができるようにネットワークエディタ内で引き離します。
-
foreach_end
ノードを選択します。 Iteration Method が“By Pieces or Points”に設定されていることを確認します。これが私たちの求めているメソッドです。要するに、このメソッドは入力内の各ポイントをループで処理します。いくつかのパラメータが以下の設定になっていることを確認します。
-
ブロックがポイントに対してループするように Piece Elements を“Points”に設定します。
-
ブロックがアトリビュートによるピースのグループ化をせずに個々のポイントすべてに対してループするように、 Piece Attribute を無効にします。
-
-
attribcreate
の出力(アトリビュートが追加されたコピー先のポイント)をforeach_begin
ノードに接続します。これは、(アトリビュートが追加された)球のポイントに対してループさせたいことをHoudiniに伝えます。
-
新しくCopy to Pointsノード(
copytopoints2
)を作成します。-
transform
ノードの出力(星のジオメトリ)をcopytopoints2
の 1番目の入力 に接続します。 -
foreach_begin
の出力をcopytopoints2
の 2番目の入力 に接続します。これは、各ポイントをループでCopy to Pointsノードに送ります。 -
copytopoints2
の出力をforeach_end
ノードに接続します。
-
-
foreach_end
のディスプレイフラグをクリックします。再度、星がポイント上にコピーされますが、そこに問題があります。というのも、すべての星がその球の法線が使われずに同じ向きになっています!
(法線とは、ポリゴンフェースの3Dの向きを示したベクトルのことです。)
この理由は、For-Eachループは入力ジオメトリから1個ずつポイント のみ を抽出するので、その球にポイント法線がなかったからです。 そのため、コピーノードは、そのコピーを適切な向きにするのに必要な情報を持っていません。
-
そのポイントの法線を修復するためにNormalノードを作成し、それを
sphere
ノードとattribcreate
ノードの間のワイヤー上にドロップします。そのNormalノードのパラメータエディタで、 Add Normals to を“Points”に設定します。これは、球のポイント上に法線アトリビュートを作成します。これによって、その球のポイント法線によって、そのコピーの向きが変更されます。
それぞれの星にバリエーションを加える ¶
この時点で、やっと本来のCopy to Pointsの出力を再現することができました!しかし、まだループによるコピーのセットアップが完了しただけです。これからコピー毎にジオメトリにバリエーションを加えていきます。
-
circle
ノードを選択します。 -
Divisions フィールドに以下のエクスプレッションを入力します:
point("../foreach_begin1", 0, "divisions", 0)
point
エクスプレッション関数は、以下の引数を受け取ります:point(path_to_geometry_node, point_number, attribute_name, index)
-
path_to_geometry_nodeはFor-Each Beginノードのパスです。コピー先となるポイントは、ループする度にこのパスに格納されていきます。
-
point_numberは 常に0 です。その理由は、ループする度に1個のポイントしか操作しないからです。
-
attribute_nameは読み込みたいPointアトリビュートの名前です。
-
アトリビュートタイプがintegerまたはfloatであれば、indexを
0
のままにすることができます。アトリビュートタイプがコンポーネント(例えば、カラーならR, G, B、ベクトルなら3つの軸)であれば、index
を0
,1
,2
などのように変更してpoint
関数を個々にコールして、各コンポーネントを別々に読み込む必要があります。
-
-
これで、処理されるポイントのPointアトリビュートを使って、ネットワークによるそのポイント上にコピーされるジオメトリの生成方法を制御できるようになりました。それぞれの星の形状は、その球にセットアップしたPointアトリビュートを使って、その星のコーナーの数を決定します。
できました!
完成 ¶
Tip
For-Eachループは、コピーの数が多くなるほど遅くなってしまいます。コピーを高速化するには、そのループをコンパイルブロックで囲んでみてください。