Vertex and fragment shader examples
Cg/HLSL でシェーダープロパティーを参照する

シェーダーセマンティクス

When writing Cg/HLSL shader programs, input and output variables need to have their “intent” indicated via semantics. This is a standard concept in HLSL shader language; see the Semantics documentation on MSDN for more details.

以下のページから例をダウンロードできます。Unity プロジェクトの Zip ファイル

頂点シェーダー入力セマンティクス

The main vertex shader function (indicated by the #pragma vertex directive) needs to have semantics on all of the input parameters. These correspond to individual Mesh data elements, like vertex position, normal mesh, and texture coordinates. See vertex program inputs for more details.

ここに、頂点位置と テクスチャ座標を 1つの入力で取得する簡単な頂点シェーダーの例があります。 ピクセルシェーダーは、単にテクスチャ座標を 1つのカラーとして可視化しています。

Shader "Unlit/Show UVs"
{
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct v2f {
                float2 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
            };

            v2f vert (
                float4 vertex : POSITION, // vertex position input
                float2 uv : TEXCOORD0 // first texture coordinate input
                )
            {
                v2f o;
                o.pos = UnityObjectToClipPos(vertex);
                o.uv = uv;
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                return fixed4(i.uv, 0, 0);
            }
            ENDCG
        }
    }
}

Instead of spelling out all individual inputs one by one, it is also possible to declare a structure of them, and indicate semantics on each individual member variable of the struct. See shader program examples to learn how to do this.

フラグメントシェーダー出力セマンティクス

Most often a fragment (pixel) shader outputs a color, and has an SV_Target semantic. The fragment shader in the example above does exactly that:

fixed4 frag (v2f i) : SV_Target

関数 frag は、fixed4 型 (低精度 RGBA カラー) の戻り値を求めます。 値が 1つだけ返されるので、 セマンティクスは関数 SV_Target そのものに表示されます。

出力を構造体で返すことも可能です。 上記のフラグメントシェーダーもこのようにして再度書き替えすることができます。 そして、まったく同じことを行うことができます。

struct fragOutput {
    fixed4 color : SV_Target;
};            
fragOutput frag (v2f i)
{
    fragOutput o;
    o.color = fixed4(i.uv, 0, 0);
    return o;
}

フラグメントシェーダーから構造体を返すのは、 主に、シェーダーが単数のカラーを返すだけでない場合に有用です。 フラグメントシェーダー出力にサポートされるその他のセマンティクスは以下のとおりです。

複数レンダリングターゲット: SV_TargetN

SV_Target1, SV_Target2, など: これらはシェーダーによって加えられた追加の色です。1度に 1つ以上のレンダーターゲットにレンダリングをする (Multiple render targets 法、または MRT) ときに使用されます。 SV_Target0SV_Target と同じです。

ピクセルシェーダーデプス出力: SV_Depth

通常は、 フラグメントシェーダーは Z バッファ値をオーバーライドしません。 デフォルト値は標準の三角形のラスタライゼーションから使用されます。ただし、 いくつかのエフェクトにおいては、ピクセルごとにカスタム化した Z バッファのデプス値を出力する必要があります。

こうすると、多くの GPU でデプスバッファの最適化が無効になってしまうことがあるということに気を付けてください。ですから、必要なばあい以外は Z バッファの値をオーバーライドしないでください。The cost incurred by SV_Depth の変更によって被る被害に関しては、GPU の構造によります。しかし、まとめると、だいたいアルファテストの負担に近いといえます (HLSL でビルトイン関数の clip() を使用)。すべての標準の不透明シェーダーのあとにデプスを修正する (例えば レンダリング順AlphaTest を使用して)シェーダーをレンダリングします。

デプス出力値は、単精度の float 型でなくてはなりません。

頂点シェーダー出力とフラグメントシェーダー入力

頂点シェーダーは、頂点のクリップの最終的な空間位置を出力する必要があります。それにより、GPU は画面のどこに、どのくらいのデプスでそれをラスタライズするかが分かります。この出力には、SV_POSITION セマンティックと float4 型の出力が必要です。

頂点シェーダーによって作成されるこの他の出力 (“interpolator” または “varying”) は、使用するシェーダーが何を必要とするかによります。頂点シェーダーから出力される値は、レンダリングされた三角形の表面を横切って補完されます。そして、各ピクセルの値は入力値としてフラグメントシェーダーに渡されます。

現段階で一般的に使用されている GPU の多くは、これらの変数にどんなセマンティクスがあるかなどほとんど関係ありません。ただし、古いシステムのいくつか (最もよく知られているのは Direct3D 9 の shader model 2 GPU) には、セマンティクスに関して以下のような特別なルールがありました。

  • TEXCOORD0, TEXCOORD1 などは、テクスチャ座標や位置などの任意の高精度のデータを示すために使用されます
  • 頂点出力とフラグメント入力に関する COLOR0COLOR1 は低精度の 0–1 の範囲のデータ (単純な色の値のなど) に使用されます

そのため、最良のクロスプラットフォームの対応として、 セマンティクス上、頂点出力とフラグメント入力を TEXCOORDn セマンティクスにするのが一般的です。

See shader program examples for examples.

Interpolator の数的制限

頂点からフラグメントシェーダーに情報を渡すために、使用できる Interpolator 変数の総数には制限があります。 制限数は、プラットフォームや GPU によって異なります 一般的な指標は以下のとおりです。

  • Up to 8 interpolators: OpenGL ES 2.0 (iOS/Android), Direct3D 11 9.x level (Windows Phone) and Direct3 9 shader model 2.0 (old PCs). Since the interpolator count is limited, but each interpolator can be a 4-component vector, some shaders pack things together to stay within limits. For example, two texture coordinates can be passed in one float4 variable (.xy for one coordinate, .zw for the second coordinate).
  • Interpolator 10 個まで - Direct3D 9 シェーダーモデル 3.0 (#pragma target 3.0)
  • Interpolator 16 個まで - OpenGL ES 3.0 (iOS/Android)、Metal (iOS)
  • Interpolator 32 個まで - Direct3D 10 シェーダーモデル 4.0 (#pragma target 4.0)

ターゲットハードウェアに関係なく、パフォーマンス上の理由で、できる限り少ない数の Interpolator を使うほうが一般的によいとされています。

他の特別なセマンティクス

スクリーンスペースのピクセル位置: VPOS

フラグメントシェーダーは、特殊な VPOS セマンティックとしてレンダリングされるピクセルの座標を受け取る事ができます。 この機能は、シェーダーモデル 3.0 から搭載されています。そのため、シェーダーに #pragma target 3.0 コンパイラディレクティブが必要です。

異なるプラットフォームでは、スクリーンスペース位置入力の基本的な型が異なるため、可搬性を最大にするために、UNITY_VPOS_TYPE 型を使用してください (たいていのプラットフォームでは float4 で、Direct3D 9 では float2)。

さらに、ピクセル位置のセマンティクスを使用して、頂点からフラグメントに渡すための構造体にクリップスペース位置 (SV_POSITION) と VPOS 両方を有することは困難です。そこで、頂点シェーダーはクリップスペース位置を別の “out” 変数として出力します。以下のシェーダーの例を参照してください。

Shader "Unlit/Screen Position"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 3.0

            // note: no SV_POSITION in this struct
            struct v2f {
                float2 uv : TEXCOORD0;
            };

            v2f vert (
                float4 vertex : POSITION, // vertex position input
                float2 uv : TEXCOORD0, // texture coordinate input
                out float4 outpos : SV_POSITION // clip space position output
                )
            {
                v2f o;
                o.uv = uv;
                outpos = UnityObjectToClipPos(vertex);
                return o;
            }

            sampler2D _MainTex;

            fixed4 frag (v2f i, UNITY_VPOS_TYPE screenPos : VPOS) : SV_Target
            {
                // screenPos.xy will contain pixel integer coordinates.
                // use them to implement a checkerboard pattern that skips rendering
                // 4x4 blocks of pixels

                // checker value will be negative for 4x4 blocks of pixels
                // in a checkerboard pattern
                screenPos.xy = floor(screenPos.xy * 0.25) * 0.5;
                float checker = -frac(screenPos.r + screenPos.g);

                // clip HLSL instruction stops rendering a pixel if value is negative
                clip(checker);

                // for pixels that were kept, read the texture and output it
                fixed4 c = tex2D (_MainTex, i.uv);
                return c;
            }
            ENDCG
        }
    }
}

表面の向き: VFACE

フラグメントシェーダーは、レンダリングされた面がカメラをむいているか、反対を向いているかを示す変数を受け取ることができます。これは、形状を両方向からみられるようにレンダリングするときに役に立ち、しばしば、葉や似たような薄いオブジェクトに使用されます。VFACE セマンティクス入力変数は、正面向きの三角形には正の数を持ち、後ろ向きの三角形には負の値を持ちます。

この機能は、シェーダーモデル 3.0 以降に加えられています。そのため、シェーダーに #pragma target 3.0 コンパイラディレクティブが必要です。

Shader "Unlit/Face Orientation"
{
    Properties
    {
        _ColorFront ("Front Color", Color) = (1,0.7,0.7,1)
        _ColorBack ("Back Color", Color) = (0.7,1,0.7,1)
    }
    SubShader
    {
        Pass
        {
            Cull Off // turn off backface culling

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 3.0

            float4 vert (float4 vertex : POSITION) : SV_POSITION
            {
                return UnityObjectToClipPos(vertex);
            }

            fixed4 _ColorFront;
            fixed4 _ColorBack;

            fixed4 frag (fixed facing : VFACE) : SV_Target
            {
                // VFACE input positive for frontbaces,
                // negative for backfaces. Output one
                // of the two colors depending on that.
                return facing > 0 ? _ColorFront : _ColorBack;
            }
            ENDCG
        }
    }
}

上記のシェーダーは、カリング構文を使い、後ろ向きのカリングを無効にしています (デフォルトでは、後ろ向きの三角形はまったくレンダリングされません)。ここで、シェーダーを多数の Quad メッシュに応用し、異なる方向に回転させます。

頂点 ID: SV_VertexID

頂点シェーダーは、使用されていない整数で示された “Vertex ID” を持つ変数を受け取ることができます。 これは、たいてい、テクスチャか ComputeBuffer から受領する頂点ごとの追加データをフェッチするときに役立ちます。

この機能は、DX10 (シェーダーモデル 4.0) と GLCore / OpenGL ES 3 以降に搭載されています。そのため、シェーダーに #pragma target 3.5 コンパイラディレクティブが必要です。

Shader "Unlit/VertexID"
{
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 3.5

            struct v2f {
                fixed4 color : TEXCOORD0;
                float4 pos : SV_POSITION;
            };

            v2f vert (
                float4 vertex : POSITION, // vertex position input
                uint vid : SV_VertexID // vertex ID, needs to be uint
                )
            {
                v2f o;
                o.pos = UnityObjectToClipPos(vertex);
                // output funky colors based on vertex ID
                float f = (float)vid;
                o.color = half4(sin(f/10),sin(f/100),sin(f/1000),0) * 0.5 + 0.5;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return i.color;
            }
            ENDCG
        }
    }
}

(以下のページから例をダウンロードできます。Unity プロジェクトの Zip ファイル)

Vertex and fragment shader examples
Cg/HLSL でシェーダープロパティーを参照する