どーも、ぐるたか@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 (ジオメトリシェーダー) の超入門サンプル | ぐるたかログ […]