Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Introduction to 3D Game Programming with DirectX.9.0 - F. D. Luna

.pdf
Скачиваний:
240
Добавлен:
24.05.2014
Размер:
6.94 Mб
Скачать

344 Chapter 19

As an example, let’s show how to set some variables in the effect

file:

// some data to set D3DXMATRIX M; D3DXMatrixIdentity(&M);

D3DXVECTOR4 color(1.0f, 0.0f, 1.0f, 1.0f);

IDirect3DTexture9* tex = 0;

 

Y

 

 

 

 

D3DXCreateTextureFromFile(Device, "shade.bmp", &tex);

// get handles to parameters

L

 

 

D3DXHANDLE MatrixHandle = Effect->GetParameterByName(0, "Matrix");

D3DXHANDLE MtrlHandle

 

 

F

 

= Effect->GetParameterByName(0, "Mtrl");

D3DXHANDLE TexHandle

 

= Effect->GetParameterByName(0, "Tex");

// set parameters

 

M

 

 

A

 

Effect->SetMatrix(MatrixHandle, & );

 

Effect->SetVector(MtrlHandle, &color);

 

E

 

 

Effect->SetTexture(TexHandle, tex);

 

T

 

 

 

Note: There are corresponding ID3DXEffect::Get* methods for each ID3DXEffect::Set* method that can be used to retrieve the value of a variable in the effect file. For example, to get a variable that is a matrix type, we would use this function:

HRESULT ID3DXEffect::GetMatrix(

D3DXHANDLE hParameter,

D3DXMATRIX* pMatrix

);

See the DirectX SDK documentation for a list of all methods.

19.6 Using an Effect

In this section and its subsections, we show how to use an effect once it has been created. The following steps summarize the overall process:

1.Obtain a handle to the technique in the effect file you wish to use.

2.Activate the desired technique.

3.Begin the currently active technique.

4.For each rendering pass in the active technique, render the desired geometry. Recall that techniques may consist of several rendering passes, and we must render the geometry once for each pass.

5.End the currently active technique.

Team-Fly®

The Effects Framework 345

19.6.1 Obtaining a Handle to an Effect

The first step to using a technique is to obtain a D3DXHANDLE to that technique. A handle to a technique can be obtained using this method:

D3DXHANDLE ID3DXEffect::GetTechniqueByName( LPCSTR pName // Name of the technique.

);

Note: In practice, an effect file typically contains several techniques, where each is designed for a particular set of hardware capabilities. Therefore, the application normally runs some capability tests on the system to determine its hardware and then selects the best technique based on those tests. See ID3DXEffect::ValidateTechnique in the following section.

19.6.2 Activating an Effect

Once the handle to the desired technique has been obtained, we must activate that technique. This is done with the following method:

HRESULT ID3DXEffect::SetTechnique(

D3DXHANDLE hTechnique // Handle to the technique to set.

);

Note: Before activating a technique you will want to validate it with the current device. That is, you will want to ensure that the hardware supports the features the technique uses and the configuration of features the technique uses. You can use the following method to do so:

HRESULT ID3DXEffect::ValidateTechnique(

D3DXHANDLE hTechnique // Handle to the technique to validate.

);

Recall that an effect file may have several techniques, each attempting to implement a particular effect using different hardware features, hoping that the implementation of at least one technique will work on the user’s system. For an effect, you will want to iterate through each technique and run it through ID3DXEffect::ValidateTechnique so that you can verify which techniques are supported and which ones are not, and then act appropriately.

19.6.3 Beginning an Effect

To render geometry using an effect, we must surround the drawing function calls between the ID3DXEffect::Begin and ID3DXEffect ::End methods. These functions essentially enable and disable the effect, respectively.

HRESULT ID3DXEffect::Begin(

UINT* pPasses,

DWORD Flags

);

P a r t I V

346Chapter 19

pPasses—Returns the number of passes in the currently active technique

Flags—Any one of the following flags:

Zero (0)—Instructs the effect to save the current device states and shader states and then restore them after the effect is finished (when ID3DXEffect::End is called). This is useful because the effect file can change the states, and it may be desirable to restore the states prior to beginning the effect.

D3DXFX_DONOTSAVESTATE—Instructs the effect to not save and restore device states (excludes shader states)

D3DXFX_DONOTSAVESHADERSTATE—Instructs the effect to not save and restore shader states

19.6.4 Setting the Current Rendering Pass

Before we can render any geometry using an effect, we must specify the rendering pass to use. Recall that a technique consists of one or more rendering passes, where each pass encapsulates different device states, samplers, and/or shaders that are to be used for that pass. The rendering pass is specified with the following method:

HRESULT ID3DXEffect::Pass(

UINT iPass // Index identifying the pass.

);

The rendering passes for a technique are labeled as 0…n-1 for n passes. Thus, we can iterate through each pass using a simple for loop and render the geometry for that pass. Section 19.6.6 shows an example.

19.6.5 Ending an Effect

Finally, after we have rendered the geometry for each pass, we disable or end the effect with ID3DXEffect::End:

HRESULT ID3DXEffect::End(VOID);

19.6.6 Example

The following code snippet illustrates the above five steps necessary to use an effect:

// In effect file: technique T0

{

pass P0

{

...

The Effects Framework 347

}

}

====================================

//In application source code:

//Get technique handle. D3DXHANDLE hTech = 0;

hTech = Effect->GetTechniqueByName("T0");

//Activate technique.

Effect->SetTechnique(hTech );

//Begin the active technique. UINT numPasses = 0; Effect->Begin(&numPasses, 0);

//For each rendering pass. for(int i = 0; i < numPasses; i++)

{

//Set the current pass. Effect->Pass(i);

//Render the geometry for the ith pass. Sphere->Draw();

}

// End the effect. Effect->End();

19.7 Sample Application: Lighting and

Texturing in an Effect File

As a warm-up, let’s create an effect file that handles lighting and texturing a 3D model. The sample runs entirely in the fixed function pipeline, implying that the effects framework is not limited to effects that use shaders. Figure 19.1 shows a screen shot of the Lighting and Texturing sample.

Figure 19.1: Screen shot from the Lighting and Texturing sample. The texture, material, and lighting states are specified inside the effect file.

P a r t I V

348 Chapter 19

The effect file is implemented as follows:

//

//File: light_tex.txt

//Desc: Effect file that handles device states for lighting

//and texturing a 3D model.

//

//

// Globals

//

matrix WorldMatrix; matrix ViewMatrix; matrix ProjMatrix;

texture Tex;

//

//Sampler

//Associated the texture ‘Tex’ with the texture stage ‘S0’

//corresponds with and also set the sampler states for the sampler

//stage ‘S0’ corresponds with.

sampler S0 = sampler_state

{

Texture = (Tex);

MinFilter = LINEAR;

MagFilter = LINEAR;

MipFilter = LINEAR;

};

//

// Effect

//

technique LightAndTexture

{

pass P0

{

//

// Set misc. render states.

pixelshader

=

null;

// No pixel shader.

vertexshader

=

null;

// No vertex shader.

fvf = XYZ | Normal

| Tex1;

// Flexible vertex format

Lighting

=

true;

// Enable lighting.

NormalizeNormals =

true;

// Renormalize normals.

SpecularEnable

=

false;

// Disable specular highlights.

//

// Set transformation states

WorldTransform[0]

=

(WorldMatrix);

ViewTransform

=

(ViewMatrix);

The Effects Framework 349

ProjectionTransform = (ProjMatrix);

//

//Set a light source at light index 0. We fill out all the

//components for light[0] because the Direct3D

//documentation recommends filling out all components

//for best 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, 0.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]

= 0.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 ‘S0’ to sampler stage 0,

//which is given by Sampler[0].

Sampler[0] = (S0);

}

}

In this effect file we are primarily setting device states, as covered in section 19.3. For instance, we set a light source and a material directly in the effect file. Furthermore, we specify transformation matrices and the texture and sampler states to apply. These specified states are then applied to any geometry that is rendered using technique LightAndTexture and rendering pass P0.

Note: Observe that to refer to variables in an effect file, we must enclose them in parentheses. For example, to refer to matrix variables, we had to write (WorldMatrix), (ViewMatrix), and (ProjMatrix). Leaving the parentheses off is illegal.

P a r t I V

350 Chapter 19

Since most of the necessary grunt work is done in the effect file, such as setting lights, materials, and textures, the application code is simply a matter of creating the effect and enabling it. The sample has the following relevant global variables:

ID3DXEffect* LightTexEffect = 0;

D3DXHANDLE WorldMatrixHandle

= 0;

D3DXHANDLE ViewMatrixHandle

= 0;

D3DXHANDLE ProjMatrixHandle

= 0;

D3DXHANDLE TexHandle

= 0;

D3DXHANDLE LightTexTechHandle = 0;

This is nothing interesting—just an ID3DXEffect pointer and some handles. The LightTexTechHandle is a handle to a technique, hence the substring “Tech” in its name.

The Setup function performs three primary steps: creates the effect, obtains handles to effect parameters and to the technique we are going to use, and initializes some of the effect parameters. Its abridged implementation is as follows:

bool Setup()

{

HRESULT hr = 0;

//

// ...[Load XFile Snipped]

//

//

// Create effect.

//

ID3DXBuffer* errorBuffer = 0; hr = D3DXCreateEffectFromFile(

Device,

// associated device

"light_tex.txt",

// effect filename

0,

// no preprocessor definitions

0,

// no ID3DXInclude interface

D3DXSHADER_DEBUG,

// compile flags

0,

// don't share parameters

&LightTexEffect,

// return effect interface pointer

&errorBuffer);

// return error messages

// output any error messages if( errorBuffer )

{

::MessageBox(0, (char*)errorBuffer->GetBufferPointer(), 0, 0); d3d::Release<ID3DXBuffer*>(errorBuffer);

}

if(FAILED(hr))

{

The Effects Framework 351

::MessageBox(0, "D3DXCreateEffectFromFile() - FAILED", 0, 0); return false;

}

//

// Save Frequently Accessed Parameter Handles

//

WorldMatrixHandle=LightTexEffect->GetParameterByName(0,

"WorldMatrix");

ViewMatrixHandle

=LightTexEffect->GetParameterByName(0, "ViewMatrix");

ProjMatrixHandle

=LightTexEffect->GetParameterByName(0, "ProjMatrix");

TexHandle

=LightTexEffect->GetParameterByName(0, "Tex");

LightTexTechHandle =

LightTexEffect->GetTechniqueByName("LightAndTexture");

//

//Set effect parameters

//Matrices

D3DXMATRIX W, P;

D3DXMatrixIdentity(&W);

LightTexEffect->SetMatrix( WorldMatrixHandle, &W);

D3DXMatrixPerspectiveFovLH(

&P, D3DX_PI * 0.25f, // 45 - degree (float)Width / (float)Height, 1.0f, 1000.0f);

LightTexEffect->SetMatrix( ProjMatrixHandle, &P);

// Texture: IDirect3DTexture9* tex = 0;

D3DXCreateTextureFromFile(Device, "Terrain_3x_diffcol.jpg", &tex);

LightTexEffect->SetTexture(TexHandle, tex);

d3d::Release<IDirect3DTexture9*>(tex);

return true;

}

The Display function is straightforward and performs the steps outlined in section 19.6:

bool Display(float timeDelta)

{

if( Device )

{

//

// ...[Camera update snipped]

//

P a r t I V

// set the new updated view matrix

352 Chapter 19

LightTexEffect->SetMatrix(ViewMatrixHandle, &V);

//

// Activate the technique and render

//

Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,

0xffffffff, 1.0f, 0);

Device->BeginScene();

// set the technique to use LightTexEffect->SetTechnique( LightTexTechHandle );

UINT numPasses = 0;

LightTexEffect->Begin(&numPasses, 0);

for(int i = 0; i < numPasses; i++)

{

LightTexEffect->Pass(i);

for(int j = 0; j < Mtrls.size(); j++)

{

Mesh->DrawSubset(j);

}

}

LightTexEffect->End();

Device->EndScene(); Device->Present(0, 0, 0, 0);

}

return true;

}

19.8 Sample Application: Fog Effect

One of the topics we regret not devoting a chapter to is Direct3D fog. Fog effects add a new level of realism to the scene and can be used to simulate certain types of weather conditions. Furthermore, fog can greatly diminish far-clip plane visual artifacts.

Although we can’t give it the attention it deserves, we do squeeze in a brief fog sample here. Although we do not go into detail, we do show and explain the Direct3D code, which is fairly intuitive.

Direct3D fog is part of the fixed function pipeline, as is controlled through render states. The following effect file sets the necessary fog states for vertex fog.

Note: Direct3D also supports pixel fog (also called table fog), which is more accurate than vertex fog.

//

// File: fog.txt

//

The Effects Framework 353

// Desc: Effect file that handles device states for linear vertex fog.

//

technique Fog

{

pass P0

{

//

// Set misc render states.

pixelshader

= null;

 

vertexshader

= null;

 

fvf

= XYZ | Normal;

Lighting

= true;

 

NormalizeNormals = true;

 

SpecularEnable = false;

 

//

 

 

// Fog states

 

 

FogVertexMode = LINEAR;

// Linear fog function.

FogStart

= 50.0f;

// Fog starts 50 units

 

 

// away from viewpoint.

FogEnd

= 300.0f;

// Fog ends 300 units

 

 

// away from viewpoint.

FogColor

= 0x00CCCCCC;// Gray colored fog.

FogEnable

= true;

// Enable vertex fog.

}

}

As you can see, linear vertex fog can be controlled through five simple render states:

FogVertexMode—Specifies the fog function to use for vertex fog. The fog function specifies how the fog increases with distance, as naturally fog is less thick near the viewpoint and becomes thicker as the distance increases. Valid assignment types are LINEAR, EXP, and EXP2. These functions are defined as:

LINEAR fog function: f

end d

end start

 

 

 

 

 

EXP fog function:

f

 

1

 

 

 

 

 

ed (density)

EXP2 fog function:

f

1

 

 

 

 

 

 

e(d (density))2

 

 

 

 

(d is the distance from the viewpoint.)

Note: If you use the EXP or EXP2 fog functions, you do not need to set FogStart and FogEnd because they are not used in these types of fog functions; instead you must set the fog density render state (e.g.,

FogDensity = someFloatType;).

P a r t I V