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

Base Framework Sample

With those details in mind, let's proceed to create a simple sample that we can use for the basis of experimentation. This sample needs to be located in the Direct3D folder in the SDK for all the path information to work without requiring you to fix things up. Figure 2 below shows the project view from Visual C++® 6 for the "Base" sample that I will use for the next several columns.

Figure 2. DirectX 8 "Base" sample project view

All five DirectX graphics sample framework modules are used here for completeness. Technically d3dfile.cpp isn't required. The class definition for this sample is a quite simple overloading of the "overridable" functions discussed above and shown below.

class CMyD3DApplication : public CD3DApplication



CD3DFont* m_pFont; // Font for drawing text

LPDIRECT3DVERTEXBUFFER8 m_pVB; // Buffer to hold vertices


HRESULT OneTimeSceneInit();

HRESULT InitDeviceObjects();

HRESULT RestoreDeviceObjects();

HRESULT InvalidateDeviceObjects();

HRESULT DeleteDeviceObjects();

HRESULT FinalCleanup();

HRESULT Render();

HRESULT FrameMove();




For our "Base" sample, rendering a simple "quad" consisting of two triangles will be sufficient to illustrate the use of the framework. From such humble beginnings all things shader-ish will flow. Do note that the "quad" will be contained in a vertexbuffer. For DirectX 8 the container for geometry data is vertexbuffers. For details on using vertexbuffers, see the Direct3D documentation.

The definition of the quad and its vertex information is quite simple, as shown below:

//a quad

#define NUM_VERTS 4

#define NUM_TRIS 2

// A structure for our custom vertex type



FLOAT x, y, z; // The untransformed position for the vertex

DWORD color; // The vertex color


// Our custom FVF, which describes our custom vertex structure


// Initialize vertices for a QUAD

CUSTOMVERTEX g_Vertices[] =


// x y z diffuse

{ -1.0f,-1.0f, 0.0f, 0xff00ff00, },//bl

{ 1.0f,-1.0f, 0.0f, 0xff00ff00, },//br

{ 1.0f, 1.0f, 0.0f, 0xffff0000, },//tr

{ -1.0f, 1.0f, 0.0f, 0xff0000ff, },//tl


A quad can be completely specified by two triangles and four vertices in a triangle fan. The vertex information consists of {x, y, z} 3D vector location information as well as diffuse color. The definition of the initial conditions of the location information places the quad about the origin. Now it's on to the "overridable" functions.


// Name: CMyD3DApplication()

// Desc: Application constructor. Sets attributes for the app.




m_strWindowTitle = _T("Base: D3D Basic Example");

m_bUseDepthBuffer = TRUE;

m_pVB = NULL;

m_pFont = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD );


In the CMyD3DApplication class constructor shown above we initialize the window title, enable using a depth-buffer, pre-initialize our vertexbuffer interface pointer to NULL, and set up a font to use for debugging output.


// Name: OneTimeSceneInit()

// Desc: Called during initial app startup, this function performs all the

// permanent initialization.


HRESULT CMyD3DApplication::OneTimeSceneInit()


return S_OK;


OneTimeSceneInit is called by the framework when the app starts up, and can be used to initialize structures that aren't tied to a D3DDevice. This sample has no one-time initialization needs, so the OneTimeSceneInit method is a stub as shown above.


// Name: FrameMove()

// Desc: Called once per frame, the call is the entry point for animating

// the scene.


HRESULT CMyD3DApplication::FrameMove()


// For our world matrix, just rotate the object about the y-axis.

D3DXMATRIX matWorld;

D3DXMatrixRotationY( &matWorld, m_fTime * 4.0f );

m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

return S_OK;


The FrameMove method above allows us to specify animation actions that happen once a frame. For this sample, we set up a simple y-rotation to rotate the "quad" about the Y-axis at the origin.


// Name: Render()

// Desc: Called once per frame, the call is the entry point for 3d

// rendering. This function sets up render states, clears the

// viewport, and renders the scene.


HRESULT CMyD3DApplication::Render()


// Clear the viewport


D3DCOLOR_XRGB(0,0,128), 1.0f, 0L );

// Begin the scene

if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )


// specify the source of stream 0, which is our vertex buffer.

// then let D3D know what vertex shader to use.

// call DrawPrimitive() which does the actual rendering

m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(CUSTOMVERTEX) );

m_pd3dDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX );

m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, NUM_TRIS );

// Output statistics

m_pFont->DrawText( 2, 0, D3DCOLOR_ARGB(255,255,255,0),

m_strFrameStats );

m_pFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0),

m_strDeviceStats );

// End the scene.



return S_OK;


The Render method above first clears the viewport using Clear. Then, within the BeginScene/EndScene pair, we call SetStreamSource to tell the D3D device that we are using vertexbuffer m_pVB with a stride of the size of our custom vertex type. Then we inform the D3D device that we are using a fixed-function FVF shader. Finally, we invoke DrawPrimitive to render the quad.


// Name: InitDeviceObjects()

// Desc: This creates all device-dependent managed objects, such as

// managed textures and managed vertex buffers.


HRESULT CMyD3DApplication::InitDeviceObjects()


// Initialize the font's internal textures

m_pFont->InitDeviceObjects( m_pd3dDevice );

return S_OK;


In this sample the InitDeviceObjects method's only task, shown above, is to initialize our debugging output font, using its corresponding InitDeviceObjects method.


// Name: RestoreDeviceObjects()

// Desc: Restore device-memory objects and state after a device is created

// or resized.


HRESULT CMyD3DApplication::RestoreDeviceObjects()


// Restore the device objects for the font


// Create the vertex buffer. Here we are allocating enough memory

// (from the default pool) to hold all our 3 custom vertices. We also

// specify the FVF, so the vertex buffer knows what data it contains.

if( FAILED( m_pd3dDevice->CreateVertexBuffer(






return E_FAIL;


// Now we fill the vertex buffer. To do this, we need to Lock() the VB

// to gain access to the vertices. This mechanism is required becuase

// vertex buffers may be in device memory.

VOID* pVertices;

if( FAILED( m_pVB->Lock( 0, sizeof(g_Vertices),

(BYTE**)&pVertices, 0 ) ) )

return E_FAIL;

memcpy( pVertices, g_Vertices, sizeof(g_Vertices) );


// Set the projection matrix


FLOAT fAspect = m_d3dsdBackBuffer.Width /


D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect,

1.0f, 100.0f );

m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );

// Set up our view matrix. A view matrix can be defined given an eye

// point, a point to look at, and a direction for which way is up.

// Here, we set the eye 4 units back along the z-axis and up 1

// unit(s), look at the origin, and define "up" to be in the y-

// direction.


D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3( 0.0f, 1.0f,-4.0f ), //from

&D3DXVECTOR3( 0.0f, 0.0f, 0.0f ), //at

&D3DXVECTOR3( 0.0f, 1.0f, 0.0f ));//up

m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

// Set up the default texture states

m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,


m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1,


m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1,


m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,


m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1,


m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,


m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,


m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER,


m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER,


m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSU,


m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSV,


m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, TRUE );

m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );

// Turn off D3D lighting, since we are providing our own vertex colors

m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );

// Turn off culling, so we see the front and back of the triangle

m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );

return S_OK;


RestoreDeviceObjects shown above performs quite a bit of work in this sample. First, the vertexbuffer m_pVB is created using CreateVertexBuffer. Next, we lock the vertexbuffer, populate it with our quad's data, and then unlock it. Then the view and projection matrices are initialized and SetTransform for the respective matrices is used to set each matrix on the device. Finally, a series of renderstates are initialized using SetTextureStageState and SetRenderState. Note that since this sample does not use multi-texture only stage 0 states are set.


// Name: InvalidateDeviceObjects()

// Desc: Called when the device-dependent objects are about to be lost.


HRESULT CMyD3DApplication::InvalidateDeviceObjects()




return S_OK;


InvalidateDeviceObjects above releases our vertexbuffer using the SAFE_RELEASE macro and invokes the InvalidateDeviceObjects method on our font to release any internal objects the font created.


// Name: DeleteDeviceObjects()

// Desc: Called when the app is exiting, or the device is being changed,

// this function deletes any device dependent objects.


HRESULT CMyD3DApplication::DeleteDeviceObjects()



return S_OK;


DeleteDeviceObjectsabove simply invokes theDeleteDeviceObjectsmethod on the font.


// Name: FinalCleanup()

// Desc: Called before the app exits, this function gives the app the

// chance to cleanup after itself.


HRESULT CMyD3DApplication::FinalCleanup()


SAFE_DELETE( m_pFont );

return S_OK;


FinalCleanupshown above uses theSAFE_DELETE macro to finalize the debug display font.


// Name: ConfirmDevice()

// Desc: Called during device intialization, this code checks the device

// for some minimum set of capabilities


HRESULT CMyD3DApplication::ConfirmDevice( D3DCAPS8* pCaps,

DWORD dwBehavior,

D3DFORMAT Format )


return S_OK;


ConfirmDeviceis quite simply, as shown above, an empty stub. This means that the framework will consider all D3D devices valid for use in this sample, regardless of their caps, vertex processing type, or back buffer format.

Figure 3 shows a screenshot from Base, showing a quad rendered with a "rainbow" diffuse color effect.

Figure 3. DirectX 8 "Base" sample, rendering a quad using diffuse color shading