メインコンテンツまでスキップ

カスタムシェーダー

Uber シェーダーでほとんどの見た目を表現できます。それ以外が必要な場合は、YauiElement.Material にカスタムマテリアルを設定してください。カスタムマテリアルは要素自身のプリミティブ (ボックスと内容。子は含まない) を描画します。

注記

要素の間でマテリアルが変わると、ドローコールが分割されます。同じマテリアルの要素は、描画順で隣り合うとき、または間にある要素がそれらと重ならないときに、まとめて描画されます。

シェーダーの書き方​

YAUI 向けのシェーダーは次のようにします。

  1. YAUI のシェーダーの共通コードである Packages/com.ruccho.yaui/Runtime/Shaders/Yaui.hlsl をインクルードします。
  2. 2 つのパスを宣言します。
    • Overlay: タグ "LightMode" = "YauiOverlay" と頂点関数 VertOverlay
    • World: 頂点関数 VertWorld
  3. Varyings 構造体を受け取る独自のフラグメント関数を書きます。FragImpl(i, world) を呼ぶと Uber シェーダーの結果を得られるので、それを加工できます。
  4. 乗算済みアルファのブレンド (Blend One OneMinusSrcAlpha) を使います。

Custom Shader サンプルの次の例は、Uber シェーダーの結果に水平方向のグラデーションで色を付けます。

Shader "Yaui/Samples/Gradient Tint"
{
Properties
{
_ColorA ("Left", Color) = (1, 0.3, 0.6, 1)
_ColorB ("Right", Color) = (0.3, 0.6, 1, 1)

// マスク (YauiMask) の中ではレンダラーが設定します。
[HideInInspector] _YauiStencilRef ("Stencil Ref", Float) = 0
[HideInInspector] _YauiStencilComp ("Stencil Comparison", Float) = 8
[HideInInspector] _YauiStencilPass ("Stencil Pass", Float) = 0
}

HLSLINCLUDE
#pragma target 4.5
// 回転した Quad と角丸のクリップは、これがあるときだけピクセルごとにクリップされます (GPU 時間がかかります)。
#define YAUI_PIXEL_CLIP
#include "Packages/com.ruccho.yaui/Runtime/Shaders/Yaui.hlsl"

float4 _ColorA;
float4 _ColorB;

half4 Tint(Varyings i, half4 color)
{
// local: 形状の中心からの相対位置と、形状の半分のサイズ。
float t = saturate(i.local.x / max(i.local.z, 1e-4) * 0.5 + 0.5);
return color * half4(lerp(_ColorA.rgb, _ColorB.rgb, t), 1.0);
}

half4 FragTintOverlay(Varyings i) : SV_Target { return Tint(i, FragImpl(i, false)); }
half4 FragTintWorld(Varyings i) : SV_Target { return Tint(i, FragImpl(i, true)); }
ENDHLSL

SubShader
{
Tags { "RenderType" = "Transparent" "Queue" = "Transparent" "RenderPipeline" = "UniversalPipeline" }
Blend One OneMinusSrcAlpha
ZWrite Off
Cull Off
Stencil
{
Ref [_YauiStencilRef]
Comp [_YauiStencilComp]
Pass [_YauiStencilPass]
}

Pass
{
Name "Overlay"
Tags { "LightMode" = "YauiOverlay" }
ZTest Always

HLSLPROGRAM
#pragma vertex VertOverlay
#pragma fragment FragTintOverlay
ENDHLSL
}

Pass
{
Name "World"
ZTest LEqual

HLSLPROGRAM
#pragma vertex VertWorld
#pragma fragment FragTintWorld
ENDHLSL
}
}
}

ピクセルごとのクリップ​

回転した Quad と角丸のクリップには、ピクセルごとの判定が必要です。有効にするには、Yaui.hlsl をインクルードする前に YAUI_PIXEL_CLIP を定義してください。これは varying を増やし、モバイルでは GPU 時間がかかるため、マテリアルを使う要素が回転せず、角丸のクリップの中にもない場合は定義しないでください (Uber シェーダーは、必要なパネルでだけこれを有効にします)。

マスク​

YauiMask でマスクされるには、上の例のように、シェーダーで _YauiStencilRef、_YauiStencilComp、_YauiStencilPass のプロパティと Stencil ブロックを宣言してください。値はレンダラーが設定します。

マスクの形​

YauiMask は通常、要素のボックスか画像のアルファで切り抜きます。要素のカスタムマテリアルが MaskOverlay という名前のパスを持つ場合、マスクの形はそのパスで描かれます (オーバーレイとカメラのパネル)。ディゾルブなど、マテリアルが作る形でも子を隠せます。

このパスは色を書かず、シェーダーの Stencil ブロックを保ち、形の外のピクセルを破棄します。頂点関数は VertMaskOverlay です。完全に透明なマスクの要素が何も切り抜かない処理も、この関数が行います。

// HLSLINCLUDE 内: Shape は要素の形をアルファで返す関数
half4 FragShapeMask(Varyings i) : SV_Target
{
clip(Shape(i) - 0.5);
return 0;
}

// SubShader 内、Overlay と World のパスと並べて:
Pass
{
Name "MaskOverlay"
ZTest Always
ColorMask 0

HLSLPROGRAM
#pragma vertex VertMaskOverlay
#pragma fragment FragShapeMask
ENDHLSL
}

背景ブラー​

Yaui/Backdrop Blur シェーダーは、要素の後ろに描かれたものをぼかし、要素の形の中に要素の色を掛けて表示します。CSS の backdrop-filter: blur() と同じです。このシェーダーでマテリアルを作り、Blur (_YauiBlur、描画先のピクセル単位の標準偏差) を設定して、要素のマテリアルにしてください。

シェーダーにタグ "YauiBackdrop" = "True" を持つ描画の前で、パネルのパスが終わり、描画先がコピーされてぼかされ、次のパスにその結果が _YauiBackdropTexture として渡されます。同じマテリアルで隣り合う要素は 1 つのコピーを共有します。独自のシェーダーでは、タグを付けて、ピクセルの位置でテクスチャを読んでください。

TEXTURE2D(_YauiBackdropTexture);
SAMPLER(sampler_YauiBackdropTexture);
float4 _YauiBackdropParams; // xy: 描画先の 1 ピクセルの UV

half4 FragFrostedOverlay(Varyings i) : SV_Target
{
half4 shape = FragImpl(i, false);
float2 uv = i.positionCS.xy * _YauiBackdropParams.xy;
half3 backdrop = SAMPLE_TEXTURE2D(_YauiBackdropTexture, sampler_YauiBackdropTexture, uv).rgb;
return half4(backdrop * shape.rgb, shape.a);
}

描画先は読み取れる必要があります。最終ブリットより前に描くカメラのパネルや、RenderTexture に描くカメラのパネルが該当します。バックバッファ (画面に描くカメラのオーバーレイのパネルなど) とワールド空間のパネルでは、背景は表示されず色だけが描かれます。

背景ブラーごとに、描画先のコピー、ぼかし、ドローコールの分割のコストがかかります。パフォーマンスを参照してください。

シェーダーモジュール​

カスタムマテリアルはパネルのドローコールを分割します。グリフの効果など、一部のプリミティブを独自の方法で描くパッケージは、代わりにシェーダーモジュールを提供できます。シェーダーモジュールは、それを選んだプリミティブに対して Uber シェーダーが呼ぶフラグメント関数です。これにより、それらのプリミティブも周りのボックス、画像、テキストと一緒に描画されます。

パッケージがモジュールを提供する手順:

  1. half4 Name(Varyings i, bool world) を定義する HLSL ファイル。ピクセルの乗算済みの色を返します。クリップはその後に適用されます。このファイルは Yaui.hlsl の後にインクルードされるため、その型や関数を使えます。プリミティブが使う機能の varying (画像の UV、色) を読みます。
  2. YauiShaderModule アセット (Create > YAUI > Shader Module)。Key、ファイルのインクルードパス、関数名を設定します。
  3. YauiShaderModules.IdOf(key) でモジュールの番号を得て、プリミティブを WithModule(id) で作るコード (カスタム要素を参照)。プロジェクトがモジュールを使っていない場合、番号は 0 になります。その場合は、独自のマテリアルなど、モジュールを使わずに描画してください。

プロジェクトがモジュールを使う手順:

  1. Resources フォルダーに YauiShaderSettings という名前で YauiShaderSettings アセット (Create > YAUI > Shader Settings) を作り、モジュールを並べます。
  2. インスペクターの Generate Uber Shader を押します。モジュールを組み込んだ Uber シェーダーがアセットの隣に書き出され、YAUI は自身の Uber シェーダーの代わりにそれを使います。

モジュールの番号はリスト内の位置で決まるため、リストを変えたらシェーダーを生成し直してください。プロジェクトで使えるモジュールは 31 個までです。キーワード YAUI_MODULE は、モジュールを使うプリミティブを含む描画でだけ有効になります。モジュールを使うプリミティブをマスクの形に使うと、その形は画像として描かれます。