こんにちは、Steemです。紅葉の季節ですね。
…と言いながら書いていたのですが、クリスマスも過ぎてしまいました…だいぶ間隔を開けてしまいましたね。
こちらは前回に続く、タイル作成シェーダーの紹介です。
というのも、換骨奪胎とはこのこと、 前回はタイルの模様をWorldXZ座標を用いて投影していたものを、今回はUV座標に基づいたものに変えています。
新たに考慮すべき点は増えていますので、ちょっとした発展形と言えるかもしれません。
動画
機能説明
今回はタイルの模様をUV座標に基づいて投影するシェーダーを、 aiOslShader を用いて作成しています。
作成したシェーダーは2つ、
- "MaskAndOffsetUV"
- "TextureCombiner" (前回記事と同一のもの)
です。これらを用いて、
- 実寸でサイズを自由に決められる
- あらゆるテクスチャを分割できる
- 一般的なテクスチャと同様UV座標を用いる
シェーディングネットワークを作成します。
なお、aiOslShader 及び OSL については前回記事で簡単に触れているのでそちらをご参照ください。
シェーディングネットワーク:
UIのイメージ :
MaskAndOffsetUVノードのコンセプト
これには、Texel Density の値を利用します。この言葉はUV Editor内 UV Toolkit にて見かけたことがあるかもしれません。
これは単位が px/unit ( = px/cm)の、実寸を用いた密度値のことで、「ジオメトリの1cmがテクスチャで言う何ピクセルに当たるか」を示す値です。この値を用いて、UV値を実寸に換算します。
なお、この計算のために便宜上「テクスチャサイズ」を設定する必要があります。
あくまで便宜上の数値なので実際はUV値と実寸値の間で直接換算することもできるのですが…
UVエディター内 ではテクスチャサイズに換算した密度(デフォルトで512px)を扱っているので、値へのアクセスのしやすさからテクスチャサイズを含めた値を用いるものとします。
また、このTexel Density 、UV Toolkit 上で確認する以外にスクリプトで容易に取得可能です。
(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;
//コピー対応テキストフィールド Read-only multi-line text field for easy viewing and copying
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();
結果表示:
MaskAndOffsetUVノード
それでは、一つ目のOSLノードについてです。
入力要素
設定するのは、タイルの寸法やオフセットのスケールといった形状に関する項目です。
具体的には、以下の項目が並びます。
- Texel Density (px /unit)
- テクスチャサイズ
- (デフォルトで512px、Texel Densityの計算に使用)
- タイル幅
- (タイル中心間の間隔)
- 目地の幅
- ブラー
- (タイルと目地の境界、Heightマップにおける傾斜に相当)
- テクスチャオフセットに用いる乱数のスケール
- (0~1の乱数にこの値を乗算する、0はオフセットなし)
- Rotate (テクスチャ全体を移動)
- Offset (テクスチャ全体を回転)
- マスク作成範囲 (UV座標で指定)
出力要素
出力されるのは以下の3つです。
- Line Mask:タイル部分と目地部分を分ける
- Random Value:タイルごとの色の違いを作成
- Texture Offset:タイルひとつひとつのテクスチャのオフセットに用いるベクトル
これらの値を適切な箇所に接続し、次のノードに処理を受け渡します。(接続先については先程載せたシェーディングネットワーク(画像)を参照のこと)
※Texture Offset
の値はMultiplyDevideノードに接続しています。こちらは入力に1をかけているだけで値を変化させていませんが、こうしたノードを経由しないとplace2dTextureノードへの入力が反映されないようなので、自身でネットワークを作成する際にはお気を付け下さい。
TextureCombinerノード
続いて、2つ目のOSLノードです。内容は前回記事と同じですが、再掲です。
入力要素
入力できる項目は
- Random Color:
- ランダム値を用いた乗算に用いるカラー
- Random Noise:
- 乗算用ノイズテクスチャ
- タイル部分のテクスチャ (カラー・ラフネス・Height)
- 目地部分のテクスチャ (カラー・ラフネス・Height)
といった、テクスチャ・マスクに関する情報です。これらを合成して最終的なテクスチャとして出力します。
なお、Metalness・Opacityの項目は入れていません。
もし拡張が必要であれば、Roughnessの計算でで用いているコードをそのままコピーし、変数の名前を変えればすぐに実装はできると思います。
(またタイル・目地それぞれにひとつの値を適用するので十分であれば、一つ目のOSLシェーダーから出力した Line Mask のカラーをaiRamp系統で調節して接続すれば事足ります。)
Random Color については、2つのカラーのRGB値を Random Value: タイルごとのランダム値 を用いてリニア補間しタイル部分に乗算することで、タイルに色のばらつきを与えます。(そのため1色目は白:RGB(1, 1, 1)が推奨です。)
リニアでなく例えばガウス分布などに近づけたい場合は乱数生成時もしくは合成時の数式の変更が必要です。
出力要素
このノードに入力した値は、
- Color Out
- Height Out
- Roughness Out
として出力されます。これらを最終的なシェーダーノードに適宜接続することで、結果が反映されることになります。
追加説明
MaskAndOffsetUV ノードでは、目地部分の作成範囲をUV座標系で指定できます。
それによって、「この部分に目地はいらないな…」という部分のUVをマスク範囲の外側に避けることが可能です。
そのため、ひとつのシェーディングネットワーク内に複数の aiOslShader を用いると、複数種類のタイルをひとつのマテリアルに含めることも可能です。
その際のマスクの合成についてですが、動画内では分かりやすさのため「Mask」はタイル部分を白・目地部分を黒にしたのですが、実際の色は反転しています。(あくまでノードの出力名はLine mask = ライン部分のマスク:目地が1、タイルが0です。)
そのため、複数のマスクを重ねて使用したい場合はスクリーン合成などするのが良いかと思われます。(aiColorCompositeノードなど使えばうまく合成できるはずです)
機能についての説明は以上です。
おわりに
今回はシェーダーとそれを含むシェーディングネットワークを作成しました。
ワールドXZ座標版もあるのでぜひご覧ください:前回)
=================
こちらのスクリプトを無料配布しています↓
ダウンロードページはこちら
(2025.12.28更新)
=================
お問い合わせはこちらまでお願いします。



