direct x基础 二

来源:互联网 发布:淘宝客如何推广才挣钱 编辑:程序博客网 时间:2024/05/29 10:24

转自     http://blog.csdn.net/eclaix/article/details/6372791


3D引擎与底层图形接口。

在真正的开发过程中,我们应该很少有机会直接使用底层的图形接口(DirectX或OpenGL ).因为图形接口直接处理顶点这种最基本数据。直接使用他们编程不是很方便。而3D引擎负责将底层的图形接口进行抽象,形成容易编程的逻辑接口。

但遗憾的是如果对底层接口不了解,似乎也不能发挥3D引擎真正的功效。^_^

毕竟引擎也只是提供一种手段,来方便我们使用图形接口而已。

 

So,如果希望得到比较高级的图形效果,那么对图形接口的了解,是必要地。

因为在游戏领域DirectX已经逐渐超越了OpenGL,坐上了第一把交椅,所以选择DirectX作为说明对象。现在DirectX主要有三个版本。Ver9, Ver10, Ver11。可以说DirectX9是一个Base,Ver10和11是它的强化版(个人理解)。而且很多基本概念都都可以从DirectX9上理解,所以这次介绍的对象是DirectX9。Ver9, Ver10, Ver11之间的区别,特别是它们较新的渲染管线和Shader会在以后的文章中介绍。(感兴趣的同学可以查阅最新的DirectX图形部分文档。)

另外,DirectX包括很多部分:Direct3D, DirectSound, DirectxInput等。图形部分特指Direct3D。

 

初级篇大概分成5个部分。

1.      基本概念以及D3D设备

2.      D3D资源, 顶点, 变换

3.      光和材质

4.      纹理(texture)及表面(surface)

5.      X文件与mesh

而且根据每个部分的内容,都会附上一段

Tutorial代码,帮助理解。(Tutorial全部来自DirectX Sample。因为它们是官方例子,而且可以充分代表相关部分的内容。最重要的是免去了自己动手的麻烦。。。^O^)

  

另外,如果希望进行DirectX相关编程,需要安装DirectX的SDK。注意不是运行文件。

可以从这个地址下载:

http://msdn.microsoft.com/en-us/directx/aa937788

 

-------------------------------------------------------------------

那么, 第一部分: 基本概念以及D3D设备

1.      DirectX3D概要介绍

下边这张图来自D3D手册. 它表现了windows应用与D3D,GDI,和图形硬件之间的关系. 可以看到, D3D直接或者通过Hal设备来操作图形硬件的设备驱动接口(DDI). 也就是说Win32应用需要通过D3D接口来使用图形硬件的各种功能.

HAL是Hardware abstraction layer的缩写. 顾名思义, 它是硬件的抽象层. 具体怎么抽象我们不需要关注, 只要意识到因为它的存在, D3D可以方便的工作在多种硬件上.

GDI是Graphics Device Interface的缩写. 是微软制作的图形设备接口. 平时画各种窗体时使用的是这一套接口. – 注意, 非游戏专用.

 

 

 

2. D3D设备的介绍, 申请, 释放. COM对象.

根据上一节的内容, 我们可以了解D3D实际是对图形设备的抽象, (或者说是使用图形设备的一种手段) .

D3D手册中是这样定义D3D设备的: 一个D3D设备是D3D的一个渲染组件, 它封装并存储了渲染状态. 一个D3D设备主要执行变换, 光照计算和 将图像光栅化到表面.( rasterizes an image to a surface).

 

 

另外, D3D设备有2个种类:

Hal Device. 这种设备直接使用硬件加速. 也是平时我们使用的设备.

Reference Device. 这种设备不使用硬件加速. 只有在debug的时候使用.(比如你想使用一个特性, 但是显卡又不支持,那么只好使用这个软件模拟的东西.) 而且, 需要注意的是, 这个东西慢的要死..

刚开始接触D3D的朋友一定对这段说明感到困惑. 没有关系, 因为这个算是D3D设备的定义,直接来自手册, 无法理解是正常的. 只需要知道, 设备有两种类型: HAL 和 REF , 就可以继续进行了.

 

那么我们第一步就来了解如何申请, 释放这个图形设备.

申请主要分两个步骤. 根据版本号来创建Direct3D对象.

然后, 根据参数创建具体的Direct3D渲染设备.

申请D3D图形设备:

    // 声明管理指针

IDirect3D9 * g_pD3D = NULL// D3D对象

IDirect3DDevice9 * g_pd3dDevice = NULL// 我们的D3D渲染设备

 

    // 首先, 创建一个D3D对象. 可以看到, 需要传递版本号作为参数.

    g_pD3D = Direct3DCreate9D3D_SDK_VERSION )

   

// 之后, 设置D3D设备的参数. 之后创建设备的时候会使用它.

    D3DPRESENT_PARAMETERS d3dpp;

    ZeroMemory( &d3dppsizeofd3dpp ) );

    d3dpp.Windowed = TRUE;  //  窗口模式

    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;  //  一种提交back buffer的方式. 效率最高

    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;   //  默认back buffer格式. 与当前显示模式一致

 

    // 之后, 我们创建一个渲染设备.  

    g_pD3D->CreateDeviceD3DADAPTER_DEFAULT,   // 使用默认显卡

D3DDEVTYPE_HAL,         // HAL设备. 使用硬件加速.

hWnd,                   // 窗体句柄. 渲染出来的图像显示在这个窗体里.

                        D3DCREATE_SOFTWARE_VERTEXPROCESSING,  // 选择软件处理顶点. 一般情况下, 我们都需要使用硬件来处理顶点. 因为速度更快. 只有不支持这个功能的情况下才用这个参数.

                        &d3dpp,                // 刚才配置的参数.

&g_pd3dDevice ) )      // 输出. 生成的D3D渲染设备.

 

--------------------- 分割 --------------------------

释放D3D图形设备:

    ifg_pd3dDevice != NULL )

        g_pd3dDevice->Release();

 

    ifg_pD3D != NULL )

        g_pD3D->Release();

 

以上就是最小限的申请, 释放操作. 第一次接触的话, 可能对有些做法有些疑问.

比如g_pD3D通过函数返回值得到, 而g_pd3dDevice为什么变成了返回值方式?

释放的时候, 不是使用delete而是release()方法?

原因是因为, D3D对象都是COM对象.

而Direct3DCreate9()这个函数, 并非COM方法, 传递进去的版本号, 也是为了生成必要的CLSID.

而在使用g_pD3D->CreateDevice()方法时, 已经变成对COM对象的操作. 需要遵守COM协议. COM协议的一个重要机制, 就是返回值必须是HRESULT类型. 用来标明成功&失败信息.

而且COM对象释放时, 不能直接Delete, 必须调用自身的release()方法.

另外, 所有的COM接口都具有前缀大写字母 I , 通过这一点, 可以方便的辨认.

关于COM的讨论已经超出这篇文章的范围, 具体需要查阅相关资料.

 

3.      渲染过程, Buffer交换.

这一节中主要讨论D3D的渲染过程.

一个最小限度的渲染函数如下.

其中有4个动作. Clear(). BeginScene(). EndScene(). Present().

VOID Render()

{

    // 将backbuffer设置为蓝色.

    g_pd3dDevice->Clear( 0, NULLD3DCLEAR_TARGETD3DCOLOR_XRGB( 0, 0, 255 ), 1.0f, 0 );

 

    // 开始这个scene的渲染.

    ifSUCCEEDEDg_pd3dDevice->BeginScene() ) )

    {

        // 各种渲染指令在这部分追加.

 

        // 结束这个scene.

        g_pd3dDevice->EndScene();

    }

 

    // 提交这个back buffer.

    g_pd3dDevice->PresentNULLNULLNULLNULL );

}

对于其中的back buffer 和 提交(present)动作, 有必要说明.

假设你的显示器分辨率为 1280*720. 那么也就是说存在 1280*720 = 921 600个象素点.(720p 为HD格式) 那么, ARGB(4字节)的格式下, 需要 921600 * 4 = 3 686 400 字节的buffer来更新一桢图像. (知道为什么显存一定要大了把.^_^)

然后, 一桢图像的数据提交给硬件以后, 一般是不可以修改的. 那么, 接下来的一桢还是要继续描绘的, 所以, 这样用于显示的buffer, 至少要2个buffer. 假设它们为BufferA和BufferB. 当BufferA绘制完以后, 提交给硬件. 然后继续绘制BufferB. 当第BufferB绘制完成后, 提交; BufferA从硬件中解放, 接下来的绘制在BufferA中进行. 渲染就是这个动作的不断重复.

其中, 提交给硬件的就是Front Buffer. 而在绘制中的就是Back Buffer.

 

 

每次导致Back Buffer和Front Buffer交换的动作, 就是提交(present())函数来实现的.

 

如果提交了一个桢数据, 而不通过present()函数来切换(swap)它的话, 那么用户将一直看到这副图像, 也就是成了静止画.

 

为了保证用户看到连续的图像, 必须保证每秒至少切换24次(电影标准). 也就是我们通常会接触到桢率这个概念:FPS(frame per second). 它的数值代表了每秒切换的次数. 大家都知道这个值是越高越好. 通常的HD标准的话, 要求是每秒切换60次. 也就是60fps. 这样人物的动作更细腻, 也更逼真.

那么, 为了达到1秒切换60次,平均留给每一桢的处理时间只有1/60秒. 是非常短的时间. 所以实时(real time)3D游戏,对计算机的性能, 还有程序的实现都有很高的要求.

作为程序开发者的我们, 写出低效率的程序, 是不被允许的^_^.

 

4.      简单游戏循环

根据以上说明, 整理一个最简单的游戏循环.

---------------------------

设置系统状态.

构建场景.

  For()

{

  1. 处理用户输入. – 处理用户命令.

  2. 根据消耗的时间(timeSinceLastFrame)更新系统状态. – 比如有一个等待1s执行的脚本命令, 需要判断它是否需要执行.

  3. 根据消耗的时间(timeSinceLastFrame)更新game unit状态. – 各个游戏单元的位置, 动画状态等更新.

  4. 各种状态更新完毕以后, 更新显示用数据, 提交给硬件进行显示. (BackBuffer渲染后-> present())

}

 

清除场景

释放各种资源

---------------------------

 

5.      例子代码.

因为本节主要说明D3D设备的申请, 释放 和 一个最简单的渲染过程.

所以选取了D3D 例子的 Tutorial 1: CreateDevice 来作为我们的例子程序. 大家可以直接从DirectX Sample Browser来获取.

//-----------------------------------------------------------------------------

// File: CreateDevice.cpp

// 这段代码只是申请释放D3D设备, 并在每桢提交back buffer.

//-----------------------------------------------------------------------------

#include <d3d9.h>  // 必要的头文件

 

// 设备的指针.

IDirect3D9 * g_pD3D = NULL// D3D对象

IDirect3DDevice9 * g_pd3dDevice = NULL// 我们的D3D渲染设备

 

// Name: InitD3D() Desc: Initializes Direct3D

HRESULT InitD3DHWND hWnd )

{

    // Create the D3D object, which is needed to create the D3DDevice.

    ifNULL == ( g_pD3D = Direct3DCreate9D3D_SDK_VERSION ) ) )

        return E_FAIL;

 

    // Set up the structure used to create the D3DDevice.

    D3DPRESENT_PARAMETERS d3dpp;

    ZeroMemory( &d3dppsizeofd3dpp ) );

    d3dpp.Windowed = TRUE;

    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

 

    // Create the Direct3D device. Here we are using the default adapter (most

    ifFAILEDg_pD3D->CreateDeviceD3DADAPTER_DEFAULTD3DDEVTYPE_HALhWnd,

                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,

                                      &d3dpp, &g_pd3dDevice ) ) )

    {

        return E_FAIL;

    }

 

    // Device state would normally be set here

    return S_OK;

}

 

// Name: Cleanup() Desc: Releases all previously initialized objects

VOID Cleanup()

{

    ifg_pd3dDevice != NULL )

        g_pd3dDevice->Release();

 

    ifg_pD3D != NULL )

        g_pD3D->Release();

}

 

// Name: Render() Desc: Draws the scene

VOID Render()

{

    ifNULL == g_pd3dDevice )

        return;

 

    // Clear the backbuffer to a blue color

    g_pd3dDevice->Clear( 0, NULLD3DCLEAR_TARGETD3DCOLOR_XRGB( 0, 0, 255 ), 1.0f, 0 );

 

    // Begin the scene

    ifSUCCEEDEDg_pd3dDevice->BeginScene() ) )

    {

        // Rendering of scene objects can happen here

 

        // End the scene

        g_pd3dDevice->EndScene();

    }

 

    // Present the backbuffer contents to the display

    g_pd3dDevice->PresentNULLNULLNULLNULL );

}

 

// Name: MsgProc() Desc: The window's message handler

LRESULT WINAPI MsgProcHWND hWndUINT msgWPARAM wParamLPARAM lParam )

{

    switchmsg )

    {

        case WM_DESTROY:

            Cleanup();

            PostQuitMessage( 0 );

            return 0;

 

        case WM_PAINT:

            Render();

            ValidateRecthWndNULL );

            return 0;

    }

 

    return DefWindowProchWndmsgwParamlParam );

}

 

 

// Name: wWinMain() Desc: The application's entry point

INT WINAPI wWinMainHINSTANCE hInstHINSTANCELPWSTRINT )

{

    // Register the window class

    WNDCLASSEX wc =

    {

        sizeofWNDCLASSEX ), CS_CLASSDCMsgProc, 0L, 0L,

        GetModuleHandleNULL ), NULLNULLNULLNULL,

        L"D3D Tutorial"NULL

    };

    RegisterClassEx( &wc );

 

    // Create the application's window

    HWND hWnd = CreateWindowL"D3D Tutorial"L"D3D Tutorial 01: CreateDevice",

                              WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,

                              NULLNULLwc.hInstanceNULL );

 

    // Initialize Direct3D

    ifSUCCEEDEDInitD3DhWnd ) ) )

    {

        // Show the window

        ShowWindowhWndSW_SHOWDEFAULT );

        UpdateWindowhWnd );

 

        // Enter the message loop

        MSG msg;

        whileGetMessage( &msgNULL, 0, 0 ) )

        {

            TranslateMessage( &msg );

            DispatchMessage( &msg );

        }

    }

 

    UnregisterClassL"D3D Tutorial"wc.hInstance );

    return 0;

}

0 0
原创粉丝点击