??xml version="1.0" encoding="utf-8" standalone="yes"?> 2、获得渲染目标,有了渲染目标Q才能给目标指定视口和摄像机 3、给q个渲染目标指定摄像机,做了q步骤之后,每更新时就会把q个摄像机看到的东西渲染到texture?br />Viewport *v = rttTex->addViewport( mReflectCam ); 4、OKQ?/p> 如果本文对你的开发有所帮助Qƈ且你手头恰好有零钱?/p> 不如打赏我一杯咖啡,鼓励我l分享优U的文章?br />
1、创建渲染目标纹理,关键要指定TU_RENDERTARGET参数Q在创徏q个渲染目标U理的过E中QOgre会自动调?nbsp; Root::getSingleton().getRenderSystem()->attachRenderTarget把这个纹理添加到Root的渲染目标中Q也是说每帧都会渲染到q个U理?br />TexturePtr texture = TextureManager::getSingleton().createManual( "RttTex",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D,
512, 512, 0, PF_R8G8B8, TU_RENDERTARGET );
RenderTarget *rttTex = texture->getBuffer()->getRenderTarget();
最l排差的原因是DrawIndexedPrimitiveUP最后一个参?em>VertexStreamZeroStride Q这个参数是用来指定点所占的字节数。我自作聪明的把点l构后增加了一个自q的数据,如:正常的顶点结?br />struct CUSTOMVERTEX
{
FLOAT x, y, z,rhw;
DWORD color;
float u,v;
};
我改了之后的点l构Q?br />struct CUSTOMVERTEX
{
FLOAT x, y, z,rhw;
DWORD color;
float u,v;
DWORD dwMyData; // 用来保存我自q的数?br />};
l果Q在我的昑֍上一切正常,q个数据也有用,然后DrawIndexedPrimitiveUP的时候,也会Ҏ最后的参数sizeof(CUSTOMVERTEX)利的读取相应的点。但是,拿到845G的内|显卡上死z花屏。后来终于知道是q个原因Q于是解军_法就是把dwMyDataLQ放到顶点结构外面去?br />
Z说说DrawIndexedPrimitiveUP的用法:
HRESULT DrawIndexedPrimitiveUP(
D3DPRIMITIVETYPEPrimitiveType, // 囑֎的类?/b>
UINTMinVertexIndex, // 指定0
UINTNumVertices, // 指定需要渲染的点的数量(如一个矩形可以由4个顶点组成,然后通过点索引来达到渲?个三角Ş的效果,那么q里应该填?Q而不?Q?/b>
UINTPrimitiveCount, // 要渲染的囑֎的数量(如一个矩形,׃个三角Şl成Q就应该填写2Q?/b>
CONST void *pIndexData, // 索引数据指针
D3DFORMATIndexDataFormat, // 索引数据格式Q一般ؓD3DFMT_INDEX16或D3DFMT_INDEX32
CONST void*pVertexStreamZeroData, // 点数据指针
UINTVertexStreamZeroStride // 点大小一般ؓsizeof(点l构)
);
记得默认情况下渲染三角Ş的顺序是逆时针的Q初学者经常范q个错误Q本来想渲染一个矩形,l果一个三角Ş时间、另一个三角Ş逆时针,l果渲染出来只看C个三角Ş了,被背面剔除掉了)?br />
DirectX讑֤的创建在DXUT中得C改进。你可以让你的应用程序直接创备而其它有框架提供的特征仍然可用?br />创徏讑֤
选择最佳的讑֤讄
修改可用的设备设|?br />降ؓ软g点处理
使用你自q讑֤
创徏讑֤
典型圎ͼ你将通过标准的Direct3DҎ创徏讑֤
HRESULT CreateDevice(
UINT Adapter,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS *pPresentationParameters,
IDirect3DDevice9 **ppReturnedDeviceInterface
);
q个Ҏ需要有效的适配器,讑֤cd(HAL or REF),H口句柄Q行为标?software/hardware vertex processing 和其它驱动标?Q以及呈现参?presentation parameters).此外QD3DPRESENT_PARAMETERl构体还拥有大量的成员指定后备缓冲区Q多重采栯定,交换效果Q窗口模式,深度模版~冲Q刷新率Q呈现间隔,以及呈现标志?br />为所有这些参数选择有效的设定是h挑战性的。框枉过DXUTCreateDevice函数化了q一选择q程?br />HRESULT DXUTCreateDevice(
UINT AdapterOrdinal = D3DADAPTER_DEFAULT,
BOOL bWindowed = TRUE,
INT nSuggestedWidth = 640,
INT nSuggestedHeight = 480,
LPDXUTCALLBACKISDEVICEACCEPTABLE pCallbackIsDeviceAcceptable = NULL,
LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallbackModifyDeviceSettings = NULL
);
最基本的用法是全部使用~省参数调用Q?br />DXUTCreateDevice();
通过q样的调用框架用缺省设|创Z个在大多数情况下可用的设备。缺省的讄如下Q?br />
Direct3D Creation Flag | Description | Default Value from DXUTCreateDevice |
---|---|---|
AdapterFormat parameter of CheckDeviceFormat | Adapter surface format. | Desktop display mode, or D3DFMT_X8R8G8B8 if the desktop display mode is less than 32 bits. |
Adapter parameter of IDirect3D9::CreateDevice | Display adapter ordinal. | D3DADAPTER_DEFAULT |
D3DPRESENT_PARAMETERS. BackBufferCount | Number of back buffers. | 2, indicating triple buffering. |
D3DPRESENT_PARAMETERS. BackBufferFormat | Back buffer format. | Desktop display mode, or D3DFMT_X8R8G8B8 if the desktop display mode is less than 32 bits. |
D3DPRESENT_PARAMETERS. AutoDepthStencilFormat | Depth format of the automatic depth-stencil surface that the device will create. | D3DFMT_D16 if the backbuffer format is 16 bits or less, or D3DFMT_D32 otherwise. |
The DeviceType parameter of IDirect3D9::CreateDevice | Enumerated type of the device. | D3DDEVTYPE_HAL if available, otherwise D3DDEVTYPE_REF or failure code if neither is available. |
D3DPRESENT_PARAMETERS. MultiSampleQuality | Quality level. | MultiSampleQuality = 0, indicating multisampling is disabled. |
D3DPRESENT_PARAMETERS. Flags | Presentation parameters flags. | D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL |
D3DPRESENT_PARAMETERS. PresentationInterval | Presentation interval. | D3DPRESENT_INTERVAL_IMMEDIATE for windowed mode, or D3DPRESENT_INTERVAL_DEFAULT for full-screen mode. |
D3DPRESENT_PARAMETERS. FullScreen_RefreshRateInHz | Rate at which the display adapter refreshes the screen. | 0, indicating windowed mode. |
D3DPRESENT_PARAMETERS. BackBufferWidth and .BackBufferHeight | Display mode resolution. | 640 x 480 pixels for windowed mode, or the desktop resolution for full-screen mode. |
D3DPRESENT_PARAMETERS. AutoDepthStencilFormat | Stencil format of the automatic depth-stencil surface that the device will create. | D3DFMT_D16 if the backbuffer format is 16 bits or less, or D3DFMT_D32 otherwise. |
D3DPRESENT_PARAMETERS. SwapEffect | Swap effect. | D3DSWAPEFFECT_DISCARD |
BehaviorFlags parameter of IDirect3D9::CreateDevice | Vertex processing flags. | D3DCREATE_HARDWARE_VERTEXPROCESSING if supported, otherwise D3DCREATE_SOFTWARE_VERTEXPROCESSING. |
D3DPRESENT_PARAMETERS. Windowed | Windowed or full-screen mode. | true, indicating windowed mode. |
hFocusWindow parameter of CreateDevice | Handle to the created window (see Using Application Windows with DXUT). | hWndFocus parameter of DXUTSetWindow |
D3DPRESENT_PARAMETERS. hDeviceWindow | Handle to the device window. | hWndDeviceFullScreen or hWndDeviceWindowed parameters of DXUTSetWindow |
D3DPRESENT_PARAMETERS. EnableAutoDepthStencil | Depth-stencil buffer creation flag. | true. |
选择最佳的讑֤讄
你可以用IsDeviceAcceptable回调函数帮助框架Z的应用程序选择最佳的讑֤讄Q就像下面的代码Q?br />bool CALLBACK IsDeviceAcceptable(
D3DCAPS9* pCaps,
D3DFORMAT AdapterFormat,
D3DFORMAT BackBufferFormat,
bool bWindowed,
void* pUserContext )
{
// TODO: return true for acceptable settings and false otherwise.
return true;
}
q个回调函数的模型基于LPDXUTCALLBACKISDEVICEACCEPTABLE原型(This callback function is modeled on the prototype LPDXUTCALLBACKISDEVICEACCEPTABLE)Q框架ؓ每个唯一的以?个设|的有效l合调用q个函数一ơ:
D3DDEVTYPE DeviceType;
UINT AdapterOrdinal;
D3DFORMAT AdapterFormat;
D3DFORMAT BackBufferFormat;
bool Windowed;
注意适配器序号和讑֤cd没有直接的传入回调函敎ͼ而是分别作ؓD3DCAPS9l构体的成员?br />通过q个回调函数Q应用程序可以拒lQ何它不支持的或不惌的组合。例如,应用E序可以使用下面的代码拒l?6bits的后备缓冲区格式和所有至不能支持像素着色器PS_2_0的设备:
bool CALLBACK IsDeviceAcceptable(
D3DCAPS9* pCaps,
D3DFORMAT AdapterFormat,
D3DFORMAT BackBufferFormat,
bool bWindowed )
{
if( pCaps->PixelShaderVersion < D3DPS_VERSION(2,0) )
return false;
if( BackBufferFormat == D3DFMT_X1R5G5B5 || BackBufferFormat == D3DFMT_R5G6B5 )
return false;
return true;
}
为每个唯一的组合调用回调函数后Q框架排列剩下的可用l合Qƈ选择它们当中最好的。排名较高的如下Q?br />D3DDEVTYPE_HALQ获取硬件加?br />如果应用E序以全屏模式显C,框架更趋向于使用匚w桌面格式的适配器格式,q样可以在全屏与H口之间快速切换。例外的是,如果桌面昄模式于32位,框架更趋向于D3DFMT_X8R8G8B8.
匚w适配器格式的后备~冲区格?br />在选择了这些排名高的组合后Q要创徏讑֤Q行为标志和呈现参数仍然是需要的。对于这些设|?Direct3D使用上面表中的缺省倹{?/p>
使用你自q讑֤
你没有必要依赖于框架来创建Direct3D讑֤。应用程序自己可以创备ƈ他传递给框架使用。就像应用程序可以覆盖框架的window creation 讄。简单的使用你想要的讄创徏一个设备,然后调用 DXUTSetDevice函数让框架在你的讑֤上渲染?br />注意Q如果应用程序创Z不依赖于框架的设备,那么应用E序也必dd@环执行完以后亲自的通过cleanup 释放讑֤接口?br />另请参阅
通过DXUT作更高的设备选择
摘要
本文要介l了在DirectX 9 SDK中提供的Effect Framework支持Q以及DirectX FX文gl构和Microsoft Hight Level Shading Language的基本知识。本文假定读者对DirectX Graphics有一定了解,q正在学习DirectX Effect Framework。希望能够与各位读者共同探讨、切?
?
Effect的v?
在计机3l场景中Q物体表面的材质代表了其光学Ҏ。最单的材质可以表现为Diffuse颜色QSpecular颜色QEmissive颜色{信息的集合Q而ؓ了表现物体表面的l节Q可?在材质中加入一张纹理——这些就构成了最基本的材质信息。在以前的Direct3DE序中,q些信息可以直接传送给讑֤Q由讑֤自动Ҏ它们来计物体表面的光学效果。但是, 仅仅有这些基本的材质信息Q已l不以满游戏制作者的要求和游戏玩家的要求了——他们希望场景中的材质更加复杂,h更多的细节,更加逼真?
在Direct3D中,除了材质的概念,q存在一个渲染状态(Render StateQ的概念。在Direct3D Device中存在很多的渲染状态,它们可以在Direct3Dq行渲染时控制渲染的程和效 果,从而实现某些带有特效的材质。程序员可以通过IDirect3DDevice*::SetRenderState()Ҏ来设|这些状态。所有的渲染状态都是一些特定的数倹{对状态的讄可以通过?~码完成Q即在程序中调用SetRenderState()ҎQ将讄什么样的状态“写歠Z在E序里,但是q样做的~点是太不灉|了——如果想要实CU新的渲染状态,需要修?E序代码。所以更好的一U方法是ؓ了实现某一U特效材质的一些渲染状态D录到一个“效果文件”中Q通过在程序运行时d该文Ӟ从中分析些|q将它们作ؓ?数调用SetRenderState()。这P要想实现一U新的特效,只需修改“效果文件”而不用更改代码?
Direct3D SDK是通过Effect Framework来支持这U机制的。而前面所q的“效果文件”在Direct3D中是?.fx文g存在的。在fx文g中保存了为实现某一Ҏ的渲染状态,包括状态名 U和它们的对应倹{所以在9.0以前版本的DirectX中就已经有Effect Framework和FX文g了,早期的Effect Framework仅仅是ؓ了实现对渲染状态进行控制?但是随着计算机显C硬件技术的发展Q图形处理单元(GPUQ正在重复CPU所走过的\——新一代的GPU已经h了可~程Ҏ,E序员可以通过对GPU~写一D늨序来控制其渲染的 输出效果。这U程序一般称为ShaderE序。目前的ShaderE序分成两种QVertex Shader和Pixel Shader。Vertex Shader主要用于?l网格模型的每一个顶点进行处理,而Pixel Shader主要用于对要l制到屏q上的每一个象素进行处理。通过ShaderQ程序员可以制作出相当丰富的实时渲染效果?/font>
同CPU一P对GPU~程也是借助一定的~程语言来进行的? 在DirectX 8中,对GPU的编E是通过一U类g汇编的语aq行的。而在DirectX 9中,使用了一U类gC语言的高U语a——Microsoft High Level Shading Language (HLSL) ?/font>
无论使用什么语a对GPU~程Q都需要把~译好的ShaderE序输送到昑֍厅RDirect3D Device可以通过SetVertexShader()和SetPixelShader()来向昑֍输送ShaderE序。然而,?于Shader和材质具有十分紧密的关系——一般来_一个Shader是Z实现一U特D的材质——最好是能够ShaderE序与材质进行整合?所以,在DirectX 8和DirectX 9中,原来的Effect Framework发生了扩充——在原来的基上加入了对ShaderE序的支持。程序员可以把Vertex Shader和Pixel ShaderE序以函?的方式直接书写在FX文g中?/font>
.FX文g
FX文g中的内容大致可以分成几部分:
预编译标志:预编译标志包?
其中最常用到的?include?defineQ同C语言中的意义很相|?include可以在一个FX文g中引入另外一个或多个文g?define可以定义FX文g中的宏替换。例如:
#include "helper_Funcs.fx"
//引入一个名为helper_funcs.fx的fx文g |
#include带来的好处和C中也是一LQ您可以在一个头文g中定义一些公有变量、函数等Q在其他文g中引用它们-׃用写很多遍了。例如:
文gpublic.fh:
mat4x4
matWorldViewProj; // 4x4世界Q视Q投影变换矩?/span> |
//定义一个名为VS_OUTPUT的结构。关于结构体定义Q下文中会有介绍
struct
VS_INPUT { float4 LocalPos : POSITION; float3 Normal : NORMAL; float4 Color : COLOR; float2 Texcoord : TEXCOORD0; }; |
struct VS_OUTPUT
{ float4 WorldPos : POSITION; float4 Color : COLOR; float2 Texcoord : TEXCOORD0; }; |
//定义一个名为CaculateWorldPosition的函数。关于函数定义,下文中会有介l?
float3
CaculateWorldPosition( float4 LocalPos ) { return mul( LocalPos, matWorldViewProj); } |
q样Q当我们在另外一个文件中includeq个头文件时Q上面所有的定义都可以直接用了?
文gclient.fx:
#include "public.fh"
|
q样不仅可以复用代码Q还可以使变量名、结构体、函数名的定义统一?
?define不仅仅可以某些帔Rh比较有意义的名称Q通过?ifdefQ?ifndef, #else, #endif{结合用,q可以用来根据一些配|控制编译过E?
变量?/p>
每个FX文g都可以有若干参数变量Q通过Effect Framework可以在程序中识别些参数的cd、名U和用途,q样可以将E序中的一些参数输送到Effect中去Q从而更加灵z?的控制效果。参数的cd很多Q可以是int, float, matrix, texture{等。例如:
matrix
matWorld; //定义一个名为matWorld的矩늱型参数变?/span> float time; //定义一个名为time的Q点类型参数变? texture texDiffuse; //定义一个名为texDiffuse的纹理类型参数变?/span> |
另外Q每个变量还有前~修饰W、Semantic、Annotation{,限于幅Q在q里不再赘述Q具体的介绍请参考DirectX C++帮助文档的DirectX Graphics > Reference > HLSL Shader Reference > Variable Declaration Syntax条目?
l构定义
在FX文g中可以定义结构体Q这些结构体一般用于Shader函数的参数和q回倹{结构体的定义与C语言方式及其cMQ例如:
struct
VS_OUTPUT //l构名称 { float4 Pos : POSITION; //成员变量?/span> float4 Color : COLOR; float2 Texcoord : TEXCOORD0; }; |
上面每个成员变量后面的标识符是该变量的semanticQHLSL~译器根据这个标识符来确定该变量的用处。不一定非得是l构体成员变量才有semanticQ一般来说Shader的输入输出参数变量都可以有semantic?/p>
函数
函数部分是在Effect Framework加入了对Vertex Shader和Pixel Shader的扩充后才加入到FX文g中的。FX文g中的函数的内容可以用汇编形式书写Q也可以用HLSL~写。目前一?都是使用HLSL。用q种语言书写的函CC语言函数十分cMQ可以说Q只要学qC语言Q书写Shader函数qԒl有余了。在同一个fx文g中可以定义很多函敎ͼ在函C也可以互 相调用,但是最lShaderE序的入口将在fx文g的Technique部分中指定。对于哪个函数是Vertex shader函数Q哪个是Pixel shader函数Q也是在Technique中指定的。关于TechniqueQ将在下文中介绍?例子Q?
float4
CalcDiffuseColor( float3 Normal )
VS_OUTPUT
Vertex_Shader( float4 InPos : POSITION, |
正如上文中所_ShaderE序分ؓ两种QVertex shader和Pixel shader。在fx函数中就有两U相应的函数QVertex shader函数和Pixel Shader函数。Vertex shader函数的输入参数是|格模型中的每一个顶Ҏ据,其输出是l过该函数特D处理的点数据Q而Pixel Shader函数的输入,则是l过g光栅化过E后l过插值的Vertex shader输出l果。至于Pixel shader的输出,一般就是经q该函数计算得到的一个颜色|卌d后备~冲中一个象素上的颜色倹{但是这个“颜色值”有时ƈ不一定代表颜艌Ӏ而且对于支持多RenderTarget的硬ӞPixel shaderq可以有多个输出Q分别对应不同的RenderTarget?/p>
technique
technique是FX文g的主体,是真正设|各U渲染状态的地方Q也是指定所使用的ShaderE序入口的地斏V在理解Technique前首先要理解Pass的概cPass是Technique的组成部?Q一个Pass׃表了l制时的一遍。通常Z辑ֈ一U效果,仅仅l制一遍网格模型是不够的,需要向framebuffer中多ơ绘Ӟq利用设|渲染状态中的BlendStateq行Alpha混合。这是l常提到的“Muli-pass Rendering”。但是随着g来强大,ShaderE序的功能越来越强,目前的趋势是所有的Ҏ材质都将可以用越来越个Pass来完成?一个technique中,可以存在一个或多个PassQ但是至要有一个Pass时该technique才会起实际作用。当存在多个passӞ默认情况下在渲染时将会按照pass在文件中的前后顺?作ؓ渲染时的前后序。technique和Pass中的内容都是以大括号括v来?
technique的例子:
technique
Tec_Shader_1_X //定义一个名为Tec_Shader_1_X的technique { pass P0 //一个名为P0的pass { VertexShader = compile vs_1_1 Vertex_Shader(); //讄Vertex ShaderE序入口函数 PixelShader = compile ps_1_1 Pixel_Shader(); //讄Pixel ShaderE序入口函数 AlphaBlendEnable= true; //讄渲染状态 ? SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha; ... //其他讄 } pass P1 //一个名为P1的pass { ... } } |
ID3DXEffect接口
上面介绍了很多fx文g相关内容Q但是在E序中如何读取和分析q些fx文g呢?在程序中对于dfx文gQ控制渲染状态、设|ShaderE序{工作都是通过D3DX库中的ID3DXEffect接口来实现的。ID3DXEffect接口提供了大量的ҎQ基本上分ؓ几个斚wQ?
ID3DXEffect接口的创建: 通过D3DX库中的D3DXCreateEffectFromFile()函数Q可以根据一个指定的文g的内Ҏ创徏一个ID3DXEffect接口。在该函数执行成功后Q所创徏的接口中包含了文g里所对应?所有内容,包括参数变量表、ShaderE序、technique和pass{?
ID3DXEffect接口的用: 通过该接口的Ҏ可以获得FX文g中的所有信息,q设|参数变量和当前的technique。所有的参数变量、technique、pass、shader{等都有自己的名UͼҎq些名称Q通过调用ID3DXEffect::GetParameterByName()、ID3DXEffect::GetTechniqueByName()和ID3DXEffect::GetPassByName(){方法就可以获得q些对象的句柄,从而在调用 ID3DXEFFECT::Set***()q行讄时用句柄而不是字W串q行索引来提高效率?/p>
通过ID3DXEffect::GetParameterDesc()、ID3DXEffect::GetTechniqueDesc()和GetPassDecs{方 法可以获得关于指定对象的所有细节描qC息?D3DX库中定义了一个D3DXPARAMETER_DESCl构来专门表C参数的cd。通过ID3DXEffect::GetParameterDesc()ҎQ可以ؓ一个参数获得这样一个结构的数据?
typedef struct
_D3DXPARAMETER_DESC { LPCSTR Name; //参数变量? LPCSTR Semantic; //参数变量的Semantic D3DXPARAMETER_CLASS Class; //参数变量的类别,可以是标量、矢量、矩c对象和l构 D3DXPARAMETER_TYPE Type; //参数变量的类? UINT Rows; //数组型参数的行数 UINT Columns; //数组型参数的列数 UINT Elements; //数组中的元素个数 UINT Annotations; //参数变量的Annotation个数 UINT StructMembers; //l构型参数变量成员的个数 DWORD Flags; //参数属? UINT Bytes; //参数大小Q以字节? } D3DXPARAMETER_DESC; |
其中的参数类型可以有下列几种Q?
typedef
enum _D3DXPARAMETER_TYPE { D3DXPT_VOID, //Void型指? D3DXPT_BOOL, //Bool? D3DXPT_INT, //整型 D3DXPT_FLOAT, //点? D3DXPT_STRING, //字符? D3DXPT_TEXTURE, //U理 D3DXPT_TEXTURE1D, //一l纹? D3DXPT_TEXTURE2D, //二维U理 D3DXPT_TEXTURE3D, //三维U理 D3DXPT_TEXTURECUBE, //立方体环境纹? D3DXPT_SAMPLER, //U理取样? D3DXPT_SAMPLER1D, //一l纹理取样器 D3DXPT_SAMPLER2D, //二维U理取样? D3DXPT_SAMPLER3D, //三维U理取样? D3DXPT_SAMPLERCUBE, //立方体环境纹理取样器 D3DXPT_PIXELSHADER, //Pixel ShaderE序 D3DXPT_VERTEXSHADER, //Vertex ShaderE序 D3DXPT_PIXELFRAGMENT, //Pixel Shader片断 D3DXPT_VERTEXFRAGMENT, //Vertex Shader片断 D3DXPT_FORCE_DWORD = 0x7fffffff } D3DXPARAMETER_TYPE; |
而真正要让Effect起作用,需要在l制|格模型前后调用ID3DXEffect::BeginPass()和EndPassҎ。在调用q两个函C前和之后Q还需调用ID3DXEffect::Begin()?ID3DXEffect::End()Ҏ来界定此ơEffect讄的v止。大致的形式如下Q?
LPD3DXEffect pd3dEffectQ?span class="unnamed1"> //ID3DXEffect接口指针
UINT numPasses; //用于接受当前所使用的technique中的pass个数 |
3DS MAX对DirectX 9 Shader Material的支持;Effect数据获取和导?/strong>
在FX文g中的参数Q大部分都是用来调整FX文g所指定的Effect的一些细节,例如Q一U带有凹凸纹理的效果Q可能在FX中就有一个参数控制着凹凸不^的程度。而这些参数是需要由工来调整的。另外,工也需要有一个途径能够FX文g定义的Effect赋予C个模型或它的一部分上去。同时美工也应该能够实时的预览该Effect在模型上的实际效果?在以前,实现q些要求只能通过自制效果预览器、模型编辑器或者ؓDCC软g~写插g来完成。这对于的工作l和工期较短的项目来说是非常困难的。幸q的是,目前的DCC软g 已经开始ؓ游戏制作提供丰富的支持功能。通过DCC软g自n可以预览到实时Effect的效果,q调整其参数。在《龙的传说》这个项目中Q我们?DS MAX 6.0来作为模型徏?工具和Shader预览工具?
?DS MAX 6.0中,新加入了一U材质类型——DirectX 9 Shader材质。这U材质是ZFX文g的。一个FX文g可以代表一U材质。它可以同MAX中的其他材质一栯予到模型?。在MAX的Viewport中可以实时地观察到FX文g中设计的效果。通过为FX中的参数讄特定的SemanticQ可以将q些参数与MAX中的场景信息联系hQ如摄像Z|、世界变换矩 늭。对于控制Effect效果的一些本地参敎ͼ可以通过为它们添加特定的AnnotationQMAX能够直接识别q些参数q在用户界面中显C它们的名称和调节控件。对应不同类型的?敎ͼMAX可以为它们生成不同的调节控g。这Pq种材质和MAX的其他材质一P可以更改U理{等的参C?对于工来说Q通过q种用户界面可以调整该FX材质的参数达到最好的效果?/p>
但是工所调整的结果必要能够保存下来才有意义。这个工作就得由E序员来完成了。要保存3DS MAX中编辑的所有内容,需要ؓ3DS MAX~写文g导出插gQ将其内部数据保存在特定格式的文件中。在《龙的传说》这个项目中Q我们用Microsoft DirectX .X 文g。如果从头开始写导出插gQ工作量是相当大的;q运的是Q在Microsoft DirectX SDK Extra中提供了一个能够导出模型和3DS MAX标准材质到X文g的插件源代码。通过修改该源代码Q可以它能够导出DirectX 9 Shader材质。在3DS MAX 6 SDK中新增加了一个IDxMaterial接口Q通过查询一个IMaterial接口是否为IDxMaterial接口Q就可以定该材质是否ؓDirectX 9 Shader材质。通过IDxMaterial接口可以获得该材质对应的FX文g的文件名Q以及其参数信息。这样就可以它们导Z?
.X文g中对Effect的支持;EffectInstance和EffectDefault
Microsoft DirectX .X文g的格式是Z模板的、可扩展的文件格式。通过为其制定新的模板Q就可以在其中加入新的内宏V一般的.X文g中的内容有三l场景的物体层关系、网格模型几何数据、材质信息、动M息等。在DirectX的众多X文g模板中有一个模板是专门用来代表Effect的实例的。当一个FX文g的参数被工加以调整从而具备一些特定的g后,?FX文g和这些参数值的集合Ş成了一个Effect实例。该模板的定义如下:
template
EffectInstance { < E331F7E4-0559-4cc2-8E99-1CEC1657928F > STRING EffectFilename; [ ... ] } |
其中Q?EffectFilename代表了该Effect实例中的FX文g名, [ ... ]代表在其中可以插入Q何X文g模板对应的数据。这样就可以代表Mcd的参数倹{?
然而要惌Direct3DE序能够识别[ ... ]中的内容Q需要用X文g模板中的EffectParampd模板Q包括EffectParamDWord, EffectParamFlaots, EffectParamString。通过q三U模板对应的数据Q所有类型的Effect参数值都可以被记录在X文g中?
最后,EffectInstance数据需要被攄在Material数据中才可以被识别?/p>
Material模板Q?
template
Material { < 3D82AB4D-62DA-11CF-AB39-0020AF71E433 > ColorRGBA faceColor; FLOAT power; ColorRGB specularColor; ColorRGB emissiveColor; [...] } |
前面的一些颜色模板表明在Material数据中这些颜色信息是必须有的Q而最后的[ ... ]则代表可以插入Q何X文g模板对应的数据。我们的EffectInstance数据可以放|在q里 ?
举一个简单的例子Q?
Material { //材质 0.500000;0.500000;0.500000;1.000000;; //faceColor 0.000000; //power 0.900000;0.900000;0.900000;; //specularColor 0.000000;0.000000;0.000000;; //emissiveColor EffectInstance { //[...]Q这里是EffectInstance "SkyboxNew01.fx"; //fx文g的文件名。通过D3DXCreateEffectFromFile()可以 //建立该文件对应的D3DXEffect对象 //下面是EffectInstance中的[...] EffectParamString { //EffectParamStringQ即字符串型参数?/span> "TexCloudTop"; //参数的名Uͼ通过该名U调用ID3DXEffect::GetXXXByName()Ҏ //可以得到与fx文g中对应的参数? "DarkClouds01.jpg"; //参数的值?/span> } EffectParamString { //同上 "TexCloudBottom"; "DarkClouds02.jpg"; } EffectParamFloats { //EffectParamFloatsQ即点数组型参数?/span> "Brightness"; //参数名称 1; //点数组大小 0.500000; //? } } } |
当我们在E序中调用D3DXLoadMeshFromX()或D3DXLoadMeshHierarchyFromX()Ӟ可以通过其LPD3DXBUFFER *ppEffectInstances参数来接收到|格所用的所有EffectInstance的信息?/p>
在程序中Q对应于X文g中的EffectInstance模板和EffectParampd模板Q有两个l构体用来代表Effect数据Q?
typedef struct
_D3DXEFFECTINSTANCE
typedef struct _D3DXEFFECTDEFAULT 需要注意的是,从文件中得到的参数类型只有以下几U: |
在调用了D3DXLoadMeshFromX()和D3DXLoadMeshHierarchyFromX()之后QX文g中的所有Effect数据信息׃上述l构体的形式攄在ppEffectInstances中了?另外Q在?DS MAX导出参数到X文gӞ对于整型和QҎl型的变量,它们的值将直接导出到X文g中去Q而对于所有的U理贴图文g参数Q导出的仅仅是该文g的文件名。所?在程序中需要再Ҏq些文g名来建立U理对象?在《龙的传说》中Q我们用一个自定义的CEffectInstancecL处理文件名转换为纹理对象的q程?一般来_建立一个完整的CEffectInstance的过E如下:
ҎD3DXEFFECTINSTANCEl构中的pEffectFilename字符串寻扑֯应的FX文g;
Ҏ该FX文g建立ID3DXEffectQƈ指针保存在CEffectInstance?
ҎD3DXEFFECTINSTANCEl构中的pDefaults讄CEffectInstance中的参数信息Q?/p>
对于长整型和点数组Q直接拷贝;
对于字符Ԍ首先调用ID3DXEffect接口中的GetParameterByName()和GetParameterDesc()ҎQ得到该参数的类型; 然后q一步判断:
如果实是字W串参数Q则直接拯
如果是纹理参敎ͼ则将该字W串作ؓU理文g名徏立纹理对象,q将指针保存在CEffectInstance中?
而在最新推出的DirectX 9 SDK Summer 2004中,通过ID3DXEffect::BeginParameterBlock()和ID3DXEffect::EndParameterBlock()ҎQ我们可以将Effect参数讄q程l一l定C个ParamBlock句柄上。这P在调用ID3DXEffect::Begin()之前可以直接用ID3DXEffect::ApplyParameterBlock()Ҏ来设|所有被l定的参数倹{例如:
[以前的做?/strong>]Q?
在读取参数时Q获得每一个参数的句柄
hParam1 = pEffect->GetParameterByName( NULL, "LightPos" ); 在实时绘制时Q分别设|每一个参? pEffect->SetValue( hParam1, value1 ); |
[在DirectX 9 SDK Summer 2004中的做法]Q?
在读取参数时Q绑定所有参数设|到同一句柄
hParam1 = pEffect->GetParameterByName( NULL, "LightPos" ); 在实时绘制时Q统一讄l定? pEffect->ApplyParameterBlock( hParamBlock ); |
q样不仅化了在读取时对参数的分析q程Q而且提高了实际绘制时参数讄q程的效率?
ȝ
以上是一些对于在DirectX 9.0中对Effect Framework的用的要介l。MQ用Effect来替代以前的标准材质是目前实时图形领域的发展势。通过Effect FrameworkQ程序员和美工可以ؓ实时三维E序实现多种多样的材质效果和视觉效果?׃内容实在太多Q限于篇q,本文只是对Effect Framework中相x늚一个M概括和简要介l,所以显得有些晦涩。在以后的文章中Q将分批对这个Framework以及在其之上q行工作的流E进行比较详l的介绍?/p>
1.L了固定管U?br />文档里列Z用DX10Ҏ模拟的一些固定管U的操作QMS那么大度把DX都开源了(^O^)?/font>
2.L了以前版本DX的设备能力检?CAPS)
为DX10和Windows Vista提供的显C硬件必LDX10的所有硬件特性。这样对于开发者就比较可以攑ֿ的用各U硬件特性了Q很cMConsoleq_
的开发?/font>
3.状态对?State Object)
"?00多个渲染状态中解脱出来?"
D3D10Ҏ染状态这个概念进行E化,一斚w使用全Shader化的架构使得状态的前后讄和互相媄响对渲染成功率降低到最?br />另外对API架构也更为简z,另一斚w对一些关键渲染状态进行封装和分类。主要分cL:
Input Layout Object 输入层对?br />q个东西很类似D3D9里的点声明Q也是对用戯入数据进行整合和pȝ?br />
Rasterizer Object 光栅化对?br />q部分主要控制光栅器的行为:填充模式(FILL_MODE),剔除模式(CULL_MODE),多采?DepthBias{等
DepthStencil Object 深度~冲对象
主要控制深度~冲的行为,像Z-buffer Enable之类?br />
Blend Object 混合对象
讄象素混合的方法,cMAlphaBlend SrcAlpha ,DestAlpha{等
Sampler Object 采样器对?br />讄U理采样状态,包括qo器和MipMap
4.新的资源讉K模式和资源视?View)概念
如果ҎD3D9的Shader使用代码和D3D10的类g码会发现一个不同?br />D3D9 Shader需要对U理q行操作Ӟ需要将U理讄到Shader可以了Q而D3D10里没有那么简单,讄前必d
各种资源整合后ؓ资源创徏一个视图,再提交给Shader讉K。这U操作在环境贴图里是很有好处的。对于CubeMap?张纹?br />可以采用一个视图设|到讑֤Q而自p讉K每张贴图只要L讉K视图可以了Q也是说把资源规整和集成化?/font>
5.新的可编E图形层(Stage)-几何Shader(Geometry Shader)
原来的VS和PS只是寚w个点或象素进行处理,而新的GS可以Ҏ个顶Ҏ象素的͘q顶点设|Shader。也是可以Ҏ量几何进行处?br />GS的用途有:
点精?br />动态粒子系l?br />皮毛pȝ
L阴媄
单Pass渲染到球形脓?br />逐多边Ş材质交换
逐多边Ş材质讄
6.讑֤的创求对ViewPortq行讄
D3D9里无需对ViewPortq行讄可以进行渲染,而且默认的RenderTarget是后备~冲
而在D3D10里,q个q程变得更ؓ自主化。取出后备缓冲的格式Q将RenderTarget讄为屏q?br />q让人感到D3D10设计更趋向于成熟的引擎设计?/font>
7.输出层(Stream Output State)
q个层的功能是将VS和GS处理完成的数据输出给用户Q由用户q行处理后再反馈l管Ul处?br />
8.多边形拓扑结构从l制代码分离
现在可以单独讄拓扑l构
g_pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
和用Draw函数l制了,很类似OpenGL
9.严格的设备对象创建时间验?br />q里的设备对象就是从讑֤创徏出来的资源。ؓ了减CPU占用QD3D10重新设计了硬件资源调用调度,所有的讑֤对象都用面向对象的方法被讑֤
理。这U设计方法避免了在渲染期的资源创建操作?br />
10.LBeginScene和EndScene
q个对于囑ŞAPI实多余
Dec2005 sdk里提供的文档让h很快惛_q只是一个过渡版?br />在DXUT的Mesh.Create函数中可以看C个很有趣的现象:
创徏D3D9对象Q用D3DX9里的载入X模型文g的函数蝲入X文g
D3D9的模型数据{成D3D10的类型。这样做无非是在告诉我们一?br />q样的信息,D3D10很有可能提供一U新的模型格式来作ؓ研究使用
。Vista的图形系lAvalon从一些视频上分析Q用了大量的XMLQ所?br />新的模型格式很有可能使用XMLQƈ且X格式的解析接口确实不方便。?br />XML的分析器可以q三方提供。得更多的研究人员能更方便的?br />q种新格式?/font>
Z提供一些羃写对应的含义,q些在一些函数前~会出?br />IA-Input Assembler State
SO-Stream Output State
OM-Output Merger State
VS-Vertex Shader
PS-Pixel Shader
GS-Geometry Shader
Powered by Davy.xu
msn:sunicdavy@sina.com
InitApp | 初始化一些图形控件和GUI的消息处理函?/span> |
OnCreateDevice | 创徏讑֤时的回调函数Q用于创?/span>D3DPOOL_MANAGED资源 |
OnResetDevice | 重设讑֤时的回调函数Q用于创?/span>D3DPOOL_DEFAULT资源 |
OnFrameMove | 动画实现处,常用于矩阵{换等操作 |
OnFrameRender | 渲染实现处,常用于渲染场?/span> |
OnLostDevice | 讑֤丢失时的回调函数Q释攄OnResetDevice创徏的资?/span> |
OnDestroyDevice | 讑֤析构时的回调函数Q释攄OnCreateDevice创徏的资?/span> |
IsDeviceAcceptable | 创徏讑֤时用来对所有可用设备进行过滤的函数 |
ModifyDeviceSettings | 更改讑֤时的回调函数Q用于实现更改设备时所需做的其他操作 |
MsgProc | 安排各空件处理消息的序 |
OnGUIEvent | E序控gl定的消息处理回调函?/span> |
使用dxut框架q行directx设计Ӟ拯directx sdk 安装目录\Samples\C++\中的Common文g内容C的程序目录下(如下??/p>
main.cpp 源文件内容如下:
开启调试时查看D3D对象的情?/strong>
?Direct3D 调试模式开启之后,你可以在M时候查看对象的调用堆栈。这会导致你的程序非常慢Q但是可以用此功能查资源泄漏(内存泄漏的一U)。开启调用堆栈,讄q个注册表键gؓ1卛_Q?/p>
\\HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Direct3D\\ D3D9Debugging\\EnableCreationStack
开启D3D调试模式Q然后重Z的工E,pȝ会l你讉Kq个附加的变量:
LPCWSTR CreationCallStack;
q个变量存储着每次创徏对象时的调用堆栈。这会导致你的程序非常慢Q但是可以用此功能查资源泄漏?/p>