在shader主函数的输入变量必须是用语义或者uniform关键字标记的.否则,将会出现编译错误.输入语义是用来联系shader的给定输入与渲染管线中相应输出的.比如,语义POSITION0就是用来指定来自顶点缓冲相应位置数据的.
由于功能不同,象素与顶点渲染器有不同的输入语义集.顶点渲染器的输入语义用来描述每一个顶点的信息,比如位置,法线,象素纹理,颜色,切线,次法线等.输入语义是直接映射于顶点声明(vertex declaration)中的usage和usage index部分,因此,想要了解顶点输入的语义,建议先看一下顶点声明的相关概念,注意,既然用可编程管线,就应该忘记灵活顶点格式(FVF).
象素渲染器语义是用来描述由光栅器单元产生的每个象素的信息的.所有的数据是由顶点渲染器输入的相应数据插值而成的,因为一个图元只有几个顶点,但是却覆盖了一大片象素,因此顶点之间的象素信息就需要权衡各顶点之间的结果来确定.
输入语义可以使用两种方法来指定:
(1)在参数声明后附加冒号与语义名字.
(2)定义一个输入结构,在结构成员后附加冒号与语义名字
顶点与象素渲染器为渲染管线的下一阶段提供数据.输出语义用来指定产生的数据怎样与下一阶段的输入相映射.比如,顶点渲染器的输出语义用来为光栅器的插值器提供相应数据,而象素渲染器的输出则为为每个渲染对象的alpha混合和深度缓冲更新提供相应数据.
一个使用输入输出结构的shader示例:
vector vClr; struct VS_INPUT { float4 vPosition : POSITION; float3 vNormal : NORMAL; float4 vBlendWeights : BLENDWEIGHT; }; struct VS_OUTPUT { float4 vPosition : POSITION; float4 vDiffuse : COLOR; }; float4x4 mWld1; float4x4 mWld2; float4x4 mWld3; float4x4 mWld4; float Len; float4 vLight; float4x4 mTot; VS_OUTPUT VS_Skinning_Example(const VS_INPUT v, uniform float len=100) { VS_OUTPUT out; // Skin position (to world space) float3 vPosition = mul(v.vPosition, (float4x3) mWld1) * v.vBlendWeights.x + mul(v.vPosition, (float4x3) mWld2) * v.vBlendWeights.y + mul(v.vPosition, (float4x3) mWld3) * v.vBlendWeights.z + mul(v.vPosition, (float4x3) mWld4) * v.vBlendWeights.w; // Skin normal (to world space) float3 vNormal = mul(v.vNormal, (float3x3) mWld1) * v.vBlendWeights.x + mul(v.vNormal, (float3x3) mWld2) * v.vBlendWeights.y + mul(v.vNormal, (float3x3) mWld3) * v.vBlendWeights.z + mul(v.vNormal, (float3x3) mWld4) * v.vBlendWeights.w; // Output stuff out.vPosition = mul(float4(vPosition + vNormal * Len, 1), mTot); out.vDiffuse = dot(vLight,vNormal); return out; }
最后再次强烈建议在看语义之前去看看顶点声明中的D3DDECLUSAGE部分,在那里,你就会明白为什么顶点输入以后会有这样的映射结果,其实常用的FVF在也是在最后转变成顶点声明才进入Translation&Lighting阶段的.