【Unity Shader入门】4、几何着色器Geometry Shaders之结构解析

  其实unity shader除了vertex shader和frag shader之外,还有一个geom shader,处理流程在vextex shader和frag shader之间。
  顶点着色器是逐顶点操作,可以进行坐标变换等计算。
  片段着色器是逐片段/像素操作,进行最终输出颜色的计算。
  几何着色器是逐图元的操作。它的输入是图元,输出也是图元。

#pragma target 4.0
#pragma geometry GS_Main
[maxvertexcount(3)] 
void GS_Main(point VS_OUTPUT IN[1], inout TriangleStream<GS_OUTPUT> triStream) 
{ 
    /*shader body*/
} 
  • 1、设定着色器编译目标级别为4.0(4.0以上才能支持)
#pragma target 4.0
  • 2、 设定几何体着色器函数名称为GS_Main
#pragma geometry GS_Main
  • 3、 [maxvertexcount(num)]
      函数前添加 [maxvertexcount(num)]
      首先 [maxvertexcount(num)]这个必须写在geomshader前面,是不可少的,主要是定义输出顶点的最大数量,输出顶点可以每次都不同,但是不超过这个数就行,注意这个数不要太大,影响性能哦。
      [NVIDIA08]指出,当GS输出在1到20个标量之间时,可以实现GS的性能峰值,如果GS输出在27-40个标量之间,则性能下降50%。
  • 4、几何着色器的输入输出

    输入类型
//point:输入类型,见下表
//VS_OUTPUT:顶点着色器传进来的类型,可以自定义结构体,v2g、v2f...
//IN[1]:IN为输入变量名,可以自定义,里面的1是顶点数量,根据输入类型,见下表
point VS_OUTPUT IN[1]
输入类型描述顶点数量
point输入图元为点1
line输入图元为线2
triangle输入图元为三角形3
lineadj输入图元为带有邻接信息的直线,由4个顶点构成3条线4
triangleadj输入图元为带有邻接信息的三角形,由6个顶点构成6

参考图:
在这里插入图片描述


输出类型

//inout:关键词
//TriangleStream:输出类型,见下表及样例
//GS_OUTPUT:几何着色器传出去的类型,可以自定义结构体,g2f、v2f...
//triStream:输出类型变量名
inout TriangleStream<GS_OUTPUT> triStream
输出类型描述
PointStream输出图元为点
LineStream输出图元为线
TriangleStream输出图元为三角形

针对每个输出类型的效果可以看下图:
在这里插入图片描述
对于GSShader有以下几点需要注意的:

  1. 每输出一个点Append到输出流中,如:pStream.Append(o);
  2. 对于TriangleStream ,如果需要改变输出图元,需要每输出点足够对应相应的图元后都要RestartStrip()一下再继续构成下一图元,如:tStream.RestartStrip();
  • 最后,贴上上面三个Shader:


PointStream

Shader "LST/GS/PointStream"
{
	Properties
	{
		_MainTex("MainTex", 2D) = "white" {}
	}

	SubShader
	{
		Pass
		{
			Tags{ "RenderType" = "Opaque" }
			LOD 200

			CGPROGRAM
			#pragma target 4.0
			#pragma vertex VS_Main
			#pragma geometry GS_Main
			#pragma fragment FS_Main
			#include "UnityCG.cginc"

			uniform sampler2D _MainTex;

			struct v2g
			{
				float4  pos     : POSITION;
				float3  normal  : NORMAL;
				float2  uv     : TEXCOORD0;
			};

			struct g2f
			{
				float4  pos     : POSITION;
				float3  normal  : NORMAL;
				float2  uv     : TEXCOORD0;
			};

			// Vertex Shader
			v2g VS_Main(appdata_base v)
			{
				v2g o = (v2g)0;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv  = v.texcoord;

				return o;
			}

			// Geometry Shader
			[maxvertexcount(3)] 
			void GS_Main(triangle v2g p[3], inout PointStream<g2f> pStream)
			{
				for (int i = 0; i < 3; i++) 
				{
					g2f o = (g2f)0;
					o.pos = p[i].pos;
					o.normal = p[i].normal;
					o.uv  = p[i].uv ;
					//将每个顶点添加到PointStream流里
					pStream.Append(o);
				}
			}

			// Fragment Shader
			float4 FS_Main(g2f i) : COLOR
			{
				return tex2D(_MainTex, i.uv);
			}

			ENDCG
		}
	}
}


LineStream

Shader "LST/GS/LineStream"
{
	Properties
	{
		_MainTex("MainTex", 2D) = "white" {}
	}

	SubShader
	{
		Pass
		{
			Tags{ "RenderType" = "Opaque" }
			LOD 200

			CGPROGRAM
			#pragma target 4.0
			#pragma vertex VS_Main
			#pragma geometry GS_Main
			#pragma fragment FS_Main
			#include "UnityCG.cginc"

			uniform sampler2D _MainTex;

			struct v2g
			{
				float4  pos     : POSITION;
				float3  normal  : NORMAL;
				float2  uv     : TEXCOORD0;
			};

			struct g2f
			{
				float4  pos     : POSITION;
				float3  normal  : NORMAL;
				float2  uv     : TEXCOORD0;
			};

			// Vertex Shader
			v2g VS_Main(appdata_base v)
			{
				v2g o = (v2g)0;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.normal = v.normal;
				o.uv  = v.texcoord;

				return o;
			}

			// Geometry Shader
			[maxvertexcount(3)] 
			void GS_Main(triangle v2g p[3], inout LineStream<g2f> lStream)
			{
				for (int i = 0; i < 3; i++) 
				{
					g2f o = (g2f)0;
					o.pos = p[i].pos;
					o.normal = p[i].normal;
					o.uv  = p[i].uv ;
					//将每个顶点添加到LineStream流里
					lStream.Append(o);
				}
			}

			// Fragment Shader
			float4 FS_Main(g2f i) : COLOR
			{
				return tex2D(_MainTex, i.uv);
			}

			ENDCG
		}
	}
}


TriangleStream

Shader "LST/GS/TriangleStream"
{
	Properties
	{
		_MainTex("MainTex", 2D) = "white" {}
	}

	SubShader
	{
		Pass
		{
			Tags{ "RenderType" = "Opaque" }
			LOD 200

			CGPROGRAM
			#pragma target 4.0
			#pragma vertex VS_Main
			#pragma geometry GS_Main
			#pragma fragment FS_Main
			#include "UnityCG.cginc"

			uniform sampler2D _MainTex;

			struct v2g
			{
				float4  pos     : POSITION;
				float3  normal  : NORMAL;
				float2  uv     : TEXCOORD0;
			};

			struct g2f
			{
				float4  pos     : POSITION;
				float3  normal  : NORMAL;
				float2  uv     : TEXCOORD0;
			};

			// Vertex Shader
			v2g VS_Main(appdata_base v)
			{
				v2g o = (v2g)0;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.normal = v.normal;
				o.uv  = v.texcoord;

				return o;
			}

			// Geometry Shader
			[maxvertexcount(3)] 
			void GS_Main(triangle v2g p[3], inout TriangleStream<g2f> tStream)
			{
				for (int i = 0; i < 3; i++) 
				{
					g2f o = (g2f)0;
					o.pos = p[i].pos;
					o.normal = p[i].normal;
					o.uv  = p[i].uv ;
					//将每个顶点添加到TriangleStream流里
					tStream.Append(o);
				}
				//添加三角面
				//每输出点足够对应相应的图元后
				//都要RestartStrip()一下再继续构成下一图元
				tStream.RestartStrip();
			}

			// Fragment Shader
			float4 FS_Main(g2f i) : COLOR
			{
				return tex2D(_MainTex, i.uv);
			}

			ENDCG
		}
	}
}

参考文档:https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-geometry-shader#return-value

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值