Unity URPのGeometryシェーダーが原点にしか描画されない問題

# はじめに
Shader初心者の私がGeometryシェーダーでつまづいた点と修正方法をここに書きます。

Geometryシェーダーで下記の動画に映っているものを作ろうとしてました。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Unity UrpのGeometryシェーダーで作りたかったもの <a href="https://t.co/V9gbwUCU2l">pic.twitter.com/V9gbwUCU2l</a></p>&mdash; Noriaki (@h4uWtExFss77493) <a href="https://twitter.com/h4uWtExFss77493/status/1665612221320413185?ref_src=twsrc%5Etfw">June 5, 2023</a></blockquote>

# 注意
Shader初心者のため間違った知識を記載している場合がございます。
もし本記事内に間違っている箇所が存在した場合、指摘いただければ幸いです。

# 環境
Unity 2021.3.1f1
Universal RP 12.1.6

# 失敗点
Geometryシェーダー内で頂点座標を変換するとオブジェクトの座標と描画される座標がズレてしまいました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Geometryシェーダーで失敗してしまったもの <a href="https://t.co/2Ehc3OI1PV">pic.twitter.com/2Ehc3OI1PV</a></p>&mdash; Noriaki (@h4uWtExFss77493) <a href="https://twitter.com/h4uWtExFss77493/status/1665616516736499712?ref_src=twsrc%5Etfw">June 5, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 失敗時の頂点シェーダーとジオメトリシェーダー
``` MissGeometry.shader
struct appdata
{
    float4 positionOS : POSITION;
	float3 normal : NORMAL;
};

struct g2f
{
	float4 positionCS : SV_POSITION;
};

appdata vert(appdata v)
{
	return v;
}

// 法線情報から頂点を時間で変化させる
[maxvertexcount(3)]
void geom(triangle appdata input[3], inout TriangleStream<g2f> stream)
{
	float3 vec1 = input[1].positionOS.xyz - input[0].positionOS.xyz;
	float3 vec2 = input[2].positionOS.xyz - input[0].positionOS.xyz;
	float3 normal = normalize(cross(vec1, vec2));
	[unroll]
	for (int i = 0; i < 3; i++)
	{
		appdata v = input[i];
		g2f o;
		v.positionOS.xyz += normal * (_SinTime.w * 0.5 + 0.5);
		o.positionCS = TransformObjectToHClip(v.positionOS.xyz);

		stream.Append(o);
	}
	stream.RestartStrip();
}

```
# 解決方法
URP環境で`TransformObjectToHClip()`をGeometryシェーダー内で使用した場合、何故かワールド座標空間の原点を呼び出してしまいます。

そのため、構造体に`クリップ空間座標`と`ワールド空間座標`を宣言し、Vertexシェーダー内で`GetVertexPositionInputs()`を使いワールド座標を取得し、Geometryシェーダー内で`TransformObjectToHClip()`を使いクリップ座標を取得することで解決しました。

# 解決時の頂点シェーダーとジオメトリシェーダー
```Geometry.shader
struct appdata
{
	float4 positionOS : POSITION;
	float3 normal : NORMAL;
};

struct VertexOutPut
{
	float3 positionWS : TEXCOORD0;
};

struct g2f
{
	float4 positionCS : SV_POSITION;
    float3 positionWS : TEXCOORD0;
};

VertexOutPut vert(appdata v)
{
	VertexOutPut o = (VertexOutPut)0;

	VertexPositionInputs vertexInput = GetVertexPositionInputs(v.positionOS.xyz);
	o.positionWS = vertexInput.positionWS;

	return o;
}

[maxvertexcount(3)]
void geom(triangle VertexOutPut input[3], inout TriangleStream<g2f> stream)
	{
	float3 vec1 = input[1].positionWS - input[0].positionWS;
	float3 vec2 = input[2].positionWS - input[0].positionWS;
	float3 normal = normalize(cross(vec1, vec2));
	[unroll]
	for (int i = 0; i < 3; i++)
	{
		VertexOutPut v = input[i];
		g2f o;

		v.positionWS.xyz += normal * (_SinTime.w * 0.5 + 0.5) * _ScaleFactor;

		o.positionWS = v.positionWS;
		o.positionCS = TransformObjectToHClip(v.positionWS);

		stream.Append(o);
	}
	stream.RestartStrip();
}
```
# おわりに
初めて記事を書いたので分かりづらい点やアドバイスなどございましたら是非意見をください。
また本記事が誰かの参考になれば幸いです。
最後まで見ていただきありがとうございました。

# 参考記事と参考動画
https://styly.cc/ja/tips/polygondestruction-go-shader/

<iframe width="560" height="315" src="https://www.youtube.com/embed/7C-mA08mp8o" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>