其实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有以下几点需要注意的:
- 每输出一个点Append到输出流中,如:pStream.Append(o);
- 对于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
}
}
}