按照书上的顺序(一般来说,写教程式的书籍,最重要的莫过于顺序,一本好书他章节排序能让你很好的理解内容)在经过 Vertex Shader 与
Pixel Shader 之后,就是书上的最后一章 Effects Framework (我参考的是《DirectX 9.0 游戏开发编程基础》这本书,第二次看了),这个后缀名
通常被命名为 "xxx.fx" 的文件,将之前所学习的渲染状态控制的灵活性完全释放出来,在这个文件中不仅能包含 Vertex Shader,也能够包含Pixel -
Shader,而且还能对 Fixed Pipeline 进行控制,DX SDK 的帮助文档中有一副对 Effects Frramework 进行描述的图示,如下:
PS:这就是Effects能操控的阶段,这释放了所有封闭的操作,程序员可以操作到更微小的 “元素” 以至于更好的控制渲染效果、效率。
利用书上的《LightAndTexture》来作为实例程序:
// File name : EffectsControl.fx
// Author : Dormy.X.Cui
// Description :
//
matrix worldMat;
matrix viewMat;
matrix projMat;
texture mountainTex;
// Texture sampler
sampler S0 = sampler_state
{
Texture = (mountainTex);
MinFilter = ANISOTROPIC;
MagFilter = ANISOTROPIC;
MipFilter = ANISOTROPIC;
};
technique LightAndTexture
{
pass P0
{
vertexshader = null;
pixelshader = null;
fvf = XYZ | Normal | Tex1;
Lighting = true;
NormalizeNormals = true;
SpecularEnable = false;
WorldTransform[0] = (worldMat);
ViewTransform = (viewMat);
ProjectionTransform = (projMat);
LightType[0] = Directional;
LightAmbient[0] = {0.2f, 0.2f, 0.2f, 1.0f};
LightDiffuse[0] = {1.0f, 1.0f, 1.0f, 1.0f};
LightSpecular[0] = {0.0f, 0.0f, 0.0f, 1.0f};
LightDirection[0] = {1.0f, -1.0f, 1.0f, 0.0f};
LightPosition[0] = {0.0f, 0.0f, 0.0f, 0.0f};
LightFalloff[0] = 0.0f;
LightRange[0] = 0.0f;
LightTheta[0] = 0.0f;
LightPhi[0] = 0.0f;
LightAttenuation0[0] = 1.0f;
LightAttenuation1[0] = 0.0f;
LightAttenuation2[0] = 0.0f;
LightEnable[0] = true;
MaterialAmbient = {1.0f, 1.0f, 1.0f, 1.0f};
MaterialDiffuse = {1.0f, 1.0f, 1.0f, 1.0f};
MaterialSpecular = {1.0f, 1.0f, 1.0f, 1.0f};
MaterialEmissive = {0.0f, 0.0f, 0.0f, 0.0f};
MaterialPower = 1.0f;
Sampler[0] = (S0);
}
}
这段程序里包含了一个 Technique 以及在 这个 Technique 中包含一个(也可以包含多个)Pass(通常被称作渲染通道),如你所见,在渲染通道的一开始我们
就声明了不使用 Vertex Shader & Pixel Shader ,而使用固定渲染管线中已有的材质与灯光处理。
效果文件编写完成后,我们转回 Application 中来调用对效果文件进行编译的API,以及从常量表中取出需要初始化的常量。
代码如下:
ID3DXBuffer *pError = NULL;
hr = ::D3DXCreateEffectFromFile(::g_pd3dDevice, L"..\\Shader\\EffectsControl.fx",
NULL, NULL,
D3DXSHADER_DEBUG | D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY,
NULL, &::g_pEffect, &pError);
if( FAILED(hr) )
{
::MessageBox(NULL, L"Call D3DXCreateEffectFromFromFile() - failed !", NULL, 0);
if( pError )
{
::MessageBoxA(NULL, (char*)pError->GetBufferPointer(), NULL, 0);
Demo::Release<ID3DXBuffer*>(pError);
return E_FAIL;
}
}
g_hWorldMatrixHandle = ::g_pEffect->GetParameterByName(NULL, "worldMat");
g_hViewMatrixHandle = ::g_pEffect->GetParameterByName(NULL, "viewMat");
g_hProjMatrixHandle = ::g_pEffect->GetParameterByName(NULL, "projMat");
g_hTexHandle = ::g_pEffect->GetParameterByName(NULL, "mountainTex");
g_hLightTexTechHandle = ::g_pEffect->GetTechniqueByName("LightAndTexture");
D3DXMATRIXA16 tmp_world;
D3DXMATRIXA16 tmp_proj;
::D3DXMatrixIdentity(&tmp_world);
::D3DXMatrixPerspectiveFovLH(&tmp_proj, D3DX_PI * 0.25f, (float)(WND_WIDTH)/(float)(WND_HEIGHT), 1.0f, 1000.0f);
g_pEffect->SetMatrix(::g_hWorldMatrixHandle, &tmp_world);
g_pEffect->SetMatrix(::g_hProjMatrixHandle, &tmp_proj);
LPDIRECT3DTEXTURE9 pTex = NULL;
hr = ::D3DXCreateTextureFromFile(::g_pd3dDevice, L"..\\Res\\Terrain_3x_diffcol.jpg", &pTex);
if( FAILED(hr) )
{
::MessageBox(NULL, L"Call D3DXCreateTextureFromFile() - failed !", NULL, 0);
return E_FAIL;
}
Demo::Release<LPDIRECT3DTEXTURE9>(pTex);
return S_OK;
这些完成后,效果文件的操作就完成了,这样我们就能够插入一些测试性的代码,比如添加一些.X文件模型看看效果,或者自己手工填充顶点缓存构造一些简单的几何体
来测试效果,效果文件很好的管理的渲染状态,从应用程序中手工调用 SetRenderState 来进行状态的设置搬家到 "xxx.fx" 文件中统一管理材质、灯光等,并且还有Shader
的支持,这样的灵活性。