Appearance
第02回 HLSL の制御構文と反復計算
前回: 第01回 Shader Graph から HLSL へ
今回の授業内容
if、for、breakの役割を理解する- 上限回数を持つ安全なループを設計する
- 反復で縞模様と近傍サンプリングを実装する
- 分岐と
step、lerpの使い分けを比較する - 反復回数と描画負荷の関係を確認する
GPU の制御構文
GPU は多数のピクセルを並列に処理します。隣接するピクセルが異なる分岐へ進むと、両方の経路を計算する必要が生じる場合があります。分岐は禁止ではありませんが、画面全体で細かく切り替わる分岐は注意します。
hlsl
float mask;
if (value >= threshold)
{
mask = 1.0;
}
else
{
mask = 0.0;
}このような2値化は step(threshold, value) でも記述できます。計算の意味が明確で、補間で置き換えられる場合は step、smoothstep、lerp を優先します。
上限付きループ
シェーダーのループは、終了条件と最大回数を明確にします。実行時の値だけを条件にした無制限の while は使いません。
hlsl
static const int MAX_ITERATIONS = 16;
float sum = 0.0;
for (int i = 0; i < MAX_ITERATIONS; i++)
{
if (i >= iterationCount)
{
break;
}
sum += 1.0 / (i + 1.0);
}MAX_ITERATIONS はシェーダーが実行する可能性のある上限です。iterationCount はマテリアルから変更する品質設定です。
反復で縞模様を作る
UV を回転しながら複数の波を重ねます。
hlsl
void IterativePattern_float(
float2 UV,
float Time,
float Iterations,
out float Out)
{
float2 p = UV * 2.0 - 1.0;
float value = 0.0;
float2x2 rotation = float2x2(0.8, -0.6, 0.6, 0.8);
[loop]
for (int i = 0; i < 12; i++)
{
if (i >= (int)Iterations) break;
p = mul(rotation, p) * 1.25;
value += sin(p.x * 4.0 + Time + i) * 0.5 + 0.5;
}
Out = value / max(Iterations, 1.0);
}反復ごとに UV の向きと大きさを変えることで、単一の正弦波より複雑な模様になります。
実習:近傍サンプリングでぼかす
テクスチャーの左右を複数回読み、平均を取ります。
hlsl
float3 color = 0.0;
float weight = 0.0;
for (int x = -4; x <= 4; x++)
{
if (abs(x) > radius) continue;
float2 offset = float2(x * texelSize.x, 0.0);
color += SAMPLE_TEXTURE2D(textureName, samplerName, uv + offset).rgb;
weight += 1.0;
}
color /= max(weight, 1.0);Custom Function Node にテクスチャーを渡す方法は Shader Graph のバージョンによりラッパー型が使われます。この実習では教員が用意したテンプレートを使い、反復回数とサンプリングの意味に集中します。
授業内課題:品質設定を作る
- 反復回数を4、8、12に切り替える
- 各設定で模様またはぼかしの差を確認する
- Game View の Stats または Profiler でフレーム時間を比較する
- 低、中、高品質の推奨値を記録する
完成条件
forループに固定の最大回数がある- プロパティで実際の反復回数を調整できる
- 反復回数による品質と負荷の違いを説明できる
今回のまとめ
HLSL の分岐とループにより、Shader Graph のノードを大量に複製せず反復計算を記述できます。ループは常に最大回数を決め、品質と処理量をセットで設計します。