DirectX 10引入的新的纹理阵列机构,将允许在一个由显卡维护的阵列中容纳512张单独的纹理,而且,在shader程序中可以使用一条新的指令来获取这个阵列中的任意一张纹理。而这种shader指令是运行在GPU中的;这样,就把原来要消耗很多CPU时间的纹理切换工作轻松地转给了GPU。由于纹理一般是直接放在显存中的,因此以这样的方式,将工作交与和显存一同位于显卡上的GPU来完成更有效率。
directx 10_DirectX10 -词条解释
导言:微软最新发布的DirectX 10具有哪些新特性、新特点,它将给图像处理带来怎样的变化?Microsoft发布的DirectX 10代表了自从可编程Shader出现以来在3DAPI方面的最巨大的进步。通过一番脱胎换骨般的重建,DirectX 10展现出一系列非常醒目的新特性,包括高度优化的运行时,强大的Geometry Shader,纹理数组等等,这些特性将引领PC实时三维图形进入一个全新的世界。
DirectX 发展简史
在过去的十年中,DirectX已经稳步成为了Microsoft Windows平台上进行游戏开发的首选API。每一代的DirectX都带来对新的图形硬件特性的支持,因此每次都能帮助游戏开发者们迈出惊人的一步。
微软DirectX API(Application Programming interface :应用程序界面) 最早发布于1995年,其设计目标是为Windows平台软件开发人员提供一个更简便的针对多媒体和游戏应用编程的标准接口。
在DirectX出台,开发者针对音频、视频等的操作必须基于硬件进行,――当然,基于OpenGL能够在很大程序上减轻工作量,但OpenGL获得的支持显然远远不够。――而显卡、声卡等的产品种类众多,要编写一款能运行在所有平台上的游戏简直是一件噩梦般的工作。
通过提供一系列的针对多媒体应用的API,如图形(包括2D与3D应用)、音频或输入设备等,DirectX提供了一整套的多媒体接口方案,这可以让开发者根据API编写相应的软件程序,而不必考虑具体的硬件,硬件的差别性显得无足轻重,编程人员得以更有效率的开发各种多媒体、游戏软件。
当然,DirectX的发展并不是一帆风顺的,最初的版本远谈不上稳定。
directx 10_DirectX10 -版本 操作系统 发布日期
DirectX 1.0 Windows 95a 9/30/95
DirectX 2.0/2.0a Windows 95OSR2/NT4.0 6/5/96
DirectX 3.0/3.0a Windows NT 4.0 SP3 9/15/96
DirectX 4.0未发布
DirectX 5.0 Windows NT 4.0/Beta for NT 5.0 7/16/97
DirectX 5.1 Windows 95/98/NT4.0 12/1/97
DirectX 5.2 Windows 95 5/5/98
DirectX 6.0 Windows 98/NT4.0 8/7/98
DirectX 6.1 Windows 95/98/98SE 2/3/99
DirectX 7.0 Windows 95/98/98SE/2000 9/22/99
DirectX 7.0a Windows 95/98/98SE/2000 9/99
DirectX 7.1 Windows 95/98/98SE/ME/2000 9/16/99
DirectX 8.0/8.0a Windows 95/98/98SE/ME/2000 9/30/2000
DirectX 8.1 Windows 95/98/98SE/ME/2000/XP 11/12/01
DirectX 9
Shader Model 2.0 Windows 95/98/98SE/ME/2000/XP 12/19/2002
DirectX 9
Shader Model 2.0b Windows 98/98SE/ME/2000/XP 8/13/2003
DirectX 9
Shader Model 3.0 Windows 98/98SE/ME/2000/XP 8/9/2004
directx 10_DirectX10 -DirectX 3D的发展
DirectX中应用在3D图形方面的特定DirectX API即Direct3D,这也是DirectX中最重要的部分。不过,DirectX 3D得到广泛应用是在DirectX 6.0之后:
DirectX 6.0:加入了双线性过滤、三线性过滤等优化3D图像质量的技术,加入环境影射凹凸贴图,使3D游戏的画面更具有真实感。
DirectX 7.0:最大的特色就是支持了T&L,中文名称是“坐标转换和光源”,3D游戏中坐标和灯光的转换工作从此由CPU转交给了GPU,比DX6.1性能提升20%。这也成就了nVIDIAGeForce 256与ATi Radeon 256的辉煌,令3DFX彻底退出市场竞争。
DirectX 7.0a:增强了力反馈游戏控制设备的性能和兼容性。
DirectX 7.1:与Windows Millennium一同发布。
DirectX 8.0/8.0a:支持Shader Model 1.0和1.1,从此在显卡中引入可编程像素着色器(Pixel Shaders)和顶点着色器(Vertex Shaders)的概念,同时应用在Xbox游戏机中。同硬件T&L仅仅实现的固定光影转换相比,VS和PS单元的灵活性更大,它使GPU真正成为了可编程的处理器。
DirectX 8.1: Pixel Shader升级到1.2、1.3、1.4版,可以支持最高每时钟28指令执行,其中1.4版当时仅ATi Radeon 8500显卡支持。
DirectX 9.0 Shader Model 2.0: SM2.0的shader性能更强,支持最高96指令的pixel shader长度,同时DirectPlay和一些音频方面也有大幅提升。
DirectX 9.0 Pixel Shader 2.0b: ATI Radeon X600/700/800系列显卡首先采纳,开始支持更多指令(最高1536)和更多临时寄存器(32相比之前为12),同时还加入新的贴面寄存器(facing register)和几何实例(geometry instancing)的支持。
DirectX 9.0 Shader Model 3.0:支持更多指令,支持指令的流量控制和动态分支,从而使得编程人员可以在shaders中加入循环操作,使得编程更加容易,首次被Geforce 6800显卡采用。
从DirectX的发展史中我们可以看到,微软的3D API和硬件一同发展,新硬件带来新的DX特性,新的DX特性加速硬件的发展,在DirectX10上面,又是一个3D图形发展的新境界。DirectX 10的架构优势
DirectX之所以在广大的开发者中流行,是得益于它的简单易用和丰富的功能特性。然而,DirectX一直被一个主要的问题所困扰,那就是高CPU负载。
在图形编程API出现之前,3D应用程序直接向图形硬件发送命令来完成图形的绘制工作。虽然这样开发工作比较繁重,但硬件效率则能在很大程度上得到保证。
而如DirectX和OpenGL这样的图形API则是通过在图形硬件和应用程序之间架起了一个中间层,这样,应用程序可以使用统一的图形编程代码来完成对底层硬件的操作,将程序员们从与大量的图形硬件交互的恶梦中解救出来。但是,这也造成了每次DirectX从应用程序那里接收到一条命令时,就必须先对这条命令进行分析和处理,再向图形硬件发送相对应的硬件命令。由于这个分析和处理的过程由CPU完成,造成了每一条3D绘图命令都会带来CPU的负载。
从技术角度,这种CPU负载给3D图象带来两个负面影响:首先,限制了画面中可以同时绘制的物体数量;其次,限制了可以在一个场景中使用的独立的特效的数量。这就使得游戏画面中的细节数量受到了很大的限制,而图像具有真实感的主要要求便是丰富的细节。
DirectX 10的主要优势便是最大程度地降低了CPU负载,主要通过三个途径来达到这个目的:第一,修改API核心,使得绘制物体和切换材质特效时的消耗降低,提高绘图效率;第二,引入新的机制,降低图形运算操作对CPU的依赖性,使更多的运算在GPU中完成;第三,使大量的物体可以通过调用单条DirectX绘制命令进行批量绘制。
下面我们就来仔细的看一下这三种方式:
提高绘图效率
在DirectX 10中,对上代DirectX版本中三维数据和绘制命令的验证过程进行了很大程度的修改。所谓三维数据和命令的验证,是指在DirectX绘制图形之前,对传给它的图形数据和绘制命令进行格式和数据完整性的检查,以保证它们被送到图形硬件时不会导致硬件出问题;这是很必要的一步操作,但是不幸的是这会带来很大的性能开销。
从上表我们可以很容易的看出,在DirectX 9中,每次绘制一帧画面之前,都会对即将使用的相关数据进行一次验证。而DirectX 10中,仅当这些数据被创建后验证一次。这很明显是可以大大提高游戏进行中的效率的。
降低图形运算对CPU的依赖
在降低图形运算对CPU的依赖方面,DirectX 10 引入的三个重要机制就是:纹理阵列(texture arrays)、绘制预测 (predicated draw)和流式输出(stream out)。不要被这三个晦涩的名词吓倒,实际上它们是三个不难理解的机制。
纹理阵列
传统的DirectX在多张纹理中进行切换的操作是种很给CPU带来很大压力的操作,因为每切换一次,都要调用一次DirectX的API函数。而每绘制一个使用新纹理的物体,就要进行一次这样的切换操作;有时为了实现特殊的材质特效,绘制一个物体时可能就要切换好几次纹理,开销很大。
所以,之前游戏中经常会出现将大量的小纹理拼合到一张大的纹理中,通过给不同的三维物体分配这张大纹理的不同局部的方式,以期减少纹理切换,提高游戏运行效率。这种方式实现起来相当复杂,而且DirectX 9中对纹理的尺寸的限制是4048×4048像素,也就是说,如果要容下更多的小纹理块,可能就得加载很多张这样的大纹理。
DirectX 10引入的新的纹理阵列机构,将允许在一个由显卡维护的阵列中容纳512张单独的纹理,而且,在shader程序中可以使用一条新的指令来获取这个阵列中的任意一张纹理。而这种shader指令是运行在GPU中的;这样,就把原来要消耗很多CPU时间的纹理切换工作轻松地转给了GPU。由于纹理一般是直接放在显存中的,因此以这样的方式,将工作交与和显存一同位于显卡上的GPU来完成更有效率。如今,在DirectX 10中,只要一开始设置好纹理阵列中的纹理,然后每次绘制一个物体时为它指定一个纹理的索引号,并同物体三维数据一起传递到shader中,就可以放心的让GPU来给物体选纹理了。
绘制预测
在一般的三维场景里,很多物体都是完全被别的物体挡在后面的。这时候如果要显卡绘制这些物体就是白费力气。尽管高级的GPU可以通过硬件算法将场景画面中被挡住的像素(注意是像素)预先剔除,但是仍然会有很多不应进行的多余运算。例如,一个完全被挡住的复杂的角色模型,它的身上可能有几千个顶点,需要做复杂的骨骼皮肤动画处理、顶点光照运算等等,然而,GPU是在处理完这些顶点之后,并要把这个角色模型一个像素一个像素地画到画面中时,才开始判断每个像素是否需要画,而当所有的像素都被剔除了时,之前做的顶点处理也就全白费了。在DirectX 10中的绘制预测便正是针对这种情况的解决,简言之,绘制预测通过用一个可以代表某个复杂物体的简单物体来判断这个物体是否被全部挡住了,例如用一个可以罩住刚才那个角色的大盒子,当绘制这个盒子时,如果发现所有的像素都被屏蔽掉了,也即是说这个盒子肯定完全看不见,那么,里面的角色绘制包括骨骼皮肤运算等之类的操作便完成不必进行。而一个盒子顶多有八个顶点,相比处理几千个顶点,开销小得多。
另外,以前这个步骤中有些真运算也需CPU完成的,在DirectX 10中,已经完全交由GPU来做,这也可以在一定程度上减轻CPU的压力。
数据流式输出
数据流式输出也是DirectX 10的重要特性,它允许GPU上的Vertex shader或Geometry shader向显存中添加数据,而这在以往的vertex shader中是不可能的。
在之前的DirectX版本中,vertex shader只能读取显存中已有的顶点数据;而DirectX 10中引入的新的Geometry shader,不但能读取显存中的顶点数据、几何(点、线段、三角形)数据,还可以生成新的几何数据放回显存。
批量绘制
在DirectX 9中,对渲染状态的管理一直是个十分信赖于CPU运算能力的操作。所谓渲染状态,是指显卡进行一次绘制操作时所需要设置的各种数据和参数。例如,要绘制一个人物角色,就需要先设置他的几何模型数据的数据格式、纹理过滤模式、半透明混合模式等等,每设置一项,都要调用一次DirectX API,占用大量CPU时间,极大的约束了渲染的性能。
为了使这些操作能够批量的进行,DirectX 10中引入了两个新的结构――状态对象(state object)和常量缓冲(constant buffers)。
状态对象就是将以前的零散状态按照功能归结为几个整体,这样,当要设置一系列相关状态时,无需为每一个状态来调用一次DirectX API,只需要调用一次将这些状态统统设置到显卡中去。
而常量缓冲是另一个十分有意义的机制。在绘制模型前的准备工作中,渲染状态的设置只是一小部分。还是拿绘制人物角色来说,能照亮这个人的光源的颜色、位置、类型、范围等等,都要提前设给显卡;为了通过骨骼来带动他的皮肤做出姿势,还要设置骨骼的位置信息等等,而这些东西主要都是通过GPU中的常量寄存器(constant registers)来传递给它的。每个常量寄存器可以存储一个4维的浮点型向量(即四个浮点数)。常量寄存器是游戏程序向GPU输入游戏场景中数据的重要途径。
在DirectX 9中,这种常量寄存器的数量是十分有限的,而且每次更新一个寄存器,都需要调用一次DirectX API函数。DirectX 10通过使用常量缓冲(constant buffer)这种结构,在每个constant buffer中都可以容纳4096个常量,而且只需调用一次API就可以更新一大批常量。
比如说,在以前的DirectX版本中,如果程序想在场景里画很多的树木和杂草,可以采用一个类似于“克隆”的方法:先做好一棵或几棵树、草的三维模型,然后在画一帧画面时,不停的在不同的位置、方向,用不同的大小为参数,调用DirectX API的绘制函数来画这些模型,就可以画出很多草木来。但是每画一棵,都要设置一大堆参数后调用一次API,这是很耗CPU时间的,所以在以前的游戏中鲜有大规模且细节丰富的森林场景。
而在DirectX 10中,我们可以先把树、草的几个模型设给显卡,然后将所有要画的树木的位置、方向和大小一次性的写入到constant buffer中,这样,显卡便一下把所有的树木和草都一起绘制出来了。
总之,DirectX 10通过提前数据验证、纹理阵列、绘制预测、流式输出、状态对象、常量缓冲等机制,帮助游戏的效果和效率上升到一个新的高度。这样,也避免了之前DirectX版本因CPU负载过大而无法对图形实施更多细节优化的问题。
Shader Model 4.0
DirectX 10另一个引人瞩目的特性便是引入了Shader Model 4.0,那么,Shader Model 4.0能够带来怎样的新特性,特别是将它与DirectX 9.0c中Shader Model 3.0相比时?
引入新Shader : Geometry shader
DirectX 10新引入的Geometry Shader,可以简单地编程操纵几何图元,同时, vertex、geometry、pixel shader采用了统一的Sahder架构。
Geometry shaders是可编程图形流水线的一大进步。它第一次允许由GPU来动态的生成和销毁几何图元数据。通过和新的数据流输出功能配合使用,许多以前无法实施的算法现在都可以在GPU中使用了。
统一的Shader架构
在DirectX 9中,Pixel shader总是在各个方面落后于vertex shaders,包括常量寄存器个数、可用的指令个数、shader长度等。程序员需要区分对待这两种shader。
而在shader model 4中,无论 vertex、geometry和pixel shader,均有统一的指令集、同样的临时/常量寄存器个数,它们将平等的共享GPU中的所有可用资源。这样,在编程时便不必再考虑每种shader自身的限制了。
百倍于DirectX 9的可用资源
对于shader中可用的资源,在Shader model 4.0中比原来有了惊人的扩充。就像早期的程序员们绞尽脑汁的省着用可怜的640k内存一样,在使用以前的DirectX开发游戏的过程中,程序员需要小心翼翼的分配珍贵的shader寄存器资源。寄存器的数量,直接影响着shader程序的复杂度。这和在640k内存的 机器上,怎么也不可能写出Microsoft Office这样的大规模软件是同一个道理。
而在DirectX 10中,将临时寄存器由原来的32个扩充到了4096个,将常量寄存器由原来的256个扩充到了65536个。
更多的渲染目标(Render Target)
所谓渲染目标,就是指GPU可以把画面绘制到的目标,我们可以把它理解为GPU的画布。一般来说,渲染目标被输出到屏幕上,这样我们就能看到画好的画面了。但是有时为了实现一些特效,某些渲染结果并不直接画到屏幕上,而是再返给GPU做进一步的特效处理,而且渲染目标中也不一定是画好的画面的颜色信息。
根据图形特效的需要,渲染目标可能是每个物体距离屏幕的远近,或者物体表面上每个像素的方向,或者每个物体表面的温度等等,之为了实现特效,可以按需要在其中绘制任何信息。为了提高这种情况下的效率,很多新的显卡都支持在同一遍Shader执行结束后,同时把不同的信息绘制到不同的渲染目标中。在DirectX 9中就已经支持这种机制了,但是它约束最多同时向四个渲染目标绘制。而DirectX 10将这个数量提升了一倍。
更多的纹理
在Shader Model 4.0中提供了对纹理阵列(Texture arrays)的支持。在前文中已经对纹理阵列有了比较详细的介绍,在这里只着重介绍一下与shader相关的部分。
在每个纹理阵列中,最多可以保存 512张同样大小的纹理。而且每张贴图的分辨率被扩展到了8192×8192。更大的分辨率意味着纹理中更丰富的细节。在一个shader中能够同时访问的纹理个数被增加到了128个,也就是说在每次执行同一个shader时,可以使用一个纹理阵列的512个纹理中的128个。所以说,在DirectX 10中,纹理的多样性和细节程度将会有大幅的提升。
新的HDR颜色格式
要说这些年来在实时图形界炒得最热的概念,应该是HDR了。它通过采用浮点格式的颜色格式来为纹理、光照等计算提供极大的精度和颜色范围(以前的纹理一般 都是采用整数型的颜色格式)。尽管最后显示到屏幕上还是每个颜色通道8位的整数格式,但是以前由于在材质、光照计算中纹理也是用每通道8位的格式来参与计算,所以在显示到画面之前,很多细节就在低精度的运算中丢失了。
而采用每颜色通道16位浮点数的纹理,能够保证在运算过程中几乎没有颜色细节信息的丢失。另外,采用16位浮点格式的颜色通道,可以表现更大的颜色范围。这些就是HDR的优越性。
对用户而言,当游戏中的画面罩上一层HDR效果后,立刻显得和真正的照片一样,有朦胧的光晕、细致的高光和十分自然的色调。
然而,采用每个颜色通道16位浮点数的格式,比采用每通道8位的整数格式的纹理要多占据一倍的显存;这给绘制的效率带来了负面的影响。所以在 DirectX 10中引入了两个新的HDR格式。第一种是R11G11B10,表示红色和绿色通道用11位浮点数,而蓝色通道采用10位浮点数表示。那么,为什么不都用 11位呢?这是为了凑32这个整数。学过计算机的人都知道,当内存中一个数据单元的宽度是32位时,对它的操作效率最高;而且在纹理数据中一般要求每个像素的数据宽度是2的倍数,如2,8,16,32,64等等。又因为人眼对蓝色的敏感度不如对红色和绿色,所以它比其他两个通道少用了一位。
另外一种格式是采用每通道9位尾数、所有通道共享5位指数的形式(众所周知,在计算机中,浮点数是采用尾数附加指数的形式来表示的),加起来还是32位。 这些新的格式使得纹理能够与原来占用同样多的显存空间,避免了大的空间和带宽消耗。同时,为了适合需要精确的科学计算的场合,DirectX 10能够支持每通道32位(4个通道加起来128位)精度的浮点数纹理。
DirectX 10中带来的这些扩充和提高,使得创建前所未有的细节的实时游戏场景真正成为可能。
几何着色器与流式输出
在DirectX 10发布之前,图形硬件只有在GPU上操作已有数据的能力。顶点着色器(Vertex Shader)和像素着色器(Pixel Shader)都允许程序操作内存中已有的数据。这种开发模型非常成功,因为它在复杂网格蒙皮和对已有像素进行精确计算方面都表现的很出色。但是,这种开发模型不允许在图像处理器上生成新数据。当一些物体在游戏中被动态的创建时(比如新型武器的外形),就需要调用CPU。可惜现在大多数游戏已经很给CPU带来了很大的压力,游戏进行时动态创建庞大数量新数据的机会就变得微乎其微了。
Shader Model 4.0中引入的几何着色器(Geometry Shader),第一次允许程序在图像处理器中创建新数据。这一革命性的事件使得GPU在系统中的角色由只可处理已有数据的处理器变成了可以以极快速度既可处理又可生成数据的处理器。在以前图形系统上无法实现的复杂算法现如今变成了现实。
几何着色器被放在顶点着色器和光栅化阶段(Rasterizer)中间。所谓光栅化,就是一行一行的扫描每个三角形,把它们一个像素一个像素的绘制到画面 上。几何着色器把经过顶点着色器处理过的顶点当作输入,对于每个顶点,几何着色器可以生成1024个顶点作为输出。这种生成大量数据的能力叫做数据扩大 (Data Amplification)。同样的,几何着色器也可以通过输出更少的顶点来删除顶点,因此,就叫做数据缩小(Data Minimization)。这两个新特性使GPU在改变数据流方面变得异常强大。
细分的虚拟位移贴图(Displacement Mapping withtessellation)
几何着色器让虚拟位移贴图可以在GPU上生成。虚拟位移贴图是在离线渲染系统中非常流行的一项技术,它可以用一个简单的模型和高度图(Height Map)渲染出非常复杂的模型。高度图是一张用来表示模型上各点高度的灰度图。渲染时,低多边形的模型会被细分成多边形更多的模型,再根据高度图上的信息,把多边形挤出,来表现细节更丰富的模型。
而在DirectX 9中,GPU无法生成新的数据,低多边形的模型无法被细分,所以只有小部分功能的虚拟位移贴图可以实现出来。现在,使用DirectX 10的强大力量,数以千计的顶点可以凭空创造出来,也就实现了实时渲染中真正的细分的虚拟位移贴图。
基于边缘(Adjacency)的新算法
几何着色器可以处理三种图元:顶点、线和三角形。同样的,它也可以输出这三种图元中的任何一种,虽然每个着色器只能输出一种。在处理线和三角形时,几何着 色器有取得边缘信息的能力。使用线和三角形边缘上的顶点,可以实现很多强大的算法。比如,边缘信息可以用来计算卡通渲染和真实毛发渲染的模型轮廓。
流式输出(Stream Output)
在DirectX 10之前,几何体必须在写入内存之前被光栅化并送入像素着色器(pixel shader)。DirectX 10引入了一个叫做数据流式输出(Stream Output)的新特性,它允许数据从顶点着色器或几何着色器中直接被传入帧缓冲内存(Frame Buffer Memory)。这种输出可以被传回渲染流水线重新处理。当几何着色器与数据流输出结合使用时,GPU不仅可以处理新的图形算法,还可以提高一般运算和物理运算的效率。
在生成、删除数据和数据流输出这些技术的支持下,一个完整的粒子系统就可以独立地在GPU上运行了。粒子在几何着色器中生成,在数据扩大的过程中被扩大与派生。新的粒子被数据流输出到内存,再被传回到顶点着色器制作动画。过了一段时间,它们开始逐渐消失,最后在几何着色器中被销毁。
高级渲染语言(HLSL 10)
DirectX 10 为以前的DirectX 9中的“高级着色语言”(High Level Shading Language )带来了诸多功能强大的新元素。其中包括可以提升常量更新速度的“常量缓冲器”(Constant Buffers),提升渲染流程中操作数据的灵活性的“视图”(view),为更广泛的算法所准备的“整数与位指令”(Integer and Bitwise Instructions),添加了switch语句。
常量寄存器(Constant Buffers)
着色程序同普通的程序一样需要使用常量来定义各种参数,例如光源的位置和颜色,摄像机的位置和投影矩阵以及一些材质的参数(例如反光度)。在整个渲染的过程中,这些常量往往需要频繁的更新,而数以百计的常量的使用以及更新无疑会给CPU带来极大的负载。DirectX 10中新加入的常量缓冲器可以根据他们的使用频率将这些常量分配到指定的缓冲器中并协调的对其进行更新。
在一个着色程序中DirectX 10支持最多16个常量缓冲器,每一个缓冲器可以存放4096个常量。与其相比DirectX 9实在是少得可怜,因为它在每个着色程序中同时最多只能支持256个常量。
∠啾