在DirectX程序中我们可以设置多个不同的视口用于显示不同的图形,每个视口都可以清空和独立绘制。渲染目标表面的深度值范围(通常是0.0到 1.0),在这之间的物体会被渲染。
我们先看以下处理多个视口的代码:
//******************************************************************** // Filename: Main.cpp // Author: Chinafish // Modifier: Chinafish // Created: 2010-06-25 12:16 // Updated: 2010-06-25 12:16 // QQ: 149200849 // MSN: china_fish@msn.com // Purpose: Set multiple view ports. //==================================================================== // Copyright(C) 2004-2010 by Chinafish. All Rights Reserved. //******************************************************************** #define STRICT #define WIN32_LEAN_AND_MEAN #include "windows.h" // Link D3D #include "d3d9.h" #pragma comment(lib, "d3d9.lib") #define Release_Safe(p){if(p!=NULL) p->Release();} #define WINDOW_TITLE "www.csinx.org - Multiple Viewports (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; 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(); HRESULT RestoreDeviceObjects(); HRESULT InvalidateDeviceObjects(); 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_MULTIPLEVIEWPORTS"; 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_MULTIPLEVIEWPORTS", 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_MULTIPLEVIEWPORTS", 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; } } 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; // Any resources or settings that need to be restored after losing the // DirectX device should probably be grouped together into one function so // they can be re-created or reset in one call. RestoreDeviceObjects(); } //----------------------------------------------------------------------------- // Name: RestoreDeviceObjects() // Desc: You are encouraged to develop applications with a single code path to // respond to device loss. This code path is likely to be similar, if not // identical, to the code path taken to initialize the device at startup. //----------------------------------------------------------------------------- HRESULT RestoreDeviceObjects() { // Set some important state settings... // Set Transform // Create a texture object, mesh object, buffer etc. return S_OK; } //----------------------------------------------------------------------------- // Name: InvalidateDeviceObjects() // Desc: If the lost device can be restored, the application prepares the // device by destroying all video-memory resources and any // swap chains. This is typically accomplished by using the SAFE_RELEASE // macro. //----------------------------------------------------------------------------- HRESULT InvalidateDeviceObjects() { // Invalidate the texture object, mesh object, buffer etc. return S_OK; } //----------------------------------------------------------------------------- // Name: ShutDown() // Desc: Release all //----------------------------------------------------------------------------- void ShutDown(void) { InvalidateDeviceObjects(); Release_Safe(g_pd3dDevice); Release_Safe(g_pD3D); } //----------------------------------------------------------------------------- // Name: Render() // Desc: Render something you want //----------------------------------------------------------------------------- void Render(void) { // // Render to the Top-left viewport // D3DVIEWPORT9 tlViewPort; tlViewPort.X = 0; tlViewPort.Y = 0; tlViewPort.Width = g_dwBackBufferWidth / 2; tlViewPort.Height = g_dwBackBufferHeight / 2; tlViewPort.MinZ = 0.0f; tlViewPort.MaxZ = 1.0f; g_pd3dDevice->SetViewport(&tlViewPort); // Clear screen with D3DCOLOR_XRGB(255, 0, 0) g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 0, 0), 1.0f, 0); g_pd3dDevice->BeginScene(); // Render geometry here... g_pd3dDevice->EndScene(); // // Render to the Top-right viewport // D3DVIEWPORT9 trViewPort; trViewPort.X = g_dwBackBufferWidth / 2; trViewPort.Y = 0; trViewPort.Width = g_dwBackBufferWidth / 2; trViewPort.Height = g_dwBackBufferHeight / 2; trViewPort.MinZ = 0.0f; trViewPort.MaxZ = 1.0f; g_pd3dDevice->SetViewport(&trViewPort); // Clear screen with D3DCOLOR_XRGB(0, 255, 0) g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 255, 0), 1.0f, 0); g_pd3dDevice->BeginScene(); // Render geometry here... g_pd3dDevice->EndScene(); // // Render to the Bottom-left viewport // D3DVIEWPORT9 blViewPort; blViewPort.X = 0; blViewPort.Y = g_dwBackBufferHeight / 2; blViewPort.Width = g_dwBackBufferWidth / 2; blViewPort.Height = g_dwBackBufferHeight / 2; blViewPort.MinZ = 0.0f; blViewPort.MaxZ = 1.0f; g_pd3dDevice->SetViewport(&blViewPort); // Clear screen with D3DCOLOR_XRGB(0, 0, 255) g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0); g_pd3dDevice->BeginScene(); // Render geometry here... g_pd3dDevice->EndScene(); // // Render to the Bottom-right viewport // D3DVIEWPORT9 brViewPort; brViewPort.X = g_dwBackBufferWidth / 2; brViewPort.Y = g_dwBackBufferHeight / 2; brViewPort.Width = g_dwBackBufferWidth / 2; brViewPort.Height = g_dwBackBufferHeight / 2; brViewPort.MinZ = 0.0f; brViewPort.MaxZ = 1.0f; g_pd3dDevice->SetViewport(&brViewPort); // Clear screen with D3DCOLOR_XRGB(255, 0, 255) g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 0, 255), 1.0f, 0); g_pd3dDevice->BeginScene(); // Render geometry here... g_pd3dDevice->EndScene(); g_pd3dDevice->Present(NULL, NULL, NULL, NULL); }
框架代码我们在前面已经有说明,这里需要说明的是在创建设备后取到后台缓冲大小,在渲染时调用 IDirect3DDevice9::SetViewport 方法来设置四个不同的视口并在其中使用不同的颜色填充。
下图为本例代码执行效果: