どーも、ぐるたか@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はプリミティブ型を意味します。他にも、pointやlineなど色んなプリミティブ型があります!
さらに頂点が3つなので、配列の長さは3つin[3]になります。
一方、出力にあるTriangleStreamはストリーム出力オブジェクトを意味します。簡単にいうと、出力されるオブジェクトの形です!今回は三角形のメッシュで出力するため、TriangleStream型を採用。他には、PointStream型、LineStream型があります。
また[maxvertexcount()]は最大出力数を意味しており、今回は最終的に三角メッシュが1つ作られるので、頂点3つ分[maxvertexcount(3)]になります!
[maxvertexcount(6)]になります!あとは、以下の処理でメッシュを作成。Append関数に出力用の変数を渡していき、最後にtristream.RestartStrip();を呼ぶことで、次の新しいストリームがスタートします!
//メッシュ作成
for(int i = 0; i < 3; i++)
{
o.pos = IN[i].pos;
triStream.Append(o);
}
//tristream.RestartStrip();//さらに他の三角メッシュを作成する時に必要
tristream.RestartStrip();は必要ありません!最後に
ジオメトリシェーダーの処理の流れを超簡単にまとめました!もっと詳しく知りたい場合は、次の参考リンクをご参照ください。
また掲載元のサイトshaders laboratoryでは、他にも様々なジオメトリシェーダーのサンプル(著作権フリー)がありますので、ぜひチェックしてみてください!


[…] Geometry Shader (ジオメトリシェーダー) の超入門サンプル | ぐるたかログ […]