zoukankan      html  css  js  c++  java
  • D3D学习摘记(I)中

     Note:这是(I)的中篇,并不是一篇独立的主题。它的上篇在这里

     

    InitD3D函数做了些什么

    在具体分析代码前,讲下D3D环境的使用逻辑。在初始化一个D3D环境时,一般只需要做两步工作。第一,创建一个D3D对象;第二,创建一个D3D设备对象。其中,和我们联系最为紧密的是D3D设备对象,它负责显示设备的各个参数设置、修改缓冲区数据等等,是具体工作的实施者。D3D对象呢?对我们而言,它除了创建D3D设备对象,没有什么特别的意义。

    一个D3D设备接口可以简单的认为是本机一块显卡的抽象,它包含了显卡所有的硬件参数及状态值,比如说,显卡显存的数量和起始的线性地址,是否支持深度缓冲(Depth Buffer),雾化(Fog),纹理(Texture) 及MipMap等。

     

    现在我们回顾一下代码。

     


     1 HRESULT InitD3D( HWND hWnd )
     2 
    {
     3     // Create the D3D object, which is needed to create the D3DDevice.

     4     if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
     5         return
     E_FAIL;
     6 

     7     // Set up the structure used to create the D3DDevice. Most parameters are
     8     //
     zeroed out. We set Windowed to TRUE, since we want to do D3D in a
     9     //
     window, and then set the SwapEffect to "discard", which is the most
    10     //
     efficient method of presenting the back buffer to the display.  And 
    11     //
     we request a back buffer format that matches the current desktop display 
    12     // format.

    13     D3DPRESENT_PARAMETERS d3dpp; 
    14     ZeroMemory( &d3dpp, sizeof
    (d3dpp) );
    15     d3dpp.Windowed =
     TRUE;
    16     d3dpp.SwapEffect =
     D3DSWAPEFFECT_DISCARD;
    17     d3dpp.BackBufferFormat =
     D3DFMT_UNKNOWN;
    18 

    19     // Create the Direct3D device. Here we are using the default adapter (most
    20     //
     systems only have one, unless they have multiple graphics hardware cards
    21     //
     installed) and requesting the HAL (which is saying we want the hardware
    22     //
     device rather than a software one). Software vertex processing is 
    23     //
     specified since we know it will work on all cards. On cards that support 
    24     //
     hardware vertex processing, though, we would see a big performance gain 
    25     // by specifying hardware vertex processing.

    26     if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
    27 
                                          D3DCREATE_SOFTWARE_VERTEXPROCESSING,
    28                                       &d3dpp, &
    g_pd3dDevice ) ) )
    29 
        {
    30         return
     E_FAIL;
    31 
        }
    32 

    33     // Device state would normally be set here
    34 
    35     return S_OK;
    36 }

     

    g_pD3D是一个全局的LPDIRECT3D9 型的变量。从SDK中可以查到,LPDIRECT3D9 就是一个IDirect3D9*型的指针,它指向将要创建好的D3D对象。创建工作由函数Direct3DCreate9负责。它接收一个枚举变量D3D_SDK_VERSION(目前它只接受该值 ) ,返回一个创建好的D3D对象。

    为什么这个指针的首字母有个I?这表明,这是一个接口(Interface)。事实上,“D3D对象”以及很多D3D资源都是通过调取COM(Component Object Model)接口获得的。有关COM的知识不在本文讲解范围之内,应该通过其他途径了解它,比如这里(实际上我也仅仅知道它“是什么”)。

    接下来要做的是创建D3D设备对象。该对象是通过D3D对象的CreateDeviece方法创建的。我们看一下SDK中的关于这个方法的介绍。

    HRESULT CreateDevice(
          UINT Adapter,    
          D3DDEVTYPE DeviceType,     
          HWND hFocusWindow,     
          DWORD BehaviorFlags,    
          D3DPRESENT_PARAMETERS *pPresentationParameters,    
          IDirect3DDevice9 **ppReturnedDeviceInterface );

    说一下我对这些参数的理解。

    Adapter : 指定显示设备的编号。主设备的值永远是“D3DADAPTER_DEFAULT”。(对于单显示器的用户(大部分是这样),直接填该值即可)

    Device Type:指定设备类型。前面提过,D3D提供的种种功能,具体实现是由显卡厂商做的HAL(Hard Abstract Layer)负责的。然而如果有些显卡因为老或者没被微软“宠幸”的关系,不支持D3D怎么办?没问题,D3D设定了一种“软件模拟”的设备类型。你可以用主存和cpu模拟任何本应作用于显卡上的计算,而代价就是拖慢系统(cpu和主存的资源被这些计算占据)。D3D还设定了一种比较特别的类型:假定你是一名比较不幸的开发者。假如如此,你的显卡不支持D3D,然而你的用户却支持。这时你就可以用“引用类型”,在开发时依然可以用软件模拟,而在发布时换成了硬件负责。总结一下,上面讲了三种设备类型:硬件、软件、引用。对应的值分别是:D3DDEVTYPE_HAL、D3DDEVTYPE_SW和D3DDEVTYPE_REF。例子用的是D3DDEVTYPE_HAL。

    hFocusWindow:一个窗口句柄,指定该D3D设备对象所联系的win32窗口。一般是当前窗口。例子中是hWnd。

    BehaviorFlags:行为旗标。常用有D3DCREATE_SOFTWARE_VERTEXPROCESSING和D3DCREATE_HARDWARE_VERTEXPROCESSING。分别指示“顶点处理”的工作是由软件模拟还是硬件管线计算。例子中用的是D3DCREATE_SOFTWARE_VERTEXPROCESSING。

    什么是“顶点处理”?这和图形学有密切的联系。我们知道3D图形最初的数据都是关于顶点信息的,比如一个顶点的位置坐标、颜色、透明度、法线等等。三个顶点能构成一个三角形,这个三角形的颜色由最后的“光栅化”阶段根据三个顶点的相关信息,通过插值算法逐一填充落在三角形内的每个像素。而顶点的数据(尤其是坐标)也会随着渲染的不同阶段而发生变化。比如一开始是该顶点本身的局部坐标,接下来会变换到世界坐标,再变换到视图坐标,然后是投影坐标…每变换一次,顶点的数据就会改变一次。另外光照计算时也会影响到顶点的颜色值。所有关于这些顶点信息的处理,是发生在什么地方呢?这就是这个参数所指定的意义。如果你选择了D3DCREATE_SOFTWARE_VERTEXPROCESSING,就会用软件模拟的方式,令cpu和主存处理这样的事情;而如果选择了D3DCREATE_HARDWARE_VERTEXPROCESSING,就会用显卡上的专用硬件来进行专门的处理,从而解放cpu和主存资源。当然,正如前面提过,前提是这块显卡必须具备这样的功能。也就是说,你必须清楚自己的显卡有没有这样的支持才行(一般现在的独立显卡都有)。D3D中有专门的函数可以查看:D3D对象中有一个GetDeviceCaps方法专司此职。请自行查阅相关资料。

    pPresentationParameters: 这是一个指针,指向一个对“显示”方面各种参数(主要是缓冲区)进行设定的结构体。待会具体讲解这个参数。

    ppReturnedDeviceInterface:指向一个D3D设备对象的指针的指针。用它来得到创建好的D3D设备对象。因此该指针你得事先声明。

     

    我们现在来讲pPresentationParameters这个结构的内容。它是一个D3DPRESENT_PARAMETERS型的指针。关于该类型的介绍还是要查看SDK。这里不得不抱怨的是,虽然它仅仅是创建D3D设备对象时需要指定的一个参数,但它本身却是一个更加无比繁杂的结构…是不是头有点大了?不过还好,这些值默认都被初始化为0,而0都是这些参数的常态。如果没有特别要求,一般只需要指定Windowed、SwapEffect和BackBufferFormat三个分量即可(例子就是如此)。不过为了稍稍刨根究底,还是全面扫一下比较好。

    typedef struct _D3DPRESENT_PARAMETERS_ {
        UINT BackBufferWidth, BackBufferHeight;
        D3DFORMAT BackBufferFormat;
        UINT BackBufferCount;
        D3DMULTISAMPLE_TYPE MultiSampleType;
        DWORD MultiSampleQuality;
        D3DSWAPEFFECT SwapEffect;
        HWND hDeviceWindow;
        BOOL Windowed;
        BOOL EnableAutoDepthStencil;
        D3DFORMAT AutoDepthStencilFormat;
        DWORD Flags;
        UINT FullScreen_RefreshRateInHz;
        UINT PresentationInterval;
    } D3DPRESENT_PARAMETERS;

    说下我的理解。

    BackBufferWidth, BackBufferHeight:顾名思义,这是指后台缓冲区的宽度和高度,单位是像素。一般这和窗口大小是相等的(指窗口模式下)。

    BackBufferFormat:指后台缓冲区的像素的数据格式。比如指定RGBA分别占几位。而一般地,在窗口模式下,使用D3DFMT_UNKNOWN会使用当前显示模式使用的像素数据格式。我们使用D3DFMT_UNKNOWN即可。

    BackBufferCount:后台缓冲区的个数,可选值有0,1,2,3. 0会被当做1对待。一般是1。

     

    MultiSampleType:多采样类型。没有太多的体会。一般是 D3DMULTISAMPLE_NONE。注意只有当SwapEffect的值为D3DSWAPEFFECT_DISCARD时,该分量才有效。MultiSampleQuality:多采样质量。值位于0到1之间。当上面的MultiSamplleType有设定时该分量才有效。

     

    SwapEffect:指缓冲区的交换方式。当前后台缓冲区交换后,换下来的那块缓冲区的数据该怎么处理?可以复制,或者丢弃。不同的值效果不同。一般是D3DSWAPEFFECT_DISCARD,表示丢弃。这时就会有新的数据直接覆盖填充这块缓冲区。

    hDeviceWindow:一个窗口句柄会有窗口位置和大小等信息,等到绘制时,后台缓冲区会向前台缓冲区复制数据。而这个分量可以指引D3D设备,让前台缓冲区往屏幕的哪个地方绘制多大的数据。一般都是当前窗口。如果选择0(默认的),就是指当前窗口了。

    Windowed:指定是否是窗口模式。true表示窗口模式,false表示全屏模式。

    EnableAutoDepthStencil:是否开启深度缓存和模板缓存。true表示开启,flase表示不开启。有关深度缓存和模板缓存的知识另行查阅。

    AutoDepthStencilForamt: 如果开启了深度缓存和模板缓存,指定它们的格式。比如指定一个像素的深度位是几位、模板缓存为是几位。注意它和BackBufferFormat用的是同一种枚举类型,只不过取值范围不同而已。

    Flags:旗标。没什么太多的体会。一般为0。

    FullScreen_RefreshRateInHz:全屏模式下的屏幕刷新率。如果窗口模式,则必须为0。一般设为0即可。

     

    PresentationInterval:缓冲区交换频率。一般选择D3DPRESENT_INTERVAL_IMMEDIATE(即为0)即可。表示数据准备好后不要等待,立即交换。

     

     

    当D3D设备对象创建好后,我们的初始化也就完成了。同时InitD3D函数也就写完了。虽然实际上没做多少事,但需要讲解的东西挺多。再稍稍总结一遍。首先,我们调用Direct3DCreate9函数,而该函数又是调用COM接口来创建了一个D3D对象,然后我们再利用这个D3D对象创建了一个D3D设备对象(它调用的也同样是COM接口)。创建D3D设备对象时,我们需要对设备做一些配置(设备类型、顶点处理方式、显示参数配置,等等),而其中显示参数配置因为参数众多,不得不专门列一个结构体出来设定。因此创建一个D3DPRESENT_PARAMETERS型的d3dpp变量设定各个分量值(缓冲区大小、数据格式、交换方式、全屏/窗口,等等)。然后将其作为创建D3D设备对象的一个参数注入到CreateDevice中。ok,搞定收工。

    (未完待续)

     

     
    参考资料:

     

    http://dev.gameres.com/Program/Visual/3D/D3DFirst_1.htm

  • 相关阅读:
    用orgmode写加密日记
    用emacs加密文件(使用ccrypt)
    C#使用注册表添加删除开机启动项
    WPF中使用第三方字体选择器
    使用rdesktop远程连接Windows桌面
    webbrowser 提交按钮没反应的问题解决办法
    C#中webBrowser加载页面中的不同域的iFrame的源代码的取得
    C# 天涯博客验证码识别(转)
    webbroser 清除COOKIES的解决办法
    使用C#实现ADSL自动拨号
  • 原文地址:https://www.cnblogs.com/lookof/p/1561559.html
Copyright © 2011-2022 走看看