こんにちは、Steemです。紅葉の季節ですね。
…と言いながら書いていたのですが、クリスマスも過ぎてしまいました。だいぶ間隔を開けてしまいましたね。(前回記事は11月の頭でした。)
今回は前回に続く、Maya用タイル作成シェーダーの紹介です。
スクリプト概要
機能
- UV座標に基づいたグリッド模様の生成を行うArnold用OSLシェーダー。
用途
- 実寸に基づいたタイル状のテクスチャの作成
- 既存のテクスチャへのタイル目地の追加
- グリッド形状のマスクの作成 等。
前回記事との違いは、前回はパターンの作成にWorldXZ座標を用いていたのに対し、今回はUV座標に基づいたものに変えています。
新たに考慮すべき点は増えていますので、ちょっとした発展形と言えるかもしれません。
「OSLシェーダー」については前回記事を参考にしてください。
操作
動画
シェーダーを用いてタイルテクスチャを合成しています。
以下の特長があります。
- 実寸で・自由に タイルの大きさを決められる
- あらゆるテクスチャを タイルにできる
シェーディングネットワーク図
動画で使用したシェーディングネットワークの概観です。(クリックで拡大)
使用しているOSLシェーダーは
- 「MaskAndOffsetWorldXZ」
- 「TextureCombiner」
の2つです。これらのノードが
- 「タイルの大きさや幅の太さ等タイルの形状を設定」
- 「タイル別 + タイル内にランダムな色の変化をつける」
- 「Color、Height、Roughnessをそれぞれ合成し、テクスチャとして出力」
といった一連の処理を行います。
操作手順
- Hypershadeでシェーディングネットワークを構築またはマテリアルをインポート(mbファイルを使用)
- MaskAndOffsetUVノード(OSL)を設定
タイルの寸法・回転といった形状設定からマスク・オフセットを出力 - TextureCombinerノード(OSL)を設定
入力されたテクスチャ・マスクの情報からColor、Height、Roughnessマップをそれぞれ合成し出力 - Arnoldレンダービューで確認
アトリビュートのイメージ :
MaskAndOffsetUVノード
まず一つ目のOSLノードです。
サイズ設定について
これには、Texel Density の値を利用しています。これは単位が px/unit (デフォルトではpx/cmにあたる)の実寸を用いた密度値のことで、「ジオメトリの1cmがテクスチャで言う何ピクセルに当たるか」を示す値です。この値を用いて、UV値を実寸に換算します。
なお、実際はUV値と実寸値の間で直接換算することも可能なのですが、便宜上「テクスチャサイズ」を介して計算するようにしています。
(特別なスクリプトを使用せずにUVエディターでこのテクセル密度は簡単に取得でき、密度の均一化操作等にも便利な単位なので、「テクスチャサイズ」「テクセル密度」を入力することで実寸に対応するuv間隔を計算する仕組みです。)
また、このTexel Densityはスクリプトで容易に取得可能です。
(Texel Densityの取得・ウィンドウ表示を行う簡単なサンプルスクリプトを載せてしまいます。)
// コピー可能なウィンドウ表示 Displays the result in a copy-friendly text window
global proc showTexelDensityInEditableTextField(string $text)
{
if (`window -exists texelDensityWin`) {
deleteUI texelDensityWin;
}
window -title "Texel Density Report" -widthHeight 500 200 texelDensityWin;
columnLayout -adjustableColumn true;
scrollField -editable false -wordWrap true -text $text -height 350 texelDensityTextField;
showWindow texelDensityWin;
}
// Calculates texel density for selected objects and outputs a formatted report
global proc calculateTexelDensitySimple()
{
texCheckSelection("any");
float $scale = 100; //小数点以下の桁数を指定 Controls the number of decimal places
int $mapSize = 512; //テクスチャサイズを指定 Assumed texture size (square texture, resolution in pixels)
$faces = `polyListComponentConversion -toFace`;
float $area3D[] = `polyEvaluate -worldFaceArea $faces`;
float $area2D[] = `polyEvaluate -uvFaceArea $faces`;
float $texelDensity = `texGetTexelDensity($mapSize)`;
//四捨五入の処理 Round to the specified number of decimal places
$texelDensity = ($texelDensity >= 0)
? int($texelDensity * $scale + 0.5) / $scale
: int($texelDensity * $scale - 0.5) / $scale;
string $result = "=== Texel Density Report (px/cm) ===\n=== " + $mapSize + "px Texture ===\n\n";
$result += ("Surface Area: " + $area3D[0] + " cm²\n");
$result += ("UV Area: " + $area2D[0] + "\n\n");
$result += ("Texel Density: " + $texelDensity + " px/cm\n");
showTexelDensityInEditableTextField($result);
}
//実行 Run the tool
calculateTexelDensitySimple();
結果表示:
入力
設定するのは、タイルの寸法やオフセットのスケールといった形状に関する項目です。
具体的には、以下の項目が並びます。
- Texel Density (px /unit)
- テクスチャサイズ
(Texel Densityの取得に使用した値を入力。UV密度の換算に使用) - タイル幅
- 目地の幅
- ブラー(タイルと目地の境界、Heightマップにおける傾斜に相当)
- テクスチャオフセットに用いる乱数のスケール (ランダム変化のスケーリング、0のときはオフセットなし)
- Rotate (模様を回転させる)
- Offset (模様を移動させる
- マスク作成範囲 (UV座標で指定)
出力
出力するのは、
- Line Mask:タイル部分と目地部分を分ける
- Random Value:タイルごとの色の違いを作成
- Texture Offset:タイルひとつひとつのテクスチャのオフセットに用いるベクトル
といったものです。これらの値を他のノードに接続します。(接続先については先程載せたシェーディングネットワークを参照のこと)
※Texture Offset の値は MultiplyDevide ノードに接続しています。こちらは入力に1をかけているだけで値を変化させていませんが、こうしたノードを経由しないとplace2dTextureノードへの入力が反映されないようなので注意が必要です。
TextureCombinerノード
続いて、2つ目のOSLノードです。内容は前回記事と同じですが、再掲です。
入力
入力できる項目は
- Random Color :ランダム値を用いた乗算に用いるカラー
- Random Noise :乗算用ノイズテクスチャ
- タイル部分のテクスチャ (カラー・ラフネス・Height)
- 目地部分のテクスチャ (カラー・ラフネス・Height)
といった、テクスチャ・マスクに関する情報です。これらを合成して最終的なテクスチャとして出力します。
出力
入力した値は、
- Color Out
- Height Out
- Roughness Out
として出力されます。これらをシェーディングエンジンに接続される最終的なシェーダーノードに適宜接続することで、結果が反映されることになります。
Metalness・Opacityといった項目は入れていませんが、必要であれば、Roughnessの計算で用いているコードをそのままコピーし、変数の名前を変えればすぐに実装は可能です。(タイル・目地それぞれに一定の値を適用するので十分であれば、一つ目のOSLシェーダーから出力した Line Mask のColorをaiRamp系統で調節して接続すれば事足ります。)
Random Color については、この2つのカラーのRGB値を Random Value: タイルごとのランダム値 を用いてリニア補間しタイル部分に乗算することで、タイルにランダムな色のばらつきを与える仕様です。(そのため1色目は乗算しても変化しない白:RGB(1, 1, 1)がデフォルトです。)
リニアでなく例えばガウス分布などに近づけたい場合は乱数生成時もしくは合成時の数式の変更が必要になります。
追加説明
MaskAndOffsetUV ノードでは、目地部分の作成範囲をUV座標系で指定できます。
それによって、「この部分に目地はいらない」という部分のUVをマスク範囲の外側に避けることが可能です。
そのため、ひとつのシェーディングネットワーク内に複数の aiOslShader を用いて合成すると、複数種類のサイズをタイルのマスクを作成することも可能です。
その際のマスクの合成についてですが、動画内では分かりやすさのため「Mask」はタイル部分を白・目地部分を黒にしたのですが、実際の色は反転しています。(あくまでノードの出力名はLine mask = ライン部分のマスク:目地が1、タイルが0です。)
そのため、複数のマスクを重ねて使用したい場合はスクリーン合成などを使用します。(aiColorCompositeノードなど使えばうまく合成できるはずです)
機能についての説明は以上です。
おわりに
今回はシェーダーとそれを含むシェーディングネットワークを作成しました。
(前回記事:ワールドXZ座標版もあるのでぜひご覧ください。)
当スクリプトの配布・販売予定については未定(調整中)です。
続報をお待ちください。



