Programming.Role.Playing.Games.with.DirectX第2章开始介绍坐标系,矩阵和向量一些数学概念,每本dx书都是必备的吗?这些就没什么好说的,直接来第一个工程,就是Draw2D,书是用固定管线来实现的,因此没什么难度,刚好自己有学过一点Shader,就用Shader也实现了一遍。就如上图,左边的就是用固定管线实现的,右边是用Shader实现的。
我用的框架是之前学习dx11的,也就是这个网站(http://www.rastertek.com/tutdx11.html)上的,封装的比较好,dx的初始化就在D3DClass内中,window的初始化在SystemClass中。这些都是基础,也没什么好讲的,就跳过。吐槽下,总感觉跨度有点大,如果是dx新手的话,而且还是英文版,上手有点难啊,直接上顶点缓存,贴图加载等。
来看下代码:
固定管线渲染:
void ModelClass::Render(IDirect3DDevice9* device, D3DXMATRIX worldMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix)
{
device->SetTexture(0, m_texture->GetTexture());
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
device->SetStreamSource(0, m_vertexBuffer, 0, sizeof(VertexType));
device->SetFVF(VERTEX_FVF);
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
device->SetTexture(0, nullptr);
}
SetTexture表面要是用那张贴图来进行纹理映射,SetSamplerState是设置纹理过滤器,SetStreamSource就是把顶点缓存与渲染流水线关联,SetFVF是告诉流水线什么顶点格式。其实也有个类似的函数SetVertexDeclaration。DrawPrimitive就是绘制的函数了,D3DPT_TRIANGLESTRIP是三角带(一时忘了叫什么来着)的意思,前3个顶点构成1个三角面,接着下一个顶点和前2个顶点再构成一个三角面。这些函数网上都可以查到详细的资料。
接下来的就是Shader的,因为顶点是D3DFVF_XYZRHW,之前还真没有用到过,网上查了下,RHW是D3D里面的一种顶点格式,是一种自带视图、投影、世界等变换和光线计算等处理的顶点格式,而且这些处理我们无法用SetTransform等进行的转换。我就认为在顶点着色器阶段对顶点的处理是无效的。然后经测试,使用RHW的话,在顶点着色器阶段对顶点的处理是无效的。
Shader渲染代码:
void ShaderModelClass::Render(IDirect3DDevice9* device, D3DXMATRIX worldMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix)
{
bool result;
UINT passMaxNum;
float time;
time = (float)::timeGetTime() / 1000.0f;
device->SetStreamSource(0, m_vertexBuffer, 0, sizeof(VertexType));
device->SetFVF(VERTEX_FVF);
result = m_colorShader->Render(device, m_texture->GetTexture(), time);
if (!result)
return;
m_colorShader->GetEffect()->Begin(&passMaxNum, 0);
for (UINT pass = 0; pass < passMaxNum; ++pass)
{
m_colorShader->GetEffect()->BeginPass(pass);
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
m_colorShader->GetEffect()->EndPass();
}
m_colorShader->GetEffect()->End();
}
这里用的是effect框架,比单独写vertexshader和pixelshader快,而且没有vertexshader和pixelshader的问题,这个我之前有说过。注意下,这里时间是用来做上图的渐变效果的。
接下来Shader:
texture modelTexture;
float time;
sampler ModelTextureSampler = sampler_state
{
Texture = <modelTexture>;
MipFilter = POINT;
MinFilter = POINT;
MagFilter = POINT;
//MipFilter = LINEAR;
//MinFilter = LINEAR;
//MagFilter = LINEAR;
//MipFilter = ANISOTROPIC;
//MinFilter = ANISOTROPIC;
//MagFilter = ANISOTROPIC;
};
struct VertexInputType
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct PixelInputType
{
float4 pos : POSITION;
float2 texcoord : TEXCOORD0;
};
PixelInputType ColorVertexShader(VertexInputType input)
{
PixelInputType output;
output.pos = input.vertex;//可以在这里随意修改顶点,会发现对结果没有任何影响
output.texcoord = input.texcoord;
return output;
}
float4 ColorPixelShader(PixelInputType input) : COLOR
{
float param = max(0.5, cos(time));//利用传过来的时间和cos函数进行变化,来实现渐变效果,用来和左边的固定管线渲染的区分
float4 color = tex2D(ModelTextureSampler, input.texcoord) * param;
return color;
}
technique ColorTechnique
{
pass pass0
{
VertexShader = compile vs_2_0 ColorVertexShader();
PixelShader = compile ps_2_0 ColorPixelShader();
}
}
这么一看,Shader的代码也很简单,也没什么说的,具体的看完整源码。
一些配置这边说下,
CharacterSet是Unicode, dx9sdk的配置,最重要的是C/C++中Language选项的ConformanceMode设置为No,不然TCHAR*不能转为LPCWSTR,这个我到现在还不知道原因。
源码下载:下载地址