当游戏的画面拟真度越来越高时,仅仅靠CPU来进行图形图像处理已经不能满足游戏的需要了。于是,人们开始尝试用硬件加速卡来协助CPU进行3D图像处理,此举在技术上和商业上都大获成功。早期比较出名的比如 Voodoo等。于是,大量的加速卡及GPU(Graphic Processing Unit)设计公司开始迅速推出自己的设计,如 ATI(刚被AMD收购),NVidia,PowerVR(市场萎缩,转向嵌入式系统的3D加速单元,参考PowerVR MBX及OpenGL ES)等开始展露头角。
GPU是计算机显卡的“心脏”,也就相当于CPU在电脑中的作用,它决定了该显卡的档次和大部分性能,同时也是2D显示卡和3D显示卡的区别依据。2D显示芯片在处理3D图像和特效时主要依赖CPU的处理能力,称为“软加速”。3D显示芯片是将三维图像和特效处理功能集中在显示芯片内,也即所谓的“硬件加速”功能。显示芯片通常是显示卡上最大的芯片(也是引脚最多的)。现在市场上的显卡大多采用NVIDIA和ATI两家公司的图形处理芯片。
GPU使显卡减少了对CPU的依赖,并进行部分原本CPU的工作,尤其是在3D图形处理时。GPU所采用的核心技术有硬体T&L、立方环境材质贴图和顶点混合、纹理压缩和凹凸映射贴图、双重纹理四像素256位渲染引擎等,而硬体T&L技术可以说是GPU的标志。
GPU能够从硬件上支持T&L(TransformandLighting,多边形转换与光源处理),T&L是3D渲染中的一个重要部分,其作用是计算多边形的3D位置和处理动态光线效果,也可以称为“几何处理”。一个好的T&L单元,可以提供细致的3D物体和高级的光线特效;
问题随之出现:每家公司可能都有自己的设计方案(产品),那么游戏和3D应用程序开发者所设计开发出来的软件就很难在不同的厂商之间的加速卡上运行,很难很好的使用这些加速卡的加速功能。也就是说,这类应用程序的移植性将会降低。
要解决移植性的问题,可以通过将加速卡功能抽象出来,统一定义接口的形式来实现。于是,人们采用了典型的分层模式,将一套应用程序分为3个层次:
应用程序层 -> 硬件抽象层 -> 硬件层
其中,应用层 就是游戏和应用软件开发人员的开发主体,他们调用统一的加速卡API来进行上层开发,而不用考虑移植性问题;
硬件抽象层 则抽象出硬件的加速功能,进行有利于应用层开发的封装,并向应用层开放API;
硬件层 将硬件驱动提供给抽象层,以实现抽象层加速功能的有效性。
这个结构有效的将游戏和应用程序 与 硬件加速卡隔离开,这就很好的提升了程序的移植能力。并且,还有一个好处就是,开发人员的知识复用率得到提高,从而降低了3D显示软件的开发门槛。
于是,众多的加速卡厂家就联合起来,形成一个组织,共同制定出了这个硬件抽象层的接口标准,这就是OpenGL。
而出于同样的目的,微软也定义了一套平行的类似于OpenGL的接口集合,就叫做 Direct 3D。
这就是OpenGL和D3D的起源。
不同的是,OpenGL只包含了3D加速接口,而DirectX除了D3D之外,还包含了声音接口Direct Sound,然后还有输入输出设备的接口,统称为DirectX。
不论OpenGL还是D3D,他们的工作流程其实是大同小异的。
下面以D3D为例,进行讨论。
3D加速卡的主要功能就是协助CPU,负责将内存中的矢量图像数据(顶点集合)进行变换、光照计算、裁剪等操作,最后经过光栅化将图像呈现给人眼。这个过程就叫做渲染,D3D把整个渲染分为9个步骤,叫做渲染流水线(管线)。
D3D的渲染管线(Rendering Pipeline):
局部坐标变换 -> 世界坐标变换 ->观察坐标变换->背面消除->光照->裁剪->投影->视口计算->光栅化
D3D里包含了倆种渲染流水线:固定管线 和 可编程管线。可编程管线就是说管线中的某些环节是可以被控制的。人们可以通过对GPU中的着色器进行编程的方式,来控制、管理加速卡的渲染效果。着色器分为 顶点着色器和像素着色器。 顶点着色器是在进行 坐标变换 和 光照计算时工作,像素着色器是在光栅化环节工作。人们对着色器进行自定义编程时,这个流水线就叫做 可编程管线。同时,D3D还提供默认的着色器程序,当游戏或应用程序完全使用默认着色器程序时,这个流水线就叫做 固定管线。
局部坐标系:就是建模坐标系,它是在建模时由3DMAX之类的工具定义的。
世界坐标系:用来统一场景中各个object的位置、尺寸等规格
在固定管线中,坐标变换分成2个步骤:局部坐标系到世界坐标系 和 世界坐标系到观察坐标系。
局部坐标系到世界坐标系变换:
投影:
// 定义视图矩阵
D3DXMATRIXA16 matProj;
// 透视投影
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f );
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );