日期:2014-05-17 浏览次数:21001 次
几何着色器是从DirectX 10才引入的着色器,是一个可选阶段,位于顶点着色器和像素着色器阶段之间。顶点着色器以顶点作为输入数据,而几何着色器以完整的图元作为输入数据,像点、直线、三角形等。之所以引进几何着色器是为了充分利用GPU的计算能力来生成几何结构和模型细节,减轻CPU的负担,让CPU更专注于逻辑控制。几何着色器的编程和其它着色器类似,在VS2012中默认生成的几何着色器代码如下:
struct GSOutput { float4 pos : SV_POSITION; }; [maxvertexcount(3)] void main( triangle float4 input[3] :SV_POSITION, inout TriangleStream<GSOutput > output ) { for (uint i = 0; i < 3;i++) { GSOutputelement; element.pos =input[i]; output.Append(element); } }
这部分代码没有对顶点进行任何处理,主要注意下几何着色器与其它着色器不同的地方:maxvertexcount用来说明几何着色器所能输出顶点的最大数量,因为几何着色器每次输出的顶点数目可以不同。而triangle则说明输入是一个三角形图元,input[3]表明每次读入三角形的三个顶点。TriangleStream说明输出是一个流类型的对象,它是一个描述三角形的顶点列表,在main方法中构造好一个顶点后,使用Append方法将其加入列表。关于几何着色器更详细的介绍当然还得参考书籍和MSDN,接下来就实现一个用几何着色器对三角形进行细分的效果。
可以看出,把一个三角形细分成四个三角形,总的顶点数增加一倍。(写到这里突然想到游戏中常用的材质细节选项,不知道是不是通过设置不同的细分参数来区别。)知道基本方法后就可以进行代码的编写。这次是对第十二篇实现的模型进行细分。
首先向项目中添加几何着色器,并重命名为SimpleGeometryShader。注意这里需要更改编译选项,之前的着色器模型是 4 级别 9_3 (/4_0_level_9_3),而几何着色器是在DirectX 10中才引入的,所以要更改着色器模型为4 (/4_0)。
然后要修改几何着色器中的结构体定义,与顶点着色器对应:
struct VertexShaderOutput { float4 posH : SV_POSITION; float3 posW : POSITION; float3 normal : NORMAL; float2 tex : TEXCOOD; float2 texa :TEXCOOD_ALPHA; }; struct GSOutput { float4 posH : SV_POSITION; float3 posW : POSITION; float3 normal : NORMAL; float2 tex : TEXCOOD; float2 texa :TEXCOOD_ALPHA; uint PrimID : SV_PrimitiveID; };
几何着色器的输入是顶点着色器的输出,所以几何着色器的main方法定义如下:
// 将输入三角形分割为四个小三角形 [maxvertexcount(8)] void main( triangle VertexShaderOutputinput[3], inout TriangleStream<GSOutput > output )
在main方法中进行计算时与其它着色器没什么区别。首先生成5个数组,对应结构体的5个属性,而每个数组均包含6个元素,对应之前图中的6个顶点。
// v1,v2,v3是原始顶点,m0,m1,m2是各边中点 // // 示意图 新数组中的序号 // v1 5 // * * // / \ / \ // / \ / a \ // m0*-----*m1 1*-----*3 // / \ / \ / \ c / \ // / \/ \ / b \ / d \ // *-----*-----* *-----*-----* //v0 m2 v2 0 2 4 float4 ph[6]; ph[0] =input[0].posH; ph[1] =0.5f*(input[0].posH + input[1].posH); ph[2] =0.5f*(input[2].posH + input[0].posH); ph[3] =0.5f*(input[1].posH + input[2].posH); ph[4] =input[2].posH; ph[5] =input[1].posH; float3 pw[6]; pw[0] =input[0].posW; pw[1] =0.5f*(input[0].posW + input[1].posW); pw[2] =0.5f*(input[2].posW + input[0].posW); pw[3] =0.5f*(input[1].posW + input[2].posW); pw[4] =input[2].posW; pw[5] =input[1].posW; float3 n[6]; n[0] =input[0].normal; n[1] =normalize(input[0].normal + input[1].normal); n[2] =normalize(input[2].normal + input[0].normal); n[3] =normalize(input[1].normal + input[2].normal); n[4] =input[2].normal; n[5] =input[1].normal; float2 t[6]; t[0] =input[0].tex; t[1] =0.5f*(input[0].tex + input[1].tex); t[2] =0.5f*(input[2].tex + input[0].tex); t[3] =0.5f*(input[1].tex + input[2].tex); t[4] =input[2].tex; t[5] =input[1].tex; float2 ta[6]; ta[0] =input[0].texa; ta[1] =0.5f*(input[0].texa