您的位置:首页 > 产品设计 > UI/UE

【翻(xue)译(xi)】3D Game Programming With DirectX11 - 4.1

2016-02-19 03:42 344 查看
前段时间学习DX的翻译笔记,诸多错误~(>_<)~当时因为发现啃英文书的时候常常因为纠结于词句的意思而没法好好思考书中的内容,所以索性写出来。其实好多词也许都翻译错了,虽然翻译的过程中一直查字典来着 - -。不管怎么说,反正学英语的效果很好的 XD~

所以打算以后还是继续用这种方式继续啃一啃!恩!

所以打算先把之前翻译好了的发出来,从第四章开始,每节一篇博文,末尾基本都有翻译存疑,意思是我也把不清怎么翻译。。。

第四章

4.1 预备,开始~

4.1.1 Direct3D 综述

Direct3D 是一个底层的图形API,让我们可以使用3d硬件加速来渲染3d世界。它提供软件接口来让我们控制图形硬件。比如,我们可以用 ID3d11DeviceContext::ClearRenderTargetView 这个函数来清除渲染目标(比如屏幕)。有Direct3D这一层在应用程序和图形硬件之间,意味着我们不需要考虑底层硬件了。只要硬件支持Direct3D

一个支持Direct3D 11 的硬件设备必须支持它的所有指令集,极少有例外(比如多重采样计算还是需要具体考虑,因为在不同的11设备上它们也会不一样)。这和Direct3D 9 形成了对照,9只需要设备支持它的一部分指令集;因此,如果一个9的应用程序想要调用一个特定的功能,检验硬件是否支持就很有必要,因为如果硬件不支持的话调用就会出错。但是在在11里边,检查设备是否支持已经不需要了!因为它精确要求设备支持所有的指令集!耶!

4.1.2 COM组件

组件对象模型(COM)是一个技术,这个技术可以让DirectX 成为独立的变成语言,而且具有向后兼容性。我们提到一个组件对象模型对象时是一个接口的,对我们来说可以看做一个C++的类。使用C++来编写DirectX的时候,许多细节我们都不用解除。我们唯一需要知道的就是,我们必须通过一些特定的函数或者COM的接口,获得COM接口的指针,而不是通过C++的 new。而且,我们用完这个指针之后使用Release函数(所有的COM接口都从IUnknon 这个接口继承,这个接口有Release函数),而不是使用delete。COM自己有自己的内存管理。

关于COM还有很多东西可以用来让我们更有效的使用DirectX,但是我们现在不需要。

Tips:COM组件都使用一个大写的“I”作为前缀,比如一个关于2d贴图的COM组件叫做 ID3D11Texture2D

4.1.3 贴图和数据资源的格式

一个2d纹理是一个数据元素的矩阵。2d纹理的其中一个用途就是用来存储2d图像数据,每个元素代表一个像素颜色。不过这也不是唯一的用途,比如,在一个先进的叫做法线贴图的技术中,每一个元素代表一个3d向量。所以,虽然把2d纹理想成存储图像是很自然的事情,它其实有更大的用途。一个1d的纹理就是一个1d的数组,3d纹理就是3d的数组。以后我们会讨论到,纹理不仅仅是数据的数组;他们会有多级分辨率纹理,GPU可以对它们有特殊的处理,比如过滤和多重采样。而且,一个纹理不能存储任意类型的数据,它只能存储一些特定格式的数据,由 DXGI_FORMAT 枚举出来。

例:DXGI_FORMAT_R32G32B32_FLOAT

注意RGBA分别代表红绿蓝和alpha通道。颜色是由基础色组成的,alpha通道是用来控制透明度的。例子中的那个格式,可以存储3个浮点数,也即可以存储一个3d坐标系里边的3d向量。另外还有无类型格式,我们只保存内存,然后当纹理被绑定到管线的时候,再重新解释这个数据(就像C++里边的重新解释)。

4.1.4 交换链和页面置换

为了避免动画的闪,应该把整个帧都画好到一个屏幕以外的地方,也就是后台缓冲区。一旦某个帧被完全画到后台缓冲区,它将会被以完整的一帧提交到屏幕上。这样一来,我们就不用看着它被画出来了——我们只看到完整的一帧。为了实现这一点,硬件使用了两个纹理缓冲区,前台缓冲区和后台缓冲区。前台缓冲区存储显示器上正在显示的图像,同时下一帧图像被画到后台缓冲区。当下一帧被画好后,后台缓冲区就替换了前台缓冲区。前后交换的过程称之为提交。提交是一个高效的操作,因为它只需要交换指针就可以了。

前后缓冲区形成了一个交换链。交换链由IDXGISwapChain接口 提交到表面(interface)。这个接口存储了前后缓冲区的材质,也提供了一些改变缓冲区大小(IDXGISwapChain::ResizeBuffers)和提交(IDXGISwapChain::Present)的方法。我们将在4.4详细讨论。

使用前后缓冲区,叫做双缓冲区。我们可以使用多余两个缓冲区。使用三个缓冲区叫做三缓冲区 - -。不过双缓冲区一般就够了。

Tips: 虽然后台缓冲区是一个纹理(所以其一个元素可以被叫做纹素),但是我们也经常把一个元素叫做像素,因为在后台缓冲区里边,它用来存储颜色信息。人们疆场会把纹理中的一个元素叫做像素,虽然它并不存储颜色信息。

4.1.5 深度缓存

深度缓存是一个不存储像素信息的纹理的例子,这个纹理存储的是特定像素的深度信息。值域是0到1,0表示最近1表示最远。后台缓存和深度缓存是一一对应的,所以他们大小也一样。

图示展示了一个简单的场景,这里一些物体遮住了另一些物体。为了让Direct3D 决定哪些像素在哪些前边,它使用了一个叫做深度缓存或者z缓存的技术。需要强调的是,我们先画哪些物体其实并没关系。

Tips: 为了解决深度问题,有人会建议从远到近画这些物体。这样一来近的就覆盖了远的。这是画家的方法。然而,这个方法有个问题——如何将所有物体从远至近排序并且切割几何体。而且,深度缓存是免费的嘛。

(为了展示深度缓存如何工作,作者举了一个栗子。略。)

所以你可以看出,我们只会用更近的像素和深度来更新深度缓存,这样一来,最终被渲染出来的就是离我们最近的那个像素。

综上所述,深度缓存的工作原理是使用一个一个深度值,然后为每一个像素进行深度测试。深度测试会让每个固定位置的像素来竞争深度值,这保证了留下的是离我们最近的像素。

深度缓冲区也是一个纹理,所以它也有一个格式,如下几种格式被用作深度缓存数据格式:

DXGI_FORMATE_D32_FLOAT_S8X24_UINT: 32位浮点数深度缓冲区,8位模板缓冲区([0,255]),24位保留;

DXGI_FORMAT_D32_FLOAT

DXGI_FORMAT_D24_UNORM_S8_UINT

DXGI_FORMAT_D16_UNORM

一个应用程序通常不需要使用模板缓存,不过如果它用了,模板缓存一般和深度缓存是一起的,比如上边第一个。所以模板缓存最好备叫做 深度/模板缓存。

4.1.6 纹理资源视图

一个texture可以被绑定到渲染管线的不同阶段。一个一般的例子:使用一个texture作为一个材质来源和shader的sample来源。一个这样用途的texture应当有以下这两个标志:

D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE

这说明这个texture将在渲染管线的两个阶段都被用到。实际上,这个资源并不被绑定到管线上,而是它的独立的资源视图被绑定到不同的管线阶段。这个主要是为了效率。SDK说明书如是说:“This allows validation and mapping in the runtime and driver to occur at view creation, minimizing type checking at bind-time.”所以说,在这个使用一张贴图作为渲染目标和着色器资源时,我们需要创建两个视图:一个渲染目标视图(ID3D11RenderTargetView)和一个着色器资源视图(ID3D11ShaderResourceView)。资源视图做两件事情:它告诉Direct3D这个资源将会如何被使用(管线的哪个阶段),和如果资源的格式是无类型,那么我们需要在在创建视图的时候声明类型。这样一来,我们就可以把无类型的纹理元素在不同的管线中解释成不同的类型,比如整数和浮点数。

为了创建一个特定的视图给这个资源,这个资源必须在创建的时候被绑定上那个特定的标志。比如,如果一个资源在创建的时候没有被绑定上 D3D11_BIND_DEPTH_STENCIL这个标签(这个标签代表将会在管线中的 深度/模板缓冲区 阶段使用),那么我们不能给这个资源创建一个ID3D11DepthStencilView。否则会报错的:

D3D11:ERROR: ID3D11Device::CreateDepthStencilView: A DepthStencilView cannot be created of a Resource that not specify D3D11_BIND_DEPTH_STENCIL

以后我们会详细说的。

Tips:2009年8月的SDK文档里边说:“Createing a fully-typed resource restricts the resource to the format it was created with. This enables the rumtime to optimize access […].”所以,你应该创建一个无类型的资源,如果你确实需要它提供的灵活性(意思就是多种方式来重新解释数据);或者,创建一个全类型的资源。

4.1.7 多重采样

因为显示器上的像素不是无限小的,所以它不能完美的画线。用像素矩阵来逼近一条直线的时候,就出现了失真。三角形的边缘也有同样的失真。

通过增加显示器分辨率降低像素大小的方法可以大大减轻这个问题直到锯齿不被发现。

不过增加显示器分辨率并不是必要的而且也不够,我们还可以使用抗锯齿技术。一种抗锯齿技术,称作“超级采样”,通过使后台缓存和深度缓存4倍于显示器分辨率来实现。3d的场景被渲染到这样一个大于显示器分辨率的后台缓存中,然后,当后台缓存提交到前台的时候,他就是用四个颜色的平均值作为实际的像素值。也就是说,多重采样是在软件中增加分辨率来实现的。

超级采样是昂贵的。因为它把需要计算和存储的像素数量四倍了。Direct3D提供了一种折衷的反走样技术,叫做多重采样。它在计算子像素的时候共享了一些计算信息,所以他会比超级采样更快一点。假设我们有一个4倍的多重采样(每个像素有4个子像素),多重采样也是用一个4倍的后台缓存和深度缓存;然而,他不会计算每一个像素,他只在每个像素计算一次,在这个像素的中心,然后和子像素共享这个颜色信息,以可见性(每个像素点进行深度/模板测试)和覆盖(子像素的中心在多边形的内部还是外部)。

Tips:注意多重采样和超级采样的不同。超级采样,每个像素点被计算一次,会是不同的颜色。多重采样,主像素的每个像素点都被计算一次,然后在多边形覆盖到的子像素点中被复制一次。因为计算颜色是图形管线中最耗时的步骤之一,所以多重采样中减少计算非常重要。不过另一方面,超级采样技术上来说更加精确,而且可以解决纹理和着色器的偏差,多重采样则不能。

Tips:多重采样中,如何将一个像素点分成四个子像素,在不同的硬件中可能不同,因为Direct3D也没有定义如何防止子像素。所以在某些机器中可能某些模式比另一些模式好。

4.1.8 Direct3D中的多重采样

在接下来,我们将会填充一个DXGI_SAMPLE_DEST 结构。

typedef struct DXGI_SAMPLE_DESC { 多重采样

UINT Count; 每个像素将被分成的子像素数量,采样个数

UINT Quality; 想要的质量等级(因硬件而异)

} DXGI_SAMPLE_DESC, *LPDXGI_SAMPLE_DESC;

较高的质量等级会更昂贵,所以必须找到合适的这种。质量等级的范围取决于纹理的格式和每个像素被分成的子像素数量。使用下边这个方法可以在给定Count和纹理类型的情况下,获得质量等级的范围。

HRESULT ID3DDevice::CheckMultisampleQualityLevels(

DXGI_FORMAT Format, UINT SampleCount, UINT *pNumQualityLevels);

将会返回0如果给定的格式和采样个数不被设备支持。否则机会通过第三个参数返回。我们可用的质量等级范围是0到pNumQualityLevels-1。

可用的最大的采样个数的数量被这样定义了:

#define D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT(32)

然而,一个4或者8的采样个数是比较城阳的,为了节约内存并且确保效果。如果你不想用多重采样的话,就把采样个数设置成1,这样质量等级就是0了。所有可以用Direct3D11的设备都支持所有纹理渲染格式的4倍多重采样。

Tips: 为了后台缓存和深度缓存,需要一个DXGI_SAMPLE_DESC 结构。后台混存和深度缓存被创建时都需要使用同样的多重采样设置。

4.1.9 特征级

Direct3D11 引进了一个新的观念叫做“特征级”(在D3D_FEATURE_LEVEL里边有枚举),它粗略地对应于Direct3D从9到11的各个版本:

typedef enum D3D_FEATURE_LEVEL

{

D3D_FEATURE_LEVEL_9_1 = 0x9100,



D3D_FEATURE_LEVEL_11_0 = 0xb000

} D3D_FEATURE_LEVEL;

特征级定义了一个严格的功能集合。这意味着如果用户的硬件不支持某个特征级,那么应用程序退到更老的一个特征级。例如为了支持更广的用户群,一个应用程序可能会支持Direct3D 11、10.1、10和9.3级的硬件。那么这个应用程序将会检查从新到旧一次检查特征级。这个次序由以下这个数组来定义:

D3D_FEATURE_LEVEL featureLevel[4] =

{

D3D_FEATURE_LEVEL_11_0,

D3D_FEATURE_LEVEL_10_1,

D3D_FEATURE_LEVEL_10_0,

D3D_FEATURE_LEVEL_9_3,

};

这个将会在Direct3D初始化的时候就被放进去,并且输出第一个支持的特征级。例如如果找到的是10.0,那么11和10.1都会被禁用,然后使用10.0。不过,实际上我们不需要考虑支持更老的设备来扩大我们的用户群。

翻译存疑:

capability set: 指令集

interface: 接口;表面(DX9龙书翻译作 表面)

texture: 纹理

texel: 纹素

backwards capatibility: 向后兼容性

mipmap: 多分辨率纹理

typeless formats: 无类型格式

reinterpret cast: 重新解释

presenting: 提交(这个可能是对的,参考DX9龙书)

double buffering: 双缓冲区

resource view: ?

This allows validation and mapping in the runtime and driver to occur at view creation, minimizing type checking at bind-time. :?

subpixels:子像素

supersampling: 超级采样

4X multisampling: 4重采样

feature level: 特征级
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: