在DirectX程序中我们可以自定义多个不同数据格式的顶点缓冲区,本例我们定义了三个顶点缓冲区(在DX9中应该最大可以支持16个)存放顶点位置,颜色和纹理的坐标。通过鼠标拖曳旋转物体,按键1和2控制纹理的采样方式最近点采样(最近点采样和线性纹理过滤)
我们先看以下代码:
- //********************************************************************
- // Filename: Main.cpp
- // Author: Chinafish
- // Modifier: Chinafish
- // Created: 2011-05-11 16:52
- // Updated: 2011-05-11 16:52
- // QQ: 149200849
- // MSN: china_fish@msn.com
- // Purpose: Multiple Vertex buffer.
- //====================================================================
- // Copyright(C) 2004-2011 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 - Multiple Vertex Buffer (DX9+VC9)"
- #define WINDOW_WIDTH 800
- #define WINDOW_HEIGHT 600
- //-----------------------------------------------------------------------------
- // GLOBALS
- //-----------------------------------------------------------------------------
- HWND g_hWnd = NULL;
- LPDIRECT3D9 g_pD3D = NULL;
- LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
- LPDIRECT3DTEXTURE9 g_pTexture = NULL;
- D3DPRESENT_PARAMETERS g_d3dpp;
- LPDIRECT3DVERTEXBUFFER9 g_pVertexBuffer = NULL;
- LPDIRECT3DVERTEXBUFFER9 g_pColorBuffer = NULL;
- LPDIRECT3DVERTEXBUFFER9 g_pTexCoordBuffer = NULL;
- LPDIRECT3DVERTEXDECLARATION9 g_pVertexDeclaration;
- float g_fSpinX = 0.0f;
- float g_fSpinY = 0.0f;
- int g_nNumVertex = 0;
- // 图片数据
- BYTE g_TexData[] = {
- 0x42, 0x4D, 0x46, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
- 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
- 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
- 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0
- };
- struct Vertex
- {
- float x, y, z;
- };
- // 顶点位置
- Vertex g_VertexData[] =
- {
- {-1.0f, 1.0f,-1.0f },
- { 1.0f, 1.0f,-1.0f },
- {-1.0f,-1.0f,-1.0f },
- { 1.0f,-1.0f,-1.0f },
- {-1.0f, 1.0f, 1.0f },
- {-1.0f,-1.0f, 1.0f },
- { 1.0f, 1.0f, 1.0f },
- { 1.0f,-1.0f, 1.0f },
- {-1.0f, 1.0f, 1.0f },
- { 1.0f, 1.0f, 1.0f },
- {-1.0f, 1.0f,-1.0f },
- { 1.0f, 1.0f,-1.0f },
- {-1.0f,-1.0f, 1.0f },
- {-1.0f,-1.0f,-1.0f },
- { 1.0f,-1.0f, 1.0f },
- { 1.0f,-1.0f,-1.0f },
- { 1.0f, 1.0f,-1.0f },
- { 1.0f, 1.0f, 1.0f },
- { 1.0f,-1.0f,-1.0f },
- { 1.0f,-1.0f, 1.0f },
- {-1.0f, 1.0f,-1.0f },
- {-1.0f,-1.0f,-1.0f },
- {-1.0f, 1.0f, 1.0f },
- {-1.0f,-1.0f, 1.0f }
- };
- struct Color
- {
- DWORD color;
- };
- // 顶点颜色
- Color g_VertexColor[] =
- {
- { D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 1.0, 1.0, 0.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 1.0, 1.0, 0.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 1.0, 1.0, 0.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 1.0, 1.0, 0.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 1.0, 0.0, 1.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 1.0, 0.0, 1.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 1.0, 0.0, 1.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 1.0, 0.0, 1.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 0.0, 1.0, 1.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 0.0, 1.0, 1.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 0.0, 1.0, 1.0, 1.0 ) },
- { D3DCOLOR_COLORVALUE( 0.0, 1.0, 1.0, 1.0 ) }
- };
- struct TexCoord
- {
- float tu, tv;
- };
- // 纹理坐标
- TexCoord g_TexCoord[] =
- {
- { 0.0f, 0.0f },
- { 1.0f, 0.0f },
- { 0.0f, 1.0f },
- { 1.0f, 1.0f },
- { 1.0f, 0.0f },
- { 1.0f, 1.0f },
- { 0.0f, 0.0f },
- { 0.0f, 1.0f },
- { 0.0f, 0.0f },
- { 1.0f, 0.0f },
- { 0.0f, 1.0f },
- { 1.0f, 1.0f },
- { 0.0f, 0.0f },
- { 1.0f, 0.0f },
- { 0.0f, 1.0f },
- { 1.0f, 1.0f },
- { 0.0f, 0.0f },
- { 1.0f, 0.0f },
- { 0.0f, 1.0f },
- { 1.0f, 1.0f },
- { 1.0f, 0.0f },
- { 1.0f, 1.0f },
- { 0.0f, 0.0f },
- { 0.0f, 1.0f }
- };
- //-----------------------------------------------------------------------------
- // 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_MULTIVERTEXBUFFER";
- 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_MULTIVERTEXBUFFER",
- 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_MULTIVERTEXBUFFER", winClass.hInstance);
- return uMsg.wParam;
- }
- //-----------------------------------------------------------------------------
- // Name: WindowProc()
- // Desc: The window's message handler
- //-----------------------------------------------------------------------------
- LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
- {
- static POINT ptLastMousePos;
- static POINT ptCurrentMousePos;
- static bool bDraging;
- switch(msg)
- {
- case WM_KEYDOWN:
- {
- switch(wParam)
- {
- case VK_ESCAPE:
- PostQuitMessage(0);
- break;
- case 0x31: // 1
- {
- // 最近点采样
- g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT );
- g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
- }
- break;
- case 0x32: // 2
- {
- // 线性纹理过滤
- g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
- g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
- }
- break;
- }
- }
- break;
- case WM_LBUTTONDOWN:
- {
- ptLastMousePos.x = ptCurrentMousePos.x = LOWORD (lParam);
- ptLastMousePos.y = ptCurrentMousePos.y = HIWORD (lParam);
- bDraging = true;
- }
- break;
- case WM_LBUTTONUP:
- {
- bDraging = false;
- }
- break;
- case WM_MOUSEMOVE:
- {
- ptCurrentMousePos.x = LOWORD (lParam);
- ptCurrentMousePos.y = HIWORD (lParam);
- if( bDraging )
- {
- g_fSpinX -= (ptCurrentMousePos.x - ptLastMousePos.x);
- g_fSpinY -= (ptCurrentMousePos.y - ptLastMousePos.y);
- }
- ptLastMousePos.x = ptCurrentMousePos.x;
- ptLastMousePos.y = ptCurrentMousePos.y;
- }
- 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;
- }
- g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
- g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
- D3DXMATRIX matProj;
- D3DXMatrixPerspectiveFovLH( &matProj, D3DXToRadian( 45.0f ),
- 640.0f / 480.0f, 0.1f, 100.0f );
- g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
- // Create Texture
- D3DXCreateTextureFromFileInMemory( g_pd3dDevice, &g_TexData, sizeof(g_TexData)/sizeof(BYTE), &g_pTexture);
- if(!g_pTexture)
- {
- MessageBox(NULL, "D3DXCreateTextureFromFileInMemory() - Failed!", "Error", NULL);
- return;
- }
- g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
- g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
- // 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.
- g_nNumVertex = sizeof(g_VertexData)/sizeof(Vertex);
- g_pd3dDevice->CreateVertexBuffer( g_nNumVertex*sizeof(Vertex), 0, 0,
- D3DPOOL_DEFAULT, &g_pVertexBuffer,
- NULL );
- // 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.
- Vertex *pVertices = NULL;
- g_pVertexBuffer->Lock( 0, sizeof(g_VertexData), (void**)&pVertices, 0 );
- memcpy( pVertices, g_VertexData, sizeof(g_VertexData) );
- g_pVertexBuffer->Unlock();
- // Create a vertex buffer that contains only the color data
- g_nNumVertex = sizeof(g_VertexColor)/sizeof(Color);
- g_pd3dDevice->CreateVertexBuffer( g_nNumVertex*sizeof(Color), 0, 0,
- D3DPOOL_DEFAULT, &g_pColorBuffer,
- NULL );
- void *pColors = NULL;
- g_pColorBuffer->Lock( 0, sizeof(g_VertexColor), (void**)&pColors, 0 );
- memcpy( pColors, g_VertexColor, sizeof(g_VertexColor) );
- g_pColorBuffer->Unlock();
- // Create a vertex buffer that contains only the texture coordinate data
- g_nNumVertex = sizeof(g_TexCoord)/sizeof(TexCoord);
- g_pd3dDevice->CreateVertexBuffer( g_nNumVertex*sizeof(TexCoord), 0, 0,
- D3DPOOL_DEFAULT, &g_pTexCoordBuffer,
- NULL );
- void *pTexCoords = NULL;
- g_pTexCoordBuffer->Lock( 0, sizeof(g_TexCoord), (void**)&pTexCoords, 0 );
- memcpy( pTexCoords, g_TexCoord, sizeof(g_TexCoord) );
- g_pTexCoordBuffer->Unlock();
- // Create a vertex declaration so we can describe to Direct3D how we'll be passing our data to it.
- D3DVERTEXELEMENT9 dwDecl[] =
- {
- // Stream Offset Type Method Usage UsageIndex
- { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
- { 1, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
- { 2, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
- D3DDECL_END()
- };
- // 创建顶点着色声明
- g_pd3dDevice->CreateVertexDeclaration( dwDecl, &g_pVertexDeclaration );
- }
- //-----------------------------------------------------------------------------
- // Name: ShutDown()
- // Desc: Release all
- //-----------------------------------------------------------------------------
- void ShutDown(void)
- {
- Release_Safe(g_pVertexBuffer);
- Release_Safe(g_pColorBuffer);
- Release_Safe(g_pTexCoordBuffer);
- Release_Safe(g_pTexture);
- Release_Safe(g_pd3dDevice);
- Release_Safe(g_pD3D);
- }
- //-----------------------------------------------------------------------------
- // Name: Render()
- // Desc: Render something you want
- //-----------------------------------------------------------------------------
- void Render(void)
- {
- // Clear screen with D3DCOLOR_XRGB(80, 0, 80)
- g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(80, 0, 80), 1.0f, 0);
- D3DXMATRIX matTrans;
- D3DXMATRIX matRot;
- D3DXMATRIX matWorld;
- D3DXMatrixTranslation( &matTrans, 0.0f, 0.0f, 5.0f );
- D3DXMatrixRotationYawPitchRoll( &matRot,
- D3DXToRadian(g_fSpinX),
- D3DXToRadian(g_fSpinY),
- 0.0f );
- matWorld = matRot * matTrans;
- g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
- g_pd3dDevice->BeginScene();
- // Render geometry here...
- g_pd3dDevice->SetTexture( 0, g_pTexture );
- g_pd3dDevice->SetVertexDeclaration( g_pVertexDeclaration );
- g_pd3dDevice->SetStreamSource( 0, g_pVertexBuffer, 0, sizeof(Vertex) );
- g_pd3dDevice->SetStreamSource( 1, g_pColorBuffer, 0, sizeof(Color) );
- g_pd3dDevice->SetStreamSource( 2, g_pTexCoordBuffer, 0, sizeof(TexCoord) );
- g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
- g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 4, 2 );
- g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 8, 2 );
- g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 12, 2 );
- g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 16, 2 );
- g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 20, 2 );
- g_pd3dDevice->EndScene();
- g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
- }
这里需要说明的是首先定义了图片数据以及顶点的位置数据,颜色数据和纹理坐标数据。 再按以前的步骤创建DX应用程序,在创建设备后通过调用 D3DXCreateTextureFromFileInMemory 方法从内存图片数据创建纹理,通过调用 IDirect3DDevice9::CreateVertexBuffer 方法创建多个我们需要格式的顶点缓冲区,通过调用 IDirect3DDevice9::CreateVertexDeclaration 方法创建顶点着色声明。在渲染时调用 IDirect3DDevice9::SetTexture 设定纹理状态,调用 IDirect3DDevice9::SetVertexDeclaration 设定顶点数据流声明,再通过多次调用 IDirect3DDevice9::SetStreamSource 方法将不同的顶点缓冲区绑定到多个设备数据流上,最后通过调用 IDirect3DDevice9::DrawPrimitive 方法按照当前指定的顶点格式渲染无索引的顶点序列,最后显示出来。
下图为本例代码执行效果: