Version: Unity 6.0 (6000.0)
言語 : 日本語
ビルトインレンダーパイプラインのグローバルイルミネーションサーフェスシェーダーの例
ビルトインレンダーパイプラインのサーフェスシェーダー言語リファレンス

ビルトインレンダーパイプラインのテッセレーションサーフェスシェーダーの例

ビルトインレンダーパイプラインでは、サーフェスシェーダーは、DirectX 11 / OpenGL Core GPU テッセレーションを一部サポートしています。

  • テッセレーションは tessellate:FunctionName モディファイアで示されます。この関数は三角形の辺と内部のテッセレーション係数を計算します。
  • テッセレーションが使用されている場合、“vertex modifier” (vertex:FunctionName) がテッセレーションの_後_に、ドメインシェーダーの生成された各頂点に対して実行されます。通常は、ディスプレイスメントマッピングです。
  • サーフェスシェーダーは任意でフォンテッセレーションを計算し、ディスプレイスメントマッピングなしでも、モデルの表面を滑らかにします。

テッセレーションシェーダー & ジオメトリシェーダー

サーフェスシェーダーは、単純なテッセレーションとディスプレイスメントをサポートしています。カスタムシェーダープログラムを作成する場合は、ジオメトリシェーダー、ハルシェーダー、ドメインシェーダーを含む、DX11 シェーダーモデル 5.0 の全機能を使用できます。

現時点でのテッセレーションのサポートに関する制限

  • 三角形ドメインのみをサポートしており、四角形や等値線テッセレーションはサポートしていません。
  • テッセレーションを使用すると、シェーダーはシェーダーモデル 4.6 ターゲットに自動的にコンパイルされ、古いグラフィックスターゲットでの実行をサポートしなくなります。

レンダーパイプラインの互換性

機能名 ユニバーサルレンダーパイプライン (URP) HD レンダーパイプライン (HDRP) カスタム SRP ビルトインレンダーパイプライン
サーフェスシェーダー いいえ

URP でシェーダーオブジェクトを効率的に作成する方法については、Shader Graph を参照してください。
いいえ

HDRP でシェーダーオブジェクトを効率的に作成する方法については、Shader Graph を参照してください。
いいえ はい

固定量のテッセレーション

モデルの表面のサイズが画面上でおおよそ同じである場合は、固定量のテッセレーションをメッシュに加えます (メッシュ全体で同じテッセレーションレベル)。

次のスクリプト例では、固定量のテッセレーションを適用します。

    Shader "Tessellation Sample" {
        Properties {
            _Tess ("Tessellation", Range(1,32)) = 4
            _MainTex ("Base (RGB)", 2D) = "white" {}
            _DispTex ("Disp Texture", 2D) = "gray" {}
            _NormalMap ("Normalmap", 2D) = "bump" {}
            _Displacement ("Displacement", Range(0, 1.0)) = 0.3
            _Color ("Color", color) = (1,1,1,0)
            _SpecColor ("Spec color", color) = (0.5,0.5,0.5,0.5)
        }
        SubShader {
            Tags { "RenderType"="Opaque" }
            LOD 300
            
            CGPROGRAM
            #pragma surface surf BlinnPhong addshadow fullforwardshadows vertex:disp tessellate:tessFixed nolightmap
            #pragma target 4.6

            struct appdata {
                float4 vertex : POSITION;
                float4 tangent : TANGENT;
                float3 normal : NORMAL;
                float2 texcoord : TEXCOORD0;
            };

            float _Tess;

            float4 tessFixed()
            {
                return _Tess;
            }

            sampler2D _DispTex;
            float _Displacement;

            void disp (inout appdata v)
            {
                float d = tex2Dlod(_DispTex, float4(v.texcoord.xy,0,0)).r * _Displacement;
                v.vertex.xyz += v.normal * d;
            }

            struct Input {
                float2 uv_MainTex;
            };

            sampler2D _MainTex;
            sampler2D _NormalMap;
            fixed4 _Color;

            void surf (Input IN, inout SurfaceOutput o) {
                half4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                o.Albedo = c.rgb;
                o.Specular = 0.2;
                o.Gloss = 1.0;
                o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex));
            }
            ENDCG
        }
        FallBack "Diffuse"
    }

上の例では tessFixed テッセレーション関数は、1 つの float4 値として 4 つのテッセレーション係数を返します。三角形の各辺の 3 つの係数、三角形の内側の 1 つの係数です。

この例では、Material プロパティで設定される定数値を返します。


距離にもとづいたテッセレーション

テッセレーションのレベルは、カメラからの距離に基づいて変更することもできます。テッセレーションのレベルは、カメラからの距離に基づいて変更することもできます。例えば、2 つの距離の値を定義することができます。

  • テッセレーションが最大であるときの距離 (例えば、10 メートル)。
  • テッセレーションレベルが徐々に低下する距離 (例えば、20 メートル)。
    Shader "Tessellation Sample" {
        Properties {
            _Tess ("Tessellation", Range(1,32)) = 4
            _MainTex ("Base (RGB)", 2D) = "white" {}
            _DispTex ("Disp Texture", 2D) = "gray" {}
            _NormalMap ("Normalmap", 2D) = "bump" {}
            _Displacement ("Displacement", Range(0, 1.0)) = 0.3
            _Color ("Color", color) = (1,1,1,0)
            _SpecColor ("Spec color", color) = (0.5,0.5,0.5,0.5)
        }
        SubShader {
            Tags { "RenderType"="Opaque" }
            LOD 300
            
            CGPROGRAM
            #pragma surface surf BlinnPhong addshadow fullforwardshadows vertex:disp tessellate:tessDistance nolightmap
            #pragma target 4.6
            #include "Tessellation.cginc"

            struct appdata {
                float4 vertex : POSITION;
                float4 tangent : TANGENT;
                float3 normal : NORMAL;
                float2 texcoord : TEXCOORD0;
            };

            float _Tess;

            float4 tessDistance (appdata v0, appdata v1, appdata v2) {
                float minDist = 10.0;
                float maxDist = 25.0;
                return UnityDistanceBasedTess(v0.vertex, v1.vertex, v2.vertex, minDist, maxDist, _Tess);
            }

            sampler2D _DispTex;
            float _Displacement;

            void disp (inout appdata v)
            {
                float d = tex2Dlod(_DispTex, float4(v.texcoord.xy,0,0)).r * _Displacement;
                v.vertex.xyz += v.normal * d;
            }

            struct Input {
                float2 uv_MainTex;
            };

            sampler2D _MainTex;
            sampler2D _NormalMap;
            fixed4 _Color;

            void surf (Input IN, inout SurfaceOutput o) {
                half4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                o.Albedo = c.rgb;
                o.Specular = 0.2;
                o.Gloss = 1.0;
                o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex));
            }
            ENDCG
        }
        FallBack "Diffuse"
    }

ここで、テッセレーション関数はテッセレーションの前の三角形の 3 つの角の頂点データを 3 つの引数として取得します。

頂点の位置に依存するテッセレーションのレベルを計算するために、これを必要とします。

この例には、ビルトインのヘルパーファイル、Tessellation.cginc が含まれていて、すべての作業を行うためにこのファイルから UnityDistanceBasedTess 関数を呼び出します。この関数は、各頂点のカメラからの距離を計算し、最後のテッセレーション係数を導き出します。


辺の長さにもとづいたテッセレーション

純粋に距離ベースのテッセレーションは、三角形のサイズがかなり近い場合にのみ有効です。上の画像では、小さな三角形を持つゲームオブジェクトはテッセレーションがあまりにも多く、三角形の大きなゲームオブジェクトは十分テッセレーションされていません。

これを改善する方法の 1 つは、画面上の三角形の辺の長さに基づいてテッセレーションのレベルを計算することです。Unity は辺が長いほど大きなテッセレーション係数を適用する必要があります。

    Shader "Tessellation Sample" {
        Properties {
            _EdgeLength ("Edge length", Range(2,50)) = 15
            _MainTex ("Base (RGB)", 2D) = "white" {}
            _DispTex ("Disp Texture", 2D) = "gray" {}
            _NormalMap ("Normalmap", 2D) = "bump" {}
            _Displacement ("Displacement", Range(0, 1.0)) = 0.3
            _Color ("Color", color) = (1,1,1,0)
            _SpecColor ("Spec color", color) = (0.5,0.5,0.5,0.5)
        }
        SubShader {
            Tags { "RenderType"="Opaque" }
            LOD 300
            
            CGPROGRAM
            #pragma surface surf BlinnPhong addshadow fullforwardshadows vertex:disp tessellate:tessEdge nolightmap
            #pragma target 4.6
            #include "Tessellation.cginc"

            struct appdata {
                float4 vertex : POSITION;
                float4 tangent : TANGENT;
                float3 normal : NORMAL;
                float2 texcoord : TEXCOORD0;
            };

            float _EdgeLength;

            float4 tessEdge (appdata v0, appdata v1, appdata v2)
            {
                return UnityEdgeLengthBasedTess (v0.vertex, v1.vertex, v2.vertex, _EdgeLength);
            }

            sampler2D _DispTex;
            float _Displacement;

            void disp (inout appdata v)
            {
                float d = tex2Dlod(_DispTex, float4(v.texcoord.xy,0,0)).r * _Displacement;
                v.vertex.xyz += v.normal * d;
            }

            struct Input {
                float2 uv_MainTex;
            };

            sampler2D _MainTex;
            sampler2D _NormalMap;
            fixed4 _Color;

            void surf (Input IN, inout SurfaceOutput o) {
                half4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                o.Albedo = c.rgb;
                o.Specular = 0.2;
                o.Gloss = 1.0;
                o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex));
            }
            ENDCG
        }
        FallBack "Diffuse"
    }

この例では、すべての作業を行うために Tessellation.cginc から UnityEdgeLengthBasedTess 関数を呼び出します。

パフォーマンス上の理由から代わりに UnityEdgeLengthBasedTessCull 関数を呼び出すと、パッチの錐台カリングが実行されます。これにより、シェーダーは少し負荷が高くなりますが、カメラのビューの外にあるメッシュ部分に対して GPU の作業を大幅に節約できます。


フォンテッセレーション

フォンテッセレーションは細分化した面の位置を修正して、結果として表面がメッシュの法線にある程度沿うようにします。低ポリゴンのメッシュを滑らかにするのにかなり効果的な方法です。

Unity のサーフェスシェーダーは、tessphong:VariableName ディレクティブを使用することで、フォンテッセレーションを自動計算します。以下はシェーダー例です。

    Shader "Phong Tessellation" {
        Properties {
            _EdgeLength ("Edge length", Range(2,50)) = 5
            _Phong ("Phong Strengh", Range(0,1)) = 0.5
            _MainTex ("Base (RGB)", 2D) = "white" {}
            _Color ("Color", color) = (1,1,1,0)
        }
        SubShader {
            Tags { "RenderType"="Opaque" }
            LOD 300
            
            CGPROGRAM
            #pragma surface surf Lambert vertex:dispNone tessellate:tessEdge tessphong:_Phong nolightmap
            #include "Tessellation.cginc"

            struct appdata {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float2 texcoord : TEXCOORD0;
            };

            void dispNone (inout appdata v) { }

            float _Phong;
            float _EdgeLength;

            float4 tessEdge (appdata v0, appdata v1, appdata v2)
            {
                return UnityEdgeLengthBasedTess (v0.vertex, v1.vertex, v2.vertex, _EdgeLength);
            }

            struct Input {
                float2 uv_MainTex;
            };

            fixed4 _Color;
            sampler2D _MainTex;

            void surf (Input IN, inout SurfaceOutput o) {
                half4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                o.Albedo = c.rgb;
                o.Alpha = c.a;
            }

            ENDCG
        }
        FallBack "Diffuse"
    }

以下の例は、通常のシェーダー (上の段) とフォンテッセレーションを使用するシェーダー (下の段) の比較です。ディスプレイスメントマッピングを一切行わない場合でも、表面はより滑らかになります。


  • 2018–03–20
  • Tessellation for Metal は 2018.1 で追加
ビルトインレンダーパイプラインのグローバルイルミネーションサーフェスシェーダーの例
ビルトインレンダーパイプラインのサーフェスシェーダー言語リファレンス