天行健 君子当自强而不息

效果框架(2)

19.5 设置常量(Setting Constants)

对于顶点和像素着色器,我们需要从程序代码中初始化效果文件中的变量以代替使用常量表,就象我们在顶点和像素着色器中做的那样,ID3DXEffect接口中有内建的设置变量的方法。我们这里不会列出所有的设置不同类型变量的方法,因为要完全列出实在是大多了—请查看DirectX SDK文档以获得完整列表。这里是一个删节的列表:

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

 

我们通过下面的方法得到变量(又叫效果参数effect parameters)句柄:

D3DXHANDLE ID3DXEffect::GetParameterByName(

     D3DXHANDLE hParent, // scope of variable - parent structure

     LPCSTR pName        // name of variable

);

它的用法与D3DXConstantTable::GetConstantByName方法一样。即第一个参数是D3DXHANDLE,它标识我们想得到的在哪个父结构中的变量句柄。对于没有父结构的全局变量,我们指定null。第二个参数是在效果文件中所显示的变量名。

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*方法用来取得效果文件中的变量值。例如,为得到一个距阵类型的变量,我们可以用这个函数:

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.

);

 

注意:实际上,一个效果文件包括几个手法,每一个都被针对一个特定的硬件能力设计。因此,应用程序通常在系统上运行一些能力测试,然后通过这些测试选择最好的通道

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)

       一旦得到了想要的手法的句柄,我们必须激活这个手法。这可以通过下面方法实现:

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.

注意:在激活一项手法前你可能想用现有设备验证它。也就是说,你也许想确保硬件支持的特色、配置手法的使用。你可以用下面的方法:

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.

一个效果文件可能有几个手法,尝试用不同的硬件特色执行一个特定效果,希望最少一个手法在用户系统上执行。对于一个效果,你将遍例每一个手法并用ID3DXEffect::ValidateTechnique运行它,因而你能检测哪个手法是被支持的而哪个不被支持,然后进行适当的动作。

 

19.6.3 启动效果

为了使用一个效果渲染几何体,绘图函数必须在ID3DXEffect::Begin 和 ID3DXEffect::End间调用。这些函数就是分别开启和关闭效果。

HRESULT ID3DXEffect::Begin(

     UINT* pPasses,

     DWORD Flags

);

pPasses—返回在当前活动的技术中的传递的数量。

Flags—下面标志的任何一个:

        Zero (0)—指定效果保存当前设备状态和着色状态,并在效果结束(这时ID3DXEffect::End被调用)后恢复它们。因为效果文件能够改变状态,对于可以保存启动效果前的状态来说,是很有用的。

        D3DXFX_DONOTSAVESTATE—指示效果不保存和恢复设备状态(除shader状态外)。

        D3DXFX_DONOTSAVESHADERSTATE—指示效果不保存和恢复shader状态。

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 结束效果(Ending an Effect)

       最后,对于每个传递,我们渲染完几何体后,停止并结束效果时使用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();

}

 

// 结束效果

Effect->End();

 

 

19.7 例子程序: Lighting and Texturing in an Effect File

       做为热身,让我们创建一个在3D模型中操作灯光和纹理的效果文件。这个例子完全运行于固定功能管线,意味着效果框架不仅限于使用着色器。图19.1展示了使用灯光和纹理例子的屏幕截图。

 

 

图19.1: 灯光和纹理例子的屏幕截图. 纹理、材质和灯光状态在效果文件中指定。

 

以下是效果文件的实现:

/*********************************************************************************
  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.2f0.2f1.0f};
        LightDiffuse[
0]         = {1.0f,  1.0f1.0f1.0f};
        LightSpecular[
0]     = {0.0f,  0.0f0.0f1.0f};
        LightDirection[
0]     = {1.0f-1.0f1.0f1.0f};
        LightPosition[
0]     = {0.0f,  0.0f0.0f0.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.0f1.0f1.0f1.0f};
        MaterialDiffuse  
= {1.0f1.0f1.0f1.0f};
        MaterialEmissive 
= {0.0f0.0f0.0f0.0f};
        MaterialPower     
= 1.0f;
        MaterialSpecular 
= {1.0f1.0f1.0f1.0f};

        
// Hook up the sampler object to sampler stage 0, which is given by Sampler[0].
        Sampler[0= (g_sampler_0);
    }
}

 

 

在这个效果文件中我们主要设置设备状态。我们直接在效果文件中设置一个光源和一个材质。此外,我们指定转换距阵和纹理及采样器状态。这些状态被指定,然后用LightAndTexture手法渲染通道P0渲染全部几何体,。

注意:考虑到在一个效果文件中涉及到的的变量,你必须把它们装入圆括号中。举例来说,涉及到距阵变量,你必须这样写:(WorldMatrix), (ViewMatrix), and (ProjMatrix)。不使用圆括号是违法的。

因为大部分必需的和繁琐的工作都在效果文件里做了,比如设置灯光、材质和纹理。应用程序代码就是做一些创建效果开启效果等简单的事情。

/**************************************************************************************************
  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.0f1000.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.0f0.0f0.0f);
    D3DXVECTOR3 up(
0.0f1.0f0.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, 0x00000000F1.0f0);

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

 

 

下载源程序


posted on 2008-04-12 21:36 lovedday 阅读(2416) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

导航

统计

常用链接

随笔分类(178)

3D游戏编程相关链接

搜索

最新评论