Flood Fillのエラーについて

Substance Designerの便利ノード [Flood Fill] はアイランドに分かれている形状にランダム性をもたせるのに重宝します。

f:id:monsho:20180906215410p:plain

このノードには3種の処理方法があり、[Safety/Speed trade-off] パラメータで変更が可能です。

  • Simple or small shapes:高速ですがエラーが発生しやすく、オススメできません
  • Complex or big shapes:デフォルトです。多くの場合で正常に処理できますが、失敗もあります
  • No failure mode:最も遅いですが、失敗はほぼありません

デフォルトの [Complex or big shapes] を選択し、[Flood Fill to Random Color/Grayscale] に接続した場合、多くの場合で成功するのですが、一部で失敗が発生します。

f:id:monsho:20180906220339p:plain

赤枠で囲った部分に横線が入っているのが見えるでしょう。
このようなエラーを回避するには [No failure mode] を選択するのが最も正しいやり方ですが、私の環境ですと、このモードを選択すると20msほど余分に処理がかかってしまいます。
大きな問題になる時間ではないとはいえ、軽く処理できるならそれに越したことはないわけで、そもそもこのようなエラーが何故発生するのか疑問に思いました。
そこで、ちょっと調べてみた結果を記事として公開することにした、という次第です。

さて、そもそも [Flood Fill] ノードから出力されているカラーの値は一体どのような値なのでしょうか?
これは、出力ピンにマウスドラッグすると判明します。

f:id:monsho:20180906220905p:plain

RGには各形状のUV値が格納されます。
このUV値は、各形状の軸並行境界ボックス(AABB)の左上を0、右下を1としたUV座標が入っています。
BAはこのAABBのサイズです。サイズ1.0はテクスチャ全体を示しています。

例えばRGの値を利用すれば各形状にテクスチャを貼り付けるようなことも可能です。

f:id:monsho:20180906221718p:plain

さて、[Flood Fill to Random Color/Grayscale] についてですが、これらはRGの値とBAの値を利用して、形状ごとに一意の値を生成、ここからランダムに色やグレースケールを求めるという手法を採っています。
とりあえず、[~ to Random Grayscale] の中身を見てみましょう。

f:id:monsho:20180906222054p:plain

[Pixel Processor] を2つ使っていますが、左下のノイズが表示されているものは [White Noise Fast] と近い処理を行っています。
重要なのはもう1つの方。こちらの中身を見てみましょう。

f:id:monsho:20180906223226p:plain

形状ごとに一意の値を求める、と前述しましたが、その部分は前半部分です。コメントで「upper-left corner」と書かれている部分までがその処理です。
あるピクセルの値を取得した際、そのピクセルが所属する形状のサイズ(BA)はその形状内では全て同一の値です。
違いがあるのはUV値となるRGの値ですが、RG * BAの計算で何が求められるかというと、そのAABBの左上からそのピクセルまでのXY軸の距離となります。
このピクセルの座標からこの値を引き算すると、求められるのはAABBの左上の座標、ということになります。
つまり、コメントどおりにこの段階で所属する形状のAABBの左上座標という、形状ごとに一意の値が求まることになるわけです。

ここで一意の値が求まっているわけですので、ノイズからサンプリングする座標をこのAABBの左上座標にしてみましょう。

f:id:monsho:20180906224837p:plain

左がオリジナルの [Flood Fill to Random Grayscale]、右がAABBの左上座標からノイズサンプリングをしたバージョンです。
サンプリングする座標が変わっているため、各形状のグレースケール値は変化していますが、縞模様は出ていません。
形状のサイズを様々に変更してみましたが、この手法で縞模様は出ませんでした。
つまり、後半の計算が縞模様を出す原因になっていると言えるわけです。
なお、[Flood Fill to Random Color] も同様の処理を行っていますが、やはり同じ改造で縞模様を消せます。

ここからはあくまでも私の想像ですが、デフォルトの [Flood Fill] 処理ではUVの値、もしくはAABBのサイズ、もしくは両方に微量の誤差が出ているのではないかと思います。
AABBの左上を求める計算でもその誤差が出ていて、同じ形状内だけど小数点以下の小さな値に微量の誤差が埋まっているのだろうと思われます。
そのままの座標をノイズサンプリングに利用した場合は誤差は切り捨てられて無視できるわけですが、65535 という大きな値をかけてしまったために誤差が顕在化しているのではないでしょうか?
[Flood Fill] ノードの中身を追ってみれば正確な原因もつかめるのかもしれませんが、軽く開いて絶望したので追いません。
なので、これらはあくまで予想ですが、そう外れてもいないんじゃないかと思っています。

というわけで、[Flood Fill] のエラー対策としては以下の手法のどれかを選ぶのがおすすめです。

  • No failure mode を使用する(簡単だけど処理時間大)
  • AABBの左上座標を用いてノイズサンプリングする(ノード化しておけばコストは安い)
  • to Random ~ の後に [Flood Fill to Color/Grayscale] を用いる(コスト安め)
  • [Flood Fill to Color/Grayscale] にノイズテクスチャを刺す(コスト安め)

3つ目と4つ目について簡単に解説します。

[Flood Fill to Color/Grayscale] は形状のAABBの中心座標の色を [Color/Grayscale Input] に刺したイメージからサンプリングします。
to Random ~ の後にこのノードを利用することで、AABB中心の色をサンプリングできます。
縞模様になっている形状の場合は縞のどの部分が選択されるか微妙ではありますが、縞模様になっていない形状についてはほぼ同じ色が取得できます。

f:id:monsho:20180906233814p:plain

ほぼ、と書いたのは、複雑な形状のためにAABB中心がその形状の外に行ってしまっているという稀有な状態の場合にうまくいかないという問題があるためです。

4つ目の手法を用いる場合の注意点としては、to Random ~は形状の境界部分が0、それ以外は0以上の値が入るように設定されている、という点です。
つまり、形状部分と境界部分が明確にされなければ、下手すると形状と境界が合体してしまうことがあるということです。
ノイズ生成時には注意しましょう。

Substance DesignerのPython Editorについて

新バージョンのSubstance DesignerにはPython Editorが搭載されているというのは前にも書きました。
これによっていろいろできるんじゃないか?と思って調べてみたことを今回は書きます。

まあ、ぶっちゃけてしまうと

今のところ使えねぇ!

です。

Python Editor

Substance DesignerのPython Editorは、メニューの[Window]→[Python Editor]から起動することが出来ます。
MayaのScriptウィンドウのような画面が出てくるでしょう。
Mayaと違うのは、上が編集画面、下がコンソール画面ということでしょうか。

ドキュメント

Python Editorの基本的な使い方、プラグインの作成方法はこちらにあります。

Python Editor - Substance Designer - Allegorithmic Documentation

また、APIのドキュメントはインストールフォルダ内にあります。
Python Editorウィンドウの[Help]→[Python API Documentation]をクリックすると開けます。

モジュール

Substance Designer特有のモジュールは sd です。
import sd でインポートできます。
あとはAPIドキュメントと先のSDのドキュメントを読めばとりあえずの機能実装はできるでしょう。

なお、Substance Automation Toolkitで使用できるPythonモジュールは pysbs です。
SDのモジュールとは別物ですね。
この時点で嫌な予感がしませんか?

プラグイン作成方法についてドキュメントを読む

最初はPython Editorの説明、操作方法等です。
How Toからプラグインの作成方法なので、そちらを見てみましょう。

Pythonプラグインの置き場所を設定したらメニューの [File]→[New Plugin]を選択してプラグイン作成ウィザードを立ち上げましょう。
プラグインの名前を決めて保存フォルダなんかも決定したらOKを押すと自動的に基本コードが生成されます。
しかもこの段階でプラグインとして登録されます。
メニューの[Scripts]→[作成したプラグイン名]で実行することが可能です。

APIドキュメントを読む

何ができるか知りたい場合、まずAPIドキュメントに目を通すのがいいでしょう。
作成したプラグインコードには run() 関数が存在し、ここに自前のコードを入力していくことになります。
ここの引数で aContext とありますが、これは sd.context 型です。

この型にはgetter以外の関数は存在しません。
ここで getSDApplication() 命令を実行し、sd.api.sdapplication を取得ます。
そして、getLocationContext()で sd.api.sdlocationcontext を取得すれば、ここから現在編集中のグラフや、選択しているノードの配列を取得することが出来ます。

さて、ここから何をやりましょうか?
というか、何ができるのでしょうか?
APIドキュメントに目を通してみましょう。

…getterがほとんど、設定したり作成したりはほぼ出来ない。
sd.tools.exportには指定したグラフの出力を行う命令がついていますが、出力するグラフと出力ディレクトリくらいしか指定できません。
他になにかないのか!と探しても特に見つからないでしょう。
まあ、つまり、そういうことなんです。

pysbsは使えない?

基本、使えません。
普通にpysbsをpipでインストールした場合、インストール先はSDとは別のPythonになるはずです。
SDにはインストールフォルダにPythonが存在するので、こちらで使えるように手動でインストールすればあるいは使えるかもしれません。

ただ、使えたとしても pysbs でグラフを作成→ファイルで保存→sdモジュールで読み込み、が関の山です。
残念ながら、sdモジュールのコンテキストやグラフに対して使用することは出来ません。

まとめ

今回のバージョンで追加された、ノードを整列する機能は、実はこのPythonプラグインとして作られていたりします。
他にもサンプルがいくつか存在してもいます。
が、現在はそれらのサンプルでできることくらいしか出来ないため、すぐになにか効率よくできる、というわけではないようです。
実はドキュメントのバージョンが古いだけでもっといろんな事ができる、という可能性を否定もしませんが。

もし、ドキュメント以上の機能が見つけた方がいましたら教えていただけるとありがたいです。

Substance Designer 2018 Summerの新ノード

というわけで、新しく追加されたノードも調べてみたので、適当に紹介してみます。

Gradient系

f:id:monsho:20180721102119p:plain

グレースケールのグラデーションを作成するノードが追加されてます。
以前はLinearだけでしたが、今回はポイントを指定してグラデーションを作成するノードになっています。
多分、Subsntace Shareでユーザが公開していたものを取り込んだのではないかと思います。

[Gradient Axial]と[Gradient Axial Reflected]は指定した2点を補間するようにグラデーションを作成します。
Reflected の方は中心で折り返す感じですね。

[Gradient Circular]は見ての通り角度に対してグラデーションがかかるようになっています。
円グラフ的なメーターのようなUIを作成するときに重宝するでしょう。
[Gradient Radial]は円状にグラデーションを作成できます。
この2つは中心ともう1点を指定することでグラデーションを変更することができます。

Cube 3D GBuffers

f:id:monsho:20180721102850p:plain

以前からあった[Cube 3D GBuffers]ノードはですが、UVの出力が追加されています。
使い道は今の所考えられていないのですが、使えばこんな事もできます。

f:id:monsho:20180721103508p:plain

だからなんだって感じですが…

Shape Extrude

f:id:monsho:20180721104439p:plain

名前の通り、形状の押し出しを行うノードです。
サンプルとして薬莢がばらまかれたようなマテリアルが示されていましたが、たしかにその手の使い方ができるノードですね。
これまでだと、そのような立体感のあるマテリアルを作成するのが少し難しかったので。
ただし、かなり重いので多用は厳禁ですかね。

Flood Fill

[Flood Fill]ノードの性能がアップ!待ってた!
これまでの[Flood Fill]は凹形に弱かったのですが、新バージョンでは凹形でも綺麗に処理してくれます。
以下のようなものを旧バージョンで試してもらえば一目瞭然です。

f:id:monsho:20180721110054p:plain

また、[Flood Fill]系のノードが2つ追加されて、1つに変更が入ってます。

f:id:monsho:20180721110955p:plain

[Flood Fill to Gradient]には角度とスロープのイメージ入力が追加されています。
[Tile Sampler]と同じように、入力したグレースケールイメージから角度とスロープのパラメータを取得して適用することができます。
[Flood Fill to Grayscale]と[Flood Fill to Color]も入力イメージからグレースケールとカラーを取得して適用するノードです。

Quad Transform、Trapezoid Transform

f:id:monsho:20180721111717p:plain

形状変形ノードが2種類追加されています。
[Quad Transform (Grayscale)]は四角ポリゴンの4点を自由に移動することで形状変形が可能です。
これまで以上に自由な形状生成が可能になったのでかなり便利なノードだと思います。
また、このノードはタイリングされないようです。

[Trapezoid Transform (Grayscale)]は台形変形です。上部と下部のサイズのみ指定可能です。
[Quad Transform]の簡易版に近い印象ですが、こちらはタイリングされます。

Shape Splatter

今回の目玉ノードがこちらになるのかなと思います。[Shape Splatter]です。
名前から[Splatter]や[Splatter Cirsular]の仲間と思われるかもしれませんが、どちらかというと[Tile Sampler]の亜種といった感じです。

f:id:monsho:20180721113317p:plain

入力ピンを見てもらえれば[Tile Sampler]に近いことがわかりますね。
なお、処理の重さも近いです。というか、こっちのほうが重いかも?

簡単な使い方としては地面に沿って何かを配置するなどです。
以下のようにするとわかりやすいでしょうか。

f:id:monsho:20180721113956p:plain

しかし、同じことは[Tile Sampler]と[Blend]の加算でも可能です。
では、こちらはどう違うのか?というと、いろんな機能が追加されています。
例えば、地面に沿って方向を変更したり、地面に平行に配置したりが可能です。

f:id:monsho:20180721114537p:plain

スロープの方向に回転していたり、平行に配置されたりしてるのがわかるでしょうか?

また、出力ピンの[Splatter Data 1/2]にはパターンのID、インデックス、UV、バウンディングボックスサイズなどが入っています。
これを利用することで後で情報を追加したりすることができます。
[Shape Splatter Data Extract]を使うとそれらの情報へのアクセスも容易になります。

f:id:monsho:20180721115140p:plain

使い道はいろいろありそうなので、面白い使い方を見つけた人は是非教えてください。

その他

[Auto Levels]に修正が入ったようですが、イマイチ差がわからず。

[Material Transform]で法線の回転がサポートされています。
使ったことがないのでわからないのですが、以前は法線方向が正常に回転しなかったっぽいですね。
これに関連して、[Normal Transform]ノードと[Normal Vector Rotation]ノードが追加されています。

f:id:monsho:20180721120036p:plain

[Normal Transform]は法線方向を形状ごと回転する、[Material Transform]との法線回転と同様のものになります。
[Normal Vector Rotation]は形状はそのままに、法線の方向だけを回転するようです。
使い道あるのでしょうか、これ?

[Shape]ノードにHemisphere、つまり半球が追加されています。
そういえばなかったな、この形状…

というわけで追加、修正ノードのまとめでした。
抜けがあるかもしれませんが、あったら教えてください。

Substance Designer 2018 Summerの新機能

唐突にバージョンアップがあったのですが、とりあえず調べてみた新機能等をサクッと紹介してみようと思います。

UIの変更

少し前のSubstance PainterのアップデートでUIが変わりましたが、Substance Designerも同様の変更が施されました。
正直な話、前の方がよか…げふんげふん。

f:id:monsho:20180721005811p:plain

特に変わったのはグラフエディタの上部のAtomicノードボタン。
以前はアイコンというよりノード名のイニシャルだったのが、アイコンに変化しました。
なれるまでに少し時間がかかりそうです。

f:id:monsho:20180721005851p:plain

ノードの整列

これまでなかったノードの整列機能が追加されました。
選択したノードを水平に並べるか、垂直に並べるかを選べます。
また、グリッドにスナップしていないノードを自動的に近いグリッドにスナップさせる機能も追加されています。

ボタン操作はグラフエディタの上部にあります。

f:id:monsho:20180721011016p:plain

左から水平に整列、垂直に整列、グリッドにスナップです。
ショートカットキーはそれぞれ H, V, S となっています。

整列機能は機械的に水平・垂直に整列するだけなので、過剰な期待は禁物です。
また、複数ノード選択→H→Vとやると、すべてのノードを1箇所にまとめることができます。
完全なクソノード配置なので止めましょう。

Input/Outputの色空間指定

Input/OutputノードのUsageに色空間指定項目が追加されています。

f:id:monsho:20180721012124p:plain

ここを変更することで出力される結果が変わるかというと、そんなこともなかったです。
指定することで良いことあるのかは今のところ不明ですね。

読み込みオンリーグラフのPixel Processor

これまでも読み込みオンリーのグラフは "Open Reference" メニューで見ることができました。
しかし、実際に見られるのは表側だけで、Pixel Processor の中身を見ることができませんでした。
今回のバージョンからは普通に内部まで覗けるようになりました。

まあ、これまでもノードをコピペして読み書き可能なグラフに持っていけば中身を見られたので、それに慣れてる人にはさほど嬉しくない機能かもしれません。

Pythonスクリプトが使えるようになった?

メニューに [Scripts] メニューが追加されています。

f:id:monsho:20180721013454p:plain

現在はサンプルがいくつか入っているだけのようですが、自分たちでも追加できるようになっているかもしれません。

追記

Pythonを使用してスクリプトを行う場合、自身のプロジェクトを設定することが可能です。

f:id:monsho:20180721095802p:plain

ここにディレクトリを設定すればOKっぽいですが、URLなのでウェブ上のものでも可能っぽいですね。
加えて、Pythonエディタが存在しています。

f:id:monsho:20180721095959p:plain

メニューの [Windows]→[Python Editor] で開けます。
開いたWindowはこんな感じ。

f:id:monsho:20180721100405p:plain

Mayaとかと同じような感じの基本的なエディタですね。
ちゃんとコンソールにエラー表示とかもされるので、最低限のエディットは可能じゃないでしょうか。

使い道としてはグラフを作成したりノードを追加したりが可能だと思うのですが、普通にテンプレートグラフ作っとけとかグラフ化しておけという感じで対応できるものではあるので、イマイチ使い道に困りそう。
なにかアイデアあったら教えてください。

次の記事では新規に追加されたノードの紹介をしていこうと思います。

Substance Painter用フィルタの作り方(応用編)

前回の実践編ではフィルタを適用したレイヤーの各イメージを法則に従って変換するという、比較的簡単なフィルタの実装を紹介しました。
この手のフィルタはSubstance Designer上でもそのまま使える便利なフィルタですが、今回紹介するのはSubstance Painterのペイント機能を主に利用したちょっと特殊なフィルタの作り方です。
作るものはこんな感じのものです。

f:id:monsho:20180616010721p:plain

ちょっと前にTwitterにも上げましたが、上のレイヤーのペイントが剥げて下のレイヤーが見える、というようなフィルタです。
剥げる部分はSPのペイント機能を使ってペイントして指定します。

このような処理はSPの機能でも実現できるか?というと、可能ではありますが少々面倒です。
下のレイヤーが見えるようにするにはマスクを使えばいいので、ペイントと各フィルタで対応できます。
しかし、剥げた部分の周囲のペイントがめくれ上がる、というのはそれほど簡単ではないと思います。
今回のフィルタはそのようなことが1つのフィルタと1つのレイヤーで実現することができます。

ただ、注意として、あまり出来は良くありません。
実用的なものにするにはもっと詰める必要はあると思いますが、そこはまあ、自分なりに応用してみてください。

今回やること

今回新しく使用している手法は以下のものとなります。

  • User定義マップを使用して他のマップに迷惑をかけないペイントを行う
  • ペイント部分を取り出して効果を適用する
  • 下のレイヤーが見えるように疑似マスクを利用する

実際に作成しながら1つ1つ見ていきましょう。

User定義マップ

User定義マップはSPで使用できるマップの一種ですが、特に用途が決まっていないのでユーザが適当に用途を決めていいマップです。
これらは何らかの情報として出力することもできますし、今回のようにフィルタの起点とすることもできます。
使い方を決めるのはユーザなので、SP上では特に何かが起こったりしないマップチャンネルです。

SPのテクスチャセット設定でチャンネルを追加できますが、ここでUserマップの追加が可能です。

f:id:monsho:20180616011410p:plain

User定義マップは複数種類が使用できますが、今回は "User0" を使用することにしましょう。

SDでフィルタを作成するときは、入力のIDに user0 を指定します。
今回はまず "Painter Filter (specific)" のテンプレートからグラフを作成し、[Input] ノードを1つ追加します。
Attributes の設定は以下のようにします。

f:id:monsho:20180616011829p:plain

Usage の項目には実は User0 という項目がドロップダウンリストには存在しませんが、直入力で設定してください。
SPで User0 チャンネルを追加してそこにペイントしたりするとこの [Input] ノードに情報が入ってくるという寸法です。

ペイント部分を取り出す

SPで User0 のチャンネルにペイントが施されていると想定して話を進めます。
前述の通り、ペイントした結果は SD の [Input] ノードに入ってきますので、これをタネとして処理を作っていきましょう。

しかし、ペイントが剥げたような処理を1から実装するのは面倒なので、以前Substance Shareにアップしたグラフを使用します。

share.allegorithmic.com

このグラフはペイントが剥げた際のペイント部の高さ、ノーマル、ペイントが剥がれている部分のマスクを出力してくれます。
これをダウンロードしたら、作成したフィルタにリンクしてください。
配置しましたら、まず以下のように組んでみましょう。

f:id:monsho:20180616021905p:plain

User0の [Input] ノードをリンクした [Paint Peeling Mask] ノードに接続します。
途中で [Histogram Scan] ノードを経由していますが、[Paint Peeling Mask] が0/1の2値画像を必要としているためです。
2値画像でなくても動作はしますが、結果を保証できないために採用しています。

[Paint Peeling Mask] の出力にあるHeightは元のHeightチャンネルに加算しておきましょう。
このノードにはペイントの基本高さを設定するパラメータがありますが、特に変更する必要は感じませんでした。

下のレイヤーが見えるようにする

SP で下のレイヤーを見えるようにする最も良い手段はマスクを利用することですが、レイヤーのカラーチャンネルに適用されたフィルタからマスクチャンネルを設定する手段はありません。

ではどうすればいいかというと、実はフィルタの出力にはアルファ値を含めることができます。
アルファ値が含まれている [Output] ノードの場合、そのチャンネルのブレンド時にアルファ値が考慮されます。
つまり、同じマスクをすべてのチャンネルに対してアルファ値として出力することで、マスクと同じ結果を生み出すことができるというわけです。

それを考慮した最終結果は以下のようになります。

f:id:monsho:20180616030646p:plain

[Paint Peeling Mask] ノードから出力されるマスクは、ペイントが剥がれている部分が1.0、ペイント部分が0.0で出力されるので、[Invert Grayscale] ノードで反転してからアルファ値として適用します。
Base Color はRGBを出力する必要があるので [Alpha Merge] ノードを利用していますが、Roughness、Metallic、Heightは1チャンネルなので [RGBA Merge] ノードを利用しています。

最後に [Paint Peeling Mask] のパラメータをExposeして終了です。
Exposeしたいパラメータは好きなものを選択しましょう。ただ、今回はノーマルを利用していないので Normal Intensity パラメータは不要でしょう。

ここで1つ注意点を。
SDで設定される入力パラメータは最大値と最小値を設定することができます。
Clamp の項目を True にしない限り、最大・最小値はスライドバーの変動可能範囲を示すだけで、数値の直接入力を行うと最大値を大きく超えて設定することができます。

しかし、SPではこの方法が不可能になっているようです。
SDで設定した最大・最小値の間でスライダーを動かすことができ、数値の直接入力でも最大・最小値の値に収めるためにClampされてしまいます。
現在はまだ回避方法はなさそうなので、十分広い範囲を指定しておく方がよいと思います。

SPでペイントする

SPではまずテクスチャセット設定ウィンドウでUser0のチャンネルを追加しましょう。
そして、ペイントマテリアルのレイヤーを上に、下地のレイヤーを下にして、ペイントマテリアルのレイヤーにフィルタを以下のように設定します。

f:id:monsho:20180616032124p:plain

"Add Paint" でペイントを追加してから "Add Filter" で Paint Peeling Filter を指定します。
あとはこの追加ペイントでUser0のみにペイントすればペイントが剥がれたような結果を確認できるでしょう。
なお、モノクロ画像をUser0に適用すればよかったりするので、ペイントではなく塗りつぶしを使ってもよかったりします。

さて、全3回でSubstance Painter用のフィルタの作成方法を紹介しました。
今回作ったものは実用しようと思うともう少し詰めないと厳しい部分はありますが、作り方はわかったのではないでしょうか。
あまり日本語情報が多くない分野だなと思っていたので、人によっては役に立つ情報なのかなと思います。

Substance Painter用フィルタの作り方(実践編)

前回はSubstance Painter用のフィルタをSubstance Designerで作る際の基本的な部分やSP上での確認方法、イテレーションなどについて紹介しました。
今回は実践編と称して、簡単だけど少し実用的なフィルタを作ってみようと思います。
作ってみたのはこんな感じのフィルタです。

f:id:monsho:20180614233752p:plain

水に濡れたような表現を実装するためのフィルタです。
こちらを追加マップも利用して作ってみましょう。

濡れた表現の実装

元ネタはこちらのリンクです。

Water drop 3b – Physically based wet surfacesseblagarde.wordpress.com

古い記事ですが、水に濡れた表現について一連の記事でいろいろ触れられています。
今回はベースカラーとラフネスの計算式だけ拝借しています。
基本方針は、物体が濡れるとベースカラーが暗くなり、ラフネスが下がるという処理を作るだけです。

まず、SDでグラフを新規作成します。テンプレートは "Painter Filter (specific w/ additional maps)" を選択します。
今回出力するのは Base Color と Roughness なので、Metallic と Height の出力ノードは削除しましょう。

上記ブログに DoWetProcess() という関数がありますが、まずその中で使われているパラメータを作成します。
Porosity というパラメータはテクスチャからフェッチしていますが、今回は入力パラメータとして一律のものを使うことにします。
WetLevel も全体で一律のパラメータにしましょう。

f:id:monsho:20180615000704p:plain

入力パラメータを追加したら Base Color の [Input] ノードに [Pixel Processor] を接続、内部をこのように記述します。

f:id:monsho:20180615002037p:plain

同様に、Roughness の [Input] ノードにも [Pixel Processor] を接続し、こう記述します。

f:id:monsho:20180615002152p:plain

[Pixel Processor] の Color Mode は各 [Input] ノードに準拠させておきましょう。
とりあえずこの出力を各 [Output] ノードに接続し、一旦 .sbsar に変換してSPで使ってみましょう。
地面とかコンクリートのマテリアルに適用するとそれっぽくなると思います。
Porosity や WetLevel もいじって、どう変化するか試してみてもいいでしょうね。

くぼみの部分だけ濡れるようにする

現在のフィルタでもSP上でマスクと組み合わせれば十分利用は可能です。
マスクを自由に生成できる、という点を考慮すればそちらの方が自由度は高いですね。
ですが、折角なので追加マップを利用して濡れている部分と濡れていない部分を分けてみましょう。

濡れた物体は溝などのくぼみが乾きにくかったりしますね。
くぼみと言えばAOがそんな感じのマップですので、AOの暗い部分だけ濡れた状態を作るようにしてみます。

最初に追加マップのAOを以下のように接続します。

f:id:monsho:20180615004234p:plain

[Histgram Scan] ノードの2つのパラメータは Expose しておきましょう。
このノードの出力はマスク情報として使用されるので、以下の [Blend] ノード2つの Opacity として設定します。

f:id:monsho:20180615004703p:plain

ここまで設定したら再度 .sbsar を出力し、SPで試してみましょう。
最初に作ったのは全体に適用してしまっていますが、今回の修正でAO部分のみ濡れている表現ができているはずです。

上部を濡れやすくする

雨で濡れているような表現も入れてみましょう。
雨が降ってきて濡れるのは基本的には上向きの部分で、下向きの部分はあまり濡れないはずです。
World Space Normal を利用することでこれを実現できます。

しかし、上向きの部分を全部濡らす、というだけではつまらないです。
濡れている/いない部分の境界部分には少しノイズを入れたいでしょう。
それを加味して、以下のようにノードを組んでみました。

f:id:monsho:20180615011902p:plain

まず、World Space Normal の Y軸パラメータを取得します。これは上向きなら1、下向きなら-1の値になります。
次の [Pixel Processor]ではこのY軸の値に0.5を乗算、その後に0.5を加算しています。
これによって -1~1 の値だったY軸の値が 0~1 の値になります。こちらの方が扱いやすいのでこうしています。
このノードを [Histgram Scan] に接続しますが、Position と Contrast はやはりパラメータとして Expose しておきましょう。

ノイズは適当なGrungeMapを利用しています。今回は13番ですね。
これはお好みでいいですし、SPで設定できるようにしてもよいでしょう。
これをそのまま利用すると、SP上でUVの切れ目でループしない問題が出てきてしまうので、[Tri Planar Grayscale] ノードを使って切れ目が目立たないようにします。

最後にGrungeMapを Background、Y軸パラメータから求めたものを Foreground に設定し、Blending Mode に Add Subを設定します。
そして、AOによるマスクの出力データとY軸の値をベースとするマスクのデータを加算して、これを最終的なマスクとします。

終結果はこうなります。

f:id:monsho:20180615013033p:plain

1つ1つのノードはわからないと思いますが、どこをどう接続するかだけ理解できれば、ここまでの説明でわかるんじゃないかと思います。
実際のフィルタ動作はSP上で確認してください。

というわけで実践編でした。
次回は応用編として、もう少し複雑なことをやってみようと思います。

Substance Painter用フィルタの作り方(基礎編)

今回の記事はSubstance Painter用のフィルタをSubstance Designerで作成する基礎的はお話です。
ちょっと前にTwitterで流したやつの作り方をやる前に、まず基本的な部分を押さえておきましょう、ということです。
チュートリアルは Allegorithmic 公式からも出ていますし、難しいものではないのですが、とりあえず作ったことがない人向けなのでかなり初歩からの解説となります。

Substance Designer編

まずはSubstance Designerで簡単なフィルタを作成します。
新しいグラフを作成しますが、テンプレートとしては以下の3つのどれかを選択します。

f:id:monsho:20180614004327p:plain

(generic) は特に指定のない[Input]ノードと[Output]ノードが1つ置かれているだけの簡単なものです。
(specific) は入力ノードと出力ノードが4つずつ置かれています。Base Color / Roughness / Metallic / Heightですね。
(specific w/ additional maps) は (specific) と同様の入力と出力を持ち、加えてメッシュからベイクされたワールド法線、ポジションなどのマップも参照できるようになっています。
今回は (specific) を選択しましょう。
グラフ名はなんでもいいですが、今回は FilterTutorial という名前にしました。

グラフが表示されたら [Input] ノード、および [Output] ノードの Base Color以外を削除してしまいましょう。
今回は使いません。
次に以下のようにノードを組みます。

f:id:monsho:20180614005217p:plain

[HSL] ノードの [Saturation] パラメータは 1.0 にしておきます。
このグラフを一旦保存して、それから .sbsar を生成します。
生成するには、生成したグラフを選択してから以下のボタンを押してください。

f:id:monsho:20180614005504p:plain

保存フォルダとファイル名を決定し、保存をします。
保存する際に以下のようなダイアログが出てきますが、[Pixel size] のパラメータは不要なのでチェックを外しておきましょう。

f:id:monsho:20180614005638p:plain

これでSD側の作業は終了です。

Substance Painter

次にSubstance Painterを起動し、適当なプロジェクトを作成するか読み込みます。
とりあえず PreviewSphere をサンプルから読み込んだ方がテストするにも簡単でしょう。

プロジェクトを開いたらSDで保存した .sbsar ファイルをドラッグ&ドロップしましょう。
すると以下のダイアログが出てきますので2つのパラメータを変更します。

f:id:monsho:20180614011433p:plain

上の方はインポートするリソースのカテゴリーで、今回は "filter" にします。
下の方はこのリソースの寿命で、"project '~'" を選択するとこのプロジェクトを編集中にのみ有効になります。
つまり、このプロジェクトを閉じるとインポートしたリソースも消えます。
今回はテストなので永続的に置かれても困りますのでこのようにしました。

ではテストです。
適当なマテリアルをFillレイヤーに追加し、ここに Add Filter でフィルタを設定、追加したテストフィルタを設定してみましょう。
Base Colorの色が鮮やかになるのがわかるでしょう。
フィルタをON/OFFすれば色が変わるのを確認できるはずです。

何をしたのか?

SDで作成したフィルタは極めて簡単です。
入力として、フィルタが設定されたレイヤーの Base Color を取得します。
この Base Color はそのレイヤーのみの結果です。それまでのレイヤーのすべてを合成した結果ではないので注意してください。
そのため、ペイントしたレイヤーにフィルタをかけるとペイント部のみに効果がかかります。

で、この入力した Base Color に [HSL] ノードを使ってサチらせます。
そしてこのノードから最後の出力ノードに出力します。
出力先は Base Color なので、入力してきた Base Color を鮮やかな色合いにするだけし直しています。

なお、[Input] / [Output] ノードで特定の情報を入出力として扱いたい場合は、Identifier もしくは Usage に適切なものを選択します。
どのようなIDが有効かは以下のドキュメントから確認できます。

Channel specific filter - Substance Painter - Allegorithmic Documentation

フィルタを修正してみる

ちょっとフィルタを修正してみましょう。
SD に戻って [HSL] ノードのすべてのパラメータを Expose してください。
これを保存し、再度 .sbsar ファイルに出力します。

今度は SP に戻って、シェルフから今回作ったフィルタを選択、右クリックしてみてください。

f:id:monsho:20180614013615p:plain

このようなダイアログが表示されるので、[Reload] を選択しましょう。
リロード後、先ほどフィルタを設定した部分に新しいフィルタをD&Dしましょう。
すると [HSL] ノードの3つのパラメータをいじれるようになっているはずです。

とまあ、こんなところです。
次回は応用編です。