`
xitong
  • 浏览: 6193756 次
文章分类
社区版块
存档分类
最新评论

DirectX 3D编程及其最简单例子

 
阅读更多

原文地址:http://blog.csdn.net/handsome0916/article/details/4636825

界面编程一直是程序员的一个比较高的门槛,Windows上最强大的3D库DirectX和开源的OpenGL库虽然强大,但是资料寥寥无几。再加上其复杂的变量类型和结构体,很多人望而却步。

大名鼎鼎的魔兽争霸是基于DirectX库上运行的,而反恐精英则使用了OpenGL技术。在图形界面的运行效率上,原来Windows自带的底层GDI库我认为已经比较高效,但DirectX却更神奇。DirectX有强大的图形库,直接和显卡的GPU打交道,而且封装了非常复杂繁琐的操作指令,我个人比较喜研究神奇的技术。

我也是DirectX的一名初学者,假如你对DirectX已经很熟,本文没有什么参考价值。由于水平有限,所以可能会有说错的地方。

一年前在网上搜了一下,DirectX的资料实在少得可怜。英文版的实在难看,于是在网上直接下载了个Microsoft DirectX SDK (April 2006),期待在帮助中找到例子。

Microsoft DirectX SDK (April 2006)的帮助有C++和.Net的例子,C++的例子都能编译通过,但是VS2008对DirectX的兼容性好像不是很好。使用VS2008打开.net的例子需要版本转换,转换后编译不通过,在他的例子里修改了一下,好不容易通过了,但是下一个例子又要改。

最近重拾对DirectX的兴趣,到微软网站下载了最新的SDK,Microsoft DirectX SDK (August 2009)。这个版本的例子和帮助中,直接去掉了.Net的例子。可能是由于我水平问题没有下载对的版本,也可能是.net对DirectX的调用还不是很方便,于是看来学DirectX,没有什么捷径好走了,还得去面对复杂而高效的C++。

我在微软的官方网站上下载DirectX的SDK是不用收费的,大家大可不用第一时间考虑有没有试用版,直接到官方网站下载。http://www.microsoft.com/directx,下载最新版本。

学习DirectX比较好的教程应该是Andy Pike写的教程,但那是针对老版本的DirectX 8,而且是英文的。网上有Aman JIANG将它的教程译成中文的版本,大家可以去搜搜。

安装了SDK后,有一些简单的例子。但是微软认为简单的例子对于DirectX的初学者来说,一点也不简单,因为它们为20多个例子写了一个通用框架,20多个例子都去调用这些公共类,这个通用框架很多东西是对于最简单的例子是没有必要的,影响了代码的阅读性。这个我和Aman JIANG一样的认为。所以对于DirectX初学者来说,SDK的帮助其实帮助不大。假如你的水平非常高,可以阅读使用它自带的例子,它的例子有VS2005和VS2008两个版本,大家可以用VS2005和VS2008这两个编辑工具直接打开对应的例子去阅读,假如你用惯了VS6.0,那么也可以用VS6.0去编写,头文件和库文件在安装目录的include和lib目录,记得要附加编译才能通过。

于是我还是回到最原始,使用Andy Pike的最原始例子,建立最原始的win32程序,使用DirectX的最简单的函数,最后是编译通过了,但是要注意,Andy Pike的例子仅仅是DirectX8的,我们下载的是最新的DirectX9,10,11的SDK,已经没有DirectX8的库了,所以我们能要做相应的修改。

下面我以一个不断旋转的正方体做一个例子,附上全部代码:(对Andy Pike的DX8的例子作了相应版本转换的修改)

阅读本例子需要一定的win32的编程基础,假如你不熟悉,很难看懂此代码,可以到我的上一篇文章去把win32的编程基础看懂。

#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
 
#include <d3dx9.h>
//d3dx8.lib d3d8.lib
LPDIRECT3D9 g_pD3D = NULL;
LPDIRECT3DDEVICE9 g_pD3DDevice = NULL;
LPDIRECT3DVERTEXBUFFER9 g_pVertexBuffer = NULL; // Buffer to hold vertices
 
struct CUSTOMVERTEX
{
    FLOAT x, y, z;                     
    DWORD colour;
};
 
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
 
 
#define SafeRelease(pObject) if(pObject != NULL) {pObject->Release(); pObject=NULL;}
 
HRESULT InitialiseD3D(HWND hWnd)
{
    //First of all, create the main D3D object. If it is created successfully we
    //should get a pointer to an IDirect3D8 interface.
    g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
    if(g_pD3D == NULL)
    {
        return E_FAIL;
    }
 
    //Get the current display mode
    D3DDISPLAYMODE d3ddm;
    if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm)))
    {
        return E_FAIL;
    }
 
    //Create a structure to hold the settings for our device
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));
 
    //Fill the structure.
    //We want our program to be windowed, and set the back buffer to a format
    //that matches our current display mode
    d3dpp.Windowed = TRUE;
    //d3dpp.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC;
         d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = d3ddm.Format;
 
    //Create a Direct3D device.
    if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                   D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDevice)))
    {
        return E_FAIL;
    }
   
         //Turn on back face culling. This is becuase we want to hide the back of our polygons
    g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
 
         //Turn off lighting becuase we are specifying that our vertices have colour
    g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
 
    return S_OK;
}
 
HRESULT InitialiseVertexBuffer()
{
    VOID* pVertices;
   
    //Store each point of the cube together with it's colour
         //Make sure that the points of a polygon are specified in a clockwise direction,
         //this is because anti-clockwise faces will be culled
         //We will use a three triangle strips to render these polygons (Top, Sides, Bottom).
    CUSTOMVERTEX cvVertices[] =
    {       
                   //Top Face
                   {-5.0f, 5.0f, -5.0f, D3DCOLOR_XRGB(0, 0, 255),},    //Vertex 0 - Blue
        {-5.0f, 5.0f, 5.0f, D3DCOLOR_XRGB(255, 0, 0),},              //Vertex 1 - Red
        {5.0f, 5.0f, -5.0f, D3DCOLOR_XRGB(255, 0, 0),},              //Vertex 2 - Red
                   {5.0f, 5.0f, 5.0f, D3DCOLOR_XRGB(0, 255, 0),},                //Vertex 3 - Green
 
                   //Face 1
                   {-5.0f, -5.0f, -5.0f, D3DCOLOR_XRGB(255, 0, 0),},  //Vertex 4 - Red
        {-5.0f, 5.0f, -5.0f, D3DCOLOR_XRGB(0, 0, 255),},    //Vertex 5 - Blue
        {5.0f, -5.0f, -5.0f, D3DCOLOR_XRGB(0, 255, 0),},    //Vertex 6 - Green
                   {5.0f, 5.0f, -5.0f, D3DCOLOR_XRGB(255, 0, 0),},              //Vertex 7 - Red
 
                   //Face 2
                   {5.0f, -5.0f, 5.0f, D3DCOLOR_XRGB(0, 0, 255),},              //Vertex 8 - Blue
        {5.0f, 5.0f, 5.0f, D3DCOLOR_XRGB(0, 255, 0),},                //Vertex 9 - Green
                  
                   //Face 3
        {-5.0f, -5.0f, 5.0f, D3DCOLOR_XRGB(0, 255, 0),},    //Vertex 10 - Green
                   {-5.0f, 5.0f, 5.0f, D3DCOLOR_XRGB(255, 0, 0),},              //Vertex 11 - Red
 
                   //Face 4
        {-5.0f, -5.0f, -5.0f, D3DCOLOR_XRGB(255, 0, 0),},  //Vertex 12 - Red
        {-5.0f, 5.0f, -5.0f, D3DCOLOR_XRGB(0, 0, 255),},    //Vertex 13 - Blue
 
                   //Bottom Face
                   {5.0f, -5.0f, -5.0f, D3DCOLOR_XRGB(0, 255, 0),},    //Vertex 14 - Green
        {5.0f, -5.0f, 5.0f, D3DCOLOR_XRGB(0, 0, 255),},              //Vertex 15 - Blue
        {-5.0f, -5.0f, -5.0f, D3DCOLOR_XRGB(255, 0, 0),},  //Vertex 16 - Red
                   {-5.0f, -5.0f, 5.0f, D3DCOLOR_XRGB(0, 255, 0),},    //Vertex 17 - Green
    };
 
    //Create the vertex buffer from our device.
 
 
    if(FAILED(g_pD3DDevice->CreateVertexBuffer(18 * sizeof(CUSTOMVERTEX),
                                               0, D3DFVF_CUSTOMVERTEX,
                                               D3DPOOL_DEFAULT, &g_pVertexBuffer,NULL)))
    {
        return E_FAIL;
    }
 
 
    //Get a pointer to the vertex buffer vertices and lock the vertex buffer
    //if(FAILED(g_pVertexBuffer->Lock(0, sizeof(cvVertices), (BYTE**)&pVertices, 0)))
         if(FAILED(g_pVertexBuffer->Lock(0, sizeof(cvVertices), (void**)&pVertices, 0)))
    {
        return E_FAIL;
    }
 
    //Copy our stored vertices values into the vertex buffer
    memcpy(pVertices, cvVertices, sizeof(cvVertices));
 
    //Unlock the vertex buffer
    g_pVertexBuffer->Unlock();
 
    return S_OK;
}
 
 
void SetupRotation()
{
    //Here we will rotate our world around the x, y and z axis.
    D3DXMATRIX matWorld, matWorldX, matWorldY, matWorldZ;
   
         //Create the transformation matrices
         D3DXMatrixRotationX(&matWorldX, timeGetTime()/400.0f);
         D3DXMatrixRotationY(&matWorldY, timeGetTime()/400.0f);       
         D3DXMatrixRotationZ(&matWorldZ, timeGetTime()/400.0f);      
 
         //Combine the transformations by multiplying them together
         D3DXMatrixMultiply(&matWorld, &matWorldX, &matWorldY);
         D3DXMatrixMultiply(&matWorld, &matWorld, &matWorldZ);
 
         //Apply the tansformation
    g_pD3DDevice->SetTransform(D3DTS_WORLD, &matWorld);
}
 
void SetupCamera()
{
         //Here we will setup the camera.
         //The camera has three settings: "Camera Position", "Look at Position" and "Up Direction"
         //We have set the following:
         //Camera Position:  (0, 0, -30)
         //Look at Position: (0, 0, 0)
         //Up direction:                   Y-Axis.
    D3DXMATRIX matView;
    D3DXMatrixLookAtLH(&matView, &D3DXVECTOR3(0.0f, 0.0f,-30.0f),          //Camera Position
                                 &D3DXVECTOR3(0.0f, 0.0f, 0.0f),          //Look At Position
                                 &D3DXVECTOR3(0.0f, 1.0f, 0.0f));                  //Up Direction
    g_pD3DDevice->SetTransform(D3DTS_VIEW, &matView);
}
 
void SetupPerspective()
{
         //Here we specify the field of view, aspect ration and near and far clipping planes.
    D3DXMATRIX matProj;
    D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, 1.0f, 1.0f, 500.0f);
    g_pD3DDevice->SetTransform(D3DTS_PROJECTION, &matProj);
}
 
 
void Render()
{
    if(g_pD3DDevice == NULL)
    {
        return;
    }
 
    //Clear the backbuffer to black
    g_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
   
    //Begin the scene
    g_pD3DDevice->BeginScene();
   
         //Setup the rotation, camera, and perspective matrices
    SetupRotation();
         SetupCamera();
         SetupPerspective();
 
 
    //Rendering our objects
         //STDMETHOD(SetStreamSource)(THIS_ UINT StreamNumber,IDirect3DVertexBuffer9* pStreamData,UINT OffsetInBytes,UINT Stride) PURE;
    g_pD3DDevice->SetStreamSource(0, g_pVertexBuffer,0, sizeof(CUSTOMVERTEX));
    //g_pD3DDevice->SetVertexShader((IDirect3DVertexShader9*)D3DFVF_CUSTOMVERTEX);
         g_pD3DDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
    g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);              //Top
         g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 8);              //Sides
         g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 14, 2);  //Bottom
 
    //End the scene
    g_pD3DDevice->EndScene();
   
    //Filp the back and front buffers so that whatever has been rendered on the back buffer
    //will now be visible on screen (front buffer).
    g_pD3DDevice->Present(NULL, NULL, NULL, NULL);
}
 
void CleanUp()
{
    SafeRelease(g_pVertexBuffer);
    SafeRelease(g_pD3DDevice);
    SafeRelease(g_pD3D);
}
 
void GameLoop()
{
    //Enter the game loop
    MSG msg;
    BOOL fMessage;
 
    PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE);
   
    while(msg.message != WM_QUIT)
    {
        fMessage = PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE);
 
        if(fMessage)
        {
            //Process message
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            //No message to process, so render the current scene
                            Render();
        }
 
    }
}
 
//The windows message handler
LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        break;
        case WM_KEYUP:
            switch (wParam)
            {
                case VK_ESCAPE:
                    //User has pressed the escape key, so quit
                    DestroyWindow(hWnd);
                    return 0;
                break;
            }
        break;
 
    }
 
    return DefWindowProc(hWnd, msg, wParam, lParam);
}
 
//Application entry point
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, INT)
{
    //Register the window class
    WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_CLASSDC, WinProc, 0L, 0L,
                     GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
                     "DX Project 3", NULL};
    RegisterClassEx(&wc);
 
    //Create the application's window
    HWND hWnd = CreateWindow("DX Project 3", "www.andypike.com: Tutorial 3",
                              WS_OVERLAPPEDWINDOW, 50, 50, 500, 500,
                              GetDesktopWindow(), NULL, wc.hInstance, NULL);
 
    //Initialize Direct3D
    if(SUCCEEDED(InitialiseD3D(hWnd)))
    {
        //Show our window
        ShowWindow(hWnd, SW_SHOWDEFAULT);
        UpdateWindow(hWnd);
 
        //Initialize Vertex Buffer
        if(SUCCEEDED(InitialiseVertexBuffer()))
        {
            //Start game running: Enter the game loop
            GameLoop();
        }
    }
   
    CleanUp();
 
    UnregisterClass("DX Project 3", wc.hInstance);
   
    return 0;
}
 

游戏动起来是怎样实现的呢?为什么我们设计的模型能像电影那样动起来呢?

我们在main函数的最后,调用了一个自定义叫GameLoop的函数,通过死循环的方式不断去调用自定义的Render函数名的函数,去刷新屏幕的显示。

其实游戏跟电影一样,也是这样将画面快速地更换,加上DirectX绘画的高效性,我们感觉不到画面其实是一卡一卡的。

DX界面的一个很重要的概念是设备(device)g_pD3DDevice,其实跟我们平时用到的GDI的DC类似,设备就是一个要绘制的对象,我们将画面绘制到设备上。

好了,这几乎是最简单的例子了,在SDK上所谓最简单的例子,其实比这个要复杂很多。初学者可以用这个作为最基本框架,作为参考去读它自带的更接近应用的框架。

值得注意的是,DX的3D的概念中,所有的3D图形都是由无数的三角形组成,一个圆球其实也是用无数个三角形构成,三角形越多,效果越平滑,跟数学上曲线是由无数折线构成的原理是一样的,当然,三角形越多消耗的GPU的处理时间当然也越多。假如你的立体几何的逻辑建模能力非常优秀,不用任何3D建模工具都能通过无数个三角形和颜色组合构建出一个物件或者人物,但我想,应该没有这么牛比的人吧。


分享到:
评论

相关推荐

    精通DirectX.3D图形与动画程序设计.pdf

    2.6 最简单的direct3d程序  2.6.1 工程项目和开发环境设置 2.6.2 创建窗口 2.6.3 初始化direct3d 2.6.4 消息循环 2.6.5 渲染图形 2.6.6 结束direct3d程序  2.7 direct3d设备对象深入探讨 2.8 direct3d表面 2.9 小...

    游戏编程--大师技巧

     世界上最简单的Windows程序  真实的Windows应用程序  Windows类  注册Windows类  创建窗口  事件处理程序  主事件循环  产生一个实时事件循环  打开多个窗口  总结  第三章 高级Windows编程  使用资源...

    游戏编程中的物理建模(中文删节版)

    了很多 3D 开发方面的书籍也做了一些例子程序,但是对 3D开发还是有许多未知,自从我 见到这书以后,我终于明白我缺少的是什么了?其实就是需要一条线把我所学过的这些知识 全部串起来,反观当下无论是纸皮书还是...

    DirectX教程 入门知识

    在下面的例子中,我们将利用Visual C++5.0来生成一个简单的DirectDraw应用程序。程序的创建将不使用方便的MFC(Microsoft Foundation Class Library,微软的C++基础类库)向导,而是使用最原始的Win32 应用程序开发...

    wpf编程宝典c#2010版pdf(全)1/3包,共118M

    书中不仅全面介绍了常见的图形界面编程技术,而且对WPF中非常有特色的文档和打印、音频和视频、动画、3D图形开发、多线程和插件等内容也进行了比较深入的介绍。 第1章 WPF概述  1.1 Windows图形演化  1.1.1 ...

    Delphi编程大师2003 1of5

    不但能使你简单的操控Delphi进行编程.而且能对初学者进行深入浅出的教学. 同时Delphi的原代码能帮助各位Delphi爱好者在编程过程中得到不同的启发与参考. 本软件含有: BorlandDelphi7.06中文版 BorlandDelphi6中文...

    Delphi编程大师2003 5of5

    不但能使你简单的操控Delphi进行编程.而且能对初学者进行深入浅出的教学. 同时Delphi的原代码能帮助各位Delphi爱好者在编程过程中得到不同的启发与参考. 本软件含有: BorlandDelphi7.06中文版 BorlandDelphi6中文...

    Delphi编程大师2003 3of5

    不但能使你简单的操控Delphi进行编程.而且能对初学者进行深入浅出的教学. 同时Delphi的原代码能帮助各位Delphi爱好者在编程过程中得到不同的启发与参考. 本软件含有: BorlandDelphi7.06中文版 BorlandDelphi6中文...

    Delphi编程大师2003 2of5

    不但能使你简单的操控Delphi进行编程.而且能对初学者进行深入浅出的教学. 同时Delphi的原代码能帮助各位Delphi爱好者在编程过程中得到不同的启发与参考. 本软件含有: BorlandDelphi7.06中文版 BorlandDelphi6中文...

    Delphi编程大师2003 4of5

    不但能使你简单的操控Delphi进行编程.而且能对初学者进行深入浅出的教学. 同时Delphi的原代码能帮助各位Delphi爱好者在编程过程中得到不同的启发与参考. 本软件含有: BorlandDelphi7.06中文版 BorlandDelphi6中文...

    vc++ 开发实例源码包

    DirectX 实例 DES加密算法源代码 如题。 Detected memory leaks 检查内存泄漏源码 DigiStatic_src 自绘CStatic实现数字效果。 DirectShow开发指南pdf附属代码 如题。 DirectShow开发指南源码 如题。 directUI_...

    vc++ 应用源码包_5

    DirectX 实例 DES加密算法源代码 Detected memory leaks 检查内存泄漏源码 DigiStatic_src 自绘CStatic实现数字效果。 DirectShow开发指南pdf附属代码 DirectShow开发指南源码 directUI_D DirectUI界面库 DOM...

    vc++ 应用源码包_6

    DirectX 实例 DES加密算法源代码 Detected memory leaks 检查内存泄漏源码 DigiStatic_src 自绘CStatic实现数字效果。 DirectShow开发指南pdf附属代码 DirectShow开发指南源码 directUI_D DirectUI界面库 DOM...

    vc++ 应用源码包_3

    DirectX 实例 DES加密算法源代码 Detected memory leaks 检查内存泄漏源码 DigiStatic_src 自绘CStatic实现数字效果。 DirectShow开发指南pdf附属代码 DirectShow开发指南源码 directUI_D DirectUI界面库 DOM...

    vc++ 应用源码包_1

    DirectX 实例 DES加密算法源代码 Detected memory leaks 检查内存泄漏源码 DigiStatic_src 自绘CStatic实现数字效果。 DirectShow开发指南pdf附属代码 DirectShow开发指南源码 directUI_D DirectUI界面库 DOM...

    vc++ 应用源码包_2

    DirectX 实例 DES加密算法源代码 Detected memory leaks 检查内存泄漏源码 DigiStatic_src 自绘CStatic实现数字效果。 DirectShow开发指南pdf附属代码 DirectShow开发指南源码 directUI_D DirectUI界面库 DOM...

    Visual C++音频视频处理技术及工程实践(含源码2/2)

    本书共16章,分为4篇,详细讲解了使用各种软件和平台进行音、视频多媒体编程的技术,以案例为对象展示实现过程、分析技术难点。主要内容包括软件Visual C++2005的开发技术、DirectSound开发音频、DirectShow/VFW开发...

Global site tag (gtag.js) - Google Analytics