ジオメトリシェーダー基本図形コード集

ShaderLabのジオメトリシェーダで以下のような形状を生成するベタ書きコード集です。

![GeomPrim.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46585/1aca1d57-d550-aee9-e307-0844c824fa45.gif)


## 正四面体
```c
Shader "Yagiri/GeometryShader/Primitive/Tetrahedron"
{

Properties
{
}
SubShader
{

Tags { "RenderType"="Opaque" }
LOD 100

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma geometry geom
#pragma fragment frag
#include "UnityCG.cginc"
#define PI2 6.28318530718

struct appdata
{
	float4 vertex : POSITION;
};

struct v2g
{
	float4 pos : POSITION;
};

struct g2f
{
	float4 pos : SV_POSITION;
	float3 normal : NORMAL;
};

v2g vert(appdata v)
{
	v2g o;
	o.pos = v.vertex;
	return o;
}


static const float3 vertexs[12] = 
{
float3(0.0, 0.5, 0.0),
float3(0.235703, -0.166665, 0.408249),
float3(0.235703, -0.166665, -0.408249),
float3(0.0, 0.5, 0.0),
float3(0.235703, -0.166665, -0.408249),
float3(-0.471405, -0.166665, 0.0),
float3(0.0, 0.5, 0.0),
float3(-0.471405, -0.166665, 0.0),
float3(0.235703, -0.166665, 0.408249),
float3(-0.471405, -0.166665, 0.0),
float3(0.235703, -0.166665, -0.408249),
float3(0.235703, -0.166665, 0.408249)
};

static const float3 normals[4] = 
{
float3(0.942809,0.333335,-0.0),
float3(-0.471404,0.333335,-0.816496),
float3(-0.471404,0.333335,0.816496),
float3(0.0,-1.0,0.0)
};

[maxvertexcount(12)]
void geom(point v2g input[1], uint id : SV_PrimitiveID, inout TriangleStream<g2f> outStream)
{
	g2f o;

	[unroll]
	for(int j = 0; j < 4; j++)
	{
		[unroll]
		for (int k = 0; k < 3; k++)
		{
			const int vid = j * 3 + k;
			o.pos = float4(vertexs[vid], 1.0);
			o.pos = UnityObjectToClipPos(o.pos);
			o.normal = UnityObjectToWorldNormal(normals[j]);
			outStream.Append(o);
		}
		outStream.RestartStrip();
	}
}

fixed4 frag(g2f i) : SV_Target
{
	float4 col = 1;
	float3 lightdir = _WorldSpaceLightPos0.xyz;
	col.xyz *= saturate(dot(i.normal, -lightdir));
	return col;
}
ENDCG
}
}
}
```

## 立方体
```c
Shader "Yagiri/GeometryShader/Primitive/Cube"
{

Properties
{
}
SubShader
{

Tags { "RenderType"="Opaque" }
LOD 100

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma geometry geom
#pragma fragment frag
#include "UnityCG.cginc"
#define PI2 6.28318530718

// vertex shaderに入る構造体
struct appdata
{
	float4 vertex : POSITION;
};

// vertex shader から geometry shaderに渡る構造体
struct v2g{
	float4 pos : POSITION;
};

// geometry shaderからfragment shaderに渡る構造体
struct g2f
{
	float4 pos : SV_POSITION;
	float3 normal : NORMAL;
};

v2g vert(appdata v)
{
	v2g o;
	o.pos = v.vertex;
	return o;
}

static const float3 vertexs[24] = {
float3(0.5, -0.5, 0.5),
float3(0.5, 0.5, 0.5),
float3(-0.5, -0.5, 0.5),
float3(-0.5, 0.5, 0.5),
float3(-0.5, -0.5, -0.5),
float3(-0.5, 0.5, -0.5),
float3(0.5, -0.5, -0.5),
float3(0.5, 0.5, -0.5),
float3(-0.5, 0.5, -0.5),
float3(-0.5, 0.5, 0.5),
float3(0.5, 0.5, -0.5),
float3(0.5, 0.5, 0.5),
float3(0.5, -0.5, -0.5),
float3(0.5, -0.5, 0.5),
float3(-0.5, -0.5, -0.5),
float3(-0.5, -0.5, 0.5),
float3(0.5, -0.5, -0.5),
float3(0.5, 0.5, -0.5),
float3(0.5, -0.5, 0.5),
float3(0.5, 0.5, 0.5),
float3(-0.5, -0.5, 0.5),
float3(-0.5, 0.5, 0.5),
float3(-0.5, -0.5, -0.5),
float3(-0.5, 0.5, -0.5)
};

static const float3 normals[6] = 
{
float3(0.0,0.0,1.0),
float3(0.0,0.0,-1.0),
float3(0.0,1.0,0.0),
float3(0.0,-1.0,0.0),
float3(1.0,0.0,0.0),
float3(-1.0,0.0,0.0)
};

[maxvertexcount(24)]
void geom(point v2g input[1], uint id : SV_PrimitiveID, inout TriangleStream<g2f> outStream)
{
	g2f o;

	[unroll]
	for(int j = 0; j < 6; j++)
	{
		[unroll]
		for (int k = 0; k < 4; k++)
		{
			const int vid = j * 4 + k;
			o.pos = float4(vertexs[vid], 1.0);
			o.pos = UnityObjectToClipPos(o.pos);
			o.normal = UnityObjectToWorldNormal(normals[j]);
			outStream.Append(o);
		}
		outStream.RestartStrip();
	}
}

fixed4 frag(g2f i) : SV_Target
{
	float4 col = 1;
	float3 lightdir = _WorldSpaceLightPos0.xyz;
	col.xyz *= saturate(dot(i.normal, -lightdir));
	return col;
}
ENDCG
}
}
}
```

## 正八面体
```c
Shader "Yagiri/GeometryShader/Primitive/Octahedron"
{

Properties
{
}
SubShader
{

Tags { "RenderType"="Opaque" }
LOD 100

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma geometry geom
#pragma fragment frag
#include "UnityCG.cginc"
#define PI2 6.28318530718

// vertex shaderに入る構造体
struct appdata
{
	float4 vertex : POSITION;
};

// vertex shader から geometry shaderに渡る構造体
struct v2g{
	float4 pos : POSITION;
};

// geometry shaderからfragment shaderに渡る構造体
struct g2f
{
	float4 pos : SV_POSITION;
	float3 normal : NORMAL;
};

v2g vert(appdata v)
{
	v2g o;
	o.pos = v.vertex;
	return o;
}

static const float3 vertexs[24] = 
{
float3(0.0, 0.0, -0.5),
float3(0.0, -0.5, 0.0),
float3(-0.5, 0.0, 0.0),
float3(0.0, 0.0, -0.5),
float3(0.5, 0.0, 0.0),
float3(0.0, -0.5, 0.0),
float3(0.5, 0.0, 0.0),
float3(0.0, 0.0, 0.5),
float3(0.0, -0.5, 0.0),
float3(0.0, 0.0, 0.5),
float3(-0.5, 0.0, 0.0),
float3(0.0, -0.5, 0.0),
float3(0.0, 0.0, -0.5),
float3(-0.5, 0.0, 0.0),
float3(0.0, 0.5, 0.0),
float3(0.0, 0.0, -0.5),
float3(0.0, 0.5, 0.0),
float3(0.5, 0.0, 0.0),
float3(0.5, 0.0, 0.0),
float3(0.0, 0.5, 0.0),
float3(0.0, 0.0, 0.5),
float3(0.0, 0.0, 0.5),
float3(0.0, 0.5, 0.0),
float3(-0.5, 0.0, 0.0)
};

static const float3 normals[8] = 
{
float3(-0.57735,-0.57735,-0.57735),
float3(0.57735,-0.57735,-0.57735),
float3(0.57735,-0.57735,0.57735),
float3(-0.57735,-0.57735,0.57735),
float3(-0.57735,0.57735,-0.57735),
float3(0.57735,0.57735,-0.57735),
float3(0.57735,0.57735,0.57735),
float3(-0.57735,0.57735,0.57735),
};

[maxvertexcount(24)]
void geom(point v2g input[1], uint id : SV_PrimitiveID, inout TriangleStream<g2f> outStream)
{
	g2f o;

	[unroll]
	for(int j = 0; j < 8; j++)
	{
		[unroll]
		for (int k = 0; k < 3; k++)
		{
			const int vid = j * 3 + k;
			o.pos = float4(vertexs[vid], 1.0);
			o.pos = UnityObjectToClipPos(o.pos);
			o.normal = UnityObjectToWorldNormal(normals[j]);
			outStream.Append(o);
		}
		outStream.RestartStrip();
	}
}

fixed4 frag(g2f i) : SV_Target
{
	float4 col = 1;
	float3 lightdir = _WorldSpaceLightPos0.xyz;
	col.xyz *= saturate(dot(i.normal, -lightdir));
	return col;
}
ENDCG
}
}
}
```

## 正二十面体
```c
Shader "Yagiri/GeometryShader/Primitive/Icosahedron"
{

Properties
{
}
SubShader
{

Tags { "RenderType"="Opaque" }
LOD 100

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma geometry geom
#pragma fragment frag
#include "UnityCG.cginc"
#define PI2 6.28318530718

// vertex shaderに入る構造体
struct appdata
{
	float4 vertex : POSITION;
};

// vertex shader から geometry shaderに渡る構造体
struct v2g{
	float4 pos : POSITION;
};

// geometry shaderからfragment shaderに渡る構造体
struct g2f
{
	float4 pos : SV_POSITION;
	float3 normal : NORMAL;
};

v2g vert(appdata v)
{
	v2g o;
	o.pos = v.vertex;
	return o;
}

static const float3 vertexs[60] = 
{
float3(0.425325, 0.138197, -0.223607),
float3(0.0, 0.0, -0.5),
float3(0.0, 0.447214, -0.223607),
float3(0.262866, -0.361803, -0.223607),
float3(0.0, 0.0, -0.5),
float3(0.425325, 0.138197, -0.223607),
float3(-0.262866, -0.361803, -0.223607),
float3(0.0, 0.0, -0.5),
float3(0.262866, -0.361803, -0.223607),
float3(-0.425325, 0.138197, -0.223607),
float3(0.0, 0.0, -0.5),
float3(-0.262866, -0.361803, -0.223607),
float3(0.0, 0.447214, -0.223607),
float3(0.0, 0.0, -0.5),
float3(-0.425325, 0.138197, -0.223607),
float3(-0.262866, 0.361803, 0.223607),
float3(0.0, 0.447214, -0.223607),
float3(-0.425325, 0.138197, -0.223607),
float3(-0.425325, -0.138197, 0.223607),
float3(-0.425325, 0.138197, -0.223607),
float3(-0.262866, -0.361803, -0.223607),
float3(0.0, -0.447214, 0.223607),
float3(-0.262866, -0.361803, -0.223607),
float3(0.262866, -0.361803, -0.223607),
float3(0.425325, -0.138197, 0.223607),
float3(0.262866, -0.361803, -0.223607),
float3(0.425325, 0.138197, -0.223607),
float3(0.262866, 0.361803, 0.223607),
float3(0.425325, 0.138197, -0.223607),
float3(0.0, 0.447214, -0.223607),
float3(0.262866, 0.361803, 0.223607),
float3(0.0, 0.447214, -0.223607),
float3(-0.262866, 0.361803, 0.223607),
float3(-0.262866, 0.361803, 0.223607),
float3(-0.425325, 0.138197, -0.223607),
float3(-0.425325, -0.138197, 0.223607),
float3(-0.425325, -0.138197, 0.223607),
float3(-0.262866, -0.361803, -0.223607),
float3(0.0, -0.447214, 0.223607),
float3(0.0, -0.447214, 0.223607),
float3(0.262866, -0.361803, -0.223607),
float3(0.425325, -0.138197, 0.223607),
float3(0.425325, -0.138197, 0.223607),
float3(0.425325, 0.138197, -0.223607),
float3(0.262866, 0.361803, 0.223607),
float3(-0.262866, 0.361803, 0.223607),
float3(0.0, 0.0, 0.5),
float3(0.262866, 0.361803, 0.223607),
float3(0.262866, 0.361803, 0.223607),
float3(0.0, 0.0, 0.5),
float3(0.425325, -0.138197, 0.223607),
float3(0.425325, -0.138197, 0.223607),
float3(0.0, 0.0, 0.5),
float3(0.0, -0.447214, 0.223607),
float3(0.0, -0.447214, 0.223607),
float3(0.0, 0.0, 0.5),
float3(-0.425325, -0.138197, 0.223607),
float3(-0.425325, -0.138197, 0.223607),
float3(0.0, 0.0, 0.5),
float3(-0.262866, 0.361803, 0.223607)
};

static const float3 normals[20] = 
{
float3(0.356822,0.491124,-0.794654),
float3(0.577351,-0.187592,-0.794654),
float3(0.0,-0.607062,-0.794654),
float3(-0.577351,-0.187592,-0.794654),
float3(-0.356822,0.491124,-0.794654),
float3(-0.57735,0.794655,-0.187593),
float3(-0.934172,-0.303531,-0.187593),
float3(-0.0,-0.982247,-0.187593),
float3(0.934172,-0.303531,-0.187593),
float3(0.57735,0.794655,-0.187593),
float3(0.0,0.982247,0.187593),
float3(-0.934172,0.303531,0.187593),
float3(-0.57735,-0.794655,0.187593),
float3(0.57735,-0.794655,0.187593),
float3(0.934172,0.303531,0.187593),
float3(-0.0,0.607062,0.794654),
float3(0.577351,0.187592,0.794654),
float3(0.356822,-0.491124,0.794654),
float3(-0.356822,-0.491124,0.794654),
float3(-0.577351,0.187592,0.794654),
};

[maxvertexcount(60)]
void geom(point v2g input[1], uint id : SV_PrimitiveID, inout TriangleStream<g2f> outStream)
{
	g2f o;

	[unroll]
	for(int j = 0; j < 20; j++)
	{
		[unroll]
		for (int k = 0; k < 3; k++)
		{
			const int vid = j * 3 + k;
			o.pos = float4(vertexs[vid], 1.0);
			o.pos = UnityObjectToClipPos(o.pos);
			o.normal = UnityObjectToWorldNormal(normals[j]);
			outStream.Append(o);
		}
		outStream.RestartStrip();
	}
}

fixed4 frag(g2f i) : SV_Target
{
	float4 col = 1;
	float3 lightdir = _WorldSpaceLightPos0.xyz;
	col.xyz *= saturate(dot(i.normal, -lightdir));
	return col;
}
ENDCG
}
}
}
```

## リング, チューブ
```c
Shader "Yagiri/GeometryShader/Primitive/RingAndTube"
{

Properties
{
_RadiusA("RadiusA", Float) = 0.5
_RadiusB("RadiusB", Float) = 0.3
_HeightA("HeightA", Float) = 0.0
_HeightB("HeightB", Float) = 0.0
}
SubShader
{

Tags { "RenderType"="Opaque" }
LOD 100
Cull Off

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma geometry geom
#pragma fragment frag
#include "UnityCG.cginc"
#define PI2 6.28318530718

struct appdata
{
	float4 vertex : POSITION;
};

struct v2g
{
	float4 pos : POSITION;
};

struct g2f
{
	float4 pos : SV_POSITION;
	float3 normal : NORMAL;
};

v2g vert(appdata v)
{
	v2g o;
	o.pos = v.vertex;
	return o;
}

float _RadiusA;
float _RadiusB;
float _HeightA;
float _HeightB;

// ※最大頂点数制限に注意
// RowN * Column * 4 = 96
[maxvertexcount(96)]
void geom(point v2g input[1], uint id : SV_PrimitiveID, inout TriangleStream<g2f> outStream)
{
	g2f o;

	const int RowN = 3;
	const int ColumnN = 8;

	[unroll]
	for (int j = 0; j < ColumnN; j++)
	{
		float nj = j / (float)ColumnN;
		float nj_ = (j + 1) / (float)ColumnN;
		float3 top = float3(
			_RadiusA * cos(PI2*nj), 
			_HeightA, 
			_RadiusA * sin(PI2*nj)
			);
		float3 bottom = float3(
			_RadiusB * cos(PI2*nj), 
			_HeightB, 
			_RadiusB * sin(PI2*nj)
			);
		float3 top_ = float3(
			_RadiusA * cos(PI2*nj_), 
			_HeightA, 
			_RadiusA * sin(PI2*nj_)
			);
		float3 bottom_ = float3(
			_RadiusB * cos(PI2*nj_), 
			_HeightB, 
			_RadiusB * sin(PI2*nj_)
			);

		[unroll]
		for(int k = 0; k < RowN; k++)
		{
			float nk = k / (float)RowN;
			float nk_ = (k + 1) / (float)RowN;

			float3 p0 = lerp(top, bottom, nk);
			float3 p1 = lerp(top, bottom, nk_);
			float3 p2 = lerp(top_, bottom_, nk);
			float3 p3 = lerp(top_, bottom_, nk_);
			
			float3 n = normalize(cross(p1 - p0, p2 - p0));
			o.normal = UnityObjectToWorldNormal(n);

			o.pos = UnityObjectToClipPos(float4(p0, 1.0));
			outStream.Append(o);
			o.pos = UnityObjectToClipPos(float4(p1, 1.0));
			outStream.Append(o);
			o.pos = UnityObjectToClipPos(float4(p2, 1.0));
			outStream.Append(o);
			o.pos = UnityObjectToClipPos(float4(p3, 1.0));
			outStream.Append(o);

			outStream.RestartStrip();
		}
	}
}

fixed4 frag(g2f i) : SV_Target
{
	float4 col = 1;
	float3 lightdir = _WorldSpaceLightPos0.xyz;
	col.xyz *= saturate(dot(i.normal, -lightdir));
	return col;
}
ENDCG
}
}
}
```