今回はSubstance Designerの謎ノード、FX-Mapについて得られた知見を書いていこうと思います。
いろいろと調べてみたのですが、まだまだわからないところがあるノードでもあります。
言葉で説明するより実際に使ってみましょう。
まずはパレットの中からFX-Mapノードを選択し、追加してみましょう。
配置しただけでは何も表示されません。
入力ピンは [バックグラウンド] と [Input Image 0] です。
とりあえず、[バックグラウンド] には均一カラー(グレースケール)の黒を、[Input Image 0] にはShapeノードでディスクを入れてみましょう。
背景が黒くなっただけでやっぱり何も表示されません。
入力ピンは [Input Image 1] が新たに追加されました。
残念ながら、この増えたピンに何かを入力しても事態は改善されません。
プロパティペインを見てもそれっぽい何かは存在していません。
ではどうするか?
FX-Mapノードを右クリックすると、Ctrl+Eで [FX-Mapを編集] というコマンドが存在するのがわかります。
そうです。このノードは内部を編集する必要があるのです。
クリックすると以下のようにFX-Map内部のグラフを編集できるようになります。
最初にあるのはこのクワドラントというノードのみです。
とりあえず、スペースキーを押してどんなノードが配置可能か見てみましょう。
コメント関連はどこにでもあるので無視するとして、配置可能なノードは反復、クワドラント、切り替えの3つしかありません。
この3つのノードはどんなものかというと、それぞれ for, switch, if という、プログラミング言語ではお馴染みのフロー制御命令です。
つまり、FX-Mapというノードは、これらのフロー制御を用いて入力されたイメージなどを加工するノードなのです。
言葉で説明してもわかりにくいので、FX-Mapをイメージした簡単なフローチャートを書いてみました。
FX-Map開始の次は100回ループです。ループ内と書かれた矢印以降の処理を100回行います。
その次にまた8回ループです。
800回ループすればいいだろって?まあ、そうなんですけどイメージのためです。
次は条件分岐で、チャートには書かれていませんがランダムに設定された位置が右半分か左半分かで処理を分けます。
右半分なら円を描画し、左半分なら四角を描画します。
このようなフローの入れ子構造で処理する機能はSDの通常のノードグラフには存在していません。
処理としてできることは簡単なものに限られますが、FX-Mapはこのような入れ子構造を実現することが出来る数少ないノードなのです。
ちなみに、このフローチャートをFX-Mapで再現するとこうなります。
見ての通り、FX-Mapのノードグラフは上から下に進んでいきます。
これはフローチャートを意識しているようにも見えますね。
では各ノードを見ていきましょう。
前述のフローチャートの実際の処理部分は円を描画、四角を描画の部分です。
これに当たるのは [クワドラント] というノードになります。
このノードは2種類の意味を持っていて、個人的にはこれがFX-Mapをわかりにくくしている要因の1つじゃないかと思っています。
クワドラントノードで図形の描画をするためにはプロパティペインのパターンから何かを選びましょう。
とりあえず、FX-Mapの初期状態に戻し、パターンを [Input Image] に変更します。これはFX-Mapノードの入力 [Input Image 0] の画像を描画するための設定です。
どうでしょうか?FX-Mapノードにディスクが表示されたはずです。
クワドラントノードのもう1つの役割は画像を4分割する機能です。
出力ピンは4つあり、左から左上、右上、左下、右下の領域を示します。
それぞれの出力ピンの先の処理は分割された4つの空間での処理を意味することになります。
実際にこの挙動を確認してみましょう。
もう1つのクワドラントノードをグラフに追加し、以前のクワドラントノードの上に置いて4つの出力ピンすべてを最初のクワドラントノードにつなげましょう。
これだけでは何も変化がありませんが、上のクワドラントノードを選択、右クリックして [ルートとして設定] を選択します。
するとどうでしょう?ディスクが4分割の空間それぞれに表示されていませんか?
どうしてこうなるのでしょう?
FX-Mapではルートとして設定されたノードから下方向に処理が進みます。ルートノードはオレンジ色になり、1つのFX-Mapでは選択できるノードは1つだけです。
この図の例では、ルートとして設定されてクワドラントによって、画像の空間は4分割されました。
そして4分割されたそれぞれの空間に対して下のクワドラントの処理(ここでは [Input Image 0] を描画する)を実行します。
いわゆる switch 命令との違いは、switch 命令が基本1回しか処理を行わないのに対して、クワドラントノードは出力ピンにつながっているものをすべて実行します。
例えば、つながっている4つのピンの内の1つを外してみてください。4つのうちの外した部分が欠けるはずです。
もう少し別の例を見ていきましょう。
下図のように設定して、左下のクワドラントノードはパターンを [Input Image] に、右下のクワドラントノードは [波] にしましょう。
結果はこうなります。
クワドラントノードは割り当てられた画像領域を4つに分割するので、クワドラント→クワドラント→クワドラントとすると今度は16分割もできます。
これを繰り返せばより細かく空間を分割することも出来ます。
いまだによくわからないクワドラントの挙動としては、クワドラントを1つ以上通過させてしまうと、何故か画像の色が暗くなる点です。
上の図ではディスクがグレーになってしまっていますが、元イメージは真っ白なはずなんですが…
この挙動には意味があるのかもしれませんが、今のところよくわかっていません。
次に反復ノードです。これは for 文による繰り返しを実現します。
例えば下図のようにすると、クワドラントノードの処理部分を反復によって複数回実行します。
反復ノードの右側出力ピンは各ループの処理です。
反復回数のプロパティで指定した回数だけこの右側出力ピンから処理が実行されます。
左側のピンは1回のみの処理を意味します。
例えば、左側のピンに"A"という処理を、右側のピンに"B"という処理を挿すと、Aが1回処理された後にBがループ回数分だけ処理されます。
まあ、ループ前の1回だけの処理を行う機能、と考えるといいでしょう。使う機会はそれほど多くないのではないでしょうか。
さて、クワドラントノードの処理は Input Image をそのまま描画するだけの処理です。
これを何度も繰り返しても何も変化はありません。上から何度も同じ画像が書き込まれるだけです。
そこで、クワドラントノードのプロパティを以下のように変更します。
パターンサイズ幅、及び高さ:0.2
ブランチオフセット:空の関数
ブランチオフセットの関数は以下のようにします。
0~1のランダム数値をオフセットとして使用します。
結果はこうなります。
ディスクの位置がランダムに変化し、反復処理されるたびにランダム値が変化しているのがわかるでしょう。
反復を使用する場合にはランダムも一緒に使わないと効果がわからなくなってしまうでしょう。
最後に切り替えです。これはそのまま if 文と考えると良いでしょう。
プロパティペインには [セレクタ] という項目がありますが、これは左か右を選択でき、それによって処理を変更することが出来ます。
もちろん関数も作成することが出来ますが、関数の出力は Boolean でなければなりません。
例として、以下のようなノード構成があったとします。
4分割した空間のそれぞれに [Input Image] か [波] を描画するようにしています。
ここでセレクタの関数は以下のようにします。
[$pos] は空間の中心座標がどこにあるかを示しています。このx値が 0.5 未満ならTrue、0.5 以上ならFalseとなります。
つまり、空間の左側はTrue、右側はFalseということです。
切り替えノードにおいてはTrueが右、Falseが左を指します。なので、結果は左側が [波]、右側が [Input Image] になるわけです。
さて、ここまでで3つのノードの解説を行いましたが、これでFX-Mapを使いこなせるかというとそういうものでもなく、やっぱりちょっと使いにくいことが否定できなかったりします。
使いにくいと感じた部分としては、例えば反復の現在のループ回数が取得できなかったり。
棒を綺麗な円状に並べたい、と思った場合は反復時の現在のループカウントが必要になりますが、これを取得する方法が今のところ見つかってません。
そもそもクワドラントノードで設定可能な画像処理の部分がやれることが意外と限られていて、あまりいい例が思いつきません。
とりあえず、Youtubeにあったチュートリアルから草地の地面を作成する場合の処理とか、
花びらっぽい形状を円状に配置することで簡単な花を作ったりすることは十分可能でしょう。
とにかくちょっとわかりにくいノードではありますが、ループや条件分岐を任意に行える機能がSDの通常ノードには存在しないので、こういうことをしたい場合は使わざるを得ないかな、と思います。
まあ、[Tile Generator] ノードや [Splatter] ノードで十分ならそちらを使っておいた方がいいです。
どうしても任意の形状を作成したい場合にのみFX-Mapを使う、という形のほうがいいんじゃないでしょうか?