TOPIC38|3Dスキャンデータとの組み合わせと物理シミュレーション
このトピックでは、キットバッシュを用いたさらなるディテールアップ、そして3Dスキャンを用いた実物の3Dモデルとの合成、さらには、Houdini(フーディニ)を用いたスケールの大きな物理シミュレーションまでを解説します。

PLATEAUでミニチュアルック映像を作る前トピックの続きです。ここでは、キットバッシュを用いたさらなるディテールアップ、そして3Dスキャンを用いた実物の3Dモデルとの合成、さらには、Houdini(フーディニ)を用いたスケールの大きな物理シミュレーションまでを解説します。
このトピックの内容は「PLATEAUでミニチュアルック映像を作る/3Dスキャンデータとの組み合わせと物理シミュレーション(2025年度PLATEAU Hands-on動画)」(2025年度PLATEAU Hands-onアーカイブ動画)でも制作方法をハンズオン形式で紹介しています。
【目次】
38.4.3 Gaussian Splattingでスキャンする
38.4.5 Gaussian Splattingで作成した3Dデータを配置する
38.4.6 1つのGaussian Splattingモデルを切り出して配置する
38.5.3 建物周辺の風ともみじ饅頭のシミュレーション(パーティクル版)
38.5.5 ビル周辺の風ともみじ饅頭のシミュレーション(煙版)
38.1 _ このトピックの見どころ
このトピックでは、主に、次の3つの内容を扱います。
① 凹凸付けや3Dモデルを配置することによるディテールアップ
まずは、PLATEAUの建物のディテールアップを目指します。
屋根の縁に凹凸を付けたり、窓をくぼませたりするほか、屋上にアンテナや取水塔などの3Dモデルを配置することでも立体感が増します。
本映像作品では扱う建物数が多く、これらを手作業で行うのは大変です。そこでHoudiniのネットワークエディタである程度自動化し、自動化できない部分やこだわりたい部分だけ手作業で調整する方法で作っていきます。
② 3Dスキャンデータを配置する
PLATEAUの3D都市モデルに、3Dスキャンしたモデルを配置すると、よりリアルな表現ができます。
本映像作品では、市電や原爆ドームのシーンで、実際の3Dスキャンデータを用いています。また木々や道路、地面にも、一部、3Dスキャンしたデータを使用しています。
今回は、3Dスキャンモデルの作成に、レーザー光を用いた「LiDARスキャン」と、数百枚の写真から画像処理技術を用いて点群データを作る「Gaussian Splatting法」の2種類の手法を使いました。それぞれの方法について解説します。

③ 物理シミュレーションの実現
本映像作品では、大量のレモンがビルから吹き出したり、ビル周辺に風が吹いて、もみじ饅頭が流れてきたりするシーンがあります。これらは、Houdiniの物理シミュレーション機能で表現しています。その方法を紹介します。

38.2 _ 選択している箇所のテクスチャを表示する
前トピックでは、本来はmaterial_overrideアトリビュートに格納されているテクスチャ情報をtex_pathという名前のカスタムなアトリビュートにコピーして、元のmaterial_overrideアトリビュートを削除することで、ビューポートではテクスチャを読み込まず、軽快に作業できるようにしました。
しかしディテールを調整するときは、ビューポート上でも、部分的にテクスチャを表示しながら確認したいものです。次のような一連のノードを作ると、それを実現できます。
【手順】選択したジオメトリだけテクスチャを表示する仕組みを作る
[1]Blastノードを追加する
ネットワークエディタ上でBlastノードを追加し、建物出力の末尾に追加します。Blastノードは、ビューポートでインタラクティブに選択したジオメトリもしくは選択しなかったジオメトリを削除できるノードです。

[2]選択したところ以外を削除する
ビューポート上で見たいところだけを選択し、[Enter]キーを押します。すると、選択範囲が消えます。[Delete Non Selected]にチェックを付けることで選択が反転し、選択したところだけが残るようになります。


[3]Labs Quick Materialノードを追加する
この段階ではマテリアルが設定されていません。この後ろにLabs Quick Materialノードを追加することで、PBRマテリアルを構成します。


[4]Attribute Wrangleノードを追加する
Attribute Wrangleノードを追加し、次のコードを入力します。
s@material_override = "{'basecolor_texture':'" + s@tex_path + "'}"; 【メモ】
このコードは、material_overrideアトリビュートの値を「{'basecolor_texture':tex_pathアトリビュートの値}」として設定する文です。この文が実行されることで、tex_pathアトリビュートにあらかじめ保存しておいた(方法はTOPIC37「テクスチャ情報を待避して、ビューポートで読み込まれないようにする」を参照)テクスチャのパスが、元のmaterial_overrideアトリビュートに代入されます。そうすることで、テクスチャが表示されるようになります。
【メモ】
Geometry Spreadsheetで確認すると、material_overrideにテクスチャのパス名が設定されていることがわかります。

[5]作業のためにアセットとしてまとめる
こうした仕組みは使う場面が多いため、アセットとしてまとめておきます。手順[3]で追加したLabs Quick Materialと手順[4]で追加したAttribute Wrangleをマウスで選択してから、右上のsubnetwork アイコンをクリックします。
すると、この2つのノードがアセットとしてまとまるので、適当な名前に変更します。ここでは「display_texture」としました。
【メモ】
ネットワークビューで[C]キーを押すとカラー一覧が表示され、まとめたときのdisplay_textureアセットのアイコンの色を、わかりやすく変えることもできます。


38.3 _ 屋根をディテールアップする
事前準備ができたところで、作業を進めていきましょう。まずは、屋根のディテールアップから始めます。
38.3.1 _ 1つの建物だけを選択する
ディテールアップは、建物を1つずつ分離して処理します。Splitノードを追加して、「選択した建物」と「それ以外」に分けます。
【手順】1つの建物だけを選択する
[1]Splitノードを追加する
作成したアセットの下に、Splitノードを追加します。

[2]編集したい建物を選択する
編集したい建物をビューポート上で選択します。すると、「選択した建物」と「選択していない建物」に分離できます。選択した建物はSplitノードの左下側から、選択していない建物はSplitノードの右下側から、それぞれ出力されます。
以下では、この切り分けた建物側(左下側)について、ディテールアップの操作をしていきます。

38.3.2 _ 重複点をまとめる
続いてポリゴンをカットして押し出す作業をしていくのですが、重複点が1つにまとまっていないため、このままカットして押し出すと、面が切れてしまいます。そこで前段階として、Fuseノードを通すことで、重複点をまとめます。

38.3.3 _ 屋根をカットして押し出す(簡易版)
次に、屋根をカットして押し出すことで、ディテールアップしていきます。
この方法は、ひとつひとつの屋根に対して手作業で行うため、今回の作例のように数が多い場合、作業量が多くなります。ある程度、自動で押し出す方法については、「38.3.5 屋上の凹凸を自動で作る」で解説します。
■ ポリゴンをカットする基本手順
ポリゴンをカットするには、PolySplitノードを使います。次の手順でPolySplitノードを作ります。
【手順】PolySplitノードを作ってポリゴンをカットする
[1]ホイールメニューから[Model]を選択する
ビューポート上でキーボードの[C]キーを押すと、ホイールメニューが表示されます。[C]キーを押したまま、上方向にある[Model]をクリックします。

[2]Polygonsを選択する
さらにホイールが表示されるので、([C]キーを押したまま)上方向にある[Polygons]をクリックします。

[3]PolySplitを選択する
次も同様にホイールが表示されるので、([C]キーを押したまま)右上の[PolySplit]を選択します。

[4]PolySplitノードが追加された
[C]キーを離すと、PolySplitノードが追加されます。

■ 屋上に凹凸を付ける
作ったPolySplitノードを使って、実際に、屋上に凹凸を付けていきます。凹凸は部分的に押し出すことで作ります。PolyExtrudeノードを使います。
【手順】屋上に凹凸を付ける
[1]凹ませる部分をカットする
PolySplitノードを選択し、マウスで切り取りポイントをクリックしながら追加することで、凹ませたい部分をカットしていきます。建物の形状にも依りますが、ほとんどの場合、1つのPolySplitノードではカットしきれないので、何度か操作を繰り返して、カットします。

[2]PolyExtrudeノードを作る
押し出したいPolySplitノード(何度か操作を繰り返したときは、その末端のPolySplitノード)をクリックして選択してから[C]キーを押し、ホイールメニューの上の[Model]を選択します。さらに([C]キーを押したまま)[Polygons]を選択します。そしてさらに([C]キーを押したまま)[PolyExtrude]を選択します。
そして[C]キーを離すと、PolyExtrudeノードが追加されます。




[3]押し出し量を決める
マウスでドラッグ操作、もしくは、Distanceパラメータを操作して、押し出し量を調整します。

[4]同様の操作でディテールアップする
この操作を繰り返して、ディテールアップします。例えば、屋上のテクスチャで四角いところがあれば、それを切り出して、上方向に押し出すなどです。
具体的な操作については、チュートリアル動画を参照してください。

↓

■ 押し出した部分のテクスチャを調整する
押し出した側面には、テクスチャが貼られていないため、黒くなります。これはuvが設定されていないのが理由です。そこで押し出す前の状態(Fuseノードの直後)からuvを引っ張ってくるよう、次の操作をして修正します。

【手順】押し出した部分にuvを貼る
[1]UV Transferノードを追加する
出力の最後にUV Transferノードを追加し、左側の入力に接続します。

[2]Fuseノードと接続する
もう片方の入力は、Fuseノードの出力と接続します。

[3]uvが設定される
押し出した部分にもuvが設定され、テクスチャが表示されるようになります。

■ マージする
最後に、ここまで作成してきた建物を、Split前の部分とマージします。
【手順】ディテールアップ後の建物をマージする
[1]Mergeノードを作成する
Mergeノードを作成します。

[2]対象の建物以外とマージする
Splitで分けた、対象建物以外の出力(右下)とマージします。

[3]ディテールアップ完了
編集した建物とそうでない部分がマージされました。

38.3.4 _ キットバッシュでディテールを出す(簡易版)
次に、屋根にさまざまな3Dモデルを配置して、ディテールを出していきます。いわゆる、キットバッシュを行っていきます。
なおこの方法は、自動で配置するものの、3Dモデルの向きが適切ではなかったり、屋根からはみ出して配置されたりします。そうした問題を解決する方法については、「38.3.6 屋根の向きに揃えて3Dモデルを配置する」で解説します。
■ 屋根の部分だけを切り出す
まずは、屋根の部分だけを切り出します。屋根は上向きなので、面の方向で判別できます。
【手順】屋根の部分だけを切り出す
[1]Deleteノードを接続する
まずは切り出すために、Deleteノードを接続します。

[2]屋根だけを切り出す
屋根は上方向を向いているので、配置したDeleteノードを次のように設定することで、屋根だけを切り出せます。
[Normal]タブ
・[Enable]にチェック
・[Direction]を「0, 1, 0」に設定
・[Spread Angle]を「0」に設定
[Operation]を[Delete Non-Selected]に設定

[3]屋根だけが切り出された
この設定をすることで、屋根だけが切り出されます。

屋根の上にまばらに3Dモデルを配置する(簡易的な方法)
こうして切り出した屋根の上に、アンテナや貯水槽などの3Dモデルを配置していきます。手作業でひとつひとつ配置するのはたいへんなので、ランダムなポイントを配置できるScatterノードを使ってオブジェクトを配置するポイントを作り、その場所に配置するようにします。
【メモ】
下記に解説する方法では、配置する3Dモデルの向きが屋根の辺と同じ向きにならず、斜めに向くこともあり不自然です。また、建物からはみ出ることもあります。これらを修正する方法については、「38.3.6 オブジェクトの自動配置を実現する」であらためて説明します。
【手順】屋根の上にまばらに3Dモデルを配置する
[1]Scatterノードを配置する
Deleteノードの下にScatterノードを配置します。すると、屋根の部分にランダムなポイントが配置されます。

[2]ポイントの数を調整する
以下の手順では、このポイントに対して、ディテールアップのための3Dモデルを配置していきます。そこで適度な数になるよう、Force Total Countパラメータでポイントの密度を調整します。

[3]Copy to Pointsノードを配置する
Copy To Pointsノードを配置し、右側の入力にScatterノードの出力を接続します。

[4]配置する3Dモデルを用意する
このポイントに対して各種3Dモデルを配置していきます。あらかじめ、配置したい3DモデルをOBJ形式などで用意しておき、Labs OBJ Importerノードを使って、オブジェクトとして読みます。今回は、6種類の3Dモデルを用いました。

[5]スケールを調整してpackする
今回は、既存のキットバッシュ用3Dモデルセットを用いました。既製品であり、PLATEAUのモデルとはスケールが合わないので、Transformノードを接続し、[Uniform Scale]パラメータでサイズを調整します。さらに、Packノードを使ってpackします。するとデータがpackされ、多くのインスタンスを作ったときのメモリの消費量を抑えられます。


[6]オブジェクトに対してユニークなIDを付ける
読み込んだ複数のオブジェクトをランダムな種類で配置するため、それぞれのオブジェクトに対して、0、1、2、という連番を付けます。そのためには、Attribute Wrangleを接続し、次の式を入力します。
i@variant = 0; ここではvariantという名前のアトリビュートに「0」を設定しています。わかりやすくするため、配置したAttribute Wrangleは、set_variantという名前に変更しました。
1つ設定したら、これらをコピーして、残りのオブジェクトに対しても操作します。設定する値は左から、0、1、2、・・・のようにします。
最後に、これらをMergeノードでひとつにまとめます。



[7]Scatterで生成した点に対してランダムな番号を生成する
今回は、オブジェクトが6種類あり、それぞれvariantアトリビュートを0~5に設定しています。そこでScatterノードで作成したポイントにも、0~5までのランダムなvariantアトリビュートを設定し、合致する種類のオブジェクトを配置するようにしていきます。
それに先立ち、まずは、Scatterノードで作成したポイントに、0~5までのランダムな値をvariantアトリビュートとして設定します。そのためには、Attribute Randomizeノードを配置し、Attribute Nameに「variant」と入力、Min Valueに「0」、Max Valueに「5」を設定します。

[8]Copy To Pointsでvariantの値が同じものとマッピングする
先ほどのCopy To Pointsノードの左側に、配置するオブジェクト群のMerge出力を接続します。
そして[Piece Attribute]にチェックを付け、「variant」と入力します。そうすることで、variantアトリビュートの値が合致するオブジェクトが配置されるようになります。
ただしAttribute Randomizeノードで設定したvariantアトリビュートがfloat型であるのに対して、オブジェクト側でAttribute Wrangleノードで設定したvariantアトリビュートはint型(32-bit integer)であるため、このままだと型が一致せずにマッチしません。そこでAttribute Randomizeノードの下にAttribute Castノードを挿入し、int型に変換します。具体的には、[Attributes]パラメータに「variant」、[Precision]パラメータに「32-bit integer」を選択します。



[9]オブジェクトが配置された
以上で完了です。ポイントに対して、ランダムなオブジェクトが配置されているのがわかります。

[10]オブジェクトの向きを調整する
よく見るとわかりますが、配置されたオブジェクトの向きが正しくありません。そこでTransformオブジェクトを追加し、Rotateパラメータで90度回転するように設定します。

[11]作業結果をマージする
最後にMergeノードを作って、設置したオブジェクトと、元のオブジェクトとをマージします。
これでビルの上にアンテナや取水塔などを配置できました。


38.3.5 _ 屋上の凹凸を自動で作る
さて、「38.3.3 屋根をカットして押し出す」で紹介した、屋根の凹凸をひとつずつ作る方法は、今回の作例のように建物数が多い場合は、現実的ではありません。そこで、屋根の凹凸を自動で作る方法を紹介します。本映像制作では、実際に、この方法を用いて作りました。
■ 建物ごとにループする
屋根を自動で処理するには、建物ひとつずつループ処理していきます。まずは、その仕組みを作ります。
【手順】建物ごとにループできるようにする
[1]重複点をひとつにまとめる
まずはFuseノードを使って、重複点をひとつにまとめます。

[2]Connectivityノードを作る
Connectivityノードを取り付けます。そして[Connectivity Type]を[Primitive]に変更します。すると建物ごとにユニークな番号が設定されたclassアトリビュートが付与され、以降の行程でループ処理できるようになります(アトリビュート名はAttributeパラメータで変更できます)。
Attributeパラメータの右側のアイコンをクリックすると、ビューポート上で、classアトリビュートの値が、色分けして表示されます。この結果から、建物ごとに異なる値が設定されていることを目視で確認できます(Geometry Spreadsheetを開けば、値としても確認できます)。


■ 屋根の部分だけ取り出す
今回は、屋上の部分を加工したいので、屋根の部分だけ取り出します。
【手順】屋根の部分だけを取り出す
[1]面の向きでグループ化してSplitする
「38.3.3 屋根をカットして押し出す」で説明した手順と同様に、面の向きでグループ化して、Splitノードに入れます。
まずは、Group Createノードを追加します。そして[Group Name]には、グループ化の名前として「roof」と入力します。そして[Base Group]のチェックを外し、[Keep by Normals]を[Enable]とします。そして、[Direction](向き)を「0, 1, 0」とします。こうすることで、面の向きが「0, 1, 0」の方向(上向きの面)の場合、roofグループが1に設定されるようになります。
そしてSplitノードを作って、その出力を接続します。

[2]屋根だけを取り出す
Splitノードの[Group]を「roof」にすることで、屋根だけを取り出します。

■ 面積が小さい部分をディテールアップの対象から外す
PLATEAUの建物には、屋根が小さいものも多くあります。小さな屋根に凹凸を付けても、あまり効果的ではないため、そうした屋根を除外します。
【手順】面積が小さい部分をディテールアップの対象から外す
[1]面積を求める
Measureノードを配置し、[Accumulate]パラメータを[Per Piece]に変更します。すると、面ごとの面積がareaアトリビュートに設定されます。面積の大きさは、色分けして表示されます。

[2]ディテールアップの対象にするか否かの閾値を設定する
areaアトリビュートの大きさを基準にして、ディテールアップするか否かを調整します。
まずは、Attribute Remapノードを配置して接続し、[Class]パラメータを[Primitive]に選択します。そして、「Original Name」に「area」と入力します。[New Name]の右側のアイコンをクリックすると、先ほどと同様に色分けして表示されます。最初は、全部赤で表示されています。
【メモ】
ビューポートでマテリアルを表示しているとテクスチャが色を消してしまいわかりにくいので、色分け確認するときは、マテリアル表示はオフにしておいてください。
このareaアトリビュートの値に基づき、「ディテールアップする場合は1」「そうでないときは0」に出力されるように調整(リマップ)します。そのためには、[Compute Range]をクリックします。すると、現在の最小値と最大値が、Input Min/Output Min、Output Min/Output Maxに設定されるので、Output Minは0、Output Maxを1に設定します。
この変更に伴い、ビューポートの色分けが変わります。[Remap]のところをマウスで調整して、「ディテールアップの対象としたい屋根が、値1に相当する赤色」になるように調整します。



[3]ディテールアップの対象にするか否かで処理を分ける
今設定したareaアトリビュートの値によって、ディテールアップの対象にするかどうかを分岐します。
Splitノードを配置し、Groupに「@area > 0」と入力します。これによって、areaの値が0よりも大きいかどうかで分岐するようになります。

■ 屋根を押し出す
こうした分岐した対象の屋根に対して、ループ処理で屋根を押し出していきます。
【手順】屋根を押し出す
[1]For-Each Connected Pieceを配置する
For-Each Connected Pieceを配置します。すると、Connectivity、Begin、Endが作られるので、先ほどのSplitの下に接続します。


[2]作業のためにループ処理の1つずつを表示する
作業のため、ビューポートにループ処理の1つずつを表示できるようにします。そのためには、Endノードの[Single Pass]にチェックを付けます。そうすることで、スライダーを動かして、1枚ずつ見ることができるようになります。
そしてビューポートでマテリアルを表示して、貼られたテクスチャを見ながら作業できるようにします。


[3]PolyExtrudeノードで縁の分だけ小さくする
PolyExtrudeノードを追加します。そして[Inset]パラメータを調整して、縁の部分だけ、一回り小さくします。

[4]uvを調整する
ビューポートでuvを表示して確認すると、屋根を小さくしたことによって、uvがズレてしまっているのがわかるので、それを調整します。
調整するには、Labs UV Transferノードを作成し、元のuvを適用するようにします。

[5]縁以外を押し下げる
縁以外を押し下げます。まずは、押し下げるために、PolyExtrudeをもうひとつ配置します。
そして先ほどの1つめのPolyExtrudeで[Output Side]にチェックを付け、[Side Group]に「extrudeSide」と入力します。すると、一回り小さくしたオブジェクトの側面がextrudeSideという名前でグループ化されます。
そして2つめのPolyExtrudeの[Group]の部分に「* ^extrudeSide」と入力します。この式は、「全体からextrudeSideを除外する」、言い換えると、extrudeSide以外、つまり、縁以外を押し下げるという意味になります。ビューポートで実際に見ながら、Distanceパラメータで押し下げる量を調整します。




[8]Single Passを外す
以上で、設定が終わりました。Endノードの[Single Pass]のチェックを外して、すべてを対象にすると、対象としたすべての屋根が同じように、縁以外が押し下げられていることがわかります。

[9]伸びすぎたオブジェクトを修正する
ビューポートでよくよく確認すると、この処理によって、横に伸びすぎたオブジェクトが存在することがわかります。こうしたものは選択して、Deleteキーを押すことで、手作業で削除していきます。
ただし削除すると、その部分に穴が空きます。空いた部分は、キーボードの[3]キーを押してポイントを選択し、[Tab]キーを押して、「Polycap」を選択することで埋めます。その結果、uvがおかしくなった場合は、UV Transferを使って、処理前のuvを適用します。
これらの微調整については、チュートリアル動画を参照してください。



[10]マージして完成
Mergeノードを使って、編集対象外にしていたオブジェクトとマージして完成です。

38.3.6 _ 屋根の方向と合わせて3Dモデルを配置する
次に屋根に並べた3Dモデルの不具合を直していきます。
「38.3.4 屋根に3Dモデルを配置してディテールアップする」で説明した方法で実際に配置するとわかりますが、配置したアセットが屋根からはみ出ていたり、屋根に対して斜めに配置されていたりします。こうしたことがないように向きをそろえて、はみ出ないようにします。

■ 対象とする屋根を切り出す
まずは、対象とする屋根を切り出すところからはじめていきます。
【手順】屋根を切り出す
[1]Nullノードを付ける
作業をわかりやすくするため、Nullノードを配置します。

[2]屋根だけを取り出す
Deleteノードを追加して、[Operations]に[Delete Non Selected]を選択、Directionに「0, 1, 0」を設定することで、上方向を向いている面――すなわち屋根だけを取り出します。

[3]縁を取り除く
「38.3.5 屋上の凹凸を自動で作る」では、PolyExtrudeノードを使って屋根に縁を付けましたが、上方向を向いている面を取り出したとき、この縁も含まれています。そこで、もうひとつDeleteノードをつなげて、この縁を削除します。縁にはextrudeSideグループを設定しているので、[Group]パラメータに「extrudeSide」を設定することで削除できます。

■ 屋根をひとつずつ処理するループを作る
こうして選択した屋根を、ひとつずつループ処理していきます。
【手順】屋根をループ処理する
[1]For-Each Connected Pieceを配置する
For-Each Connected Pieceを配置します。すると、Connectivity、Begin、Endが作られるので、先ほどのDeleteの下に接続します。

[2]そのうちの1つを選んで作業する
最終的にはループ処理しますが、そのうちのひとつの屋根に対してビューポートで確認しながら作業するほうがやりやすいので、いったん、Endノードの[SinglePass]にチェックを付けて、そのうちのひとつの屋根だけにします。このときスライダーで、作業しやすい屋根を選ぶと、以降の操作がしやすいです。

■ 配置するポイントをオブジェクトサイズに応じて限定する
次に、Scatterノードを使って屋根の面にポイントを作り、そこにオブジェクトを配置していくのですが、このときオブジェクトサイズに基づいた内枠内(図中の点線内)に限れば、屋根からはみ出ることはありません。そこでScatterでポイントを作成したあと、この条件を満たさないポイント(図中の点線外)を除外する処理を加えます。
【メモ】
もしオブジェクト同士が重なることも防ぎたいのなら、Fuseノードを使って、近い点をまとめる方法をとるとよいでしょう。

【手順】屋根からはみ出ないように配置する
[1]Scatterノードを配置する
ループの内部にScatterノードを配置します。

[2]縁だけのグループを作る
Groupノードを作り、次の操作をします。すると、縁の部分だけがedgeグループとしてまとまります。
・Group Nameを「edge」にする
・Group Typeを「Edge」にする
・Base Groupの[Enable]のチェックを外す
・Include by Edgesの[Enable]にチェックを付ける
・[Unshared Edges]にチェックを付ける

[3]ポリゴンをラインに変換する
Convert Lineノードを接続します。するとポリゴンがラインに変換されます。

[4]縁だけを取り出す
Dissolveノードを配置し、Groupに「edge」と入力、[Operation]で[Dissolve Non Selected]を選択します。そうするとedgeグループ以外が消え、縁だけのラインが残ります。

[5]ポイントを縁に投影する
Scatterの出力とDissolveの出力をRayノードで接続します。そしてRayノードの[Method]を[Minimum Distance]にすると、Scatterが出力するポイントがDissolveの出力の縁の最も近いところに投影されます。



[6]縁との距離を測る
投影したポイントと投影前のポイントの距離を測ります。Attribute Wrangleノードを配置して、下記の式を入力します。この式によって、それぞれのポイントの距離がdistアトリビュートに設定されます。
f@dist = distance(@P, point(1, "P", @ptnum)); distアトリビュートの左側のスライダーをクリックして色分けして表示すると、縁から近いところ(距離distが0に近い)は青色、遠いところは赤色で表示されます。



[7]オブジェクトのスケールを決める
このポイントにオブジェクトを配置していきます。オブジェクトのサイズは同じではなく、ランダムにしたいと思います。そこで、Attribute Randomizeノードを使って、ランダムなスケール値を発生させます。
ここでは、Attribute Nameに「pscale」、Dimensionsを「1」、Min Valueに「1」、Max Valueに「3」を設定しました。これにより、pscaleアトリビュートには、1から3までのランダムな値が設定されます。これを以下では、配置するオブジェクトのスケールとします。

[8]オブジェクトが屋根からはみ出てしまうポイントを削除する
Attribute Wrangleノードを使って、オブジェクトのサイズや縁までの距離を勘案し、配置したときに縁からはみ出てしまうポイントを削除します。そのためには、次の式を入力します。
float obj_dist = f@pscale * 0.5
if(obj_dist>f@dist)removepoint(0, @ptnum); この式は、縁からの距離がオブジェクトサイズの半分以下のときは、そのポイントを削除するものです。
ビューポートで確認すると、縁に近いポイントが削除されてなくなるのがわかります。


[9]実際のオブジェクトをインスタンス化する
すでに説明した「38.3.4 屋根にアセットを配置してディテールアップする」のときと同様に、Labs OBJ Importerノードを使って読み込み、Attribute Wrangleノードで番号を付けあとにMergeノードでまとめた配置するオブジェクト一式をコピーして接続し、これらのポイントにインスタンス化します。
サイズが大きすぎるので、オブジェクトのサイズやポイントの数を調整します(サイズやポイントを調整する様子については、動画を参照してください)。



■ 適切な向きにする
最後にオブジェクトの向きを屋根と同じ向きにそろえます。
【手順】オブジェクトの向きを屋根と同じにする
[1]方向ベクトルを作る
Dissolveノードの下にUnique PointsノードとOrientation along Curveノードを追加します。そうすると、曲線に沿った方向ベクトルを作れます。ここでは、Y Axisに「up」、Tangent(Z Axis)に法線ベクトルを意味する「N」を設定しています。この方向は、ビューポートで確認できます。
以下では、この「N」を方向として扱います。


[2]Rayするときに方向アトリビュートを参照する
Rayノードの[Point Attributes]に「* N」と入力します。すると、Pointに関するすべてのアトリビュートとNアトリビュートを参照できるようになります。
Nullを仮置きしてビューポートで確認すると、ポイントが縁の方向を持っていることがわかります。


[3]Scatterが出力するポイントに反映させる
このNをScatterが出力するポイントに反映するため、先ほど配置したひとつめのAttribute Wrangleの式を次のように変更します。これでポイントに対して、Nアトリビュートがコピーされます。ここではy方向を0にし、念のため、normalize関数を使って、単位ベクトル(長さが1のベクトル)にしています。
ビューポートで確認すると、縁の方向を向いていることがわかります。
f@dist = distance(@P, point(1, "P", @ptnum));
@N = point(1, "N", @ptnum);
@N.y = 0;
@N = normalize(@N) 

[4]インスタンス化するときに方向を合わせる
以上で完成です。正しい向きを向くようになります。ただしこれまでの工程では、オブジェクトを90度回転させているため、元のオブジェクトの回転をしないよう、Rotateを「0」に設定します。
あとはポイント数を調整し、マージして完成です。


38.4 _ 3Dスキャンと組み合わせてディテールアップする
最近は、スマートフォンを使って手軽に3Dスキャンできるようになりました。PLATEAUと、こうした3Dスキャンしたモデルを組み合わせると、よりディテールアップします。
38.4.1 _ 3Dスキャンの技術
3Dスキャンには、主に、レーザー光を用いて測定する方法と、角度を変えて写したたくさんの写真を画像処理することで生成する方法の2種類があります。今回の作例では、次の2つの方法でスキャンして、3Dモデルを作りました。
① LiDARスキャン
レーザー光を用いたスキャンです。ポリゴンモデルを作成します。今回の作例では、もみじ饅頭やお好み焼きなど、小物をスキャンするのに用いました。撮影はiPhone、iOSアプリケーションのPolycamを使ってスキャンしました。
② Gaussian Splatting
角度を変えて写したたくさんの写真から3Dモデルを作る手法のひとつです。画像処理によるスキャンです。Gaussian Splattingは、3D Gaussianと呼ばれる、ガウス分布に基づいて中心から離れるほどぼやけている楕円形状の集合で3Dを表現します。今回の作例では、市電や原爆ドームなど、現地にあるものを、角度を変えてたくさん撮影し、Postshotというソフトウェアを使って、3Dモデルを生成しました。
なお、Gaussian Splattingで作られた3Dモデルは、3D Gaussianの集合で描画するのが正しいやり方ですが、今回の作例では、簡易的に、3D Gaussianではなく球で代替して表現しています。
38.4.2 _ LiDARスキャンをする
まずは、LiDARスキャンを使って3Dモデルを作る方法から説明します。
iPhoneなら、LiDARスキャンは簡単です。App StoreからPolycamというアプリをインストールして、指示とおりに操作するだけです。生成したデータは、Webから確認できます。
本作品では、お好み焼きやもみじ饅頭など室内で撮影したもののほか、広島市内の交差点などもLiDARスキャンしたものを用いています。
Web画面でダウンロード操作すると、各種形式でダウンロードできます。今回は、OBJ形式としてダウンロードしました。




38.4.3 _ Gaussian Splattingでスキャンする
Gaussian Splattingを用いた3Dスキャンでは、「Postshot」というソフトウェアを用いました。
角度を変えながら、全体像が写ったたくさんの写真(400~600枚)をカメラで撮影して、Postshotにドラッグ&ドロップしてインポートします。すると、自動で処理が始まります。数分待つと、3Dデータが浮かび上がってきます。
処理が終わったら、[File]メニューから[Export Scene Rdnc Field]を選択します。そして、.ply形式で書き出します。




38.4.4 _ LiDARスキャンした3Dモデルを配置する
こうして作成した3Dスキャンしたデータを、Houdini上に配置していきます。
まずは、LiDARスキャンした3Dモデルから説明します。以下では、LiDARスキャンした「道路」をPLATEAUの地面に貼り付ける例を示します。これは実際に、本映像作品にあるシーンの一部です。
■ LiDARスキャンした3Dモデルを読み込む
まずは、LiDARスキャンした3Dモデルを読み込みます。OBJ形式ファイルとしてエクスポートしているので、一般的なOBJ形式の3Dモデルを配置するのと、基本的な流れは同じです。
【手順】LiDARスキャンした3Dモデルを読み込む
[1]Geometryノードを配置する
まずは、Geometryノードを配置します。ここではGEO_conerという名前にしました。

[2]Labs OBJ Importerを配置する
手順[1]で作成したGeometryノードをダブルクリックして、その内部に入ります。
LiDARスキャンした画像はOBJ形式ファイルでエクスポートしているので、OBJ形式を読み込むためのLabs OBJ Importerノードを配置します。OBJFileパラメータに、LiDARスキャンしてエクスポートしたOBJ形式ファイルを選択すると、読み込まれてビューポートに表示されます。
【メモ】
図38-117は、真上から見た角度なのでわかりにくいですが、これはLiDARスキャンでありテクスチャではありません。横方向から見ると、電柱などが立体で立っています。

[3]material_overrideアトリビュートのテクスチャをtex_pathアトリビュートにコピーしてから削除する
TOPIC37で行ったのと同じく、ビューポート上でテクスチャを読み込むと重くなるので、material_overrideアトリビュートをtex_pathアトリビュートにコピーし、material_overrideアトリビュートを削除します。その方法はTOPIC37「テクスチャ情報を待避して、ビューポートで読み込まれないようにする」と同じなので、該当箇所をコピペすることで連結します。この操作をすることで、ビューポートにテクスチャが表示されなくなります。

[4]選択した箇所だけテクスチャを表示されるようにする
作業にあたり、選択したものだけテクスチャを表示できるようにするため、「38.2 作業中に選択しているところだけテクスチャを表示する」で作成したdisplay_textureアセットをコピーして接続しておきます。そうすることで、テクスチャがビューポート上で見えるようになります。

■ 使う部分を切り取る
今回は、LiDARスキャンした写真を全部使うのではなく、必要な箇所だけ切り取って、部分的に使います。そこで以下の手順で、必要箇所を切り取っていきます。
【手順】必要箇所のみ切り取る
[1]Blastノードを接続する
Blastノードを接続します。そして右上の三角形をクリックします。すると、ビューポート
上で選択範囲を指定できるようになります。

[2]範囲選択する
使いたい部分を選択します。通常、Blastノードでは四角形で範囲選択しますが、左から3番目のBrushツールをクリックすると、マウスでドラッグしながらブラシで選択できるようになります。


[3]選んだ部分だけ残す
Blastノードのデフォルトの動作は、「選んだものを消す」ので、そうではなく選んだものを残すため、[Delete Not Selected]にチェックを付けます。
【メモ】
作業の都合上、以降掲載する図では、blast1という名前がblast3に置き換わっていますが、途中、作業工程を中略するためにBlastノードを作り直したためです。前図のblast1は、以降、blast3と読み替えてください。

↓

[4]同様にして、もう一箇所切り取る
本作品では、もう一箇所使っています。同様にして切り取ります。

■ シーンに配置する
こうして切り出したモデルをシーンに配置していきます。
ここでは、下記のシーンをあらかじめ用意した状態で進めます。この三角のコーナーの2箇所に、今回、LiDARスキャンした3Dモデルを配置します。

【手順】シーンに配置する
[1]すべてのオブジェクトが見られるようにする
ビューポートでは、通常、背後のオブジェクトは、隠れて見えません。[Show all Object]を選択し、すべてのオブジェクトが見える状態で作業をやりやすくします。

[2]Transformノードを使って合わせる

[3]もうひとつの位置も調整する
同様にして、もうひとつも調整します。同じ位置、向きであるはずなので、配置したTransformノードをコピペすれば位置と向きがほぼ合います。とはいえ完全に合うわけではないので、微調整は必要です。

[4]マージする
Mergeノードを作成して、これら2つをマージします。

■ レンダリングする処理を加える
これで配置は完了です。あとは地面や建物と同様に、レンダリングする処理を加えます。その方法は、地面や建物と同じなので、ここでの解説は省略します。TOPIC37「37.2.3 Karmaでレンダリングする」を参照してください。
38.4.5 _ Gaussian Splattingで作成した3Dデータを配置する
次に、Gaussian Splattingで作成した3Dデータを配置していきます。
本映像作品では、原爆ドームのカットは、ほぼすべてGaussian Splattingです。背景の川や飛んでいる鳥はポリゴンですが、建物だけでなく木々、そして車もGaussian Splattingです。

また公園のシーンですが、地面はLiDARスキャン、遊具、植物、街灯は、Gaussian Splattingです。

■ HoudiniにおけるGaussian Splattingデータの扱い
Gaussian Splattingでスキャンした3Dデータは、ガウス分布による球(周囲がぼやけた球)を使って再現するのが望ましいのですが、Houdini 20.5のKarmaでは、Gaussian Splattingに対応しておらず、次のバージョンであるHoudini 21で対応予定です。そのため今回は単純な点群データとして扱い、3D Gaussianが本来表示される位置に球(周囲がぼやけない単純な球)をインスタンス化することで擬似的に再現しています。Houdiniでは点群データを直接扱うこともできますが、今回は、格段に扱いやすくできる「GSOPs」というプラグインを使っています。
【メモ】
インストール方法については、「Houdini GSOPs インストール方法 日本語」で検索すると見つかるQiitaの記事を参照してください。
■ Gaussian Splattingデータをインポートする
まずは、Gaussian Splattingデータをインポートします。
【手順】Gaussian Splattingデータをインポートする
[1]Gaussian Splats Importノードを追加する
GSOPsプラグインに含まれているGaussian Splats Importノードを追加します。「gsimport」と入力すると見つけやすいです。

[2]plyファイルを選択する
エクスポートしておいたGaussian Splatsのplyファイルを「Splat file(.ply)」のところで選択します。読み込みが終わると、ビューポートで確認できます。

■ 必要な箇所を切り出す
ここで例として取り込んだGaussian Splattingデータは、市電を写したものなのですが、広範囲にわたっています。拡大すると電車の3Dデータは確かにあるのですが、背景など不要な部分も多いので、以下、必要な部分だけを切り出していきます。

【手順】必要な箇所を切り出す
[1]作業しやすいように、ざっくりと向きを調整する
よく見るとわかるのですが、取り込んだ映像は上下反転しています。そこで、Transformノードを追加し、Rotatesで「180」を設定することで回転して直します。また、ほかの角度も向きも見やすく調整します。

[2]使用する範囲以外を削除する
Deleteノードを配置します。[Entity]を[Point]に設定し、[Bounding Volume]を[Enable]にします。すると、ビューポート上でバウンディングボックスが表示されるので、電車の部分を選択します。
[Operation]を[Delete Non Selected]を選択することで、選択した部分以外が消える(つまり電車の部分が残る)ようになります。このようにして、いったん、電車が含まれるバウンディングボックスを、ざっくりと切り取ります。



[3]軸を合わせる
さらに微調整を続けます。まずは、Transformノードを使って、電車のモデルの向きとXYZ軸が合うように調整します。

[4]さらに小さく切り取る
Deleteノードを追加して、さらに電車の部分だけを切り取ります。

[5]細かい点を削除していく
Blastノードを接続し、[Group Type]で[Points]を選択します。すると、点を削除できるので、電線や地面など不必要な点を選択して、削除していきます。

[6]FileCacheを配置する
作業が完了したらFileCacheノードを配置し、同じ演算が行われないようにすることで、処理を軽量化します。

■ シーンに配置する
こうして切り出した3Dデータをシーンに配置します。
【手順】シーンに配置する
[1]Gaussian Splats Transformで配置する
シーンに配置するときは、Transformして配置することになりますが、その際、通常のTransformではなく、GSOPsプラグインに含まれるGaussian Splats Transformを使うようにします。そうしないと「点のスケール」が自動で変わらないためです。

[2]位置や向き、大きさを調整する
地面のテクスチャを参考にしながら、線路に乗せるように位置や向き、大きさを調整します。

[3]レンダリングの準備をする
最後にNullノードを置いて出力を作り、レンダリングしやすくしておきます。

■ レンダリングする
レンダリングするには、このNullノードの出力をLOPネットにもってくればよいのですが、SOP Importノードを使って持ってきてしまうと、小さな点で構成され、ポツポツと穴が空いてしまいます。そこで、Gaussian Splattingモデル(や点群モデル)の場合は、LOPネットでレンダリングする際、点のところに球をインスタンス化するようにして作ります。

【手順】Gaussian Splattingモデルを正しくレンダリングする
[1]Sphereノードを作る
LOPネットを開いて、Sphereノードを作ります。

[2]Instancerノードを作成する
Instancerノードを作成して、2つめの入力に接続します。

[3]Object Mergeノードを使って、点の場所に球をインスタンス化する
Instancerノードをダブルクリックして内部に入ります。そして、Object Mergeノードを作成します。Object 1のところに、Gaussian Splattingモデルの出力(Nullノード)を設定します。すると、LOPネット内で球をインスタンス化できます。

[4]レンダリング処理につなぐ
Instancerノードの外に出てプレビューを確認すると、この時点で、球として表現できていることがわかります。このInstancerノードの出力を、これまで作成してきたレンダリングの設定につなぎます。

[5]作業を軽くする
インスタンス化された球をレンダリングするため、この状態だとビューポートが重くなります。そこで作業しやすくするため、軽量化します。
SphereとInstancerの間に、Configure Primitiveノードを追加します。そして、次の設定をします。
・[Primitives]に「/sphere1」(直前にあるSphereノードの名前)を設定
・[Kind]にチェックを付けて[Component]を選択
・[Draw Mode]にチェックを付けて、[Origin Axes]または[Bounding Box]を選択([Full Geometry]以外を選択)。

[6]シェーダーを作りはじめる
シェーダーを作っていきます。Material Libraryをダブルクリックしてなかに入り、Karma Material Builderを作ります。名前は「gs_train」としました。


[7]使用しないノードを削除する
作成したKarma Material Builderをダブルクリックしてなかに入ります。不要なmtlxdisplacementとMaterial Propertiesを削除します。

[8]点の色を参照するMtlx Geometry Colorノードを追加する
それぞれの点の色を参照するため、Mtlx Geometry Colorノードを追加します。outをMtlx Standard Surfaceのbase_colorとemission_colorに接続します。

[9]アルファチャンネルの値を参照する
アルファチャンネルの値を参照するため、Mtlx Geometry Property Valueノードを追加し、Geompropに「displayOpacity」と入力します。そしてoutをopacityに接続します。


[10]アサインする
ひとつ上の階層に戻り、これをアサインします。Assign Materialで[Number of Materials]で[+]をクリックして項目を追加し、[Primitives]の部分で、「/instancer1/*」(Instancerノードに付けた名称以下のすべての意味)を設定します。そして[Material Path]には、先ほど作成した、gs_trainを設定します。
【メモ】
上記の設定は、どちらも、Geometry Spreadsheetからドラッグ&ドロップすることで設定できます。

[11]完成
以上で完成です。レンダリングすると、正しく色が表示されているのがわかります。

38.4.6 _ 1つのGaussian Splattingデータを切り出して配置する
電車の例では、Gaussian Splattingデータをひとつだけ配置しました。
次に、1つのGaussian Splattingデータから複数のモデルを切り出して配置する方法を紹介します。作例では、海外の住宅地のGaussian Splattingデータを取り込み、その「木」の部分だけを切り出して、シーンに配置しています。
■ Gaussian Splattingデータの読み込み
今回は、PolyCamから入手できる海外の住宅地のGaussian Splattingを使いました。Gaussian Splats Importを使って読み込んだところを図 38-160に示します。このデータには、たくさんの木があります。これらの木を切り出して、シーンの川辺に配置していきます。
まずは、Transformノードを使って位置やサイズ、傾きを調整し、ざっくりと必要な箇所だけを切り出したあと、軸を原点にそろえます。ここから作業をスタートします。
【メモ】
PolyCamは、連番画像をアップロードすることでGaussian Splatting を作成・閲覧できるサイトです。同名スマートフォンアプリケーションでGaussian Splattingの撮影・作成・閲覧も行うことができます。有料版を利用することでサイト上のGaussian Splattingデータをダウンロードでき、商用利用も可能です。


■ 1本ずつ木を切り出す
さらに1本ずつ、木を切り出していきます。切り出した木には、tree_0、tree_1のような名前を付け、あとで配置するときに、この名前で木の種類を選択できるようにしておきます。また、別の処理で使うため、同じく連番をvariantという名前のアトリビュートに設定しておきます。
【メモ】
variantアトリビュートは、映像作品の作成に使用したもので、本トピックの説明範囲では登場しません。
【手順】木を切り出す
[1]木の形に切り取り、地面に接するようにする
まずは、Deleteノードで切り取り、Centerノードで軸をセンターにします。そのあと、Blastノードで不要なポイントを削除します。そして地面に接する部分のY軸が0になるように、Transformノードで調整します。

[2]使用しないアトリビュートを削除する
Attribute Deleteノードを使って、今回使用しないアトリビュートを削除します。使用するのは「Alpha」「Cd」「orient」「scale」なので、これを[Point Attributes]欄に入力し、[Delete Non Selected]にチェックを付けます。
【メモ】
Alpha、Cd、orient、scaleは、次の意味のアトリビュートです。
Alpha:透明度を扱うアトリビュート。0が完全な透明、1が完全な不透明のいわゆるアルファチャンネル(float型)
Cd:色を扱うアトリビュート。RGB3チャンネル分(vector型)
orient:位置・回転・スケールを扱うアトリビュート。quaternionという四元数(vector4型)
scale:スケールを扱うアトリビュート。XYZの3軸方向(vector型)

[3]名前を付ける
Nameノードで名前を付けます。ここでNameパラメータに「$OS」と入力します。するとノードエディタ上で設定している名前がNameパラメータに設定されます。このNameノード自身は、tree_0と名付けておきます。

[4]packする
Packノードでpackします。

[5]連番を付ける
Attribute Wrangleを使って連番のパラメータを設定します。ここではvariantアトリビュートに「0」を設定するため、次のように記述します。
i@variant = 0; 
■ 残りの木々を切り出してマージする
同様にして、残りの木々も切り出します。それぞれtree_1、tree_2のような連番とし、variantアトリビュートも1、2のように連番で設定します。それらをMergeノードでひとまとめにします。

■ 地面を配置する
これから木を配置していくのですが、場所を決めるための地面をテクスチャ付きで表示しておきます。Object Mergeノードを使って地面のジオメトリを読み込み、「38.2 作業中に選択しているところだけテクスチャを表示する」で作成しておいたdisplay_textureアセットに接続して、テクスチャ有で表示できるようにしておきます。

■ 木を配置する
準備ができたら、木を配置します。Labs Pick and Placeノードを使います。
【手順】木を配置する
[1] Labs Pick and Placeノードを配置する
配置するにあたって、Labs Pick and Placeノードを配置します。左側に地面を接続し、右側に木々を接続します。

[2]置きたい位置に配置する
ドラッグ&ドロップすることによって、好きな位置に木を配置できます。
木の数は、Placementsパラメータで増減できます。またIDパラメータで木の種類を変更できます。


■ スケール変更に伴う点群処理を調整する
Gaussian Splatting(もしくは点群)の場合、配置する木のスケールを変えるときは、インスタンス化する球の大きさを調整する必要があります。以下、その処理を作っていきます。
【手順】スケールに伴い、インスタンス化する球の大きさを調整する
[1]Attribute Wrangleノードを配置する
Labs Pick and Placeノードの下に、Attribute Wrangleノードを配置します。配置したAttribute Wrangleノードには、Labs Pick and Placeノードの右側の出力から接続します(左側の出力は両入力が出てくるのに対して、右側の出力は右側の入力、すなわち、木々のデータだけが出てきます)。
そして、次のコードを入力します。これは、現在の場所t、回転r、スケールsを取り出し、そのスケールsのxの値(yやzでも良い)をpt_scaleという名前のアトリビュートに設定します。
vector t, r, s;
cracktransform(XFORM_SRT, XFORM_XYZ, {0, 0, 0}, 3@transform, t, r, s);
f@pt_scale = s.x

[2]unpackする
Unpackノードを追加してunpackします。このとき、transfer_attributeパラメータにpt_scaleと入力することで、このアトリビュートをpackされた状態から引き継ぎます。

[3]スケール値をかける
点のスケールは、scaleパラメータに設定されています。そこで、この値にpt_scaleをかけ算するよう、Attribute Wrangleで設定します。

コラム:車を配置する
本作品では、車も木の配置と同じように配置しています。1枚のGaussian Splattingデータに複数の車が含まれていて、それを切り出して配置しています。
車のように同じ大きさのものを配置するときは、右クリックしたメニューから、スケールを固定すると操作しやすいです。


38.5 _ 大規模な物理シミュレーションをする
Houdiniには、物理シミュレーションの機能があり、物理法則に基づいて、オブジェクトを動かせます。本映像作品のシーンには、オブジェクト数が比較的多い大規模な物理シミュレーションを使った演出があります。以下では、こうした大きなシミュレーションをする手法や工夫を解説します。
38.5.1 _ 物理シミュレーションのシーン
本節では、本映像作品において、物理シミュレーションを用いた以下の2つのシーンについて解説します。
① 大量のレモン発生のシミュレーション
ビルの屋上や地面から、大量のレモンが湧き出るシーンです。レモンが放り投げられて、ポンポンと落ちてくる剛体シミュレーションは、RBD Bullet Solverノードで実現ています。
レモンを次々と湧き出させるには、Scatterノードを使って湧き出すポイントを作り、そのポイントに対して、適度なアニメーションフレームごとにレモンのオブジェクトをインスタンス化することで実現しています。
ビルの間から出てくる場面も、地面から湧き出てくる場面も考え方は同じですが、地面から湧き出る場面では、レモンを発生する面を建物から除外することで、建物が建っていない地面からだけ湧き出るようにします。

② もみじ饅頭が風で流されるシミュレーション
もみじ饅頭が風に流されて、ビルの合間を流れていくシーンです。発生場所に、風のように流れるパーティクルを作って、そのポイントに、もみじ饅頭をインスタンス化することでそれらしく見せる簡易な方法と、煙のシミュレーションができるPyro Solverノードを使って実際に煙を発生させ、そこに、もみじ饅頭を浮かべてシミュレーションする本格的な方法の2つを紹介します。

■ 大量にレモンが湧き出るシーンのシミュレーション
まずは、大量のレモンが湧き出てくるシミュレーションから始めます。
ここでは下図のように、地面と建物を読み込んだ状態から始めます。今回使用しているレモンのデータは、インターネットからFBX形式で入手したものです。


■ レモンを読み込んで整理する
まずは、レモンを読み込み、中心をそろえたり、サイズを調整したりするところから始めます。
【手順】レモンを読み込んで整理する
[1]レモンのオブジェクトを参照する
Object Mergeノードを使って、レモンのFBXデータを参照します。このとき[Transform]プロパティを[Into This Object]に設定すると、FBXデータに含まれるすべての階層のTransform情報(位置・回転・スケール)が適応された状態で正しく読み込むことができるため、あとでの調整がしやすくなります。

[2]中心をそろえる
中心がズレていると、物理演算をしたときにブレるので、中心にそろえるため、Centerノードを使います。

[3]大きさを調整する
今回使用しているレモンのオブジェクトは、サイズがかなり大きかったため、Transformノードを使って、調整しました。

[4]ノードに名前を付ける
こうして調整したノードに対して、Nameノードを使って名前を設定します。ここでは、「lemon」という名前を付けました。

[5]Nullノードを置く
いったんここまでの流れを、他の箇所から参照しやすくするため、Nullノードを付けます。ここでは「GEO_lemon」という名前にしました。

[6]packする
このあと、このレモンを参照して剛体シミュレーションをしていくのですが、メモリ効率の向上とパフォーマンス向上のため、packしておきます。pack後には、先ほど付けた名前であるnameを参照できるように、Transfer Attributesにnameを設定しておきます。

[7]Nullノードを付ける
pack済みのデータを参照しやすくするため、Nullノードをして名前を付けておきます。GEO_lemon_packedという名前にしました。

■ 剛体シミュレーションを試す
大きな範囲のシミュレーションは時間がかかるため、最初は小さいスケールではじめて、最終的に大きなシーンに当てはめるのが、効率が良いやり方です。そこでまずは、この1つのレモンに対して、剛体シミュレーションを試していきます。
【手順】剛体シミュレーションを試す
[1]RBD Configureを接続する
剛体シミュレーションをするには、さまざまな設定が必要です。その設定を作るため、RBD Configureノードを作成して接続します。

[2]RBD Bullet Solverを接続する
剛体シミュレーションを実現するRBD Bullet Solverノードを配置し、3つの接続点をつなぎます。接続点は、それぞれ左から「レンダージオメトリ」「拘束ジオメトリ」「プロキシジオメトリ」です。作成したRBD Configureノードの出力をそれぞれ接続します。

以上で、シミュレーションを実現できます。左下の[▶]ボタンをクリックすると、レモンが自由落下します。

■ レモンが放り投げられるように動きを変える
次に、この設定を変更して、「レモンが放物線状に、放り投げられて落下する」というように動きを変えていきます。
【手順】レモンが放り投げられるように動きを変える
[1]初速を与える
放り投げられるような動きにするには、初速を与えます。ここでは初速をランダムな値とします。初速はvアトリビュートで設定します。Attribute Randomizeノードを追加し、vアトリビュートに対して、MinValueを「-1」「0.5」「-1」のように設定します。
実際に実行して確認しながら、各パラメータを調整します。試すと、この値では重力に比べて小さく、あまり上に飛び出ないので、チュートリアル動画では、Global Scaleを10に設定して、10倍値とすることで初速を大きくしています。

[2]角速度を与える
初速だけだと、上に上がって落ちているだけです。角速度を与えることで、レモンが回るようにします。
角速度はwアトリビュートで設定します。そこでもうひとつAttribute Randomizeノードを追加して、wアトリビュートを設定します。ここでは、MinValueを「-1」「-1」「-1」のように設定し、Global Scaleは10としました。実際に実行し、必要に応じて、パラメータの値を調整します。

■ 特定の場所から、レモンがたくさん出現するようにする
ここまでで、1つのレモンを放物線上に放り投げる動きができました。次に、この動きを使って、特定の場所から、レモンがたくさん出現するようにします。
【手順】特定の場所からレモンがたくさん出現するようにする
[1]平面を作る
レモンを発生させる面として、まず、Gridノードで平面を作ります。

[2]Scatterノードで点を作る
Scatterノードを使って、この平面上に、レモンを発生させるためのポイントを作ります。Force Total Countには「3」を設定し、いったん、3つの点を作るようにしました。

[3]初速と角速度を設定するノードを追加する
先ほど作成した、レモンを放物線状に投げるノード一式から、初速と角速度を設定する2つのAttribute Randomizeノードをコピーして、Scatterノードに下に配置します。

[4]RBD Configureをコピーする
先ほど作成したRBD Configureをコピーして、もうひとつ作ります。そして、Pack後のGEO_lemon_packedノードから接続します。

[5]RBD Packでpackする
RBD Configureの後ろにRBD Packノードを接続して、さらにpackします。接続点は3箇所あり、すべてを接続します。RBD Packは、入力のジオメトリとConstraintジオメトリ、プロキシジオメトリを単一ジオメトリにパックするもので、以降、3つの線を接続せずに1つの線で接続するだけで済むようになります。
【メモ】
RBD Packすると、関連するConstraintジオメトリやプロキシジオメトリを1つのジオメトリとして扱えるため、RDBシミュレーションに必要な情報を保持した状態で、ポイント上にインスタンス化できるようになります。

[6]Copy To Pointsでポイントにインスタンス化する
平面上のポイントに、レモンをインスタンス化します。そのためには、Copy To Pointsノードを使います。Copy To Pointsノードを作成し、左側にはレモンをRBD Packしたもの、右側をScatterで作成した平面上のポイントを接続します。すると、そのポイントにレモンがインスタンス化されます。

[7]RBD Unpackする
このままだと、RBD Bullet Solverで処理できないので、RBD Unpackを使ってunpackします。すると、RBDオブジェクトとして取り出せるようになります。

[8]RBD Bullet Solverを接続する
RBD Bullet Solverを配置し、3つの接続点をつなぎます。これで剛体シミュレーションが実行できるようになります。

[9]正しく動作するように調整する
先ほど作成したRBD Unpackですが、これはジオメトリ、Constraintジオメトリ、プロキシジオメトリをunpackするだけで、ほかのアトリビュートは引き継がれません。そこでTransfer Attributesに、vアトリビュートとwアトリビュートを追加することで、このvとwの2つのアトリビュートも引き継がれるようにします。
さらに、[Enforce Unique Name Attribute per Instance]にチェックを付けます。そうすると、インスタンス化されたジオメトリに、それぞれ異なる名前(nameアトリビュート)を付けられるようになります。ここにチェックを付けないと、同じ名前が付けられるのですが、RBD Bullet Solverは、同名のジオメトリは同じ物体としてシミュレーションするため、チェックを付けなかったときは、インスタンス化した3つのレモンが同じ動きになってしまいます。


[10]湧き出るようにする
さて、以上で、平面上の3箇所から、レモンが放物線状に投げられるようになりましたが、3つのレモンが落ちれば終わりで、次々と湧き出てくるわけではありません。
湧き出るようにするには、RBD Bullet Solverの[Emit RBDs]にチェックを付けます。するとアニメーションの1フレームごとに新しくレモンが作られるようになります。つまり、次々と湧き出るようになります。

[11]Emit数を変更する
しかし1フレームごとに作るのでは数が多すぎて、レモンが重なってしまいます。そこで、何フレームかおきにEmitするように変更します。
そのためには、RBD Configureノードの[Emission]の項目にある[RBD Bullet Emit]のところに、Emitする条件式を設定します。ここでは次のように入力します。
$F%10 == 0$Fはフレーム数、%は割り算の余りを示します。つまり、この式は、「フレーム数を10で割った値が0のとき」という条件です。この条件により、10フレームごとにEmitされるようになります。

■ レモンが発生する場所を変える
これで基本的な設定は終わりました。ここからさらに少しずつ改良を重ねます。
まずは、レモンが発生する場所をランダムにします。これは簡単で、ScatterノードのGlobal Seedに「$F」と入力します。Global Seedは乱数発生の元となる数(シード、乱数の種)で、同じ値だと同じ乱数の系列が、違う値だと異なる乱数の系列が得られるようになります。
$Fはフレーム番号を示す変数なので、Global Seedに$Fを入力すると、フレームごとに乱数の系列が変わり、バラツキが生じるようになります。その結果、Scatterノードが生成する点の場所が、フレームごとに違う場所になります。Global Seedの値のデフォルトは「0」で、フレームによって変化しないため、まったく同じ場所からレモンが発生してしまいます。

■ レモンの大きさを変える
同様にして、レモンの大きさをランダムにします。大きさは拡大率を示すpscaleアトリビュートです。そこで、Attribute Randomizeを追加して、この拡大率pscaleアトリビュートをランダムな値に設定します。
Attribute Randomizeでランダムな値を設定する際には、Dimensionsを「1」に設定し、「Min Value」と「Max Value」で乱数の範囲を指定します。これもフレームごとに別のランダムな値にしたいので、[Options]タブにある「Global Seed」の部分の後ろに「+$F」と追記します。これでフレーム番号が加算されるので、フレームごとにランダム値が変わるようになります。


■ ビルに配置する
以上でレモンが湧き出て、次々と放り投げられる平面ができました。これを実際のビルに配置します。今回は、真ん中が少しくぼんでいるビルのなかに配置しました。
実際に動かすと、レモンが湧き出てきますが、ビルをレモンが貫通します。貫通する原因は、コリジョンが設定されていないためです。そこで、RBD Bullet Solverノードの[Collision]タブにある、[Collision Geometry]にチェックを付け、[Collision Type]を[Static]に、[Collision Shape]を[Concave]にそれぞれ設定します。これで、レモンがビルにぶつかって跳ね返るようになります。
あとは必要に応じて、レモンが飛び出す初速などを、実際にシミュレーションを見ながら調整していきます。



38.5.2 _ 地面から湧き出るレモンのシミュレーション
次に、これを応用して、地面から湧き出てくるレモンの作り方を説明します。基本的な作り方は同じですが、発生点となるポイントの作り方が、少し違います。

【手順】レモンが地上から湧き出るようにする
[1]レモンを湧き出したい場所に平面を作る
Gridノードを使って、レモンを湧き出したい場所に、平面を作ります。

[2]行数、列数を大きくする
配置したGridノードのRowsパラメータとColumnsパラメータを、例えば、それぞれ「100」に設定して、分割数を大きくします。

[3]山を作る
Soft Transformノードを追加して、山を作ります。Soft Transformノードを追加したのち、Soft Radiusの値を大きくしたり、TranslateのYの値を大きくしたりすることで、山を作ります。


[4]底面をフラットにする
Exclude Volumeノードを配置します。すると、底面がフラットなジオメトリが作られます。

[5]レモンの発生源となるポイントを作る
Point from Volumeノードを使って、手順[4]で作成したジオメトリから、レモンの発生源となるポイントを作ります。ポイントの数は[Point Separation]、ランダムの度合いは[Jitter Scale]で、それぞれ調整します。

[6]建物と重なる部分を除外するためのグループを作る
このあと、このポイントからレモンが湧き出るようにするのですが、このままだと、建物と重なる部分からもレモンが出てきてしまうので、建物から重なる場所は除外するように設定します。
それに先立ち、グループ化するGroup Createノードを作ります。グループ名は「in_bldg」という名前にしました。Group Typeは[Points]とします。

[7]建物のコライダーに含まれている部分をグループ化する
Object Mergeノードを作り、先ほど、レモンがビルにめり込まないようにするために作った建物のコライダーをObject1の部分にドラッグして参照します。そして、そのObject Mergeノードを、手順[6]で作成したグループに接続します。
[Base Group]の[Enable]のチェックを外し、[Keep in Bounding Regions]の[Binding Type]で[Bounding Object(points or vertices only)]を選択します。この操作によって、建物の内部に含まれているポイントがグループ化されます。


[8]ポイントを削除する
Blastノードを作り、[Group]の部分で、今グループ化した「in_bldg」を設定します。これで手順[7]でグループ化したポイントが削除されます。

[9]インスタンス化する
先ほど、ビルの上からレモンが飛び出る一連の仕組みをコピーして接続し、残ったポイントにレモンをインスタンス化します。

[10]レモンの向きをランダムにする
Attribute Randomizeノードを配置して、orientアトリビュートにランダムな値を設定します。そうすると、レモンの向きがランダムになります。

[11]レモンの重なりを解消する
レモンが重なってしまっているので、これを解消します。そのためには、1フレーム目で重なりを検知するようにします。
found_overlapアトリビュートに「1」を設定すれば、これを実現できるので、Point Wrangleノードを取り付けて、VEXpressionを設定します。
i@found_overlap = 1これだけだとUnpackするときに、このfound_overlapパラメータが引き継がれないので、RBD UnpackのTransfer Attributeで、この「found_overlap」を設定します。


[12]SolverのEmitを外す
RBD Bullet Solverの[Setup]タブにある[Emit RBDs]のチェックを外します。

[13]レモン全体をマージする
以上で完成です。シミュレーションを実行すれば、レモンがあふれてきます。建物との衝突判定も付いているので、あふれたレモンは、道の間を流れてきます。
最後に、「ビルから湧き出るレモン」と、今作った「地面から湧き出るレモン」をObject Mergeでひとつにマージします。

38.5.3 _ 建物周辺の風ともみじ饅頭のシミュレーション(パーティクル版)
次に、建物の周辺に風が吹いて、もみじ饅頭が流れてくるシーンの作り方を説明します。ここでは、建物と地面を配置した状態で、ここにGEO_manjuというジオメトリを作ったところから始めます。

■ 建物のコリジョン用のジオメトリ
以降の工程では、もみじ饅頭が、めり込まないようにするため、地面や建物との衝突判定が必要になります。そこでObject Mergeを使って、「地面」と「建物」を参照して、それぞれをマージしたジオメトリを作っておきます。ここではNullノードで終端し、GEO_collisionという名前を付けました。


■ パーティクルを作る
本トピックでは、「パーティクルを用いた方法」とPyro Solverノードを使って物理エンジンによる煙を作って、「煙に乗せる方法」の2つを説明します。
まずは、比較的簡単な前者の方法から説明します。ビルの周りにパーティクルを作り、そのパーティクルにもみじ饅頭をインスタンス化するというやり方です。まずは、そのためのパーティクルを作っていきます。
【手順】パーティクルを作る
[1]パーティクルのソースとなるBoxを作る
パーティクルのソースとなる場所を作ります。今回は、シーン上に2つのBoxを作って、マージしました。

[2]Boxからポイントを作る
Points from Volumeを使って、手順[1]で作成したBoxから、ポイントを作成します。
ただし、Boxのスケールが大きいため、そのまま接続するとポイント数が多く、重くなりがちです。そこで接続前に[Point Separation]の値を適切に変更してから、接続するのが良いです。またJitter Scaleを設定して、ランダム感を出します。

[3]ノイズを加える
Attribute Noiseノードを使って、ノイズを加えます。noiseというアトリビュート名にしました。

[4]ノイズに応じてポイントを消す
手順[3]で加えたノイズに応じて、ポイントを消するようにします。そのためには、Blastノードを接続し、[Group]に「@noise <= 0.7」と入力します。そうすることで、加わったノイズが0.7以下のときのポイントだけ消えるようになります。
ここでAttribute Noiseノードの設定に戻り、[Animation]にチェックを付けます。そうすると、ノイズがフレームごとに変わるため、「ノイズで揺らいだポイントが発生する」という動きになります。


[5]DOP Networkを作成する
これらの下に、DOP Networkを作成して接続します。DOP NetworkはHoudiniで物理シミュレーションを行うためのノードです。このDOP Networkの内部でノードを組むことで、さまざまな物理シミュレーションの設定や調整・計算を行うことができます。

[6]Static Objectとマージする
DOP Networkをダブルクリックして、なかに入って、さらに操作を続けます。地面や建物の障害物を参照するため、Static Objectノードを作ります。そして、Object Mergeノードを使って、もともとの入力とマージします。このとき、マージの順序を変えて、Static Objectが先に計算されるようにします。


[7]風で動くようにする
風で動くようにしたいので、POP Windノードを作成して接続します。風向きは、Wind Velocityで設定します。今回は、[Noise]タブの「Amplitude」や「Swirl Size」のパラメータを調整する際、ノイズも加えています。

[8]すべてのポイントに対して効果を付ける
POP Sourceノードの[Emission Type]を[All Points]に設定します。

[9]実行して確認する
これで風に流されるポイントが作られました。シミュレーションを実行して確認すると、ポイントが風で流れていくのがわかります。

■ 風がビルを避けるようにする
シミュレーションを実行してみるとわかりますが、このままだと、風を模したポイントがビルのなかを貫通します。そこで衝突判定して、避けるようにしていきます。
【手順】風が地面や建物を避けるようにする
[1]SOP PathとOBJ Pathを設定する
Static ObjectノードのSOP PathとObj Pathの両方に、あらかじめ作成しておいた地面や建物のコリジョンを示すジオメトリ(「■建物のコリジョン用のジオメトリ」で作成したGEO_collision)を設定します。

[2]コリジョンを設定する
同じくStatic Objectノードの[Collisions]タブで、コリジョンの判定方法を選択します。ここではボリュームと衝突判定するため、[Collision Detection]を[Use Volume Collisions]に設定します。
そして[Mode]を[Volume Sample]に設定します。

[4]コリジョン判定のボリュームを作る
手順[3]を対象とするボリュームを作っていきます。ひとつ上の階層に移動し、地面や建物のコリジョンのジオメトリであるGEO_collisionにVBD from Polygonsノードを作成して接続します。このとき処理を軽くするため、Voxel Sizeは、「1」など大きめの値に設定しておきます(デフォルト値の0.1は、地面や建物などの大きなジオメトリに対しては小さすぎて、たくさん分割されてしまい重くなります)。
すると、建物がボリュームとして構成されます。[Distance VBD]には「collision」と入力して名前を付けておきます。
そして、さらにNullノードを付けて、他から参照しやすくします。ここではVBD_collisionという名前を付けました。


[5]Static Objectから衝突判定のボリュームとして設定する
手順[4]のようにして作成したボリュームをStatic Objectの[Proxy Volume]の部分に設定します。これでシミュレーションすると、ポイントが地面や建物と衝突して避ける動きになります。
【メモ】
[Display Geometry]のチェックを外して[Collision Guide]にチェックを付けると、見やすく目視で確認できます。実際にシミュレーションを見ながら、風の動きを調整します。

■ もみじ饅頭をインスタンス化する
このようにして作成したポイントに、もみじ饅頭をインスタンス化していきます。もみじ饅頭のデータは、PolyCamでスキャンしたものをあらかじめ用意しておきます。

【手順】風を模したポイントに、もみじ饅頭をインスタンス化する
[1]不要なアトリビュートを削除する
まずは、Attribute Deleteノードを追加して、不要なアトリビュートを削除します。今回は、ポイントの位置を示すP(Point)だけあれば十分なので、[Point Attributes]に「P」を入力し、[Delete Non Selected]にチェックを付けることで、P以外を削除します。

[2]もみじ饅頭のデータを参照する
Object Mergeノードを配置して、Object 1にもみじ饅頭のジオメトリを設定して、参照します。

[3]ポイントにインスタンス化する
Copy To Pointsノードを作成して、ポイントに、もみじ饅頭をインスタンス化します。ポイントの数が多いため、このまま接続すると重くなるので、[Pack and Instance]にチェックを付けてから接続します。
すると、ポイントにもみじ饅頭がインスタンス化されます。

38.5.4 _ サイズや向きをランダムにする
最後に、サイズや向きをランダムにします。これは、Attribute Randomizeノードを使って、pscaleアトリビュート(サイズ)とorientアトリビュート(向き)を設定するだけなので、説明は割愛します。

38.5.5 _ ビル周辺の風ともみじ饅頭のシミュレーション(煙版)
ここまでは、パーティクルにもみじ饅頭をインスタンス化して、風に乗ってくるように見せる方法を紹介しました。次に、もう少しリアルに、本当に物理演算で煙を発生させ、そこにもみじ饅頭を乗せて動かしていく方法を紹介します。
次のようにGEO_manju_windというジオメトリを作った状態で始めます。ここに「煙」を発生させていきます。

■ 煙を作る
まずは、このシーンに、煙を発生させます。
【手順】吹き出す煙を作る
[1]地面のジオメトリを参照する
GEO_manju_windのなかに入ります。まずは、Object Mergeノードを作成して、地面のジオメトリを参照します。

[2]コリジョンをコピーする
こちらの作業の流れでも、衝突判定のために、地面や建物のコリジョンが必要になるので、先ほど作ったコリジョンの部分(VBD_collision)をコピーしてきます。

[3]地面に厚みを付ける
現在の状況では、地面(ground)が板ポリゴンなので、流体がしっかりと衝突しません。そこで、地面に厚みを付けます。そのためには、Fuseノードを取り付け、さらに後ろにExclude Volumeノードをつなぎます。このままだと真っ黒ですが、その後ろにNormalを接続すると直ります。
画面を見ながら、Exclude VolumeノードのDepthパラメータで厚みを調整します。ここでは「-10」に設定しました。



[4]煙のソースを設定する
地面から煙が出るよう、Pyro Sourceノードを配置します。配置したら、[Mode]を[Surface Scatter]にします。デフォルトだと分割数が多くポイントの数が多くなるので、[Particle Separation]を「1」に設定します。
設置したら、[initialize]と書かれている部分をクリックし、[Source Smoke]を選択します。すると、煙を出すのに必要なフィールドとして、DensityとTemperatureの2つが追加されます。



[5]発生点にゆらぎを付ける
このままだと規則的な場所から煙が出るので、ポイントを少しズラして、ゆらぎが出るようにします。そのために、Point Jitterノードを接続します。どの程度ズラするかを、Scaleで設定します。

[6]煙の濃さをゆらがせる
densityフィールドは、煙の濃さを調整する役割のパラメータです。これにもノイズによるゆらぎを設定するため、Attribute Noiseノードを追加します。
[Attribute Names]には「density」を設定。[Operation]を[Multiply]にして適度な乗算値を設定します。また[Noise Pattern]を調整し、[Animation]にもチェックしてアニメーションするようにもします。

[7]浮力をゆらがせる
temperatureフィールドは、温度の分布を決めるもので、値が大きいほど浮力が大きくなります。これもdensityフィールドと同様に、Attribute Noiseノードを付けて調整します。

[8]初速を設定する
同様にして、初速vもゆらがせます。これはFloat型ではなくVector型なので、Attribute Namesで[Vector]を選択したうえで、初速「v」を設定します。

[9]ボリュームとして構成する
ここまで作ってきたポイント群をボリュームに変換します。Volume Rasterize Attributesノードを接続して、次のようにします。
・Voxel Sizeを「1」に設定(デフォルト値は値が小さく、変更前に接続すると処理が重くなるので、接続前に設定するのが望ましい)
・Coverageで[+]をクリックしてアトリビュートルール追加。「v」を追加で設定
・[General]の[Attributes]で、「density」「temperature」「v」の3つを設定

[10]流体シミュレーションを構成する
流体シミュレーションを構成するため、Pyro Solverを接続します。接続前に、Voxel Sizeをあらかじめ大きめの値(今回は「5」)に設定しておきます。
[Sourcing]タブを開きます。「density」「temperature」「flame」「vel」の4つのソースボリュームがありますが、flameは使わないので、[×]をクリックして削除します。


[11]動作確認する
この状態でシミュレーションを動かすと、地面から煙が上がっていく様子がわかります。

[12]建物の衝突判定を付ける
このPyro Solverの右側の入力に、建物のジオメトリを接続します。そして[Collision]タブで[Collision Type]を[SDF + Volume Velocity]を選択します。これで建築物モデルとの衝突判定が設定されるようになります。

[13]風を加える
Pyro Solverの[Shape]タブで[Wind]にチェックを付けて、風を加えます。風の速度や方向を調整します。ここでは、強さ(Wind Speed)は「60」としました。

[14]キャッシュをとる
ここまで作成してきた一連の流れにNullノード、FileCacheノードを接続して、キャッシュをとります。

■ 煙に沿ってポイントが動くようにする
これで煙が風に流されるシミュレーションができました。ここに、先ほどのパーティクル版と同じ仕組みをコピーして、もみじ饅頭をインスタンス化する処理が、このシミュレーション上で動くようにします。
【手順】煙に沿ってポイントが動くようにする
[1]新しく作った流体シミュレーションで動かす
これまでパーティクルで作成してきた仕組みをコピーしてきます。そして、POPネットに入り、これまでパーティクルで動かしていたpopwindを削除します。そして、その場所にPOP Advect by Volumesノードを挿入します。そして[SOP]の部分で、先ほどとったキャッシュを設定します。さらに、[Advection Type]を[Update Velocity]に変更し、[Advection Method]を[Trace]に設定します。


[2]シミュレーションの確認
以上で完成です。実際にシミュレーションすると、先ほどのパーティクルの場合と違い、ぶつかったときにそこに対流せず、風で流れていくため、見栄えが自然になります。

■ もみじ饅頭をインスタンス化する
最後に、このポイントに対して、Copy To Pointsノードで、もみじ饅頭をインスタンス化すれば完成です。

38.6 _ まとめ
このトピックでは、HoudiniでPLATEAUの3D都市モデルを扱う際に、ディテールアップするさまざまな手法と物理シミュレーションの方法を解説しました。
PLATEAUの3D都市モデルは建物の数が多いことから、ひとつひとつ手作業で行うのは、とてもたいへんです。できるだけ、ネットワークエディタでループ処理するなどして、省力化することが重要です。
また建物の数が多いということは、ビューポート上での操作や物理シミュレーションが重くなるということでもあります。テクスチャを読み込まないようにしたり、シミュレーションの分割数を減らしたりすることで軽量化することにも注意を払いましょう。
【文】
大澤文孝
【監修】
塚島 建(WOW inc.)




