65.9K
CodeProject 正在变化。 阅读更多。
Home

Direct3D 入门

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.76/5 (32投票s)

2004年3月9日

CPOL

5分钟阅读

viewsIcon

194820

downloadIcon

2100

开始 Direct3D 编程并创建一个窗口。

引言

在本教程中,我将帮助您开始学习Direct3D并创建一个兼容Direct3D的窗口。我假设您熟悉Win32编程。我使用Visual Studio.NET来完成我的工作,但当然您也可以使用任何C++编译器,您需要DirectX SDK 8.0或更高版本来编译提供的代码,可以 在此处 下载(仅需要头文件和库)。

DirectX的故事始于1995年,当时微软推出了Windows 95。但Windows 95在对各种硬件,特别是图形硬件的支持方面存在许多问题。这些问题导致大多数游戏程序员改用MS-DOS。但很快,微软就为Windows 95开发者提供了Game SDK,以改进驱动程序支持,这个项目后来被称为DirectX。在1995年至1998年间,微软专注于DirectX,并为DirectX添加了许多新功能,在此三年期间发布了大约六个不同的版本。最后,他们发布了Windows 98,它非常适合支持DirectX,并使游戏开发者的编程更加容易,以至于他们几乎所有人都将项目迁移到支持DirectX,这让微软非常高兴!

DirectX是一个软件接口,它位于标准硬件特定驱动程序和硬件之上的硬件抽象层(HAL)。DirectX创建了一个通用的硬件独立层,支持各种不同类型的硬件。使用DirectX时,您可以在一个硬件上编写程序,DirectX将保证您的程序能在所有其他DirectX兼容的硬件组件上运行。

好了,关于DirectX就说到这里,让我们开始工作吧!

入门

如果您使用Microsoft Visual C++,请创建一个空的Win32项目,并在“项目属性”>“链接器”>“输入”>“附加依赖项”中添加d3d8.lib(主Direct3D库)、d3dx8.lib(主库的扩展)和winmm.lib(Windows多媒体库)。

然后,您可以将以下代码作为新源文件输入

#include <windows.h>
#include <d3d8.h>

HWND hWnd;
LPDIRECT3D8 pD3D;
LPDIRECT3DDEVICE8 pDevice; 

LRESULT CALLBACK WndProc( HWND hWnd , UINT message , 
    WPARAM wParam , LPARAM lParam){
    switch(message){ 
    case WM_CLOSE: 
        PostQuitMessage(0); 
        return 0; 
    } 
    return DefWindowProc(hWnd,message,wParam,lParam); 
}

bool CreateSimpWindow(int width, int height){

    // Create A Window Class Structure 
    WNDCLASSEX wc;
    wc.cbClsExtra = 0;
    wc.cbSize = sizeof(wc); 
    wc.cbWndExtra = 0; 
    wc.hbrBackground = NULL;
    wc.hCursor = NULL; 
    wc.hIcon = NULL; 
    wc.hIconSm = NULL; 
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpfnWndProc = WndProc;
    wc.lpszClassName = "X3D"; 
    wc.lpszMenuName = NULL;
    wc.style = CS_VREDRAW|CS_HREDRAW|CS_OWNDC;

    // Register Window Class
    RegisterClassEx(&wc); 

    // Create Window 
    hWnd = CreateWindowEx(0, 
       "X3D", "X3D Direct3D Tutorial 1", 
       WS_OVERLAPPEDWINDOW|WS_VISIBLE, 100,100,width,height,
       NULL,NULL,wc.hInstance,0);

    return true;
}

bool InitD3D(){
    if((pD3D = Direct3DCreate8(D3D_SDK_VERSION))==NULL){
        return false;
    }
    D3DDISPLAYMODE d3ddm;
    pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.BackBufferFormat = d3ddm.Format;
    d3dpp.Windowed = true;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    if(FAILED(pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
    hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice))){
        return false;
    }
    return true;
} 

void RenderD3DScene(){
    pDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1,0);
    pDevice->Present(NULL,NULL,NULL,NULL);
} 

void MessageLoop(){
    MSG msg; 
    while(true){
        RenderD3DScene();
        if(PeekMessage(&msg,hWnd,0,0,PM_REMOVE)){
             if(msg.message==WM_QUIT)return;
             TranslateMessage(&msg); 
             DispatchMessage(&msg); 
        }
    } 
}

INT WINAPI WinMain( HINSTANCE , HINSTANCE , LPSTR , INT ){

    if(!CreateSimpWindow(400, 400))return 1;

    if(!InitD3D())return 2; 

    MessageLoop(); 

    return 0;
} 

如果一切顺利,这段代码将创建一个带有黑色背景的窗口。这可能会让您觉得我可以用更简单的方法创建一个黑色窗口,当然您也可以。然而,这里的目标是以最少的代码,尽可能简单地正确初始化Direct3D。在以后的教程中,您将使用Direct3D做更多的事情。为了让事情更简单,我将代码分解为几个函数:CreateSimpWindowMessageLoopWndProcInit3D(初始化Direct3D)和Render3DScene(渲染Direct3D场景)。本教程仅解释Direct3D函数。

我们从第二行开始,我们包含了Direct3D 8头文件:d3d8.h,然后定义了两个新变量

LPDIRECT3D8 pD3D;
LPDIRECT3DDEVICE8 pDevice; 

pD3D是指向IDirect3D8接口的指针,它实际上是一个COM对象,您可以使用它创建其他Direct3D接口,如IDirect3DDevice

现在,让我们看一下InitD3D函数

if((pD3D = Direct3DCreate8(D3D_SDK_VERSION))==NULL){
   return false;
}

Direct3DCreate8宏为我们轻松创建了一个IDirect3D8接口,唯一需要的参数是D3D_SDK_VERSION,这是一个指定Direct3D版本头文件的宏,以确保Direct3D头文件和库文件兼容。现在我们有了一个IDirect3D8对象,但要开始绘图,我们需要一个IDirect3DDevice8对象。IDirect3D8:CreateDevice为我们创建了一个IDirect3DDevice8对象,但首先我们需要提供它的参数

D3DDISPLAYMODE d3ddm;
pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);

在这里,我们创建了一个D3DDISPLAYMODE结构的实例,然后用默认图形适配器显示模式填充它。运行这些命令后,d3ddm将包含有关桌面显示设置的信息,例如分辨率、颜色深度、刷新频率(您可以自定义这些值,稍后教程中会进一步解释),然后我们创建一个D3DPRESENT_PARAMETERS结构的实例

D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.BackBufferFormat = d3ddm.Format;
d3dpp.Windowed = true;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

首先,我们通过调用ZeroMemory宏将其置空(此宏简单地将所有分配的内存用零值填充),然后我们将缓冲区颜色深度设置为与桌面颜色深度相同,并指定程序将在窗口中运行,最后我们指定D3D_SWAPEFFECT_DISCARD,这使得Direct3D在开始绘制后用随机值填充缓冲区(此选项通常用于调试目的,以确保我们正确地清除了屏幕)。我们所做的一切都是为了准备d3dpp,以便将其作为第五个参数传递给IDirect3D8:CreateDevice函数。

if(FAILED(pD3D->CreateDevice( D3DADAPTER_DEFAULT,
   D3DDEVTYPE_HAL, hWnd,
   D3DCREATE_SOFTWARE_VERTEXPROCESSING,
   &d3dpp, &pDevice))){
   return false;
}

第一个参数指定我们的IDirect3DDevice8对象使用默认适配器。第二个参数是设备类型,我们将其设置为D3DDEVTYPE_HAL,它使设备在硬件抽象层中创建,而不是D3DDEVTYPE_REF,后者导致在软件层中创建缓冲区,这比硬件慢,但支持完整的特性集,用于调试目的。下一个参数只是我们窗口的句柄,第四个参数指定Direct3D应在软件中处理所有顶点操作,这也可以是D3DCREATE_HARDWARE_VERTEXPROCESSING,用于硬件顶点处理,通常更快,但仅支持部分显卡。第五个参数指定我们通过d3dpp使用的设备显示模式,以及定义其他属性。最后,pDevice是指针,用于保存创建的Direct3D设备。好了,Direct3D现在应该已成功初始化,现在是时候使用RenderD3DScene函数进行绘图了。

pDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1,0);
pDevice->Present(NULL,NULL,NULL,NULL);

首先,我们使用IDirect3DDevice8:Clear()函数将颜色缓冲区填充为黑色。第一个参数是我们想要清除的区域数量,设置为0表示我们想要清除整个缓冲区。第二个参数是指向我们要清除的矩形数组的指针,将第一个参数指定为0会忽略此参数,所以我们使用NULL。下一个参数指定缓冲区类型,在以后的教程中您将了解其他类型的缓冲区。第四个参数指定颜色,您可以使用D3DCOLOR_XRGB(r,g,b)宏来计算您想要的颜色,在这种情况下,0是黑色。最后两个使用的参数是深度缓冲区和模板缓冲区,您将在以后学习它们,现在只需使用默认值。然后,我们使用Present函数将缓冲区呈现到屏幕上,现在只需为参数使用NULL,它们将在以后的教程中更详细地解释。

结论

好了,编译代码,向Direct3D编程世界问好吧!如果有什么看似复杂的地方,目前不用担心,您很快就会熟悉Direct3D的。继续看接下来的教程,您也可以尝试更改一些值。如果您在DirectX文档中阅读有关已解释函数的更多信息,这将极大地帮助您理解程序是如何工作的。最后,如果您有任何问题,请随时通过联系我。祝您好运!

© . All rights reserved.