2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Last updated at Posted at 2023-06-05

はじめに

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

Geometryシェーダーで下記の動画に映っているものを作ろうとしてました。

注意

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

環境

Unity 2021.3.1f1
Universal RP 12.1.6

失敗点

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

失敗時の頂点シェーダーとジオメトリシェーダー

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();
}

おわりに

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

参考記事と参考動画

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?