HLSL看似复杂,其实真正使得其法的话,要比固定流水线来的更加容易.加之可以随心所欲的控制顶点和像素,要比固定渲染线中枯燥无味的反复调用那些状态函数精彩的多.所以我建议正在埋头苦学D3D的同学们一定不要觉得已经掌握了固定渲染流水线的操作方法而忽视这一部分精彩的内容.
当然,事物也不都是完美的,就HLSL来说,也有它的弊端.一个我认为最别扭的地方就是debug!因为HLSL针对的是GPU编码,所以以往的经典CPU下断点调试行不通.所幸的是MS在.net环境下提供了一种将HLSL模拟为运行在CPU下的马马乎乎的调试方法,不过那个效率...先介绍一下VS2003环境下的调试方法,分以下几个关键步骤,记牢:
1.确认DX SDK中的HLSL编译器已经正确安装.
2.配置DX选项卡:VS2003环境下,工具->选项->调试->directx:
将Direct3D Runtime设为"Use Debug Version of Direct3D",再将Direct3D Debug Option下的Enable Sha der Debugging选中.
3.在D3D主程序CPP文件开头出添加两行语句:#define DEBUG_VS 和 #define DEBUG_PS.
4.在回调函数 ModifyDeviceSettings()中添加如下代码:
#ifdef DEBUG_VS //如果要调试顶点渲染器
if(pDeviceSettings->DeviceType != D3DDEVTYPE_REF) //如果设备类型不是参考设备
{
pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE; //禁用硬顶点运算和纯设备环境
pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; //开启软顶点运算
}
#endif
#ifdef DEBUG_PS //如果要调试像素渲染器
pDeviceSettings->DeviceType = D3DDEVTYPE_REF; //设备类型改为参考设备
#endif
static bool bFirst = TRUE;
if(bFirst)
{
bFirst = FALSE;
if(pDeviceSettings->DeviceType == D3DDEVTYPE_REF)
DXUTDisplaySwitchingToREFWarning();
} //切换至参考设备时提示
另外,为确保程序在任何显卡上都能顺利运行(不考虑性能),如果设备能力不能支持以下两点其中之一时,需要将设备行为标志设置为软顶点运算:
(1).硬件的空间转换以及光照运算.
(2).顶点渲染器版本不低于1.1
所以在以上代码的前面还要加上以下语句:
if((pCaps->DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||
pCaps->VertexShaderVersion < D3DVS_VERSION(1, 1))
{
pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
5.在程序中,出现任何类似于CompileXXXShader()的函数,即对渲染器(效果)文件进行编译时,在该函数的行为标志参数的对应位置都要逻辑或"D3DXSHADER_DEBUG|D3DXSHADER_SKIPOPTIMIZATION"一对参数
6.在.fx文件中设置断点及条件,进行调试.
OK,以上就是在VS2003环境下的HLSL标准调试法.其实这种调试法的可应用度不高,最好的办法还是切至ASM下进行跟踪,但还是要掌握另一门GPU语言 就是ASM咯.
另外要注意的是,新手在入门时编写的HLSL语句往往存在着一些语法上的错误而非逻辑错误,这种错误往往会导致程序在运行的启动阶段就崩溃掉了,更别提下断点调试.因为前面所提到过,由于GPU下运行代码的局限性,编程环境不能像在cpp文件中一样在编译阶段给出HLSL语法上的错误提示,所以由此种原因造成的程序崩溃往往使一些入门的新手晕头转向,无处可查.
其实还是有一些手段可以解决这类问题的.利用HLSL编译函数中的错误反馈缓冲就可以很好的解决这一问题.具体做法是:对渲染器\效果文件进行编译的一类函数,一般都带有一个缓冲区类型的输出参数,这个参数一旦为非空,所返回的信息就是对于渲染器\效果文件中语法错误的定位以及描述.
举个例子:D3DXCreateEffectFromFile()中的最后一个参数:LPD3DXBUFFER* pErrorBuf 就是用来输出效果文件中的语法错误信息的.你可以把它设置为NULL,这样无错还好,有错的话你就无从得知了,所以最好还是声明一个Buffer来接受它.那么我们怎样来利用这个Buffer呢?很简单,用MessageBox把Buffer里面的东西显示出来就好拉,不过MessageBox中的文本字符是LPCWSTR的,而Buffer中的字符串是以LPCSTR存放的,所以还是改用另外一个函数MessageBoxA()就可以了:
LPD3DXBUFFER pError = NULL;
D3DXCreateEffectFromFile(...... ,&pError)
if(pError)
{
MessageBoxA(NULL, (LPCSTR)pError->GetBufferPointer(), "1", 0);
SAFE_RELEASE(pError);
}
有了这两句话,我们就可以偷窥了 ^ _ ^
待续...