【Unity】Geometry Shader(ジオメトリシェーダー)の超入門サンプル【初心者向け】

どーも、ぐるたか@guru_takaです。

ジオメトリシェーダーの勉強を学びはじめました。備忘録もかねて、ジオメトリシェーダーの超基本をサンプルに沿って紹介します。

拝借するサンプル

こちらのサンプルをお借りします。コメントは追加しています。
Flat shading with a geometry shader

完成図はこちらです。球体に三角メッシュが浮き彫りになってます!

Shader "Custom/Geometry/FlatShading"
{
    Properties
    {
        _Color("Color", Color) = (1,1,1,1)
        _MainTex("Albedo", 2D) = "white" {}
    }
   
    SubShader
    {
 
        Tags{ "Queue"="Geometry" "RenderType"= "Opaque" "LightMode" = "ForwardBase" }
 
        Pass
        {
            CGPROGRAM
 
            #include "UnityCG.cginc"
            #pragma vertex vert
            //Geometry Shader ステージのときに呼び出される
            #pragma geometry geom
            #pragma fragment frag
 
            float4 _Color;
            sampler2D _MainTex;
 
            struct v2g
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 vertex : TEXCOORD1;
            };
 
            struct g2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
                float light : TEXCOORD1;
            };
 
            v2g vert(appdata_full v)
            {
                v2g o;
                o.vertex = v.vertex;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = v.texcoord;
                return o;
            }
 
            [maxvertexcount(3)]
            void geom(triangle v2g IN[3], inout TriangleStream<g2f> triStream)
            {
                g2f o;
 
                //法線ベクトルの計算(ライティングで使用)
                float3 vecA = IN[1].vertex - IN[0].vertex;
                float3 vecB = IN[2].vertex - IN[0].vertex;
                float3 normal = cross(vecA, vecB);
                normal = normalize(mul(normal, (float3x3) unity_WorldToObject));
 
                //ライティングの計算
                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                o.light = max(0., dot(normal, lightDir));
 
                o.uv = (IN[0].uv + IN[1].uv + IN[2].uv) / 3;

                //メッシュ作成
                for(int i = 0; i < 3; i++)
                {
                    o.pos = IN[i].pos;
                    triStream.Append(o);
                }
                //tristream.RestartStrip();//さらに他の三角メッシュを作成する時に必要
            }
 
            half4 frag(g2f i) : COLOR
            {
                float4 col = tex2D(_MainTex, i.uv);
                col.rgb *= i.light * _Color;
                return col;
            }
 
            ENDCG
        }
    }
    Fallback "Diffuse"
}

ザックリした解説

まず#pragma geometry geomを入れましょう。Geometry Shaderの処理フェーズで呼び出されるようになります!


引用:Graphics Pipeline | Microsoft

基本的な関数はこちらです。

[maxvertexcount(3)]
void geom(triangle v2g in[3], inout TriangleStream outStream)
{
                g2f o;

                //中略

                //メッシュ作成
                for(int i = 0; i < 3; i++)
                {
                    o.pos = IN[i].pos;
                    triStream.Append(o);
                }
                //tristream.RestartStrip();//さらに他の三角メッシュを作成する時に必要
}
  • 入力:triangle v2g in[3]
  • 出力:inout TriangleStream triStream

入力のtriangleはプリミティブ型を意味します。他にも、pointlineなど色んなプリミティブ型があります!

さらに頂点が3つなので、配列の長さは3つin[3]になります。

一方、出力にあるTriangleStreamはストリーム出力オブジェクトを意味します。簡単にいうと、出力されるオブジェクトの形です!今回は三角形のメッシュで出力するため、TriangleStream型を採用。他には、PointStream型、LineStream型があります。

また[maxvertexcount()]は最大出力数を意味しており、今回は最終的に三角メッシュが1つ作られるので、頂点3つ分[maxvertexcount(3)]になります!

MEMO
もし三角メッシュが2枚作られる場合は、[maxvertexcount(6)]になります!

あとは、以下の処理でメッシュを作成。Append関数に出力用の変数を渡していき、最後にtristream.RestartStrip();を呼ぶことで、次の新しいストリームがスタートします!

                //メッシュ作成
                for(int i = 0; i &lt; 3; i++)
                {
                    o.pos = IN[i].pos;
                    triStream.Append(o);
                }
                //tristream.RestartStrip();//さらに他の三角メッシュを作成する時に必要
MEMO
今回は三角メッシュ1つのみなので、tristream.RestartStrip();は必要ありません!

最後に

ジオメトリシェーダーの処理の流れを超簡単にまとめました!もっと詳しく知りたい場合は、次の参考リンクをご参照ください。

また掲載元のサイトshaders laboratoryでは、他にも様々なジオメトリシェーダーのサンプル(著作権フリー)がありますので、ぜひチェックしてみてください!

参考リンク

参考 Unity Graphics Programming vol.1Indie Visual Lab 参考 ジオメトリシェーダ入門e.blog

1 COMMENT

コメントを残す