在DirectX 9的渲染管线中,可编程的Shader只有顶点着色器和片段着色器两类。但是在DirectX 10开始,渲染管线增加了一个【可选】的几何体着色器。
优点:可以修改网格(增删改模型的顶点及三角面等)
缺点:几何体着色器并行调用硬件困难,并行程度低,效率和顶点着色器有很大的差距
实现流程:(以一个简单的实例为准)
Shader "Custom/GeometryLearn"
{
Properties
{
Height("SingleH",float)=0.5
}
SubShader
{
Pass
{
Tags
{
"RenderType"="Opaque"
}
CGPROGRAM
#pragma target 5.0
#pragma vertex VS_Main
#pragma geometry GS_Main
#pragma fragment FS_Main
#include "UnityCG.cginc"
float Height;
struct GS_INPUT
{
float4 pos:POSITION;
};
struct FS_INPUT
{
float4 pos:SV_POSITION;
};
GS_INPUT VS_Main(appdata_base v)
{
GS_INPUT output;
output.pos=v.vertex;
return output;
};
//vs的输出作为gs的输入
[maxvertexcount(3)]
//输入 point line triangle lineadj triangleadj----输出: PointStream只显示点,LineStream只显示线,TriangleStream全显
void GS_Main(triangle GS_INPUT p[3],inout LineStream<FS_INPUT> triStream)
{
for(int i=0;i<3;i++)
{
FS_INPUT output;
//读取原来的点,这里不做改变
float4 pos=float4(p[i].pos.x,p[i].pos.y,p[i].pos.z,p[i].pos.w);
output.pos=UnityObjectToClipPos(pos);
if(pos.y<Height)
{
triStream.Append(output);
}
}
triStream.RestartStrip();
}
//gs的输出作为fs的输入
float4 FS_Main(FS_INPUT i):COLOR
{
return fixed4(1,1,1,1);
}
ENDCG
}
}
}
更复杂一点的例子:从球体表面挤出锥体
Shader "MyShader/GSTest"
{
Properties
{
_Color("MianColor",color)=(1,1,1,1)
_Length("Length", Range(0.01, 10)) = 0.02
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
Cull Off
CGPROGRAM
#pragma target 4.0
#pragma vertex vert
#pragma fragment frag
#pragma geometry geom
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2g
{
float4 vertex : POSITION;
float3 nor:NORMAL;
};
struct g2f
{
float4 vertex : SV_POSITION;
float3 norg:NORMAL;
};
float _Length;
fixed4 _LightColor0;
fixed4 _Color;
v2g vert(appdata_base v)
{
v2g o;
o.vertex = v.vertex;
o.nor=v.normal;
return o;
}
void ADD_VERT(float3 v,g2f o,inout TriangleStream<g2f> tristream)
{
o.vertex = UnityObjectToClipPos(v);
tristream.Append(o);
}
void ADD_TRI(float3 p0,float3 p1,float3 p2,g2f o,inout TriangleStream<g2f> tristream)
{
ADD_VERT(p0,o,tristream);
ADD_VERT(p1,o,tristream);
ADD_VERT(p2,o,tristream);
tristream.RestartStrip();
}
[maxvertexcount(9)]
void geom(triangle v2g IN[3], inout TriangleStream<g2f> tristream)
{
g2f o;
//--------计算原模型三角面的法线
float3 edgeA = IN[1].vertex - IN[0].vertex;
float3 edgeB = IN[2].vertex - IN[0].vertex;
float3 normalFace = normalize(cross(edgeA, edgeB));
//-------
o.norg=-normalFace;
//根据模型三角面信息额外生成一个向外突出的锥体
float3 v0 = IN[0].vertex;
float3 v1 = IN[1].vertex;
float3 v2 = IN[2].vertex;
float3 v3 = (IN[0].vertex+IN[1].vertex+IN[2].vertex)/3 + normalFace * _Length;
ADD_TRI(v0,v3,v2,o,tristream);
ADD_TRI(v0,v1,v3,o,tristream);
ADD_TRI(v2,v3,v1,o,tristream);
}
fixed4 frag (g2f i) : SV_Target
{
//实现简单的Lambert光照
float3 LightDir = normalize(_WorldSpaceLightPos0.xyz);
float3 diffuseColor =_LightColor0*max(dot(i.norg, LightDir), 0);
return _Color*float4(diffuseColor,1);
}
ENDCG
}
}
}