精华内容
下载资源
问答
  • DirectX 10

    2009-08-19 19:09:00
    DirectX 10 DirectX 10 几何渲染单元 在DirectX 10的图形流水线体系中,最大的结构性变化就是在几何处理阶段增加了几何渲染单元(Geometry Shader)。几何渲染单元被附加在顶点渲染单元之后,但它并不像顶点渲染...

    DirectX 10

      DirectX 10
      
      几何渲染单元

      在DirectX 10的图形流水线体系中,最大的结构性变化就是在几何处理阶段增加了几何渲染单元(Geometry Shader)。几何渲染单元被附加在顶点渲染单元之后,但它并不像顶点渲染单元那样输出一个个顶点,而是以图元作为处理对象。图元在层次上比顶点高一级,它由一个或多个顶点构成。由单个顶点组成的图元被称为“点”,由两个顶点组成的图元被称为“线”,由三个顶点组成的图元被称为“三角形”。几何渲染单元支持点、线、三角形、带邻接点的线、带邻接点的三角形等多种图元类型,它一次最多可处理六个顶点。借助丰富的图元类型支持,几何渲染单元可以让GPU提供更精细的模型细节。
      几何渲染单元赋予GPU自行创造新几何物体、为场景添加内容的神奇能力。灵活的处理能力使GPU更加通用化,以往很多必须倚靠CPU才能完成的工作,现在完全可交由GPU处理。如此一来,CPU就有更多时间处理人工智能、寻址等工作。更令人惊喜的是,几何渲染单元还让物理运算的加入变得更简单,DirectX 10可创建具备物理特性的盒子、模拟刚性物体,物理运算有望在它的带领下逐渐走向普及。可以预见,借助几何渲染单元这一武器,显卡性能将产生质的飞跃,我们也将体验到速度更流畅、画面更精美、情节更细致的游戏。
      改进的API和驱动功效
      我们知道,每一个游戏角色、武器和景物在3D程序中都是一个Object(对象),而每一帧游戏画面就可能出现数百个Object。在显卡工作时,每一个Object都要从应用程序传输到API接口,然后通过显卡驱动程序到达显卡。在现有的DirectX体系中,任何一个Object进行操作或者渲染,都会导致系统资源的额外消耗,游戏的Object越多,所耗费的传递时间就越长,造成的额外消耗也就越多。据统计,现有的DirectX 9图形芯片在工作时,只有60%的性能用于运算3D程序,其余40%的运算能力被白白浪费了!
      为了改变这一现状,DirectX 10在渲染程序中采用了动态索引功能,Object被驱动程序自动加载,数据可以分类并连续输入,这样一来,单次传输的数据量就增加了,从而大大降低了额外耗费的时间。通过引入新的API及驱动程序,DirectX 10将图形芯片的执行效能提升至80%。在不增加显卡硬件成本的前提下,显卡性能得到了大幅提升。
      并行引擎支持技术
      为了提升多块显卡协作的工作效率,微软在DirectX 10中提出了“Parallel Engine Support(并行引擎支持)”的概念,它可以预先把两个GPU需要的数据分别传输到两块对应的GPU当中,帧渲染将完全由驱动控制和调配,两块显卡的工作强度可以获得很好的平衡。而在目前主从卡的运作模式中,主卡要对从卡框架、渲染数量进行判定,而引入并行引擎支持技术后,主从卡的概念将消失,两块甚至多块显卡的协作威力将充分体现。
      
      统一渲染架构

      DirectX 10最大的革新就是统一渲染架构(Unified Shader Architecture)。目前各类图形硬件和API均采用分离渲染架构,即顶点渲染和像素渲染各自独立进行,前者的任务是构建出含三维坐标信息的多边形顶点,后者则是将这些顶点从三维转换为二维,这样便可以通过视觉欺骗在屏幕上显示出“三维”的场景。与此对应,GPU中也有专门的顶点渲染单元和像素渲染单元来分别执行这两项工作(由于工作量不同,这两种渲染单元的数量不相等,顶点渲染单元通常只有像素渲染单元的1/3~1/2)。在过去几年中,这种分离式设计对计算机图形领域的发展做出了一定的贡献。
      不过,微软认为这种分离渲染架构不够灵活,不同的GPU,其像素渲染单元和顶点渲染单元的比例不一样,软件开发人员在编写代码时必须考虑这个比例,这就大大限制了开发人员自由发挥的空间。另外,不同的图形游戏或软件对像素渲染和顶点渲染的需求不一样,导致GPU的运算资源得不到充分利用。为此,微软在DirectX 10中提出了统一渲染架构的思想:在相同物理类型的渲染单元上执行不同类型的渲染程序。换句话说,只用一种渲染单元,让它既能完成顶点渲染,也能完成像素渲染,甚至还能实现几何渲染。这样一来,渲染单元可以得到最大程度的利用,减少了资源闲置的情形。目前,Xbox 360的显示芯片Xenos就采用了统一渲染架构,该芯片一共有48个渲染单元,它们可全部用于顶点渲染或像素渲染,没有固定分配比例。此外,ATI也打算在新一代的R600芯片中采用统一渲染架构。
      当然,统一渲染架构也并非完美无瑕。相对顶点渲染来说,像素渲染将面临大规模使用纹理所带来的材质延迟,这是统一渲染架构急待解决的问题。据悉,NVIDIA下一代的G80有可能继续坚持分离式设计。到底是统一架构好还是分离设计好?相信只有等G80和R600同台竞技后,答案才会揭晓。不过有一点可以肯定,在微软的大力推动下,统一渲染架构是大势所趋。
      Vista
      除统一渲染架构外,DirectX 10的另一大特色就是与Windows Vista紧密结合,Vista系统将调用GPU资源来渲染Aero Glass 3D界面,这样图形API就与操作系统核心高度整合在一起。举个例子,当我们点击应用程序时,CPU将立刻收到驱动程序的指令,而软件界面渲染指令则通过DirectX 10直接传送给GPU,这样,Vista就能与CPU和GPU同时沟通,让3D界面渲染工作变得更高效。
      相比之下,在DirectX 9环境中,Vista(软件)界面的渲染工作就要“迟钝”一些了:用户点击运行某个软件,Vista将相应的指令发送给CPU,要求CPU进行后续处理;CPU接到运行指令的同时向GPU发出请求,要求GPU在屏幕上渲染出界面。GPU(支持DirectX 9)识别Vista界面渲染指令后完成相应的工作(注意:DirectX 8显卡无法完成渲染工作,必须让CPU通过软件模拟来实现,此时系统速度非常缓慢)。换句话说,在“DirectX 9显卡+Vista”的平台中,CPU还是核心,GPU必须在CPU的控制下工作,而Vista系统也必须通过CPU来调用GPU的资源。
      DirectX9还有一个不足之处,那就是它只能进行单任务渲染,即无法同时完成两个场景的渲染工作(如无法在运行游戏的同时为软件渲染3D界面),应用范围受到极大的限制。而DirectX 10则允许GPU同时渲染多个不相关的3D场景,工作效率大为提高。因此,尽管DirectX 9显卡大都能驱动Vista华丽的Aero Glass视觉模式,但很多方面受到了限制,只有DirectX 10显卡才是Vista的理想“伴侣”。
      SM 4.0
      从DirectX 8开始,Shader Model(渲染单元模式)在DirectX体系中的地位就日趋重要,其版本和渲染单元的规格也成为了决定显卡性能高低的关键因素(编注:关于Shader Model的具体介绍,请大家参阅本报今年第7期D15版)。随着DirectX 10时代的到来,Shader Model也升级到了4.0版本。与眼下如日中天的Shader Model 3.0(以下简称SM 3.0)相比,Shader Model 4.0(以下简称SM 4.0)有哪些可喜的变化?
      首先,SM4.0中的指令长度被提升到大于64K(即64×1024)的水平,这是SM 3.0规格(渲染指令长度允许大于512)的128倍。显然,SM 4.0在为渲染出电影级别的游戏画面做准备。由于渲染指令长度大幅提升,SM 4.0中相应的寄存器规格也有所增强,如Constant寄存器采用16×4096阵列、tmp寄存器则有4096个、input寄存器采用16/32规格等,上述指标都比以前的DirectX有明显的改进。其次,SM 4.0在纹理数量方面也有提高。DirectX 10允许程序员在渲染物体时使用128个纹理,而DirectX 9只提供4/16规格,更多的纹理意味着物体表面精度更接近真实,游戏开发者拥有更广泛的选择。
      从上述情况不难看出,DirectX 10在性能方面的提升是巨大的,它将进一步解放CPU的资源。当然,我们也必须看到,DirectX 10对硬件(尤其是显卡)的要求也更为苛刻,GPU在设计上也将更加复杂。
      DirectX 10.1
      正如以前的DX版本一样,DX10.1也是DX10的超集,因此它将支持DirectX 10的所有功能,同时它将支持更多的功能,提供更高的性能。
      DX10.1的一个主要提高是改善的shader资源存取功能,在多样本AA时,在读取样本时有更好的控制能力。除此之外,DX10.1还将可以创建定制的下行采样滤波器。
      DX10.1还将有更新的浮点混合功能,对于渲染目标更有针对性,对于渲染目标混合将有新的格式,渲染目标可以实现独立的各自混合。阴影功能一直是游戏的重要特效,Direct3D 10.1 的阴影滤波功能也将有所提高,从而可望进一步提高画质。
      在性能方面,DirectX 10.1将支持多核系统有更高的性能。而在渲染,反射和散射时,Direct3D 10.1将减少对API的调用次数,从而将获得不错的性能提升。
      其他方面,DX10.1的提高也不少,包括32bit浮点滤波,可以提高渲染精确度,改善HDR渲染的画质。完全的抗锯齿应用程序控制也将是DX10.1的亮点,应用程序将可以控制多重采样和超级采样的使用,并选择在特定场景出现的采样模板。DX10.1将至少需要单像素四采样。
      DX10.1还将引入更新的驱动模型,WDDM 2.1。与DX10的WDDM2.0相比,2.1有一些显著的提高。
      首先是更多的内容转换功能,WDDM2.0支持处理一个命令或三角形后进行内容转换,而WDDM2.1则可以让内容转换即时进行。由于GPU同时要并行处理多个线程,因此内容转换的即时性不仅可以保证转换质量,还可以提升GPU效率,减少等待时间。另外,由于WDDM 2.1支持基于过程的虚拟内存分配,处理GPU和驱动页面错误的方式也更为成熟。
    展开全文
  • DirectX10

    2007-01-02 16:44:00
    DirectX经过几年的发展,目前DirectX已经...但微软并没有止步不前,目前DirectX 9.0c的继任者DirectX 10已经呼之欲出,这种即将随同微软Windows Vista操作系统一同面世的DirectX API将再次撼动当今显示卡市场的格局,
    DirectX经过几年的发展,目前DirectX已经发展到了V9.0c版本,DirectX9.0带来的电影级画面渲染效果给我们造成的震撼绝不亚于当年3Dfx的Voodoo对整个3D游戏业的影响。但微软并没有止步不前,目前DirectX 9.0c的继任者DirectX 10已经呼之欲出,这种即将随同微软Windows Vista操作系统一同面世的DirectX API将再次撼动当今显示卡市场的格局,因为这又将是一个新时代的开始 ,当然具体到商业领域,势必又将引发目前图形业双雄在标准确立乃至最终产品规格上的较量。那么,作为DirectX发展史上又一个里程碑式的标准,它给我们带来了什么呢?下面让我们就目前各方已经掌握的信息来为大家介绍一下DirectX10最主要的几大技术进步:
    


    详细解读DirectX10几大技术进步
    让人期待的DirectX 10.0

    1、Shader Model 4.0

      相信大家在选购显卡时已经都向是否支持DirectX9.0c看齐,而Shader Model 3.0则是DirectX9.0c最大的特色。虽然DirectX9.0c与DirectX9.0b仅仅只是一个字母之差,但DirectX9.0c所支持的SM3.0与DirectX9.0b所支持的SM2.0在功能、特效方面却有差很大的差别。在而呼之欲出的DirectX10中,Shader Model也将升级到Shader Model4.0,那么SM4.0比SM3.0优势在哪呢?

    详细解读DirectX10几大技术进步
    DX10的游戏画面几乎可以以假乱真

       SM4.0规格令游戏程序开发员有更大的空间,相比原先的Shader Model 3.0自然继续有所提升,特别是对于最大指令数从512条增加到了64000条;暂存器数量也从原先的32个增加到惊人的4096个,而同时Texture由SM3.0的16个提升至128个,并硬件支持RGBE,令HDR不再需要特别的Decoding处理也能实现,HDR+AA将不再有这么多的麻烦。对于2D的纹理尺寸支持来看,DirectX 10也有惊人的提升,8192x8192的最高纹理分辩率比原先最高2048x2048的分辩率要高出许多。早在此前的E3上,微软就公布部分飞行模拟X中的DX9/DX10的游戏画面对比。从画面上我们可以看到其水面效果十分的逼真,同时淡化了DirectX 9.0版本比较虚假的山脉在水中的倒影。在上图中,左边的为现实世界的真实场景,右边为游戏里的虚拟环境,你能看的出有多大区别吗?

    2、统一渲染架构

      相对SM4.0,其实在Shader Model 4.0中微软将引入统一着色架构,这才是DX10最大的更进。我们都知道,微软在DirectX 9中引入的了2.0/2.X/3.0三个版本的Vertex Shader(顶点着色引擎)以及Pixel Shader(像素着色引擎)。其中支持2.0版的着色引擎是DirectX 9的GPU的最低标准,而当前主流的显卡已经都硬件支持加入了拥有更多高级处理功能的3.0版本着色引擎。不过,即便是DirectX9.0c,对于功能相仿Vertex Shader、Pixel Shader来说,目前图形芯片厂商仍需要在GPU中划分两个区域来存放Vertex Shader阵列和Pixel Shader贴图流水线。这无疑是一种资源冗余,而且这也加重GPU的设计难度及成本。当Direct X10把渲染流程更细分为Vertex Shader、Geometry Shader及Pixel Shader,这个情况将会更为明显。那么,有没有可能把这两者整合在一起呢?答案就是肯定的!

      而在DirectX 10中引入了统一渲染架,通过一个整合Vertex Shader、 Pixel Shader的可编程整合光影处理器来完成目前Vertex Shader、Pixel Shader所有的工作。所谓统一渲染架构,最容易的理解方式就是Shader单元不再分离,显示核心不再为Shader类型不同而配置不同类型的Shader单元,对于主流的显示核心,Pixel Shader单元以及Vertex Shader单元的概念都应该已经非常熟悉了,而在统一渲染架构中这两种Shader单元将不再分离,转而所有的Shader单元都可以为需要处理的数据进行处理,不管和是Pixel Shader数据还是Vertex Shader数据。而调配哪几组Shader单元负责处理什么数据或者进行什么样子类型的计算,则由一个被称为Small Sets of Instructions(SSI)的部分来控制。这样在硬件上,设计者就无需为不同的着色引擎设计不同的执行单元,只要按照所对应的接口以及操作方式全部融为一体,仅设置一种独立的Shader执行单元。这意味着GPU厂家可以用更小的核心来实现现在需要用8000万甚至更多晶体管才能实现的功能!

    3、Physics(物理加速)技术

      最近热门的技术就是物理加速及其应用,物理计算是下一代游戏体验当中的关键部分,它将增加游戏的真实感、沉浸感和带来更加有趣的体验。NVIDIA同样对物理加速非常感兴趣,在未来的DX10产品中会加入物理加速的支持。

      虽然,物理加速的概念很早之前就已经提出,但时至今日依然处于概念性阶段——AGEIA的物理加速卡仅有几款游戏能够支持,而ATI的GPU物理加速才刚刚进行完Demo演示,NVIDIA的SLI物理加速也要等待游戏厂商采用Havok FX引擎才能够出台!推广进程如此缓慢因为标准的不统一。AGEIA和Havok两大阵营的物理加速引擎互不兼容、各自为政,这就使得很多游戏仅能支持一种物理引擎,这种情形非常类似于3D时代开荒初期在技术和规范上百花齐放!

      这一现状有望在DX10推出之后得到改善,有了微软API的支持,无论哪种物理引擎都拥有发挥的空间,相信将会有更多的游戏加入更多的物理运算。未来,DX10 GPU将是更趋向化通用型的处理器,也就是说,原本许多交由CPU进行的3D处理会被转移到GPU上面来,因为强大的GPU比CPU更适合做这些工作,由此游戏性能会大幅提高。微软表示,DX10会开放两个SDK,分别照顾到AGEIA和Havok,其中AGEIA的PPU直接作用于SDK独立进行物理运算,在Havok引擎的调动下NVIDIA的GPU也可以动态的处理物理运算!

    4、Geometry Shader技术

      另外,DirectX 10还带来了一个被称为Geometry Shader的新版“Shader”,可以处理Pixel Shaders和Vertex Shaders不能完成的任务。目前DirectX的处理模式是:1.顶点数据准备,2.Vertex Shader,3.完成Vertex Shader。4.光栅化计算,5.PixelShader,6.完成PixelShader,这是一个D3D标准的处理模式,这个过程是是顺序进行的(DirectX 10之前)。因此,只能吸收和输出一个单独顶点的旧版Vertex Shaders是不能创建或者破坏三角形的。

    详细解读DirectX10几大技术进步
    WGF 2.0中的Geometry Shader

      而新的Geometry Shader的作用就是对每个Vertex数据临近的数据进行Vertex函数处理也就是用来判定临近的,类似数据操作的点来进行计算,而这种函数处理直接关系到整个渲染模型的形状;也就是说其可以快速的把模型类似的顶点结合起来进行快速运算,虽然其操作不会象Vertex Shader那样的进行完整的操作,只是处理器单个顶点的相关函数操作,但是这种操作却可以确定整个模型的物理形状,这将大大加速处理器速度,因为其它Shader单元将不再去需要判定数据所存在的位置,而只是需要简单的为特定区域进行操作就可以了。

      此外,Geometry Shader中还具备一个被称为Stream Out的技术,这种技术允许GPU可以重复利用已经计算的结果(允许继续由Vertex Shader数据来调用处理好的结果),从而减少计算。目前我们已经得知,NVIDIA即将发布的GeForce 8800GTX将拥有多达128个Stream Out单元。

     
    展开全文
  • DirectX 10:信息摘要

    2021-04-06 04:40:52
    在此处了解有关DirectX 10的信息-信息发布后将更新
  • Beginning DirectX 10

    2009-11-30 12:52:04
    Beginning DirectX 10
  • DirectX10.rar

    2014-04-08 13:44:14
    DirectX10.rar
  • DirectX10+MSVC

    2021-05-03 14:46:04
    这两天在学DirectX10,今天终于使用 MSVC (visual studio和visual c++使用的c/c++编译器) 成功编译了第一个示例程序。 最初的想法是使用g++编译directx程序,但是只支持directx9, 而且必须使用MinGW自带的头文件。...

    最近在学 DirectX10,今天终于使用 MSVC (visual studio和visual c++使用的c/c++编译器) 成功编译了第一个示例程序。

    先搞 DirectX:

    查阅资料了解到,windows10其实是自带 DirectX12 ,但那只是运行时支持,而不是 DirectX SDK(软件开发工具包) 。所以需要自己下载 DirectX10。那就去 MSDN (算是微软官网)下载相关资源,得知 DirectX 的后续版本已经被整合到了 windows SDK 中,这个 SDK 占用空间很大,而且只能装在 C 盘。

    幸好仍然提供旧版本的 DirectX SDK 下载,下载之后,安装在 E盘。

    DirectX文档结构
    最重要的就是 include 和 lib 文件,里面就是头文件和相应的库文件。

    最初的打算是使用 MinGW 的 g++ 命令编译 DirectX10 程序,但是经过多次尝试还是以失败告终,总是会有莫名奇妙的错误。只能换成 MSVC 。又通过查资料得知可以单独下载编译器,而不需要安装完整的visual studio IDE(众所周知,Visual Studio动辄好几个G,十分臃肿,最关键的是其中的许多东西其实是用不到的)。

    具体方法是下载 visual c++ build tools ,在安装时只选择编译器即可。注意:无法选择安装路径。默认装到C盘。安装完成后一看,c盘又小了一个G,肯定又是安装了很多不需要的东西。 (ーー゛)

    visual c++ build tools 安装完成后在开始菜单栏就会出现相应的命令行界面,选择 Visual C++ 2015 x64 Native Command Prompt(其他的工具可自行尝试), 最关键的是 cl 命令,这就是编译命令。

    cl /EHsc /Fea.exe InitDirect3D.cpp d3dApp.cpp d3dUtil.cpp GameTimer.cpp 
    

    使用上述命令运行示例程序,此命令会将编译后的文件自动链接为exe文件

    /EHsc 说明程序内部使用了异常处理,类似 Java 的 try catch 那种
     /Fe 重命名exe文件(默认是主函数所在程序名)
    

    InitDirect3D.cpp 是程序入口,其余 cpp 文件是依赖文件。
    使用预处理命令链接 lib 库,(此预处理命令 MinGW 是不支持的)

    #pragma comment(lib, "gdi32.lib")
    #pragma comment(lib, "user32.lib")
    #pragma comment(lib, "dlib/d3d10.lib")
    #pragma comment(lib, "dlib/d3dx10d.lib")
    

    此示例程序使用了 Windows API,所以应包含有 windows.h 文件。

    gdi32 user32 就是Windows API 的动态链接库,是 windows 自带的 dll 文件,d3d10 d3dx10d 是此程序使用到的静态链接库,我将它们从 DirectX 的 lib 文件夹拷贝到了项目的 dlib 文件夹中。

    执行编译命令,一大堆报错。

    首先是类型转换错误,比如:type ‘float’ unexcepted ,或者 cannot convert to … 等等;在网上找了一大堆资料,都没说到重点,有说把示例程序改成非 UNICODE 码的,还有说更改cpp文件保存时使用的字符集的。我在前两天刚看了 windows程序设计(第五版) 一书,再加上观察报错,认为这个错误是因为 UNICODE 的编码问题。也就是说函数参数要求非 UNICODE 码,但传入的是 UNICODE 码。

    我想起在 windows 程序设计一书中作者这样写道: 如果程序中定义了名为 UNICODE 的宏,那么函数就处理 UNICODE 编码,如果没有定义,那就是非 UNICODE 码,比如 ASCII 码,或者扩展 ASCII 码。(实现此技术并不难,使用 #ifdef 对函数名进行条件宏替换就可以做到)

    于是在include的头文件之前 定义了 UNICODE 宏,就像下面这样:

    #ifndef D3DAPP_H
    #define D3DAPP_H
    #define UNICODE     //我自己加的,位于 d3dApp.cpp 文件中
    
    #include "d3dUtil.h"
    #include "GameTimer.h"
    #include <string>
    

    再次编译错误少了一大半,剩下的错误是找不到某些 DirectX10 的头文件。
    再次经过相当长时间的折腾,发现 MSVC 的include文件夹在:

    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include
    

    将头文件放入此文件夹即可。

    注意: 编译信息提示缺什么再放什么,不要放多余的头文件,因为在

    C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\um
    

    文件夹下还有系统自带的 DirectX 头文件(为什么这里也有,奇怪(ーー゛))。所以如果两个地方有相同的头文件,就会引发 “宏重定义” 错误。当然,也可以直接将需要的头文件拷贝到项目中,只需将 include<> 改为 include"" (#include< >指示预处理程序到预定义的缺省路径下寻找文件;#include“ ”指示预处理程序先到当前目录下寻找文件,再到预定义的缺省路径下寻找文件。)

    做完这一切,再次运行 cl 命令,终于看到了 a.exe,运行得到结果:

    哈哈哈
    写在结尾: 其实到这就行了,但是我不想每次编译 cpp 文件都输入长长的 cl 命令,再次查询资料了解到了 makefile 技术,它可以实现自动编译,语法很简单,这就不写了,下面是我的 makefile:

    Makefile

    展开全文
  • DirectX 10 3D游戏编程入门
  • <div><p>Having an issue with my laptop for some reason not using DirectX 10 or 11. The machine ran windows 10 prior to my install of Pop! OS which i am on version 20.04 video card installed is a Intel...
  • Introduction to 3D Game Programming with DirectX 10
  • install directx 10 for XP need this software ,if not we could not update directx 9 into directx10
  • 介绍 DirectX10

    2009-05-18 23:54:15
    DirectX 10展现出一系列非常醒目的新特性,包括高度优化的运行时,强大的Geometry Shader,纹理数组等等,这些特性将引领PC实时三维图形进入一个全新的世界。
  • <div><p>I have added a Directx10 Renderer to the library. This is under a separate VS2010 project which is based on the DX9 version. <p>The project contains an effect which is loaded from a character ...
  • DirectX 10 教程3:初始化DirectX 10

    千次阅读 2014-05-05 11:40:53
    本教程开始介绍真正的DirectX 10编程,但只涉及两件事:初始化Direct3D和关闭Direct3D。 更新后的框架 我们需要在在框架中添加一个类用于处理所有Direct3D方法,名称为D3Dclass类。结构图如下: 框架结构图 ...
    

    源代码:dx10tut03.zip

    本教程开始介绍真正的DirectX 10编程,但只涉及两件事:初始化Direct3D和关闭Direct3D。

    更新后的框架

    我们需要在在框架中添加一个类用于处理所有Direct3D方法,名称为D3Dclass类。结构图如下:

    框架结构图

    框架结构图

    如你所见,D3Dclass位于GraphicsClass之中。前面的教程我们说过所有与图形相关的类都会封装在GraphicsClass中,所以新的D3Dclass类也应放入其中。

    下面看一下GraphicsClass的改变:

    Graphicsclass.h


    1
    2
    3
    4
    5
    // Filename: graphicsclass.h
    #ifndef _GRAPHICSCLASS_H_
    #define _GRAPHICSCLASS_H_

    下面是第一个变化,我们取消了windows.h,取而代之的是d3dclass.h。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    ///
    // MY CLASS INCLUDES //
    ///
    #include "d3dclass.h"
     
     
    /
    // GLOBALS //
    /
    const bool FULL_SCREEN = false;
    const bool VSYNC_ENABLED = true;
    const float SCREEN_DEPTH = 1000.0f;
    const float SCREEN_NEAR = 0.1f;
     
     
    // Class name: GraphicsClass
    class GraphicsClass
    {
    public:
        GraphicsClass();
        GraphicsClass(const GraphicsClass&);
        ~GraphicsClass();
     
        bool Initialize(int, int, HWND);
        void Shutdown();
        bool Frame();
     
    private:
        bool Render();
     
    private:

    第二个变化是新的指向D3Dclass的指针,名称为m_D3D。我在所有的类变量之前都加了前缀m_,这样当我编写代码时就可以知道哪些是类成员变量而哪些不是。


    1
    2
    3
    4
        D3DClass* m_D3D;
    };
     
    #endif

    Graphicsclass.cpp

    上一个教程中的这个类是空的,没有任何代码。现在我们就需要在GraphicsClass类中编写代码进行D3Dclass对象的初始化和关闭。我们还在Render方法中调用BeginScene和EndScene,这样就可以使用Direct3D进行绘制了。第一个变化时在构造函数中,首先基于安全的考虑将指针初始化为null,所有类指针我们都是这样处理的。


    1
    2
    3
    4
    GraphicsClass::GraphicsClass()
    {
        m_D3D = 0;
    }

    第二个变化在Initialize方法中。我们创建了D3Dclass对象并调用它的Initialize方法,传递的参数为屏幕宽度、屏幕高度,窗口句柄和Graphicsclass.h文件中的4个全局变量。D3Dclass会根据这些参数创建Direct3D系统。在说到d3dclass文件时会涉及更多细节。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    bool GraphicsClass::Initialize(int screenWidth, int screenHeight, HWND hwnd)
    {
        bool result;
     
     
        // Create the Direct3D object.
        m_D3D = new D3DClass;
        if(!m_D3D)
        {
            return false;
        }
     
        // Initialize the Direct3D object.
        result = m_D3D->Initialize(screenWidth, screenHeight, VSYNC_ENABLED, hwnd, FULL_SCREEN,
            SCREEN_DEPTH, SCREEN_NEAR);
        if(!result)
        {
            MessageBox(hwnd, L"Could not initialize Direct3D.", L"Error", MB_OK);
            return false;
        }
     
        return true;
    }

    下一个变化是GraphicsClass中的Shutdown方法。因为所有图形对象的关闭操作位于这个方法内,所以也需将D3Dclass类的关闭代码放入其中。我还检查了指针是否被初始化,如果没有就无需关闭了,这也就是为什么在类的构造函数中将所有指针设为null的原因。如果发现指针已经被初始化后才会关闭D3Dclass并清理指针。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void GraphicsClass::Shutdown()
    {
        // Release the D3D object.
        if(m_D3D)
        {
            m_D3D->Shutdown();
            delete m_D3D;
            m_D3D = 0;
        }
     
        return;
    }

    Frame方法也更新为可以在每帧调用Render方法。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    bool GraphicsClass::Frame()
    {
        bool result;
     
     
        // Render the graphics scene.
        result = Render();
        if(!result)
        {
            return false;
        }
     
        return true;
    }

    最后一个变化时在Render方法中。我们调用D3D对象将屏幕清除为灰色,然后调用EndScene将会在显示在屏幕上。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    bool GraphicsClass::Render()
    {
        // Clear the buffers to begin the scene.
        m_D3D->BeginScene(0.5f, 0.5f, 0.5f, 1.0f);
     
     
        // Present the rendered scene to the screen.
        m_D3D->EndScene();
     
        return true;
    }

    下面看一下D3Dclass的头文件:

    D3dclass.h


    1
    2
    3
    4
    5
    // Filename: d3dclass.h
    #ifndef _D3DCLASS_H_
    #define _D3DCLASS_H_

    首先要指定链接的库。前两个库包含了创建并绘制3D图像的所有Direct3D函数。第三个库包含了一些工具,这些工具可以获取诸如屏幕刷新率、使用的显卡等硬件信息。


    1
    2
    3
    4
    5
    6
    /
    // LINKING //
    /
    #pragma comment(lib, "d3d10.lib")
    #pragma comment(lib, "d3dx10.lib")
    #pragma comment(lib, "dxgi.lib")

    下一步需要包含这些库的头文件,只需用到d3d10.h和d3dx10.h。


    1
    2
    3
    4
    5
    //
    // INCLUDES //
    //
    #include <d3d10.h>
    #include <d3dx10.h>

    D3Dclass的类定义尽量保持简单。它有常规的构造函数,复制的构造函数和析构函数。更重要的是Initialize和Shutdown方法,本教程我们主要介绍这两个方法。还有几个本教程中不重要的辅助方法和几个私有变量。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    // Class name: D3DClass
    class D3DClass
    {
    public:
        D3DClass();
        D3DClass(const D3DClass&);
        ~D3DClass();
     
        bool Initialize(int, int, bool, HWND, bool, float, float);
        void Shutdown();
         
        void BeginScene(float, float, float, float);
        void EndScene();
     
        ID3D10Device* GetDevice();
     
        void GetProjectionMatrix(D3DXMATRIX&);
        void GetWorldMatrix(D3DXMATRIX&);
        void GetOrthoMatrix(D3DXMATRIX&);
     
        void GetVideoCardInfo(char*, int&);
     
    private:
        bool m_vsync_enabled;
        int m_videoCardMemory;
        char m_videoCardDescription[128];
        IDXGISwapChain* m_swapChain;
        ID3D10Device* m_device;
        ID3D10RenderTargetView* m_renderTargetView;
        ID3D10Texture2D* m_depthStencilBuffer;
        ID3D10DepthStencilState* m_depthStencilState;
        ID3D10DepthStencilView* m_depthStencilView;
        ID3D10RasterizerState* m_rasterState;
        D3DXMATRIX m_projectionMatrix;
        D3DXMATRIX m_worldMatrix;
        D3DXMATRIX m_orthoMatrix;
    };
     
    #endif

    对那些熟悉Direct3D的人可能会注意到这个类中并没有视矩阵变量,我把它放在了以后教程中会编写的camera类中了。

    D3dclass.cpp


    1
    2
    3
    4
    // Filename: d3dclass.cpp
    #include "d3dclass.h"

    与其他类一样,我们首先在构造函数中将所有指针初始化为null。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    D3DClass::D3DClass()
    {
        m_device = 0;
        m_swapChain = 0;
        m_renderTargetView = 0;
        m_depthStencilBuffer = 0;
        m_depthStencilState = 0;
        m_depthStencilView = 0;
        m_rasterState = 0;
    }
     
     
    D3DClass::D3DClass(const D3DClass& other)
    {
    }
     
     
    D3DClass::~D3DClass()
    {
    }

    Initialize方法用于创建Direct3D。我将所有必需代码放在此处,还有一些东西是用于后面的教程的。这个方法的参数screenWidth和screenHeight是窗体的宽和高,它们是在SystemClass中创建的。Hwnd变量为窗体的句柄,Direct3D需要这个句柄访问创建的窗体。Fullscreen变量表示是否全屏,Direct3D需要这个信息创建窗体。screenDepth和screenNear表示3D环境的深度设置。Vsync变量表示Direct3D的绘制是根据屏幕刷新率还是尽可能快地绘制。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    bool D3DClass::Initialize(int screenWidth, int screenHeight, bool vsync, HWND hwnd, bool fullscreen,
                              float screenDepth, float screenNear)
    {
        HRESULT result;
        IDXGIFactory* factory;
        IDXGIAdapter* adapter;
        IDXGIOutput* adapterOutput;
        unsigned int numModes, i, numerator, denominator, stringLength;
        DXGI_MODE_DESC* displayModeList;
        DXGI_ADAPTER_DESC adapterDesc;
        int error;
        DXGI_SWAP_CHAIN_DESC swapChainDesc;
        ID3D10Texture2D* backBufferPtr;
        D3D10_TEXTURE2D_DESC depthBufferDesc;
        D3D10_DEPTH_STENCIL_DESC depthStencilDesc;
        D3D10_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
        D3D10_VIEWPORT viewport;
        float fieldOfView, screenAspect;
        D3D10_RASTERIZER_DESC rasterDesc;
     
     
        // Store the vsync setting.
        m_vsync_enabled = vsync;

    在初始化Direct3D前我们必须从显卡/显示器中获取刷新率。每台电脑都有所不同,因此我们需要查询这个信息。我们需要查询分子和分母的值,将它们传递到DirectX,然后就能计算出正确地刷新率。如果没有这步而是设置一个当前计算机上可能不存在的默认值,DirectX的性能会下降,并会在调试时显示错误。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    // Create a DirectX graphics interface factory.
        result = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory);
        if(FAILED(result))
        {
            return false;
        }
     
        // Use the factory to create an adapter for the primary graphics interface (video card).
        result = factory->EnumAdapters(0, &adapter);
        if(FAILED(result))
        {
            return false;
        }
     
        // Enumerate the primary adapter output (monitor).
        result = adapter->EnumOutputs(0, &adapterOutput);
        if(FAILED(result))
        {
            return false;
        }
     
        // Get the number of modes that fit the DXGI_FORMAT_R8G8B8A8_UNORM display format for the adapter output (monitor).
        result = adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM,
            DXGI_ENUM_MODES_INTERLACED, &numModes, NULL);
        if(FAILED(result))
        {
            return false;
        }
     
        // Create a list to hold all the possible display modes for this monitor/video card combination.
        displayModeList = new DXGI_MODE_DESC[numModes];
        if(!displayModeList)
        {
            return false;
        }
     
        // Now fill the display mode list structures.
        result = adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM,
            DXGI_ENUM_MODES_INTERLACED, &numModes, displayModeList);
        if(FAILED(result))
        {
            return false;
        }
     
        // Now go through all the display modes and find the one that matches the screen width and height.
        // When a match is found store the numerator and denominator of the refresh rate for that monitor.
        for(i=0; i<numModes; i++)
        {
            if(displayModeList[i].Width == (unsigned int)screenWidth)
            {
                if(displayModeList[i].Height == (unsigned int)screenHeight)
                {
                    numerator = displayModeList[i].RefreshRate.Numerator;
                    denominator = displayModeList[i].RefreshRate.Denominator;
                }
            }
        }

    有了刷新率的分子和分母,最后要获得的就是显卡的名称和显存的大小。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // Get the adapter (video card) description.
    result = adapter->GetDesc(&adapterDesc);
    if(FAILED(result))
    {
        return false;
    }
     
    // Store the dedicated video card memory in megabytes.
    m_videoCardMemory = (int)(adapterDesc.DedicatedVideoMemory / 1024 / 1024);
     
    // Convert the name of the video card to a character array and store it.
    error = wcstombs_s(&stringLength, m_videoCardDescription, 128, adapterDesc.Description, 128);
    if(error != 0)
    {
        return false;
    }

    有了刷新率分子和分母信息和显卡信息,我们就可以释放所用的结构体和接口了。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // Release the display mode list.
    delete [] displayModeList;
    displayModeList = 0;
     
    // Release the adapter output.
    adapterOutput->Release();
    adapterOutput = 0;
     
    // Release the adapter.
    adapter->Release();
    adapter = 0;
     
    // Release the factory.
    factory->Release();
    factory = 0;

    有了刷新率就可以开始初始化DirectX了。首先需要填充交换链的描述。交换链就是前缓存和后备缓存。通常使用一块后备缓存,将内容绘制其上,然后将内容交换到前缓存,并显示在屏幕上,这也就是称为交换链的原因。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // Initialize the swap chain description.
    ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
     
    // Set to a single back buffer.
    swapChainDesc.BufferCount = 1;
     
    // Set the width and height of the back buffer.
    swapChainDesc.BufferDesc.Width = screenWidth;
    swapChainDesc.BufferDesc.Height = screenHeight;
     
    // Set regular 32-bit surface for the back buffer.
    swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;

    交换链描述的下一部分是刷新率。刷新率表示一秒内将后备缓存中的内容绘制到前缓存的次数。如果vsync设置为true,则刷新率锁定为系统设置(比方说60hz),这意味着每秒绘制60次(系统刷新率越高次数越多)。如果将vsync设置为false,则以尽可能快的速度绘制,但这样做会导致图像出现瑕疵。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    // Set the refresh rate of the back buffer.
    if(m_vsync_enabled)
    {
        swapChainDesc.BufferDesc.RefreshRate.Numerator = numerator;
        swapChainDesc.BufferDesc.RefreshRate.Denominator = denominator;
    }
    else
    {
        swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
        swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
    }
     
    // Set the usage of the back buffer.
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
     
    // Set the handle for the window to render to.
    swapChainDesc.OutputWindow = hwnd;
     
    // Turn multisampling off.
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.SampleDesc.Quality = 0;
     
    // Set to full screen or windowed mode.
    if(fullscreen)
    {
        swapChainDesc.Windowed = false;
    }
    else
    {
        swapChainDesc.Windowed = true;
    }
     
    // Set the scan line ordering and scaling to unspecified.
    swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
    swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
     
    // Discard the back buffer contents after presenting.
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
     
    // Don't set the advanced flags.
    swapChainDesc.Flags = 0;

    填充完交换链描述后,就可以创建Direct3D设备了。Direct3D设备非常重要,它是调用所有Direct3D方法的接口。


    1
    2
    3
    4
    5
    6
    7
    // Create the swap chain and the Direct3D device.
    result = D3D10CreateDeviceAndSwapChain(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION,
                                           &swapChainDesc, &m_swapChain, &m_device);
    if(FAILED(result))
    {
        return false;
    }

    有了设备和交换链后,我们需要一个指向后备缓存的指针,然后将它链接到交换链。我们使用CreateRenderTargetView方法将后备缓存链接到交换链。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // Get the pointer to the back buffer.
    result = m_swapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&backBufferPtr);
    if(FAILED(result))
    {
        return false;
    }
     
    // Create the render target view with the back buffer pointer.
    result = m_device->CreateRenderTargetView(backBufferPtr, NULL, &m_renderTargetView);
    if(FAILED(result))
    {
        return false;
    }
     
    // Release pointer to the back buffer as we no longer need it.
    backBufferPtr->Release();
    backBufferPtr = 0;

    我们还需要创建一个深度缓存描述,用来创建一个深度缓存。同时,还将一个模板缓存链接到了深度缓存。模板缓存可以用来实现诸如运动模糊、体积阴影等效果。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // Initialize the description of the depth buffer.
    ZeroMemory(&depthBufferDesc, sizeof(depthBufferDesc));
     
    // Set up the description of the depth buffer.
    depthBufferDesc.Width = screenWidth;
    depthBufferDesc.Height = screenHeight;
    depthBufferDesc.MipLevels = 1;
    depthBufferDesc.ArraySize = 1;
    depthBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    depthBufferDesc.SampleDesc.Count = 1;
    depthBufferDesc.SampleDesc.Quality = 0;
    depthBufferDesc.Usage = D3D10_USAGE_DEFAULT;
    depthBufferDesc.BindFlags = D3D10_BIND_DEPTH_STENCIL;
    depthBufferDesc.CPUAccessFlags = 0;
    depthBufferDesc.MiscFlags = 0;

    现在我们已经创建了深度/模板缓存。我们使用了CreateTexture2D方法创建了缓存,因此缓存其实是一张2D纹理。这是因为当绘制的多边形光栅化之后,它们其实就是在2D缓存中的有颜色的像素,绘制到屏幕上的就是这个2D缓存。


    1
    2
    3
    4
    5
    6
    // Create the texture for the depth buffer using the filled out description.
    result = m_device->CreateTexture2D(&depthBufferDesc, NULL, &m_depthStencilBuffer);
    if(FAILED(result))
    {
        return false;
    }

    现在设置深度模板描述,让我们可以控制深度测试的类型。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // Initialize the description of the stencil state.
    ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));
     
    // Set up the description of the stencil state.
    depthStencilDesc.DepthEnable = true;
    depthStencilDesc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL;
    depthStencilDesc.DepthFunc = D3D10_COMPARISON_LESS;
     
    depthStencilDesc.StencilEnable = true;
    depthStencilDesc.StencilReadMask = 0xFF;
    depthStencilDesc.StencilWriteMask = 0xFF;
     
    // Stencil operations if pixel is front-facing.
    depthStencilDesc.FrontFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;
    depthStencilDesc.FrontFace.StencilDepthFailOp = D3D10_STENCIL_OP_INCR;
    depthStencilDesc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
    depthStencilDesc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
     
    // Stencil operations if pixel is back-facing.
    depthStencilDesc.BackFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;
    depthStencilDesc.BackFace.StencilDepthFailOp = D3D10_STENCIL_OP_DECR;
    depthStencilDesc.BackFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
    depthStencilDesc.BackFace.StencilFunc = D3D10_COMPARISON_ALWAYS;

    填充完描述后就可以创建深度模板状态了。


    1
    2
    3
    4
    5
    6
    // Create the depth stencil state.
    result = m_device->CreateDepthStencilState(&depthStencilDesc, &m_depthStencilState);
    if(FAILED(result))
    {
        return false;
    }

    创建了深度模板状态之后,我们就可以将它设置到Direct3D设备了。


    1
    2
    // Set the depth stencil state on the D3D device.
    m_device->OMSetDepthStencilState(m_depthStencilState, 1);

    最后需要创建深度模板缓存的视图,这样Direct3D就能知道将深度缓存作为一个深度模板纹理,之后就可以通过Direct3D设备调用CreateDepthStencilView方法了。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // Initailze the depth stencil view.
    ZeroMemory(&depthStencilViewDesc, sizeof(depthStencilViewDesc));
     
    // Set up the depth stencil view description.
    depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    depthStencilViewDesc.ViewDimension = D3D10_DSV_DIMENSION_TEXTURE2D;
    depthStencilViewDesc.Texture2D.MipSlice = 0;
     
    // Create the depth stencil view.
    result = m_device->CreateDepthStencilView(m_depthStencilBuffer, &depthStencilViewDesc, &m_depthStencilView);
    if(FAILED(result))
    {
        return false;
    }

    最后就可以调用OMSetRenderTargets,这个方法将渲染目标视图和深度模板缓存绑定到渲染管道,通过这种方法将图形管道绘制的图像传送到后备缓存。写入到后备缓存之后,就可以将它交换到前缓存,在屏幕上显示内容。


    1
    2
    // Bind the render target view and depth stencil buffer to the output render pipeline.
    m_device->OMSetRenderTargets(1, &m_renderTargetView, m_depthStencilView);

    创建了渲染目标之后,我们可以继续做一些额外的工作,赋予更多的控制权,为下面的教程做准备。首先要创建的是光栅状态,让我们可以控制多边形的绘制方式,比如绘制为网格或同时绘制多边形的前后表面。默认状态时DirectX已经有了一个光栅状态,除非你自己创建一个,否则无法改变这个状态。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
        // Setup the raster description which will determine how
    //and what polygons will be drawn.
        rasterDesc.AntialiasedLineEnable = false;
        rasterDesc.CullMode = D3D10_CULL_BACK;
        rasterDesc.DepthBias = 0;
        rasterDesc.DepthBiasClamp = 0.0f;
        rasterDesc.DepthClipEnable = true;
        rasterDesc.FillMode = D3D10_FILL_SOLID;
        rasterDesc.FrontCounterClockwise = false;
        rasterDesc.MultisampleEnable = false;
        rasterDesc.ScissorEnable = false;
        rasterDesc.SlopeScaledDepthBias = 0.0f;
     
        // Create the rasterizer state from the description we just filled out.
        result = m_device->CreateRasterizerState(&rasterDesc, &m_rasterState);
        if(FAILED(result))
        {
            return false;
        }
     
        // Now set the rasterizer state.
        m_device->RSSetState(m_rasterState);

    视口也需要被设置,这样Direct3D就可以将剪裁空间坐标映射到渲染目标空间,下面的代码设置为整个窗口尺寸。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // Setup the viewport for rendering.
    viewport.Width = screenWidth;
    viewport.Height = screenHeight;
    viewport.MinDepth = 0.0f;
    viewport.MaxDepth = 1.0f;
    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
     
    // Create the viewport.
    m_device->RSSetViewports(1, &viewport);

    下面我们将创建投影矩阵。投影矩阵用来将世界空间变换到2D视口空间。我们需要保存这个矩阵的副本,这样就可以将它传递到shader中。


    1
    2
    3
    4
    5
    6
    // Setup the projection matrix.
    fieldOfView = (float)D3DX_PI / 4.0f;
    screenAspect = (float)screenWidth / (float)screenHeight;
     
    // Create the projection matrix for 3D rendering.
    D3DXMatrixPerspectiveFovLH(&m_projectionMatrix, fieldOfView, screenAspect, screenNear, screenDepth);

    我们还需创建一个世界矩阵,用来将模型的顶点从对象空间转换到世界空间。这个矩阵还用来旋转、平移和缩放3D场景中的物体。开始时可以将这个矩阵设置为单位矩阵并保存它的副本,这个副本需要传递到shader用于绘制。


    1
    2
    // Initialize the world matrix to the identity matrix.
    D3DXMatrixIdentity(&m_worldMatrix);

    通常还需要创建一个视矩阵。视矩阵用来计算我们观察世界的位置,你可以将它想象成一个相机,你只能看到这个相机中能看到的动向。因此我会在以后的教程汇一个在camera类中创建这个矩阵,这样更符合逻辑,本教程不需要视矩阵。

    在Initialize方法中要创建的最后一个东西是正交投影矩阵,这个矩阵用来绘制平面上的输入用户界面之类的2D内容,下一个教程中我们会在平面上绘制一个2D图像。


    1
    2
    3
    4
    5
        // Create an orthographic projection matrix for 2D rendering.
        D3DXMatrixOrthoLH(&m_orthoMatrix, (float)screenWidth, (float)screenHeight, screenNear, screenDepth);
     
        return true;
    }

    Shutdown方法释放并清理所有在Initialize方法中用到的指针,它非常简单。但是在清理之前我放置了一个调用,强制交换链变为窗口模式。如果没有这步且在全屏模式释放交换链时,程序会报错。为了避免这个错误,在关闭Direct3D前我总是强制进入窗口模式。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    void D3DClass::Shutdown()
    {
        // Before shutting down set to windowed mode or when you release the swap chain it will throw an exception.
        if(m_swapChain)
        {
            m_swapChain->SetFullscreenState(false, NULL);
        }
     
        if(m_rasterState)
        {
            m_rasterState->Release();
            m_rasterState = 0;
        }
     
        if(m_depthStencilView)
        {
            m_depthStencilView->Release();
            m_depthStencilView = 0;
        }
     
        if(m_depthStencilState)
        {
            m_depthStencilState->Release();
            m_depthStencilState = 0;
        }
     
        if(m_depthStencilBuffer)
        {
            m_depthStencilBuffer->Release();
            m_depthStencilBuffer = 0;
        }
     
        if(m_renderTargetView)
        {
            m_renderTargetView->Release();
            m_renderTargetView = 0;
        }
     
        if(m_swapChain)
        {
            m_swapChain->Release();
            m_swapChain = 0;
        }
     
        if(m_device)
        {
            m_device->Release();
            m_device = 0;
        }
     
        return;
    }

    D3Dclass中有几个辅助函数。前两个是BeginScene和EndScene。BeginScene会在每帧绘制一个新3D场景前调用,它将缓存清空做好绘制的准备。在每帧最后所有绘制完成后,Endscene让交换链显示场景。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    void D3DClass::BeginScene(float red, float green, float blue, float alpha)
    {
        float color[4];
     
     
        // Setup the color to clear the buffer to.
        color[0] = red;
        color[1] = green;
        color[2] = blue;
        color[3] = alpha;
     
        // Clear the back buffer.
        m_device->ClearRenderTargetView(m_renderTargetView, color);
         
        // Clear the depth buffer.
        m_device->ClearDepthStencilView(m_depthStencilView, D3D10_CLEAR_DEPTH, 1.0f, 0);
     
        return;
    }
     
    void D3DClass::EndScene()
    {
        // Present the back buffer to the screen since rendering is complete.
        if(m_vsync_enabled)
        {
            // Lock to screen refresh rate.
            m_swapChain->Present(1, 0);
        }
        else
        {
            // Present as fast as possible.
            m_swapChain->Present(0, 0);
        }
     
        return;
    }

    下一个方法返回指向Direct3D设备的指针,它经常会被框架调用。


    1
    2
    3
    4
    ID3D10Device* D3DClass::GetDevice()
    {
        return m_device;
    }

    后面三个辅助方法将投影矩阵、世界矩阵和正交矩阵返回给调用函数。大多数shader都需要这些矩阵进行绘制。本教程中我们不使用这三个方法。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    void D3DClass::GetProjectionMatrix(D3DXMATRIX& projectionMatrix)
    {
        projectionMatrix = m_projectionMatrix;
        return;
    }
     
     
    void D3DClass::GetWorldMatrix(D3DXMATRIX& worldMatrix)
    {
        worldMatrix = m_worldMatrix;
        return;
    }
     
     
    void D3DClass::GetOrthoMatrix(D3DXMATRIX& orthoMatrix)
    {
        orthoMatrix = m_orthoMatrix;
        return;
    }

    最后一个辅助类返回显卡的名称和显存大小,知道这些信息可以帮助程序员在不同配置下进行调试工作。


    1
    2
    3
    4
    5
    6
    void D3DClass::GetVideoCardInfo(char* cardName, int& memory)
    {
        strcpy_s(cardName, 128, m_videoCardDescription);
        memory = m_videoCardMemory;
        return;
    }

    总结

    现在我们终于完成了Direct3D的初始化和关闭的代码,编译并运行代码后你会看到一个与前一个教程相同的窗口,但本教程中Direct3D已被初始化。

    练习

    1.编译代码运行程序,按下escape键退出。

    2.改变graphicsclass.h中的full screen变量,重新编译观看结果。

    3.将GraphicsClass::Render中的清除颜色变为黄色。

    4.将显卡名称和内存大小信息保存在一个文本文件中。

    展开全文
  • DirectX 10 For XP 让 Windows 支持 DirectX10
  • Microsoft DirectX 10 Technical Brief
  • DirectX10技术详解

    2009-05-18 23:56:20
    DirectX 10大大改变软件开发人员进行Windows游戏开发的方式,而且很有希望给用户同时带来更好的画面和强劲的性能。
  • DirectX10/11的教程

    2011-11-13 09:23:18
    RasterTek的教程。含DirectX11的38课,DirectX10的37课,还有DirectX11地形的9课,Oracle的4课。都是文字,高清,可复制。
  • Introduction to 3D Game Programming with DirectX 10 随书源代码。
  • DirectX 3d编程,这本书讲得很基础,包含了矩阵,向量等操作,Introduction to 3D Game Programming with DirectX 10(中文版)
  • DirectX 10 Sample

    2020-11-24 23:07:03
    <div><p>Pulls in and updates files from pull request #56 and brings the implementation in line with the current source tree.</p><p>该提问来源于开源项目:libRocket/libRocket</p></div>

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,020
精华内容 808
关键字:

directx10