青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

永遠也不完美的程序

不斷學(xué)習(xí),不斷實踐,不斷的重構(gòu)……

常用鏈接

統(tǒng)計

積分與排名

好友鏈接

最新評論

Effect Framework(轉(zhuǎn))

原創(chuàng):劉宏春 2005年5月16日

Effect Framework

摘要

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

簡介

Effect的起源

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

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

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

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

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

 .FX文件

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

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

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

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

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

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

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

文件public.fh:

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

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

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的函數(shù)。關(guān)于函數(shù)定義,下文中會有介紹

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

 

這樣,當我們在另外一個文件中include這個頭文件時,上面所有的定義都可以直接使用了。

文件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不僅僅可以使某些常量具有比較有意義的名稱,通過與#ifdef,#ifndef, #else, #endif等結(jié)合使用,還可以用來根據(jù)一些配置控制編譯過程。

變量表

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

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

 

另外,每個變量還有前綴修飾符、Semantic、Annotation等,限于篇幅,在這里不再贅述,具體的介紹請參考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語言方式及其類似,例如:

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

 

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

函數(shù)

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

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

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

 

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

technique

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

technique的例子:

technique Tec_Shader_1_X //定義一個名為Tec_Shader_1_X的technique
{
    pass P0 //一個名為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 //一個名為P1的pass
    {
        ...
    }
}

 

ID3DXEffect接口

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

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

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

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

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

typedef struct _D3DXPARAMETER_DESC
{
    LPCSTR Name;               //參數(shù)變量名
    LPCSTR Semantic;           //參數(shù)變量的Semantic
    D3DXPARAMETER_CLASS Class; //參數(shù)變量的類別,可以是標量、矢量、矩陣、對象和結(jié)構(gòu)
    D3DXPARAMETER_TYPE Type;   //參數(shù)變量的類型
    UINT Rows;                 //數(shù)組型參數(shù)的行數(shù)
    UINT Columns;              //數(shù)組型參數(shù)的列數(shù)
    UINT Elements;             //數(shù)組中的元素個數(shù)
    UINT Annotations;          //參數(shù)變量的Annotation個數(shù)
    UINT StructMembers;        //結(jié)構(gòu)型參數(shù)變量成員的個數(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, //浮點型
    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)用這兩個函數(shù)之前和之后,還需調(diào)用ID3DXEffect::Begin()和 ID3DXEffect::End()方法來界定此次Effect設(shè)置的起止。大致的形式如下:

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

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

 

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

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

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

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

.X文件中對Effect的支持;EffectInstance和EffectDefault

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

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

 

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

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

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

Material模板:

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

 

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

舉一個簡單的例子:

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文件的文件名。通過D3DXCreateEffectFromFile()可以
                                 //建立該文件對應(yīng)的D3DXEffect對象
        //下面是EffectInstance中的[...]

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

 

當我們在程序中調(diào)用D3DXLoadMeshFromX()或D3DXLoadMeshHierarchyFromX()時,就可以通過其LPD3DXBUFFER *ppEffectInstances參數(shù)來接收到網(wǎng)格所用的所有EffectInstance的信息。

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

typedef struct _D3DXEFFECTINSTANCE
{ //EffectInstance
    LPSTR pEffectFilename; //fx文件名
    DWORD NumDefaults; //參數(shù)個數(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, //浮點數(shù)組
    D3DXEDT_DWORD = 3,  //長整型
    D3DXEDT_FORCE_DWORD = 0x7fffffff //此值不使用
} D3DXEFFECTDEFAULTTYPE;

 

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

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


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


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

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

[以前的做法]:

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

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

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

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

 

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

在讀取參數(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é)束綁定,返回句柄

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

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

 

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

總結(jié)

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

posted on 2009-01-06 17:06 狂爛球 閱讀(1337) 評論(0)  編輯 收藏 引用 所屬分類: 圖形編程

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            国产精品视频观看| 欧美精品观看| 激情婷婷亚洲| 国产欧美日韩视频| 国产一区欧美日韩| 久久亚洲图片| 免费毛片一区二区三区久久久| 亚洲国产精品va在看黑人| 亚洲二区免费| 欧美日韩专区| 久久爱www久久做| 久久综合伊人| 亚洲视频视频在线| 性欧美xxxx大乳国产app| 黄色成人av网站| 最新亚洲一区| 国产一区二区剧情av在线| 欧美jizz19性欧美| 欧美午夜剧场| 欧美成ee人免费视频| 欧美日韩成人综合| 久久久久成人精品免费播放动漫| 欧美成人激情视频| 欧美一级免费视频| 欧美精品国产一区| 久久99在线观看| 欧美激情一区二区三区在线视频| 羞羞漫画18久久大片| 欧美jizzhd精品欧美巨大免费| 亚洲综合三区| 欧美精品免费视频| 农村妇女精品| 国产日韩精品综合网站| 亚洲人成网站999久久久综合| 国产欧美日韩三级| 99视频精品| 91久久国产精品91久久性色| 亚洲自拍另类| 亚洲天堂av高清| 久久久久久久999精品视频| 亚洲一区视频在线| 欧美日本高清视频| 亚洲高清资源综合久久精品| 国产一区二区三区久久精品| 一区二区三区欧美| 一区二区三区毛片| 牛牛国产精品| 欧美高清一区二区| 在线成人激情黄色| 欧美一级一区| 久久精品国产精品亚洲| 国产精品一区三区| 一本久久知道综合久久| 日韩一级精品| 欧美大秀在线观看| 亚洲国产高清自拍| 亚洲人成在线播放| 欧美韩日精品| 亚洲欧洲一区二区天堂久久 | 欧美日韩国产成人| 欧美护士18xxxxhd| 亚洲经典三级| 欧美国产综合视频| 亚洲精品久久久久久久久久久久久 | 一区二区三区四区国产| 99riav久久精品riav| 欧美高清视频一区二区| 亚洲第一页中文字幕| 亚洲国产日韩在线| 欧美91精品| 亚洲三级毛片| 亚洲尤物视频网| 国产精品试看| 欧美在线视频二区| 蜜桃av一区二区| 亚洲三级免费电影| 欧美日韩亚洲综合| 亚洲一区免费看| 久久一二三四| 亚洲精品美女在线观看播放| 欧美电影免费观看| 亚洲美女91| 久久国内精品自在自线400部| 国内精品久久久久久久果冻传媒 | 亚洲欧美日韩视频二区| 久久久国产一区二区三区| 在线观看日韩一区| 欧美日韩dvd在线观看| 亚洲一区日韩在线| 鲁大师影院一区二区三区| 亚洲黄色免费电影| 国产精品久久久对白| 欧美主播一区二区三区美女 久久精品人| 久久一区二区三区av| 亚洲免费成人av| 国产精品视频999| 久久久噜噜噜久久狠狠50岁| 亚洲精品一区二区三区蜜桃久| 欧美一区免费视频| 亚洲日本视频| 国产一区视频观看| 欧美日韩成人在线| 久久久av毛片精品| 一本色道久久综合狠狠躁篇的优点 | 99热这里只有成人精品国产| 国产精品亚洲а∨天堂免在线| 久久夜色精品国产亚洲aⅴ| 日韩一级欧洲| 欧美成年人视频网站| 午夜久久影院| 日韩一级黄色av| 亚洲第一偷拍| 国产一区二区高清不卡| 欧美精品一区二区三区在线看午夜 | 久久狠狠亚洲综合| 一本久道久久综合婷婷鲸鱼| 韩国欧美一区| 国产亚洲精品激情久久| 欧美日韩一区二区三区在线看| 久久男人av资源网站| 亚洲欧美视频在线观看视频| 亚洲国产另类精品专区| 老牛影视一区二区三区| 欧美与欧洲交xxxx免费观看| 亚洲午夜av电影| 99re6这里只有精品视频在线观看| 黄色欧美成人| 国产一区二区在线观看免费| 国产视频一区在线观看一区免费| 99re6热在线精品视频播放速度| 在线精品视频一区二区| 国内精品视频在线播放| 国产精品看片资源| 国产精品都在这里| 欧美三区在线视频| 欧美视频不卡中文| 欧美视频在线观看视频极品| 欧美区日韩区| 欧美日韩dvd在线观看| 欧美日韩国产天堂| 欧美三区在线观看| 国产精品地址| 国产精品美女久久久浪潮软件 | 欧美黄色一级视频| 美女黄色成人网| 欧美18av| 欧美—级高清免费播放| 欧美激情精品久久久久久变态| 欧美激情一区二区三区| 欧美精品日韩综合在线| 欧美精品在欧美一区二区少妇| 欧美日韩国产精品一区二区亚洲| 欧美精品一区二区三区在线看午夜 | 国产精品麻豆va在线播放| 国产精品人人做人人爽| 国产色综合天天综合网| 在线观看日韩国产| 99国产精品久久| 亚洲永久免费av| 久久精品欧美日韩精品| 免费一级欧美片在线观看| 欧美激情2020午夜免费观看| 亚洲高清在线| 亚洲无线一线二线三线区别av| 亚洲综合色噜噜狠狠| 久久精品人人爽| 欧美精品尤物在线| 国产三级精品在线不卡| 亚洲国产精品视频| 午夜久久99| 欧美福利电影在线观看| 日韩视频免费看| 久久久久欧美| 欧美日韩在线播放三区| 国产性做久久久久久| 亚洲免费电影在线| 久久精品九九| 亚洲福利一区| 亚洲欧美另类综合偷拍| 欧美**人妖| 国产女主播一区二区三区| 亚洲人成在线观看网站高清| 欧美一区二区三区免费看| 亚洲国产mv| 欧美在线高清视频| 欧美日韩在线免费| 在线播放精品| 午夜久久tv| 一本久道久久综合狠狠爱| 久久久欧美一区二区| 国产精品亚洲美女av网站| 亚洲欧洲日产国码二区| 久久精品在线播放| 一区二区欧美精品| 欧美精品一区二区蜜臀亚洲| 国产一区二区三区免费在线观看| 国产精品99久久久久久久vr| 亚洲大片精品永久免费| 久久精品国产清高在天天线| 国产精品乱码一区二区三区|