DirectX的一大特色之一便是Shader渲染,包括顶点Shader渲染以及像素Shader渲染。设置Shader机制是为了使程
序员能够控制GPU绘制顶点或像素的方式,简单的说,我们设计的Shader代码是运行在GPU硬件中的,这样提高了渲
染效率。上篇幅简要简绍了下DirectX管线渲染的基本步骤,本篇幅从绘制基本的正方体开始详细描述绘制过程。
1,Vertex Shader
struct VertexIn
{
float3 pos : POSITION;
float4 color : COLOR;
};
Vertex Shader是对模型的每一个顶点进行操作加工的代码,所以输入输出自然都是一个顶点结构数据。
上图的float3和float4是HLSL内置类型。
级着色器语言(High Level Shader Language,简称HLSL),由微软拥有及开发的一种语言,HLSL 独立的工作在 Windows 平台上,只能供微软的Direct3D使用。 HLSL是微软抗衡GLSL的产品,同时不能与OpenGL标准兼容。他跟Nvidia的Cg非常相似。 HLSL的主要作用为将一些复杂的图像处理,快速而又有效率地在显示卡上完成,与组合式或低阶Shader Language相比,能降低在编写复杂特殊效果时所发生编程错误的机会。 HLSL已经整合到了 DirectX 9中。
HLSL我会在后面专门写一篇笔记学习
POSITION和COLOR分别对应顶点的坐标以及颜色向量,这两个声明是在C++语言中设置输入布局InputLayout内容设定的。
struct VertexOut
{
float4 posH : SV_POSITION;
float4 color : COLOR;
};
SV_POSITION是默认固定的系统值,不得改变,其他可以为任意设定值,因为顶点输出需要内存对齐,所以输出的顶点是经过矩阵计算后得出的float4格式的值,一般为(x,y,z,w)w表示其缩放值,一般为1.
Shader计算顶点的函数模型如下:
VertexOut VS(VertexIn in)
{
VertexOut out;
out.pos=mul(float4(in.pos,1),modelMatrix);
out.pos=mul(out.pos,worldMatrix);
out.pos=mul(out.pos,viewMatrix);
out.color=in.color;
return out;
}
2.Pixel Shader
根据管线渲染步骤,顶点Shader计算是先于像素Shader计算的,在光栅化阶段,一个三角形在其所覆盖的每个像素处使用插值来计算相应顶点的各个属性,然后把插值后的顶点传递给像素着色器。在简单的没有Geometry Shader和Tessellator时,顶点着色器的输出就是像素着色器的输入
float4 PS(VertexOut pin):SV_TARGET
{
return pin.color;
}
SV_TARGET是系统值,表示该函数返回的是用于下一个阶段OutPut Merger的颜色值,这里只简单的做了颜色值得传递。
3.常量缓冲区
在HLSL中,设置常量缓冲区声明为cbuffer,在着色器Shader代码里,我们经常把刷新频率相似的常量放置在相同的常量缓存中。如世界矩阵以及其他转换矩阵是针对当个物体设计,放在同一个常量缓存里,而场景灯光的位置,朝向,颜色等这下针对整个场合都要每帧渲染的的数据,以相同格式放在一个cbuffer里
4.Effect框架利用
Effect框架是微软提供给我们的一个开源的代码库,用来把shader代码和相应的渲染状态合理的组织到一起,来实现一个针对性的特效。比如渲染水面、云彩、阴影等不同特效时,需要用到不同的渲染状态,这样每个特效都可以写成单独的Effect。
Effect组成为:
technique11:一个特效的一种渲染方法即为technique11,一个特效可以有多种方法。
pass:一个technique11必须包含至少一个pass,指的是物体的实际渲染过程,一个technique11可以包含多个pass以实现混合效果
下面为一个特效的简单effect
cbuffer PerFrame
{
float4x4 g_worldViewProj;
};
struct VertexIn
{
float3 pos : POSITION;
float4 color : COLOR;
};
struct VertexOut
{
float4 posH : SV_POSITION;
float4 color : COLOR;
};
VertexOut VS(VertexIn vin)
{
VertexOut vout;
vout.posH = mul(float4(vin.pos,1.f),g_worldViewProj);
vout.color = vin.color;
return vout;
1
}
float4 PS(VertexOut pin):SV_TARGET
{
return pin.color;
}
technique11 BasicDraw
{
Pass p0
{
SetVertexShader(CompileShader(vs_5_0,VS()));
SetPixelShader(CompileShader(ps_5_0,PS()));
}
}
如图所示,一个Effect包含了特效所需要的所有常量缓存,Vertex渲染方法,Pixel渲染方法,而后包含一个technique11方法,里面包含一个名为p0的Pass,Pass里指定了用于Vertex和Pixel渲染的方法。
既然我们使用了Effect来封装一整个渲染的过程,那在C++里面为其编辑就要用到effect专有的接口了。