19.5
設置常量(Setting
Constants)
對于頂點和像素著色器,我們需要從程序代碼中初始化效果文件中的變量以代替使用常量表,就象我們在頂點和像素著色器中做的那樣,ID3DXEffect接口中有內(nèi)建的設置變量的方法。我們這里不會列出所有的設置不同類型變量的方法,因為要完全列出實在是大多了—請查看DirectX
SDK文檔以獲得完整列表。這里是一個刪節(jié)的列表:
HRESULT
ID3DXEffect::SetFloat(
D3DXHANDLE hParameter,
FLOAT f
);
|
Sets a
floating-point variable in the effect file identified by
hParameter to
the value
f
|
HRESULT
ID3DXEffect::SetMatrix(
D3DXHANDLE hParameter,
CONST D3DXMATRIX* pMatrix
);
|
Sets a
matrix variable in the effect file identified by
hParameter to
the value pointed to by
pMatrix
|
HRESULT
ID3DXEffect::SetString(
D3DXHANDLE hParameter,
CONST LPCSTR pString
);
|
Sets a
matrix variable in the effect file identified by
hParameter to
the value pointed to by
pString
|
HRESULT
ID3DXEffect::SetTexture(
D3DXHANDLE hParameter,
LPDIRECT3DBASETEXTURE9 pTexture
);
|
Sets a
texture variable in the effect file identified by
hParameter to
the value pointed to by
pTexture
|
HRESULT
ID3DXEffect::SetVector(
D3DXHANDLE hParameter,
CONST D3DXVECTOR4* pVector
);
|
Sets a
vector variable in the effect file identified by
hParameter to
the value pointed to by
pVector
|
HRESULT
ID3DXEffect::SetVertexShader(
D3DXHANDLE hParameter,
LPDIRECT3DVERTEXSHADER9
pVertexShader
);
|
Sets a
vertex shader variable in the effect file identified by
hParameter to
the value pointed to by
pVertexShader
|
HRESULT
ID3DXEffect::SetPixelShader(
D3DXHANDLE hParameter,
LPDIRECT3DPIXELSHADER9 pPShader
);
|
Sets a
pixel shader variable in the effect file identified by
hParameter to
the value pointed to by
pPShader
|
我們通過下面的方法得到變量(又叫效果參數(shù)effect
parameters)句柄:
D3DXHANDLE ID3DXEffect::GetParameterByName(
D3DXHANDLE hParent, // scope of variable -
parent structure
LPCSTR pName // name of variable
);
|
它的用法與D3DXConstantTable::GetConstantByName方法一樣。即第一個參數(shù)是D3DXHANDLE,它標識我們想得到的在哪個父結(jié)構(gòu)中的變量句柄。對于沒有父結(jié)構(gòu)的全局變量,我們指定null。第二個參數(shù)是在效果文件中所顯示的變量名。
Gets the handle of a top-level parameter or a structure
member parameter by looking up its semantic with a case-insensitive search.
D3DXHANDLE GetParameterBySemantic(
D3DXHANDLE hParameter,
LPCSTR pSemantic
);
Parameters
- hParameter
- [in] Handle of the parameter, or NULL for
top-level parameters.
- pSemantic
- [in] String containing the semantic name.
Return Values
Returns the handle of the first parameter that matches
the specified semantic, or NULL if the semantic was not found. See Handles.
做為例子,以下顯示如何設置效果文件中的一些變量:
// some data
to set
D3DXMATRIX M;
D3DXMatrixIdentity(&M);
D3DXVECTOR4 color(1.0f, 0.0f, 1.0f, 1.0f);
IDirect3DTexture9* tex = 0;
D3DXCreateTextureFromFile(Device, "shade.bmp", &tex);
// get
handles to parameters
D3DXHANDLE MatrixHandle = Effect->GetParameterByName(0, "Matrix");
D3DXHANDLE MtrlHandle = Effect->GetParameterByName(0, "Mtrl");
D3DXHANDLE TexHandle = Effect->GetParameterByName(0, "Tex");
// set
parameters
Effect->SetMatrix(MatrixHandle, &M);
Effect->SetVector(MtrlHandle, &color);
Effect->SetTexture(TexHandle, tex);
|
注意:對每一個ID3DXEffect::Set*方法都有相應的ID3DXEffect::Get*方法用來取得效果文件中的變量值。例如,為得到一個距陣類型的變量,我們可以用這個函數(shù):
HRESULT ID3DXEffect::GetMatrix(
D3DXHANDLE hParameter,
D3DXMATRIX* pMatrix
);
|
要取得所有的方法列表,查看DirectX
SDK文檔。
19.6.1
獲得效果句柄(
Obtaining a Handle to an Effect)
使用手法的第一步是獲得一個手法D3DXHANDLE??梢杂眠@個方法得到一個手法句柄:
D3DXHANDLE ID3DXEffect::GetTechniqueByName(
LPCSTR pName // Name of the technique.
);
|
注意:實際上,一個效果文件包括幾個手法,每一個都被針對一個特定的硬件能力設計。因此,應用程序通常在系統(tǒng)上運行一些能力測試,然后通過這些測試選擇最好的通道。
Gets the handle of a technique by looking up its name.
D3DXHANDLE GetTechniqueByName(
LPCSTR pName
);
Parameters
- pName
- [in] String containing the technique name.
Return Values
Returns the handle of the first technique that has the
specified name, or NULL if the name was not found.
19.6.2
激活一個效果(
Activating an Effect)
一旦得到了想要的手法的句柄,我們必須激活這個手法。這可以通過下面方法實現(xiàn):
HRESULT ID3DXEffect::SetTechnique(
D3DXHANDLE hTechnique // Handle to the
technique to set.
);
|
Sets the active technique.
HRESULT SetTechnique(
D3DXHANDLE hTechnique
);
Parameters
- hTechnique
- [in] Unique handle to the technique.
Return Values
If the method succeeds, the return value is S_OK. If
the method fails, the return value can be D3DERR_INVALIDCALL.
注意:在激活一項手法前你可能想用現(xiàn)有設備驗證它。也就是說,你也許想確保硬件支持的特色、配置手法的使用。你可以用下面的方法:
HRESULT ID3DXEffect::ValidateTechnique(
D3DXHANDLE hTechnique // Handle to the
technique to validate.
);
|
Validate a technique.
HRESULT ValidateTechnique(
D3DXHANDLE hTechnique
);
Parameters
- hTechnique
- [in] Unique identifier.
Return Values
If the method succeeds, the return value is D3D_OK. If
the method fails, the return value can be D3DERR_INVALIDCALL.
一個效果文件可能有幾個手法,嘗試用不同的硬件特色執(zhí)行一個特定效果,希望最少一個手法在用戶系統(tǒng)上執(zhí)行。對于一個效果,你將遍例每一個手法并用ID3DXEffect::ValidateTechnique運行它,因而你能檢測哪個手法是被支持的而哪個不被支持,然后進行適當?shù)膭幼鳌?/p>
19.6.3
啟動效果
為了使用一個效果渲染幾何體,繪圖函數(shù)必須在ID3DXEffect::Begin
和
ID3DXEffect::End間調(diào)用。這些函數(shù)就是分別開啟和關(guān)閉效果。
HRESULT ID3DXEffect::Begin(
UINT* pPasses,
DWORD Flags
);
|
pPasses—返回在當前活動的技術(shù)中的傳遞的數(shù)量。
Flags—下面標志的任何一個:
Zero (0)—指定效果保存當前設備狀態(tài)和著色狀態(tài),并在效果結(jié)束(這時ID3DXEffect::End被調(diào)用)后恢復它們。因為效果文件能夠改變狀態(tài),對于可以保存啟動效果前的狀態(tài)來說,是很有用的。
D3DXFX_DONOTSAVESTATE—指示效果不保存和恢復設備狀態(tài)(除shader狀態(tài)外)。
D3DXFX_DONOTSAVESHADERSTATE—指示效果不保存和恢復shader狀態(tài)。
Starts an active technique.
HRESULT Begin(
UINT* pPasses,
DWORD Flags
);
Parameters
- pPasses
- [out] Pointer to a value returned that indicates
the number of passes needed to render the current technique.
- Flags
- [in] DWORD that determines if state modified by an
effect is saved and restored. The default value 0 specifies that
ID3DXEffect::Begin and ID3DXEffect::End will save and restore all state
modified by the effect (including pixel and vertex shader constants). Valid
flags can be seen at Effect State Save and Restore Flags.
Return Values
If the method succeeds, the return value is D3D_OK. If
the method fails, the return value can be one of the following:
D3DERR_INVALIDCALL, D3DXERR_INVALIDDATA.
Remarks
An application sets one active technique in the effect
system by calling ID3DXEffect::Begin. The effect system responds by
capturing all the pipeline state that can be changed by the technique in a state
block. An application signals the end of a technique by calling
ID3DXEffect::End, which uses the state block to restore the original state.
The effect system therefore takes care of saving state when a technique becomes
active and restoring state when a technique ends. If you choose to disable this
save and restore functionality, see D3DXFX_DONOTSAVESAMPLERSTATE.
Within the ID3DXEffect::Begin and
ID3DXEffect::End pair, an application uses ID3DXEffect::BeginPass to set the
active pass, ID3DXEffect::CommitChanges if any state changes occured after the
pass was activated, and ID3DXEffect::EndPass to end the active pass.
D3DXFX
Options for saving and creating effects.
Effect State Save and Restore Flags |
|
|
Name |
Description |
Value |
D3DXFX_DONOTSAVESTATE |
No state is saved when calling
ID3DXEffect::Begin or restored when calling ID3DXEffect::End.
|
(1 << 0) |
D3DXFX_DONOTSAVESAMPLERSTATE |
A stateblock saves state when calling
ID3DXEffect::Begin and restores state when calling
ID3DXEffect::End. |
(1 << 2) |
D3DXFX_DONOTSAVESHADERSTATE |
A stateblock saves state (except shaders and
shader constants) when calling ID3DXEffect::Begin and restores
state when calling ID3DXEffect::End. |
(1 << 1) |
Effect Creation Flag |
|
|
Name |
Description |
Value |
D3DXFX_NOT_CLONEABLE |
The effect will be non-cloneable and will not
contain any shader binary data. ID3DXBaseEffect::GetPassDesc will not
return shader function pointers. Setting this flag reduces effect memory
usage by about 50% because it eliminates the need for the effect system
to keep a copy of the shaders in memory. This flag is used by
D3DXCreateEffect, D3DXCreateEffectFromFile, and
D3DXCreateEffectFromResource. |
(1 << 11) |
The effect system uses state blocks to save and restore
state automatically.
19.6.5
結(jié)束效果(Ending
an Effect)
最后,對于每個傳遞,我們渲染完幾何體后,停止并結(jié)束效果時使用ID3DXEffect::End方法:
HRESULT ID3DXEffect::End(VOID);
|
19.6.6
例子
下面的代碼片斷示例了使用一個效果的必要的五個步驟:
//
有效果文件中
technique T0
{
pass P0
{
...
}
}
===============================
//
在應用程序中,取得手法句柄
D3DXHANDLE hTech = 0;
hTech
= Effect->GetTechniqueByName("TO");
//
激活手法
Effect->SetTechnique(hTech );
//
啟動激活的手法
UINT
numPasses = 0;
Effect->Begin(&numPasses, 0);
//
遍例每個傳遞
for(int i = 0; i < numPasses; i++)
{
//
設置當前傳遞
Effect->BeginPass(i);
//
在傳遞中渲染幾何體
Sphere->Draw();
Effect->EndPass();
}
//
結(jié)束效果
Effect->End();
|
19.7
例子程序: Lighting and Texturing
in an Effect File
做為熱身,讓我們創(chuàng)建一個在3D模型中操作燈光和紋理的效果文件。這個例子完全運行于固定功能管線,意味著效果框架不僅限于使用著色器。圖19.1展示了使用燈光和紋理例子的屏幕截圖。

圖19.1:
燈光和紋理例子的屏幕截圖.
紋理、材質(zhì)和燈光狀態(tài)在效果文件中指定。
以下是效果文件的實現(xiàn):
/*********************************************************************************
Effect file that handles device states for lighting and texturing a 3D model.
*********************************************************************************/
matrix g_world_matrix;
matrix g_view_matrix;
matrix g_proj_matrix;
texture g_texture;
sampler g_sampler_0 = sampler_state
{
Texture = (g_texture);
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
};
technique g_light_texture_tech
{
pass pass0
{
// set misc render states
pixelshader = null;
vertexshader = null;
fvf = XYZ | Normal | Tex1;
Lighting = true;
NormalizeNormals = true;
SpecularEnable = false;
// set transformation states
WorldTransform[0] = (g_world_matrix);
ViewTransform = (g_view_matrix);
ProjectionTransform = (g_proj_matrix);
// Set a light source at light index 0. We fill out all the components for light[0] because
// Direct3D documentation recommends us to fill out components for bese performance.
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, 1.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] = 1.0f;
// Finally, enable the light.
LightEnable[0] = true;
// Set Material components, this is like calling IDirect3DDevice9::SetMaterial.
MaterialAmbient = {1.0f, 1.0f, 1.0f, 1.0f};
MaterialDiffuse = {1.0f, 1.0f, 1.0f, 1.0f};
MaterialEmissive = {0.0f, 0.0f, 0.0f, 0.0f};
MaterialPower = 1.0f;
MaterialSpecular = {1.0f, 1.0f, 1.0f, 1.0f};
// Hook up the sampler object to sampler stage 0, which is given by Sampler[0].
Sampler[0] = (g_sampler_0);
}
}
在這個效果文件中我們主要設置設備狀態(tài)。我們直接在效果文件中設置一個光源和一個材質(zhì)。此外,我們指定轉(zhuǎn)換距陣和紋理及采樣器狀態(tài)。這些狀態(tài)被指定,然后用LightAndTexture手法和渲染通道P0渲染全部幾何體,。
注意:考慮到在一個效果文件中涉及到的的變量,你必須把它們裝入圓括號中。舉例來說,涉及到距陣變量,你必須這樣寫:(WorldMatrix),
(ViewMatrix), and
(ProjMatrix)。不使用圓括號是違法的。
因為大部分必需的和繁瑣的工作都在效果文件里做了,比如設置燈光、材質(zhì)和紋理。應用程序代碼就是做一些
創(chuàng)建效果和
開啟效果等簡單的事情。
/**************************************************************************************************
Demonstrates using an effect file to light and texture a 3D model.
Use the arrow keys to rotate.
**************************************************************************************************/
#include <vector>
#include "d3dUtility.h"
#pragma warning(disable : 4100)
using namespace std;
const int WIDTH = 640;
const int HEIGHT = 480;
IDirect3DDevice9* g_device;
ID3DXMesh* g_mesh;
vector<D3DMATERIAL9> g_materials;
vector<IDirect3DTexture9*> g_textures;
ID3DXEffect* g_light_texture_effect;
D3DXHANDLE g_world_matrix_handle;
D3DXHANDLE g_view_matrix_handle;
D3DXHANDLE g_proj_matrix_handle;
D3DXHANDLE g_texture_handle;
D3DXHANDLE g_light_texture_tech_handle;
////////////////////////////////////////////////////////////////////////////////////////////////////
bool setup()
{
// load the XFile data
ID3DXBuffer* material_buffer;
DWORD num_materials;
HRESULT hr = D3DXLoadMeshFromX("mountain.x", D3DXMESH_MANAGED, g_device, NULL, &material_buffer, NULL,
&num_materials, &g_mesh);
if(FAILED(hr))
{
MessageBox(NULL, "D3DXLoadMeshFromX() - FAILED", "ERROR", MB_OK);
return false;
}
// extract the materials, load textures.
if(material_buffer != NULL && num_materials != 0)
{
D3DXMATERIAL* xmaterials = (D3DXMATERIAL*) material_buffer->GetBufferPointer();
for(DWORD i = 0; i < num_materials; i++)
{
// the MatD3D property doesn't have an ambient value set when it loaded, so set it now:
xmaterials[i].MatD3D.Ambient = xmaterials[i].MatD3D.Diffuse;
// save the ith material
g_materials.push_back(xmaterials[i].MatD3D);
// check if the ith material has an associative texture
if(xmaterials[i].pTextureFilename != NULL)
{
// yes, load the texture for the ith subset.
IDirect3DTexture9* texture;
D3DXCreateTextureFromFile(g_device, xmaterials[i].pTextureFilename, &texture);
// save the loaded texture
g_textures.push_back(texture);
}
else
{
// no texture for the ith subset
g_textures.push_back(NULL);
}
}
}
safe_release<ID3DXBuffer*>(material_buffer);
// create effect
ID3DXBuffer* error_buffer;
hr = D3DXCreateEffectFromFile(g_device, "LightTextureShader.cxx", NULL, NULL, D3DXSHADER_DEBUG, NULL,
&g_light_texture_effect, &error_buffer);
// output any error messages
if(error_buffer)
{
MessageBox(NULL, (char*) error_buffer->GetBufferPointer(), "ERROR", MB_OK);
safe_release<ID3DXBuffer*>(error_buffer);
}
if(FAILED(hr))
{
MessageBox(NULL, "D3DXCreateEffectFromFile() - FAILED", "ERROR", MB_OK);
return false;
}
// save frequently accessed parameter handles
g_world_matrix_handle = g_light_texture_effect->GetParameterByName(NULL, "g_world_matrix");
g_view_matrix_handle = g_light_texture_effect->GetParameterByName(NULL, "g_view_matrix");
g_proj_matrix_handle = g_light_texture_effect->GetParameterByName(NULL, "g_proj_matrix");
g_texture_handle = g_light_texture_effect->GetParameterByName(NULL, "g_texture");
g_light_texture_tech_handle = g_light_texture_effect->GetTechniqueByName("g_light_texture_tech");
//
// set effect paramters
//
// set matrixs
D3DXMATRIX world_matrix, proj_matrix;
D3DXMatrixIdentity(&world_matrix);
g_light_texture_effect->SetMatrix(g_world_matrix_handle, &world_matrix);
D3DXMatrixPerspectiveFovLH(&proj_matrix, D3DX_PI * 0.25f, (float)WIDTH/HEIGHT, 1.0f, 1000.0f);
g_light_texture_effect->SetMatrix(g_proj_matrix_handle, &proj_matrix);
// set texture
IDirect3DTexture9* texture;
D3DXCreateTextureFromFile(g_device, "Terrain_3x_diffcol.jpg", &texture);
g_light_texture_effect->SetTexture(g_texture_handle, texture);
safe_release<IDirect3DTexture9*>(texture);
//g_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
void cleanup()
{
safe_release<ID3DXMesh*>(g_mesh);
for(DWORD i = 0; i < g_textures.size(); i++)
safe_release<IDirect3DTexture9*>(g_textures[i]);
safe_release<ID3DXEffect*>(g_light_texture_effect);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
bool display(float time_delta)
{
// update the scene: allow user to rotate around scene.
static float angle = (3.0f * D3DX_PI) / 2.0f;
static float height = 5.0f;
if(GetAsyncKeyState(VK_LEFT) & 0x8000f)
angle -= 0.5f * time_delta;
if(GetAsyncKeyState(VK_RIGHT) & 0x8000f)
angle += 0.5f * time_delta;
if(GetAsyncKeyState(VK_UP) & 0x8000f)
height += 5.0f * time_delta;
if(GetAsyncKeyState(VK_DOWN) & 0x8000f)
height -= 5.0f * time_delta;
D3DXVECTOR3 position(cosf(angle) * 10.0f, height, sinf(angle) * 10.0f);
D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXMATRIX view_matrix;
D3DXMatrixLookAtLH(&view_matrix, &position, &target, &up);
g_light_texture_effect->SetMatrix(g_view_matrix_handle, &view_matrix);
// activate the technique and render
g_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000F, 1.0f, 0);
g_device->BeginScene();
// set the technique to use
g_light_texture_effect->SetTechnique(g_light_texture_tech_handle);
UINT num_passes;
g_light_texture_effect->Begin(&num_passes, 0);
for(UINT i = 0; i < num_passes; i++)
{
g_light_texture_effect->BeginPass(i);
for(UINT j = 0; j < g_materials.size(); j++)
g_mesh->DrawSubset(j);
g_light_texture_effect->EndPass();
}
g_light_texture_effect->End();
g_device->EndScene();
g_device->Present(NULL, NULL, NULL, NULL);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK wnd_proc(HWND hwnd, UINT msg, WPARAM word_param, LPARAM long_param)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
if(word_param == VK_ESCAPE)
DestroyWindow(hwnd);
break;
}
return DefWindowProc(hwnd, msg, word_param, long_param);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, PSTR cmd_line, int cmd_show)
{
if(! init_d3d(inst, WIDTH, HEIGHT, true, D3DDEVTYPE_HAL, &g_device))
{
MessageBox(NULL, "init_d3d() - failed.", 0, MB_OK);
return 0;
}
if(! setup())
{
MessageBox(NULL, "Steup() - failed.", 0, MB_OK);
return 0;
}
enter_msg_loop(display);
cleanup();
g_device->Release();
return 0;
}
下載源程序