在DirectX程序中我们可以使用 D3DPT_POINTLIST, D3DPT_LINELIST, D3DPT_LINESTRIP, D3DPT_TRIANGLELIST, D3DPT_TRIANGLESTRIP, D3DPT_TRIANGLEFAN 几种图元类型绘制顶点。

我们先看以下使用这几种绘制图元类型的代码:

//********************************************************************
//      Filename: Main.cpp
//        Author: Chinafish
//      Modifier: Chinafish
//       Created: 2010-06-25 16:13
//       Updated: 2010-06-25 16:13
//            QQ: 149200849
//           MSN: china_fish@msn.com
//       Purpose: Primitive types.
//====================================================================
//  Copyright(C) 2004-2010 by Chinafish. All Rights Reserved.
//********************************************************************
  
#define STRICT 
#define WIN32_LEAN_AND_MEAN 
#include "windows.h" 

// Link D3D 
#include "d3d9.h"
#include "d3dx9.h"
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
 
#define Release_Safe(p){if(p!=NULL) p->Release();} 

#define WINDOW_TITLE    "www.csinx.org - Primitive Types (DX9+VC7)"
#define WINDOW_WIDTH	800 
#define WINDOW_HEIGHT	600 

//----------------------------------------------------------------------------- 
// GLOBALS 
//----------------------------------------------------------------------------- 
HWND					g_hWnd			= NULL; 
LPDIRECT3D9				g_pD3D			= NULL; 
LPDIRECT3DDEVICE9		g_pd3dDevice	= NULL;
D3DPRESENT_PARAMETERS	g_d3dpp;

LPDIRECT3DVERTEXBUFFER9 g_pPointList_VB     = NULL;
LPDIRECT3DVERTEXBUFFER9 g_pLineStrip_VB     = NULL;
LPDIRECT3DVERTEXBUFFER9 g_pLineList_VB      = NULL;
LPDIRECT3DVERTEXBUFFER9 g_pTriangleList_VB  = NULL;
LPDIRECT3DVERTEXBUFFER9 g_pTriangleStrip_VB = NULL;
LPDIRECT3DVERTEXBUFFER9 g_pTriangleFan_VB   = NULL;

#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_DIFFUSE )

struct Vertex
{
	float x, y, z; // Position of vertex in 3D space
	DWORD color;   // Color of vertex
};

bool g_bRenderInWireFrame = false;

//
// We'll store the vertex data in simple arrays until we're ready to load 
// them into actual Direct3D Vertex Buffers. Seeing the vertices laid out 
// like this should make it easier to understand how vertices need to be 
// passed to be considered valid for each primitive type.
//

Vertex g_VertexData[] = 
{
	{-2.0f, 0.0f, 0.0f,  D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 ) },
	{-1.0f, 1.0f, 0.0f,  D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 ) },
	{-1.0f, 0.0f, 0.0f,  D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 ) },
	{ 0.0f, 1.0f, 0.0f,  D3DCOLOR_COLORVALUE( 1.0, 1.0, 0.0, 1.0 ) },
	{ 0.0f, 0.0f, 0.0f,  D3DCOLOR_COLORVALUE( 0.0, 1.0, 1.0, 1.0 ) },
	{ 1.0f, 1.0f, 0.0f,  D3DCOLOR_COLORVALUE( 1.0, 0.0, 1.0, 1.0 ) },
	{ 1.0f, 0.0f, 0.0f,  D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 ) },
	{ 2.0f, 1.0f, 0.0f,  D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 ) }
};

DWORD					g_dwBackBufferWidth  = 0;
DWORD					g_dwBackBufferHeight = 0;
//----------------------------------------------------------------------------- 
// PROTOTYPES 
//----------------------------------------------------------------------------- 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow); 
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void InitD3D();
void ShutDown(void); 
void Render(void); 

//----------------------------------------------------------------------------- 
// Name: WinMain() 
// Desc: The application's entry point 
//----------------------------------------------------------------------------- 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{ 
	WNDCLASSEX winClass; 
	MSG        uMsg; 
	memset(&uMsg,0,sizeof(uMsg)); 

	winClass.lpszClassName = "CLASS_PRIMITIVETYPES"; 
	winClass.cbSize        = sizeof(WNDCLASSEX); 
	winClass.style         = CS_HREDRAW | CS_VREDRAW; 
	winClass.lpfnWndProc   = WindowProc; 
	winClass.hInstance     = hInstance;
	winClass.hIcon         = LoadIcon(hInstance, (LPCTSTR)NULL);
	winClass.hIconSm       = LoadIcon(hInstance, (LPCTSTR)NULL);
	winClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
	winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	winClass.lpszMenuName  = NULL;
	winClass.cbClsExtra    = 0;
	winClass.cbWndExtra    = 0; 

	if(!RegisterClassEx(&winClass)) 
		return E_FAIL; 

	g_hWnd = CreateWindowEx(NULL, "CLASS_PRIMITIVETYPES", 
		WINDOW_TITLE, 
		WS_EX_TOPMOST, 0, 0, 
		WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, 
		hInstance, NULL); 
	
	if(g_hWnd == NULL) 
		return E_FAIL; 
	
	// Adjust window 
	RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
	AdjustWindowRect(&rect, GetWindowLong(g_hWnd, GWL_STYLE), FALSE);
	SetWindowPos(g_hWnd, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
		SWP_NOZORDER | SWP_NOMOVE);

	ShowWindow(g_hWnd, nCmdShow); 
	UpdateWindow(g_hWnd);
	
	// Init or reset D3D
	InitD3D();

	while(uMsg.message != WM_QUIT)
	{
		if(PeekMessage(&uMsg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&uMsg);
			DispatchMessage(&uMsg);
		}
		else
		{
			// Render a frame
			Render();
		}
	}
	
	ShutDown();
	
	UnregisterClass("CLASS_PRIMITIVETYPES", winClass.hInstance);
	
	return uMsg.wParam;
}

//-----------------------------------------------------------------------------
// Name: WindowProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
	case WM_KEYDOWN:
		{
			switch(wParam)
			{
			case VK_ESCAPE:
				PostQuitMessage(0);
				break;
			case 0x57: // W
				{
					g_bRenderInWireFrame = !g_bRenderInWireFrame;
					if( g_bRenderInWireFrame == true )
						g_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
					else
						g_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
				}
				break;
			}
		}
		break;
	case WM_CLOSE:
		{
			PostQuitMessage(0);
		}
	case WM_DESTROY:
		{
			PostQuitMessage(0);
		}
		break;
	default:
	{
		return DefWindowProc(hWnd, msg, wParam, lParam);
	}
	break;
	}
	
	return 0;
}

//-----------------------------------------------------------------------------
// Name: InitD3D()
// Desc: This function will only be called once during the application's
//       initialization phase. Therefore, it can't contain any resources that
//       need to be restored every time the Direct3D device is lost or the
//       window is resized.
//-----------------------------------------------------------------------------
void InitD3D()
{
	// Create D3D
	g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
	if(!g_pD3D)
	{
		MessageBox(NULL, "Direct3DCreate9() - Failed!", "Error", NULL);
		return;
	}
	
	D3DDISPLAYMODE d3ddm;
	g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
	
	ZeroMemory(&g_d3dpp, sizeof(g_d3dpp));
	g_d3dpp.Windowed               = TRUE;
	g_d3dpp.SwapEffect             = D3DSWAPEFFECT_DISCARD;
	g_d3dpp.BackBufferFormat       = d3ddm.Format;
	g_d3dpp.EnableAutoDepthStencil = TRUE;
	g_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
	g_d3dpp.PresentationInterval   = D3DPRESENT_INTERVAL_IMMEDIATE;
	
	g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
		g_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,
		&g_d3dpp, &g_pd3dDevice);
	
	if(!g_pd3dDevice)
	{
		return;
	}

	//
	// Cache the width & height of the back-buffer...
	//

	LPDIRECT3DSURFACE9 pBackBuffer = NULL;
	D3DSURFACE_DESC d3dsd;
	g_pd3dDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
	pBackBuffer->GetDesc(&d3dsd);
	pBackBuffer->Release();
	g_dwBackBufferWidth  = d3dsd.Width;
	g_dwBackBufferHeight = d3dsd.Height;
	
	// Light and cullmode
	g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
	g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

	D3DXMATRIX mProjection;
	D3DXMatrixPerspectiveFovLH( &mProjection, D3DXToRadian( 45.0f ), 1.0f, 1.0f, 100.0f );
	g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &mProjection );

	Vertex *pVertices = NULL;

	//
	// Point List
	//

	g_pd3dDevice->CreateVertexBuffer( 8*sizeof(Vertex), 0, D3DFVF_MY_VERTEX,
		D3DPOOL_DEFAULT, &g_pPointList_VB,
		NULL );

	pVertices = NULL;
	g_pPointList_VB->Lock( 0, sizeof(g_VertexData), (void**)&pVertices, 0 );
	memcpy( pVertices, g_VertexData, sizeof(g_VertexData) );
	g_pPointList_VB->Unlock();

	//
	// Line List
	//

	g_pd3dDevice->CreateVertexBuffer( 8*sizeof(Vertex), 0, D3DFVF_MY_VERTEX,
		D3DPOOL_DEFAULT, &g_pLineList_VB,
		NULL );

	pVertices = NULL;
	g_pLineList_VB->Lock( 0, sizeof(g_VertexData), (void**)&pVertices, 0 );
	memcpy( pVertices, g_VertexData, sizeof(g_VertexData) );
	g_pLineList_VB->Unlock();

	//
	// Line Strip
	//

	g_pd3dDevice->CreateVertexBuffer( 8*sizeof(Vertex), 0, D3DFVF_MY_VERTEX,
		D3DPOOL_DEFAULT, &g_pLineStrip_VB,
		NULL );

	pVertices = NULL;
	g_pLineStrip_VB->Lock( 0, sizeof(g_VertexData), (void**)&pVertices, 0 );
	memcpy( pVertices, g_VertexData, sizeof(g_VertexData) );
	g_pLineStrip_VB->Unlock();

	//
	// Triangle List
	//

	g_pd3dDevice->CreateVertexBuffer( 8*sizeof(Vertex), 0, D3DFVF_MY_VERTEX,
		D3DPOOL_DEFAULT, &g_pTriangleList_VB,
		NULL );

	pVertices = NULL;
	g_pTriangleList_VB->Lock( 0, sizeof(g_VertexData), (void**)&pVertices, 0 );
	memcpy( pVertices, g_VertexData, sizeof(g_VertexData) );
	g_pTriangleList_VB->Unlock();

	//
	// Triangle Strip
	//

	g_pd3dDevice->CreateVertexBuffer( 8*sizeof(Vertex), 0, D3DFVF_MY_VERTEX,
		D3DPOOL_DEFAULT, &g_pTriangleStrip_VB,
		NULL );

	pVertices = NULL;
	g_pTriangleStrip_VB->Lock( 0, sizeof(g_VertexData), (void**)&pVertices, 0 );
	memcpy( pVertices, g_VertexData, sizeof(g_VertexData) );
	g_pTriangleStrip_VB->Unlock();

	//
	// Triangle Fan
	//

	g_pd3dDevice->CreateVertexBuffer( 8*sizeof(Vertex), 0, D3DFVF_MY_VERTEX,
		D3DPOOL_DEFAULT, &g_pTriangleFan_VB,
		NULL );

	pVertices = NULL;
	g_pTriangleFan_VB->Lock( 0, sizeof(g_VertexData), (void**)&pVertices, 0 );
	memcpy( pVertices, g_VertexData, sizeof(g_VertexData) );
	g_pTriangleFan_VB->Unlock();
}

//-----------------------------------------------------------------------------
// Name: ShutDown()
// Desc: Release all
//-----------------------------------------------------------------------------
void ShutDown(void)
{
	Release_Safe(g_pPointList_VB);
	Release_Safe(g_pLineList_VB);
	Release_Safe(g_pLineStrip_VB);
	Release_Safe(g_pTriangleList_VB);
	Release_Safe(g_pTriangleStrip_VB);
	Release_Safe(g_pTriangleFan_VB);
	Release_Safe(g_pd3dDevice);
	Release_Safe(g_pD3D);
}

//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Render something you want
//-----------------------------------------------------------------------------
void Render(void)
{
	D3DXMATRIX mWorld;
	D3DXMatrixTranslation( &mWorld, 0.0f, 0.0f, 10.0f );
	g_pd3dDevice->SetTransform( D3DTS_WORLD, &mWorld );

	int nNum = sizeof(g_VertexData)/sizeof(Vertex);

	//////////////////////////////////////////////////////////////////////////////////
	D3DVIEWPORT9 vp1;
	vp1.X      = 0;
	vp1.Y      = 0;
	vp1.Width  = (g_dwBackBufferWidth-20) / 3 + 10;
	vp1.Height = g_dwBackBufferHeight / 2;
	vp1.MinZ   = 0.0f;
	vp1.MaxZ   = 1.0f;

	g_pd3dDevice->SetViewport(&vp1);

	// Clear screen with D3DCOLOR_XRGB(0, 0, 0)
	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
	
	g_pd3dDevice->BeginScene();
	
	// Render geometry here...
	g_pd3dDevice->SetStreamSource( 0, g_pPointList_VB, 0, sizeof(Vertex) );
	g_pd3dDevice->SetFVF( D3DFVF_MY_VERTEX );

	// D3DPT_POINTLIST
	// D3DPT_LINELIST
	// D3DPT_LINESTRIP
	// D3DPT_TRIANGLELIST
	// D3DPT_TRIANGLESTRIP
	// D3DPT_TRIANGLEFAN
	g_pd3dDevice->DrawPrimitive( D3DPT_POINTLIST, 0, nNum );
	
	g_pd3dDevice->EndScene();

	//////////////////////////////////////////////////////////////////////////////////
	D3DVIEWPORT9 vp2;
	vp2.X      = 10 + (g_dwBackBufferWidth-20) / 3;
	vp2.Y      = 0;
	vp2.Width  = (g_dwBackBufferWidth-20) / 3;
	vp2.Height = g_dwBackBufferHeight / 2;
	vp2.MinZ   = 0.0f;
	vp2.MaxZ   = 1.0f;

	g_pd3dDevice->SetViewport( &vp2 );

	// Clear screen with D3DCOLOR_XRGB(0, 0, 0)
	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

	g_pd3dDevice->BeginScene();

	// Render geometry here...
	g_pd3dDevice->SetStreamSource( 0, g_pLineList_VB, 0, sizeof(Vertex) );
	g_pd3dDevice->SetFVF( D3DFVF_MY_VERTEX );

	// D3DPT_POINTLIST
	// D3DPT_LINELIST
	// D3DPT_LINESTRIP
	// D3DPT_TRIANGLELIST
	// D3DPT_TRIANGLESTRIP
	// D3DPT_TRIANGLEFAN
	g_pd3dDevice->DrawPrimitive( D3DPT_LINELIST, 0, nNum / 2);

	g_pd3dDevice->EndScene();
	
	//////////////////////////////////////////////////////////////////////////////////
	D3DVIEWPORT9 vp3;
	vp3.X      = 10 + ((g_dwBackBufferWidth-20) / 3) * 2;
	vp3.Y      = 0;
	vp3.Width  = (g_dwBackBufferWidth-20) / 3 + 10;
	vp3.Height = g_dwBackBufferHeight / 2;
	vp3.MinZ   = 0.0f;
	vp3.MaxZ   = 1.0f;

	g_pd3dDevice->SetViewport(&vp3);

	// Clear screen with D3DCOLOR_XRGB(0, 0, 0)
	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

	g_pd3dDevice->BeginScene();

	// Render geometry here...
	g_pd3dDevice->SetStreamSource( 0, g_pLineStrip_VB, 0, sizeof(Vertex) );
	g_pd3dDevice->SetFVF( D3DFVF_MY_VERTEX );

	// D3DPT_POINTLIST
	// D3DPT_LINELIST
	// D3DPT_LINESTRIP
	// D3DPT_TRIANGLELIST
	// D3DPT_TRIANGLESTRIP
	// D3DPT_TRIANGLEFAN
	g_pd3dDevice->DrawPrimitive( D3DPT_LINESTRIP, 0, nNum - 1);

	g_pd3dDevice->EndScene();

	//////////////////////////////////////////////////////////////////////////////////
	D3DVIEWPORT9 vp4;
	vp4.X      = 0;
	vp4.Y      = g_dwBackBufferHeight / 2;
	vp4.Width  = (g_dwBackBufferWidth-20) / 3 + 10;
	vp4.Height = g_dwBackBufferHeight / 2;
	vp4.MinZ   = 0.0f;
	vp4.MaxZ   = 1.0f;

	g_pd3dDevice->SetViewport(&vp4);

	// Clear screen with D3DCOLOR_XRGB(0, 0, 0)
	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

	g_pd3dDevice->BeginScene();

	// Render geometry here...
	g_pd3dDevice->SetStreamSource( 0, g_pTriangleList_VB, 0, sizeof(Vertex) );
	g_pd3dDevice->SetFVF( D3DFVF_MY_VERTEX );

	// D3DPT_POINTLIST
	// D3DPT_LINELIST
	// D3DPT_LINESTRIP
	// D3DPT_TRIANGLELIST
	// D3DPT_TRIANGLESTRIP
	// D3DPT_TRIANGLEFAN
	g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, nNum / 3 );

	g_pd3dDevice->EndScene();

	//////////////////////////////////////////////////////////////////////////////////
	D3DVIEWPORT9 vp5;
	vp5.X      = 10 + (g_dwBackBufferWidth-20) / 3;
	vp5.Y      = g_dwBackBufferHeight / 2;
	vp5.Width  = (g_dwBackBufferWidth-20) / 3;
	vp5.Height = g_dwBackBufferHeight / 2;
	vp5.MinZ   = 0.0f;
	vp5.MaxZ   = 1.0f;

	g_pd3dDevice->SetViewport( &vp5 );

	// Clear screen with D3DCOLOR_XRGB(0, 0, 0)
	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

	g_pd3dDevice->BeginScene();

	// Render geometry here...
	g_pd3dDevice->SetStreamSource( 0, g_pTriangleStrip_VB, 0, sizeof(Vertex) );
	g_pd3dDevice->SetFVF( D3DFVF_MY_VERTEX );

	// D3DPT_POINTLIST
	// D3DPT_LINELIST
	// D3DPT_LINESTRIP
	// D3DPT_TRIANGLELIST
	// D3DPT_TRIANGLESTRIP
	// D3DPT_TRIANGLEFAN
	g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, nNum - 2 );

	g_pd3dDevice->EndScene();

	//////////////////////////////////////////////////////////////////////////////////
	D3DVIEWPORT9 vp6;
	vp6.X      = 10 + ((g_dwBackBufferWidth-20) / 3) * 2;
	vp6.Y      = g_dwBackBufferHeight / 2;
	vp6.Width  = (g_dwBackBufferWidth-20) / 3 + 10;
	vp6.Height = g_dwBackBufferHeight / 2;
	vp6.MinZ   = 0.0f;
	vp6.MaxZ   = 1.0f;

	g_pd3dDevice->SetViewport(&vp6);

	// Clear screen with D3DCOLOR_XRGB(0, 0, 0)
	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

	g_pd3dDevice->BeginScene();

	// Render geometry here...
	g_pd3dDevice->SetStreamSource( 0, g_pTriangleFan_VB, 0, sizeof(Vertex) );
	g_pd3dDevice->SetFVF( D3DFVF_MY_VERTEX );

	// D3DPT_POINTLIST
	// D3DPT_LINELIST
	// D3DPT_LINESTRIP
	// D3DPT_TRIANGLELIST
	// D3DPT_TRIANGLESTRIP
	// D3DPT_TRIANGLEFAN
	g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, nNum - 2);

	g_pd3dDevice->EndScene();

	g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}
				

框架代码我们在前面已经有说明,这里需要说明的是首先要定义顶点数据结构,这里定义了3D坐标和颜色。在创建设备后通过调用 IDirect3DDevice9::CreateVertexBuffer 方法创建我们需要的顶点缓冲区。在渲染时调用 IDirect3DDevice9::SetStreamSource 方法将顶点缓冲区绑定到设备数据流上,通过调用 IDirect3DDevice9::SetFVF 方法指定当前顶点数据流声明,通过调用 IDirect3DDevice9::DrawPrimitive 方法按照当前指定的顶点格式渲染无索引的顶点序列,最后显示出来。

下图为本例代码执行效果:

[返回目录][我有话说]