在dx10中,处于vertex和fragment shader之间还有一个可选项geometry shader,中文名几何体着色器,用来进行图元操作。不同于vertex函数接收的是最原始的几何数据,geometry接收来自vertex进行空间变换后的一个或一组几何图元,处理完毕后返回不同数量的几何图元给光栅阶段。其出现的原因就是随着显卡性能和图形API的更新升级,更多的渲染流程阶段变得可控可编程,可以给予我们开发者更多更自由的编程权限,比如之前的tessellation就是。
下图揭示了每个可编程阶段的处理流程:
可以看得出来geometry shader在vertex和tessellation之后,光栅化到fragment之前,geometry shader专门处理vertex之后的几何图元。处理顶点、线段、三角面的图元函数,实际函数中,接收vertex shader返回的顶点,经过开发运算,返回点线面图元数据流,下面是geometry shader能做的事情,如下:
Shader "Custom/GsWireShader"
{
Properties
{
_MainColor("Main Color",color) = (1,1,1,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma geometry geom
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
};
//vertex到geometry数据结构
struct v2g
{
float4 vertex : POSITION;
};
//geometry到fragment数据结构
struct g2f
{
float4 vertex : SV_POSITION;
};
float4 _MainColor;
//首先vertex函数将顶点数据传入geometry函数
v2g vert (appdata v)
{
v2g o;
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
//geometry函数一次接受3个图元数据,返回线框数据
//maxvertexcount设置vertex到geometry每次输出最大顶点数量为3
//inout输出修饰类型有PointStream/LineStream/TriangleStream,分别显示顶点/线段/三角面
[maxvertexcount(3)]
void geom(triangle v2g vg[3], inout LineStream<g2f> ls)
{
for (int i = 0; i < 3; i++)
{
g2f gf;
gf.vertex = vg[i].vertex;
ls.Append(gf);
}
ls.RestartStrip();
}
//frag函数接受geometry函数输出数据渲染主颜色
fixed4 frag (g2f i) : SV_Target
{
return _MainColor;
}
ENDCG
}
}
}
效果如下:
geometry shader要注意的地方就是,因为其插入到vertex和fragment之间,所以由以前的appdate-v2f的结构传递变成了appdata-v2g-g2f,多了一层,同时inout输入输出修饰类型可以为Point/Line/Triangle三种stream,分别返回点,线段和三角面数据流。
geometry shader能实现很多炫酷的效果,我们后面继续学习geometry shader着色效果。