• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            李錦俊(mybios)的blog

            游戲開發(fā) C++ Cocos2d-x OpenGL DirectX 數(shù)學(xué) 計(jì)算機(jī)圖形學(xué) SQL Server

              C++博客 :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
              86 Posts :: 0 Stories :: 370 Comments :: 0 Trackbacks

            公告

            QQ:30743734
            EMain:mybios@qq.com

            常用鏈接

            留言簿(16)

            我參與的團(tuán)隊(duì)

            最新隨筆

            搜索

            •  

            積分與排名

            • 積分 - 370201
            • 排名 - 67

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            Effect Framework

            摘要

            本文簡(jiǎn)要介紹了在DirectX 9 SDK中提供的Effect Framework支持,以及DirectX FX文件結(jié)構(gòu)和Microsoft Hight Level Shading Language的基本知識(shí)。本文假定讀者對(duì)DirectX Graphics有一定了解,并正在學(xué)習(xí)DirectX Effect Framework。希望能夠與各位讀者共同探討、切磋。

            簡(jiǎn)介

            Effect的起源

            在計(jì)算機(jī)3維場(chǎng)景中,物體表面的材質(zhì)代表了其光學(xué)特性。最簡(jiǎn)單的材質(zhì)可以表現(xiàn)為Diffuse顏色,Specular顏色,Emissive顏色等信息的集合;而為了表現(xiàn)物體表面的細(xì)節(jié),可以 在材質(zhì)中加入一張紋理——這些就構(gòu)成了最基本的材質(zhì)信息。在以前的Direct3D程序中,這些信息可以直接傳送給設(shè)備,由設(shè)備自動(dòng)根據(jù)它們來(lái)計(jì)算物體表面的光學(xué)效果。但是, 僅僅有這些基本的材質(zhì)信息,已經(jīng)不足以滿足游戲制作者的要求和游戲玩家的要求了——他們希望場(chǎng)景中的材質(zhì)更加復(fù)雜,具有更多的細(xì)節(jié),更加逼真。

            在Direct3D中,除了材質(zhì)的概念,還存在一個(gè)渲染狀態(tài)(Render State)的概念。在Direct3D Device中存在很多的渲染狀態(tài),它們可以在Direct3D進(jìn)行渲染時(shí)控制渲染的流程和效 果,從而實(shí)現(xiàn)某些帶有特效的材質(zhì)。程序員可以通過(guò)IDirect3DDevice*::SetRenderState()方法來(lái)設(shè)置這些狀態(tài)。所有的渲染狀態(tài)都是一些特定的數(shù)值。對(duì)狀態(tài)的設(shè)置可以通過(guò)硬 編碼完成,即在程序中調(diào)用SetRenderState()方法,將設(shè)置什么樣的狀態(tài)“寫死”在程序里,但是這樣做的缺點(diǎn)就是太不靈活了——如果想要實(shí)現(xiàn)一種新的渲染狀態(tài),就需要修改 程序代碼。所以更好的一種方法是將為了實(shí)現(xiàn)某一種特效材質(zhì)的一些渲染狀態(tài)值記錄到一個(gè)“效果文件”中,通過(guò)在程序運(yùn)行時(shí)讀取該文件,從中分析出這些值,并將它們作為參 數(shù)調(diào)用SetRenderState()。這樣,要想實(shí)現(xiàn)一種新的特效,只需修改“效果文件”而不用更改代碼。

            Direct3D SDK是通過(guò)Effect Framework來(lái)支持這種機(jī)制的。而前面所述的“效果文件”在Direct3D中是以*.fx文件存在的。在fx文件中保存了為實(shí)現(xiàn)某一特效的渲染狀態(tài),包括狀態(tài)名 稱和它們的對(duì)應(yīng)值。所以在9.0以前版本的DirectX中就已經(jīng)有Effect Framework和FX文件了,早期的Effect Framework僅僅是為了實(shí)現(xiàn)對(duì)渲染狀態(tài)進(jìn)行控制。 但是隨著計(jì)算機(jī)顯示硬件技術(shù)的發(fā)展,圖形處理單元(GPU)正在重復(fù)CPU所走過(guò)的路——新一代的GPU已經(jīng)具有了可編程特性,程序員可以通過(guò)對(duì)GPU編寫一段程序來(lái)控制其渲染的 輸出效果。這種程序一般稱為Shader程序。目前的Shader程序分成兩種,Vertex Shader和Pixel Shader。Vertex Shader主要用于對(duì)3維網(wǎng)格模型的每一個(gè)頂點(diǎn)進(jìn)行處理,而Pixel Shader主要用于對(duì)要繪制到屏幕上的每一個(gè)象素進(jìn)行處理。通過(guò)Shader,程序員可以制作出相當(dāng)豐富的實(shí)時(shí)渲染效果。

            同CPU一樣,對(duì)GPU編程也是借助一定的編程語(yǔ)言來(lái)進(jìn)行的。 在DirectX 8中,對(duì)GPU的編程是通過(guò)一種類似于匯編的語(yǔ)言進(jìn)行的。而在DirectX 9中,使用了一種類似于C語(yǔ)言的高級(jí)語(yǔ)言——Microsoft High Level Shading Language (HLSL) 。

            無(wú)論使用什么語(yǔ)言對(duì)GPU編程,都需要把編譯好的Shader程序輸送到顯卡去。Direct3D Device可以通過(guò)SetVertexShader()和SetPixelShader()來(lái)向顯卡輸送Shader程序。然而,由 于Shader和材質(zhì)具有十分緊密的關(guān)系——一般來(lái)說(shuō),一個(gè)Shader就是為了實(shí)現(xiàn)一種特殊的材質(zhì)——最好是能夠?qū)hader程序與材質(zhì)進(jìn)行整合。 所以,在DirectX 8和DirectX 9中,原來(lái)的Effect Framework發(fā)生了擴(kuò)充——在原來(lái)的基礎(chǔ)上加入了對(duì)Shader程序的支持。程序員可以把Vertex Shader和Pixel Shader程序以函數(shù) 的方式直接書寫在FX文件中。

            ?.FX文件

            FX文件中的內(nèi)容大致可以分成幾部分:

            • 預(yù)編譯標(biāo)志
            • 變量表
            • 結(jié)構(gòu)定義
            • 函數(shù)
            • Technique

            預(yù)編譯標(biāo)志:預(yù)編譯標(biāo)志包括

            • #define
            • #elif
            • #else
            • #endif
            • #error
            • #if
            • #ifdef
            • #ifndef
            • #include
            • #line
            • #pragma
            • #undef

            其中最常用到的是#include和#define,同C語(yǔ)言中的意義很相似:用#include可以在一個(gè)FX文件中引入另外一個(gè)或多個(gè)文件。#define可以定義FX文件中的宏替換。例如:

            #include "helper_Funcs.fx" ???? //引入一個(gè)名為helper_funcs.fx的fx文件
            #include "public_variables.fh" //引入一個(gè)名為public_variables.fh的文件
            #define MATRICES_COUNT 25????? //定義宏MATRICES_COUNT為25
            #define VSHADER VShader_2_0??? //定義宏VSHADER為VShader_2_0

            #include帶來(lái)的好處和C中也是一樣的-您可以在一個(gè)頭文件中定義一些公有變量、函數(shù)等,在其他文件中引用它們-就不用寫很多遍了。例如:

            文件public.fh:

            mat4x4 matWorldViewProj; // 4x4世界-視-投影變換矩陣
            float3 lightPosisiton;?? // 三維光源位置向量
            float4 lightColor;?????? // 光源的顏色
            float time;????????????? // 當(dāng)前時(shí)間

            //定義一個(gè)名為VS_OUTPUT的結(jié)構(gòu)。關(guān)于結(jié)構(gòu)體定義,下文中會(huì)有介紹

            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;
            };

            //定義一個(gè)名為CaculateWorldPosition的函數(shù)。關(guān)于函數(shù)定義,下文中會(huì)有介紹

            float3 CaculateWorldPosition( float4 LocalPos )
            {
            ??? return mul( LocalPos, matWorldViewProj);
            }

            這樣,當(dāng)我們?cè)诹硗庖粋€(gè)文件中include這個(gè)頭文件時(shí),上面所有的定義都可以直接使用了。

            文件client.fx:

            #include "public.fh"


            VS_OUTPUT VS_main( VS_INPUT In ) // 可以直接使用結(jié)構(gòu)體定義VS_OUTPUT和VS_INPUT
            {
            ??? VS_OUTPUT Out = 0;
            ??? Out.WorldPos = CaculateWorldPosition( In.LocalPos ); // 可以直接使用函數(shù)
            ??? Out.Color = In.Color;
            ??? Out.Texcoord = In.Texcoord;
            }

            ?

            這樣不僅可以復(fù)用代碼,還可以使變量名、結(jié)構(gòu)體、函數(shù)名的定義統(tǒng)一。

            而#define不僅僅可以使某些常量具有比較有意義的名稱,通過(guò)與#ifdef,#ifndef, #else, #endif等結(jié)合使用,還可以用來(lái)根據(jù)一些配置控制編譯過(guò)程。

            變量表

            每個(gè)FX文件都可以有若干參數(shù)變量,通過(guò)Effect Framework可以在程序中識(shí)別出這些參數(shù)的類型、名稱和用途,這樣就可以將程序中的一些參數(shù)輸送到Effect中去,從而更加靈活 的控制效果。參數(shù)的類型很多,可以是int, float, matrix, texture等等。例如:

            matrix matWorld;????//定義一個(gè)名為matWorld的矩陣類型參數(shù)變量
            float time;?????????//定義一個(gè)名為time的浮點(diǎn)類型參數(shù)變量
            texture texDiffuse; //定義一個(gè)名為texDiffuse的紋理類型參數(shù)變量

            ?

            另外,每個(gè)變量還有前綴修飾符、Semantic、Annotation等,限于篇幅,在這里不再贅述,具體的介紹請(qǐng)參考DirectX C++幫助文檔的DirectX Graphics > Reference > HLSL Shader Reference > Variable Declaration Syntax條目。

            結(jié)構(gòu)定義

            在FX文件中可以定義結(jié)構(gòu)體,這些結(jié)構(gòu)體一般用于Shader函數(shù)的參數(shù)和返回值。結(jié)構(gòu)體的定義與C語(yǔ)言方式及其類似,例如:

            struct VS_OUTPUT //結(jié)構(gòu)名稱
            {
            ??? float4 Pos : POSITION; //成員變量。
            ??? float4 Color : COLOR;
            ??? float2 Texcoord : TEXCOORD0;
            };

            ?

            上面每個(gè)成員變量后面的標(biāo)識(shí)符是該變量的semantic,HLSL編譯器根據(jù)這個(gè)標(biāo)識(shí)符來(lái)確定該變量的用處。不一定非得是結(jié)構(gòu)體成員變量才有semantic,一般來(lái)說(shuō)Shader的輸入輸出參數(shù)變量都可以有semantic。

            函數(shù)

            函數(shù)部分是在Effect Framework加入了對(duì)Vertex Shader和Pixel Shader的擴(kuò)充后才加入到FX文件中的。FX文件中的函數(shù)的內(nèi)容可以用匯編形式書寫,也可以用HLSL編寫。目前一般 都是使用HLSL。用這種語(yǔ)言書寫的函數(shù)與C語(yǔ)言函數(shù)十分類似,可以說(shuō),只要學(xué)過(guò)C語(yǔ)言,書寫Shader函數(shù)就綽綽有余了。在同一個(gè)fx文件中可以定義很多函數(shù),在函數(shù)中也可以互 相調(diào)用,但是最終Shader程序的入口將在fx文件的Technique部分中指定。對(duì)于哪個(gè)函數(shù)是Vertex shader函數(shù),哪個(gè)是Pixel shader函數(shù),也是在Technique中指定的。關(guān)于Technique,將在下文中介紹。 例子:

            float4 CalcDiffuseColor( float3 Normal )
            {
            ??? float4 Color; ...//用于實(shí)現(xiàn)該函數(shù)功能的多條語(yǔ)句
            ??? return Color;
            }

            VS_OUTPUT Vertex_Shader( float4 InPos : POSITION,
            ???????????????????????? float3 InNor : NORMAL,?
            ???????????????????????? float3 InTexcoord : TEXCOORD )
            {
            ??? VS_OUTPUT Out; ...//用于實(shí)現(xiàn)該函數(shù)功能的多條語(yǔ)句
            ??? Out.Color = CalcDiffuseColor(InNor); //函數(shù)調(diào)用
            ??? return Out;
            }

            ?

            正如上文中所說(shuō),Shader程序分為兩種:Vertex shader和Pixel shader。在fx函數(shù)中就有兩種相應(yīng)的函數(shù):Vertex shader函數(shù)和Pixel Shader函數(shù)。Vertex shader函數(shù)的輸入?yún)?shù)是網(wǎng)格模型中的每一個(gè)頂點(diǎn)數(shù)據(jù),其輸出是經(jīng)過(guò)該函數(shù)特殊處理的頂點(diǎn)數(shù)據(jù);而Pixel Shader函數(shù)的輸入,則是經(jīng)過(guò)硬件光柵化過(guò)程后經(jīng)過(guò)插值的Vertex shader輸出結(jié)果。至于Pixel shader的輸出,一般就是經(jīng)過(guò)該函數(shù)計(jì)算得到的一個(gè)顏色值,即要畫到后備緩沖中一個(gè)象素上的顏色值。但是這個(gè)“顏色值”有時(shí)并不一定代表顏色。而且對(duì)于支持多RenderTarget的硬件,Pixel shader還可以有多個(gè)輸出,分別對(duì)應(yīng)不同的RenderTarget。

            technique

            technique是FX文件的主體,是真正設(shè)置各種渲染狀態(tài)的地方,也是指定所使用的Shader程序入口的地方。在理解Technique前首先要理解Pass的概念。Pass是Technique的組成部分 ,一個(gè)Pass就代表了繪制時(shí)的一遍。通常為了達(dá)到一種效果,僅僅繪制一遍網(wǎng)格模型是不夠的,需要向framebuffer中多次繪制,并利用設(shè)置渲染狀態(tài)中的BlendState進(jìn)行Alpha混合。這就是經(jīng)常提到的“Muli-pass Rendering”。但是隨著硬件越來(lái)越強(qiáng)大,Shader程序的功能越來(lái)越強(qiáng),目前的趨勢(shì)是所有的特效材質(zhì)都將可以用越來(lái)越少個(gè)Pass來(lái)完成。 一個(gè)technique中,可以存在一個(gè)或多個(gè)Pass,但是至少要有一個(gè)Pass時(shí)該technique才會(huì)起實(shí)際作用。當(dāng)存在多個(gè)pass時(shí),默認(rèn)情況下在渲染時(shí)將會(huì)按照pass在文件中的前后順序 作為渲染時(shí)的前后順序。technique和Pass中的內(nèi)容都是以大括號(hào)括起來(lái)。

            technique的例子:

            technique Tec_Shader_1_X //定義一個(gè)名為Tec_Shader_1_X的technique
            {
            ??? pass P0 //一個(gè)名為P0的pass
            ??? {
            ??????? VertexShader = compile vs_1_1 Vertex_Shader(); //設(shè)置Vertex Shader程序入口函數(shù)
            ??????? PixelShader = compile ps_1_1 Pixel_Shader();?? //設(shè)置Pixel Shader程序入口函數(shù)
            ??????? AlphaBlendEnable= true;??????????????????????? //設(shè)置渲染狀態(tài)???????
            ??????? SrcBlend = SrcAlpha;??
            ??????? DestBlend = InvSrcAlpha;?
            ??????? ... //其他設(shè)置
            ??? }
            ??? pass P1 //一個(gè)名為P1的pass
            ??? {
            ??????? ...
            ??? }
            }

            ?

            ID3DXEffect接口

            上面介紹了很多fx文件相關(guān)內(nèi)容,但是在程序中如何讀取和分析這些fx文件呢?在程序中對(duì)于讀取fx文件,控制渲染狀態(tài)、設(shè)置Shader程序等工作都是通過(guò)D3DX庫(kù)中的ID3DXEffect接口來(lái)實(shí)現(xiàn)的。ID3DXEffect接口提供了大量的方法,基本上分為幾個(gè)方面:

            • 獲得Effect參數(shù)變量信息
            • 設(shè)置Effect參數(shù)變量
            • 獲得technique信息
            • 設(shè)置當(dāng)前使用的technique
            • 開始和結(jié)束使用當(dāng)前的technique
            • 執(zhí)行一個(gè)pass(渲染繪制遍)

            ID3DXEffect接口的創(chuàng)建: 通過(guò)D3DX庫(kù)中的D3DXCreateEffectFromFile()函數(shù),可以根據(jù)一個(gè)指定的文件的內(nèi)容來(lái)創(chuàng)建一個(gè)ID3DXEffect接口。在該函數(shù)執(zhí)行成功后,所創(chuàng)建的接口中就包含了文件里所對(duì)應(yīng)的 所有內(nèi)容,包括參數(shù)變量表、Shader程序、technique和pass等。

            ID3DXEffect接口的使用: 通過(guò)該接口的方法可以獲得FX文件中的所有信息,并設(shè)置參數(shù)變量和當(dāng)前的technique。所有的參數(shù)變量、technique、pass、shader等等都有自己的名稱,根據(jù)這些名稱,通過(guò)調(diào)用ID3DXEffect::GetParameterByName()、ID3DXEffect::GetTechniqueByName()和ID3DXEffect::GetPassByName()等方法就可以獲得這些對(duì)象的句柄,從而在調(diào)用 ID3DXEFFECT::Set***()進(jìn)行設(shè)置時(shí)使用句柄而不是字符串進(jìn)行索引來(lái)提高效率。

            通過(guò)ID3DXEffect::GetParameterDesc()、ID3DXEffect::GetTechniqueDesc()和GetPassDecs等方 法可以獲得關(guān)于指定對(duì)象的所有細(xì)節(jié)描述信息。 D3DX庫(kù)中定義了一個(gè)D3DXPARAMETER_DESC結(jié)構(gòu)來(lái)專門表示參數(shù)的類型。通過(guò)ID3DXEffect::GetParameterDesc()方法,可以為一個(gè)參數(shù)獲得這樣一個(gè)結(jié)構(gòu)的數(shù)據(jù)。

            typedef struct _D3DXPARAMETER_DESC
            {
            ??? LPCSTR Name;?????????????? //參數(shù)變量名
            ??? LPCSTR Semantic;?????????? //參數(shù)變量的Semantic
            ??? D3DXPARAMETER_CLASS Class; //參數(shù)變量的類別,可以是標(biāo)量、矢量、矩陣、對(duì)象和結(jié)構(gòu)
            ??? D3DXPARAMETER_TYPE Type;?? //參數(shù)變量的類型
            ??? UINT Rows;?????????????????//數(shù)組型參數(shù)的行數(shù)
            ??? UINT Columns;????????????? //數(shù)組型參數(shù)的列數(shù)
            ??? UINT Elements;???????????? //數(shù)組中的元素個(gè)數(shù)
            ??? UINT Annotations;????????? //參數(shù)變量的Annotation個(gè)數(shù)
            ??? UINT StructMembers;??????? //結(jié)構(gòu)型參數(shù)變量成員的個(gè)數(shù)
            ??? DWORD Flags;?????????????? //參數(shù)屬性
            ??? UINT Bytes;??????????????? //參數(shù)大小,以字節(jié)記
            } D3DXPARAMETER_DESC;

            ?

            其中的參數(shù)類型可以有下列幾種:

            typedef enum _D3DXPARAMETER_TYPE
            {
            ??? D3DXPT_VOID, //Void型指針
            ??? D3DXPT_BOOL, //Bool型
            ??? D3DXPT_INT, //整型
            ??? D3DXPT_FLOAT, //浮點(diǎn)型
            ??? D3DXPT_STRING, //字符串
            ??? D3DXPT_TEXTURE, //紋理
            ??? D3DXPT_TEXTURE1D, //一維紋理
            ??? D3DXPT_TEXTURE2D, //二維紋理
            ??? D3DXPT_TEXTURE3D, //三維紋理
            ??? D3DXPT_TEXTURECUBE, //立方體環(huán)境紋理
            ??? D3DXPT_SAMPLER, //紋理取樣器
            ??? D3DXPT_SAMPLER1D, //一維紋理取樣器
            ??? D3DXPT_SAMPLER2D, //二維紋理取樣器
            ??? D3DXPT_SAMPLER3D, //三維紋理取樣器
            ??? D3DXPT_SAMPLERCUBE, //立方體環(huán)境紋理取樣器
            ??? D3DXPT_PIXELSHADER, //Pixel Shader程序
            ??? D3DXPT_VERTEXSHADER, //Vertex Shader程序
            ??? D3DXPT_PIXELFRAGMENT, //Pixel Shader片斷
            ??? D3DXPT_VERTEXFRAGMENT, //Vertex Shader片斷
            ??? D3DXPT_FORCE_DWORD = 0x7fffffff
            } D3DXPARAMETER_TYPE;

            ?

            而真正要讓Effect起作用,需要在繪制網(wǎng)格模型前后調(diào)用ID3DXEffect::BeginPass()和EndPass方法。在調(diào)用這兩個(gè)函數(shù)之前和之后,還需調(diào)用ID3DXEffect::Begin()和 ID3DXEffect::End()方法來(lái)界定此次Effect設(shè)置的起止。大致的形式如下:

            LPD3DXEffect pd3dEffect; //ID3DXEffect接口指針
            ... //初始化該指針
            ... //程序中的其他部分
            ...

            UINT numPasses; //用于接受當(dāng)前所使用的technique中的pass個(gè)數(shù)
            pd3dEffect->Begin( & numPasses, 0 ) //開始使用當(dāng)前的technique
            for( UINT iPass = 0; iPass < numPasses; iPass ++ )
            {
            ??? //遍歷所有的pass
            ??? pd3dEffect->BeginPass( iPass ); //調(diào)用BeginPass
            ??? DrawMesh();???????????????????? //然后進(jìn)行模型的繪制。
            ??? pd3dEffect->EndPass();????????? //調(diào)用EndPass
            }
            pd3dEffect->End();????????????????? //不要忘記結(jié)束當(dāng)前technique

            ?

            3DS MAX對(duì)DirectX 9 Shader Material的支持;Effect數(shù)據(jù)獲取和導(dǎo)出

            在FX文件中的參數(shù),大部分都是用來(lái)調(diào)整FX文件所指定的Effect的一些細(xì)節(jié),例如,一種帶有凹凸紋理的效果,可能在FX中就有一個(gè)參數(shù)控制著凹凸不平的程度。而這些參數(shù)是需要由美工來(lái)調(diào)整的。另外,美工也需要有一個(gè)途徑能夠?qū)X文件定義的Effect賦予到一個(gè)模型或它的一部分上去。同時(shí)美工也應(yīng)該能夠?qū)崟r(shí)的預(yù)覽該Effect在模型上的實(shí)際效果。 在以前,實(shí)現(xiàn)這些要求只能通過(guò)自制效果預(yù)覽器、模型編輯器或者為DCC軟件編寫插件來(lái)完成。這對(duì)于小的工作組和工期較短的項(xiàng)目來(lái)說(shuō)是非常困難的。幸運(yùn)的是,目前的DCC軟件 已經(jīng)開始為游戲制作提供豐富的支持功能。通過(guò)DCC軟件自身就可以預(yù)覽到實(shí)時(shí)Effect的效果,并調(diào)整其參數(shù)。在《龍的傳說(shuō)》這個(gè)項(xiàng)目中,我們使用3DS MAX 6.0來(lái)作為模型建立 工具和Shader預(yù)覽工具。

            在3DS MAX 6.0中,新加入了一種材質(zhì)類型——DirectX 9 Shader材質(zhì)。這種材質(zhì)是基于FX文件的。一個(gè)FX文件就可以代表一種材質(zhì)。它可以同MAX中的其他材質(zhì)一樣賦予到模型上 。在MAX的Viewport中可以實(shí)時(shí)地觀察到FX文件中設(shè)計(jì)的效果。通過(guò)為FX中的參數(shù)設(shè)置特定的Semantic,可以將這些參數(shù)與MAX中的場(chǎng)景信息聯(lián)系起來(lái),如攝像機(jī)位置、世界變換矩 陣等。對(duì)于控制Effect效果的一些本地參數(shù),可以通過(guò)為它們添加特定的Annotation,使MAX能夠直接識(shí)別這些參數(shù)并在用戶界面中顯示它們的名稱和調(diào)節(jié)控件。對(duì)應(yīng)不同類型的參 數(shù),MAX可以為它們生成不同的調(diào)節(jié)控件。這樣,這種材質(zhì)就和MAX的其他材質(zhì)一樣,可以更改紋理等等的參數(shù)了。 對(duì)于美工來(lái)說(shuō),通過(guò)這種用戶界面就可以調(diào)整該FX材質(zhì)的參數(shù)達(dá)到最好的效果。

            但是美工所調(diào)整的結(jié)果必須要能夠保存下來(lái)才有意義。這個(gè)工作就得由程序員來(lái)完成了。要保存3DS MAX中編輯的所有內(nèi)容,需要為3DS MAX編寫文件導(dǎo)出插件,將其內(nèi)部數(shù)據(jù)保存在特定格式的文件中。在《龍的傳說(shuō)》這個(gè)項(xiàng)目中,我們使用Microsoft DirectX .X 文件。如果從頭開始寫導(dǎo)出插件,工作量是相當(dāng)大的;幸運(yùn)的是,在Microsoft DirectX SDK Extra中提供了一個(gè)能夠?qū)С瞿P秃?DS MAX標(biāo)準(zhǔn)材質(zhì)到X文件的插件源代碼。通過(guò)修改該源代碼,可以使它能夠?qū)С鯠irectX 9 Shader材質(zhì)。在3DS MAX 6 SDK中新增加了一個(gè)IDxMaterial接口,通過(guò)查詢一個(gè)IMaterial接口是否為IDxMaterial接口,就可以確定該材質(zhì)是否為DirectX 9 Shader材質(zhì)。通過(guò)IDxMaterial接口可以獲得該材質(zhì)對(duì)應(yīng)的FX文件的文件名,以及其參數(shù)信息。這樣就可以將它們導(dǎo)出了。

            .X文件中對(duì)Effect的支持;EffectInstance和EffectDefault

            Microsoft DirectX .X文件的格式是基于模板的、可擴(kuò)展的文件格式。通過(guò)為其制定新的模板,就可以在其中加入新的內(nèi)容。一般的.X文件中的內(nèi)容有三維場(chǎng)景的物體層級(jí)關(guān)系、網(wǎng)格模型幾何數(shù)據(jù)、材質(zhì)信息、動(dòng)畫信息等。在DirectX的眾多X文件模板中有一個(gè)模板是專門用來(lái)代表Effect的實(shí)例的。當(dāng)一個(gè)FX文件的參數(shù)被美工加以調(diào)整從而具備一些特定的值之后,該 FX文件和這些參數(shù)值的集合就形成了一個(gè)Effect實(shí)例。該模板的定義如下:

            template EffectInstance
            {
            ??? < E331F7E4-0559-4cc2-8E99-1CEC1657928F >
            ??? STRING EffectFilename;
            ??? [ ... ]
            }

            ?

            其中, EffectFilename代表了該Effect實(shí)例中的FX文件名, [ ... ]代表在其中可以插入任何X文件模板對(duì)應(yīng)的數(shù)據(jù)。這樣就可以代表任何類型的參數(shù)值。

            然而要想讓Direct3D程序能夠識(shí)別[ ... ]中的內(nèi)容,需要使用X文件模板中的EffectParam系列模板,包括EffectParamDWord, EffectParamFlaots, EffectParamString。通過(guò)這三種模板對(duì)應(yīng)的數(shù)據(jù),所有類型的Effect參數(shù)值都可以被記錄在X文件中。

            最后,EffectInstance數(shù)據(jù)需要被放置在Material數(shù)據(jù)中才可以被識(shí)別。

            Material模板:

            template Material
            {
            ??? < 3D82AB4D-62DA-11CF-AB39-0020AF71E433 >
            ??? ColorRGBA faceColor;
            ??? FLOAT power;
            ??? ColorRGB specularColor;
            ??? ColorRGB emissiveColor;
            ??? [...]
            }

            ?

            前面的一些顏色模板表明在Material數(shù)據(jù)中這些顏色信息是必須有的,而最后的[ ... ]則代表可以插入任何X文件模板對(duì)應(yīng)的數(shù)據(jù)。我們的EffectInstance數(shù)據(jù)就可以放置在這里 。

            舉一個(gè)簡(jiǎn)單的例子:

            Material { //材質(zhì)
            ??? 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
            ??? {????????????????????????????//[...],這里是EffectInstance
            ??????? "SkyboxNew01.fx";??????? //fx文件的文件名。通過(guò)D3DXCreateEffectFromFile()可以
            ???????????????????????????????? //建立該文件對(duì)應(yīng)的D3DXEffect對(duì)象
            ??????? //下面是EffectInstance中的[...]

            ??????? EffectParamString?
            ????????{??????????????????????? //EffectParamString,即字符串型參數(shù)值?
            ????????????"TexCloudTop";?????? //參數(shù)的名稱,通過(guò)該名稱調(diào)用ID3DXEffect::GetXXXByName()方法
            ???????????????????????????????? //可以得到與fx文件中對(duì)應(yīng)的參數(shù)
            ??????????? "DarkClouds01.jpg";? //參數(shù)的值?
            ????????}?
            ????????EffectParamString
            ??????? {??????????????????????? //同上
            ??????????? "TexCloudBottom";
            ??????????? "DarkClouds02.jpg";
            ??????? }
            ??????? EffectParamFloats
            ??????? {?????????????????????? //EffectParamFloats,即浮點(diǎn)數(shù)組型參數(shù)值
            ??????????? "Brightness";?????? //參數(shù)名稱
            ??????????? 1;????????????????? //浮點(diǎn)數(shù)組大小
            ??????????? 0.500000;?????????? //值
            ??????? }
            ??? }
            }

            ?

            當(dāng)我們?cè)诔绦蛑姓{(diào)用D3DXLoadMeshFromX()或D3DXLoadMeshHierarchyFromX()時(shí),就可以通過(guò)其LPD3DXBUFFER *ppEffectInstances參數(shù)來(lái)接收到網(wǎng)格所用的所有EffectInstance的信息。

            在程序中,對(duì)應(yīng)于X文件中的EffectInstance模板和EffectParam系列模板,有兩個(gè)結(jié)構(gòu)體用來(lái)代表Effect數(shù)據(jù):

            typedef struct _D3DXEFFECTINSTANCE
            { //EffectInstance
            ??? LPSTR pEffectFilename;?//fx文件名
            ??? DWORD NumDefaults; //參數(shù)個(gè)數(shù)
            ??? LPD3DXEFFECTDEFAULT pDefaults; //參數(shù)數(shù)組
            } D3DXEFFECTINSTANCE, *LPD3DXEFFECTINSTANCE;

            typedef struct _D3DXEFFECTDEFAULT
            { //EffectDefault,即EffectParam
            ??? LPSTR pParamName;?????????? //參數(shù)名
            ??? D3DXEFFECTDEFAULTTYPE Type; //參數(shù)類型
            ??? DWORD NumBytes;???????????? //參數(shù)大小,以字節(jié)記
            ??? LPVOID pValue;????????????? //指向參數(shù)的值的指針
            } D3DXEFFECTDEFAULT, *LPD3DXEFFECTDEFAULT;

            需要注意的是,從文件中得到的參數(shù)類型只有以下幾種:
            typedef enum _D3DXEFFECTDEFAULTTYPE
            {
            ??? D3DXEDT_STRING = 1, //字符串
            ??? D3DXEDT_FLOATS = 2, //浮點(diǎn)數(shù)組
            ??? D3DXEDT_DWORD = 3,? //長(zhǎng)整型
            ??? D3DXEDT_FORCE_DWORD = 0x7fffffff //此值不使用
            } D3DXEFFECTDEFAULTTYPE;

            ?

            在調(diào)用了D3DXLoadMeshFromX()和D3DXLoadMeshHierarchyFromX()之后,X文件中的所有Effect數(shù)據(jù)信息就以上述結(jié)構(gòu)體的形式放置在ppEffectInstances中了。 另外,在從3DS MAX導(dǎo)出參數(shù)到X文件時(shí),對(duì)于整型和浮點(diǎn)數(shù)組型的變量,它們的值將直接導(dǎo)出到X文件中去;而對(duì)于所有的紋理貼圖文件參數(shù),導(dǎo)出的僅僅是該文件的文件名。所以 在程序中需要再根據(jù)這些文件名來(lái)建立紋理對(duì)象。 在《龍的傳說(shuō)》中,我們使用一個(gè)自定義的CEffectInstance類來(lái)處理將文件名轉(zhuǎn)換為紋理對(duì)象的過(guò)程。 一般來(lái)說(shuō),建立一個(gè)完整的CEffectInstance的過(guò)程如下:

            根據(jù)D3DXEFFECTINSTANCE結(jié)構(gòu)中的pEffectFilename字符串尋找對(duì)應(yīng)的FX文件;
            根據(jù)該FX文件建立ID3DXEffect,并將指針保存在CEffectInstance中;
            根據(jù)D3DXEFFECTINSTANCE結(jié)構(gòu)中的pDefaults設(shè)置CEffectInstance中的參數(shù)信息:?


            對(duì)于長(zhǎng)整型和浮點(diǎn)數(shù)組,直接拷貝;?
            對(duì)于字符串,首先調(diào)用ID3DXEffect接口中的GetParameterByName()和GetParameterDesc()方法,得到該參數(shù)的類型; 然后進(jìn)一步判斷:


            如果確實(shí)是字符串參數(shù),則直接拷貝
            如果是紋理參數(shù),則將該字符串作為紋理文件名建立紋理對(duì)象,并將指針保存在CEffectInstance中。

            而在最新推出的DirectX 9 SDK Summer 2004中,通過(guò)ID3DXEffect::BeginParameterBlock()和ID3DXEffect::EndParameterBlock()方法,我們可以將Effect參數(shù)設(shè)置過(guò)程統(tǒng)一綁定到一個(gè)ParamBlock句柄上。這樣,在調(diào)用ID3DXEffect::Begin()之前就可以直接使用ID3DXEffect::ApplyParameterBlock()方法來(lái)設(shè)置所有被綁定的參數(shù)值。例如:

            [以前的做法]:

            在讀取參數(shù)時(shí):獲得每一個(gè)參數(shù)的句柄

            hParam1 = pEffect->GetParameterByName( NULL, "LightPos" );
            hParam2 = pEffect->GetParameterByName( NULL, "LightColor" );
            ...

            在實(shí)時(shí)繪制時(shí):分別設(shè)置每一個(gè)參數(shù)

            pEffect->SetValue( hParam1, value1 );
            pEffect->SetValue( hParam2, value2 );
            ...
            pEffect->Begin();
            // 繪制
            ...

            ?

            [在DirectX 9 SDK Summer 2004中的做法]:

            在讀取參數(shù)時(shí):綁定所有參數(shù)設(shè)置到同一句柄

            hParam1 = pEffect->GetParameterByName( NULL, "LightPos" );
            hParam2 = pEffect->GetParameterByName( NULL, "LightColor" );
            ...
            pEffect->BeginParameterBlock(); // 開始綁定
            pEffect->SetValue( hParam, value1 );
            pEffect->SetValue( hParam, value2 );
            ...
            hParamBlock = pEffect->EndParameterBlock(); // 結(jié)束綁定,返回句柄

            在實(shí)時(shí)繪制時(shí):統(tǒng)一設(shè)置綁定值

            pEffect->ApplyParameterBlock( hParamBlock );
            pEffect->Begin;
            // 繪制
            ...

            ?

            這樣不僅簡(jiǎn)化了在讀取時(shí)對(duì)參數(shù)的分析過(guò)程,而且提高了實(shí)際繪制時(shí)參數(shù)設(shè)置過(guò)程的效率。

            總結(jié)

            以上就是一些對(duì)于在DirectX 9.0中對(duì)Effect Framework的使用的簡(jiǎn)要介紹。總之,使用Effect來(lái)替代以前的標(biāo)準(zhǔn)材質(zhì)是目前實(shí)時(shí)圖形領(lǐng)域的發(fā)展趨勢(shì)。通過(guò)Effect Framework,程序員和美工可以為實(shí)時(shí)三維程序?qū)崿F(xiàn)多種多樣的材質(zhì)效果和視覺(jué)效果。 由于內(nèi)容實(shí)在太多,限于篇幅,本文只是對(duì)Effect Framework中相關(guān)概念的一個(gè)總體概括和簡(jiǎn)要介紹,所以顯得有些晦澀。在以后的文章中,將分批對(duì)這個(gè)Framework以及在其之上進(jìn)行工作的流程進(jìn)行比較詳細(xì)的介紹。

            posted on 2006-11-20 16:54 李錦俊(mybios) 閱讀(3296) 評(píng)論(0)  編輯 收藏 引用 所屬分類: Direct3D
            久久人人爽人人爽人人AV东京热 | 狠狠色丁香久久婷婷综合五月| 亚洲国产另类久久久精品黑人 | 久久人妻少妇嫩草AV蜜桃| 精品久久久久久无码不卡| 99久久人妻无码精品系列| 欧美与黑人午夜性猛交久久久 | 精品久久久久久国产潘金莲| 青青久久精品国产免费看| 久久综合狠狠色综合伊人| 成人午夜精品无码区久久| 久久久WWW免费人成精品| 久久精品午夜一区二区福利| 青青青青久久精品国产h久久精品五福影院1421 | 99麻豆久久久国产精品免费| 伊人色综合九久久天天蜜桃| 国产精品九九久久免费视频| 国产精品久久波多野结衣| 亚洲午夜久久久影院| 久久免费视频1| 午夜精品久久久久久影视777| 一级做a爰片久久毛片人呢| 久久久久AV综合网成人| 久久久久久国产精品无码下载 | 国产精品9999久久久久| 亚洲av日韩精品久久久久久a| 国产精品成人久久久| 亚洲国产成人久久综合区| 久久精品视频91| 久久人人爽人人爽人人片AV东京热| 色综合久久综精品| 国产精品99久久久久久董美香| 久久精品一区二区国产| 久久夜色精品国产网站| 久久精品一本到99热免费| 久久久久国产精品熟女影院| 日本人妻丰满熟妇久久久久久| 伊人久久大香线蕉亚洲| 久久婷婷五月综合97色一本一本 | 亚洲AV伊人久久青青草原| 亚洲精品国产综合久久一线|