DirectX 12 持续整理 ——4.Direct3D 初始化

绝大部分内容来自于《Introduction to 3D Game Programming with DirectX12 Frank D. Luna》

4. Direct3D 初始化 (Direct3D Initialization)

  从此之后,所接触的内容不再是一些枯燥的数学题了,而是和 DirectX 本身切实相关。在本章中,所要了解的内容包括熟悉 Direct3D 中所包含的类型,基本图形概念,以及 Direct3D 初始化的一系列步骤等等。

  所要了解的内容有以下几个:
  1. 需要对 Direct3D 在硬件中的编程所扮演的角色有一个基本的了解;
  2. COM 在Direct3D 中起到的作用;
  3. 了解基本的图形概念。这其中包括 2D 图像的存储,页面翻转,深度缓冲,多重采样,以及 CPU 和 GPU 之间是如何协调工作的;
  4. 要如何进行 Direct3D 初始化;
  5. 在本章中会展示一个通用的框架结构,此框架会贯穿全书,所以要尽可能了解它。

4.1 基本概念

4.1.1 Direct3D 12 概述

  Direct3D是工作在图形处理单元(GPU:Graphics Processing Unit)上的底层应用程序接口(API:Application Programming Interface),所以当我们渲染3D世界图形时,能够使用硬件条件进行加速。每当 Direct3D 应用程序执行函数时,Direct3D 硬件驱动程序会直接将命令转换为GPU所能理解的指令进行执行,因此不必担心 GPU 的工作细节,只需要注意 GPU 所能支持的 Direct3D 版本就可以了。

Direct3D 12 概述:https://msdn.microsoft.com/zh-cn/communitydocs/game-development/directx-12-white-paper/ta15073002

4.1.2 COM

  组件对象模型(COM:Component Object Model)允许 DirectX 独立为一种新的编程语言(理解上可以这么说)并能够向下兼容,换句话说就是面向组件编程。通常来说,我们把 COM 对象称之为接口,而这些接口的细节大多是以 C++ 语言来完成的。使用 COM 组件我们可以通过特殊的方式或者函数来获取 COM 接口的指针,而不必再使用 C++ 的 new 关键字了。此外,COM 对象使用的是引用计数,当我们完成了一个过程需要释放接口对象时,就需要调用 Release 函数(相当于 C++ 的 delete 关键字)来完成释放内存的操作,并将引用计数置为 0 。

  为此,我们使用Windows运行时库(WRL:Windows Runtime Library)的 Microsoft::WRL::ComPtr 类(#include <wrl.h>)来管理COM对象的生命周期。当一个 ComPtr 超出生命周期之外,则Release函数会被自动调用来释放 COM 对象,这时就不需要去手动调用它。

COM智能指针:https://msdn.microsoft.com/magazine/dn904668

  ComPtr主要有3个函数被经常使用:
  1. Get:返回一个COM对象的指针。一般情况下,当一个 COM 对象需要作为参数传递给函数时调用Get。例如:

ComPtr<ID3D12RootSignature> mRootSignature;
...
mCommandList->SetGraphicsRootSignature(mRootSignature.Get());

  2. GetAddressOf:返回一个 COM 对象地址的指针。可以在某个函数需要 COM 对象的指针时,使用GetAddressOf来获得指针:

ComPtr<ID3D12CommandAllocator> mDirectCmdListAlloc;
...
ThrowIfFailed(md3dDevice->CreateCommandAllocator(
    D3D12_COMMAND_LIST_TYPE_DIRECT,
    mDirectCmdListAlloc.GetAddressOf()
    )
);

  3. Reset:将一个 ComPtr 置为 nullptr(空指针),并将 COM 引用计数为0。

4.1.3 纹理格式(Textures Formats)

  对于一个 2D 纹理(Textures)来说,它可以看作是一个矩阵,矩阵中的每一个元素都是一个数据点,而每个数据点都是这个 2D 图片的颜色像素。然而在映射中,上述矩阵的每一个元素并非一个颜色像素,而是一个 3D 向量,这样,就可以将一个 2D 的图像映射到 3D 物体表面,这就相当于把一张平面图贴在 3D 物体上。

  当然,纹理不仅仅是一个二维数据组成的数据结构那么简单。它可以被GPU进行特殊处理,让它能够被应用过滤器和多重采样等功能中。

  而且,纹理的数据元素不能是任意类型,它的类型是有限的(以下是DXGI_FORMAT 枚举类型的部分数据成员):
  1. DXGI_FORMAT_R32G32B32_FLOAT:每个数据元素是由3个32位的浮点数组成。
  2. DXGI_FORMAT_R16G16B16A16_UNORM:每个数据元素是由4个16位映射到 [0,1] 范围数字组成。
  3. DXGI_FORMAT_R32G32_UINT:每个数据元素为2个32位的无符号整数。
  4. DXGI_FORMAT_R8G8B8A8_UNORM:每个数据元素映射至 [0,1] 范围,由4个8位无符号数组成。
  5. DXGI_FORMAT_R8G8B8A8_SNORM:每个数据元素映射至 [-1,1] 范围,由4个8位有符号数组成。
  6. DXGI_FORMAT_R8G8B8A8_SINT:4个8位有符号整数、每个元素映射至 [-128,127] 。
  7. DXGI_FORMAT_R8G8B8A8_UINT:4个8位无符号整数、每个元素映射至 [0,255] 。

DXGI_FORMAT enumeration: https://msdn.microsoft.com/en-us/library/windows/desktop/bb173059

4.1.4 交换链(Swap Chain)和页面翻转(Page Flipping)

  为了避免画面闪烁,最好将整个画面帧都写入一个被叫做后缓冲(back buffer)里。当一个画面帧存在于后缓冲中,这个画面就不会在屏幕展示出来,而是作为备用的帧在后端。当前缓冲(front buffer)存储的画面帧在显示器上显示完成,则前后缓冲执行翻转操作,前后缓冲区指针调换,将后缓冲作为前缓冲,存储的画面帧进行显示,此过程被称之为呈现(presenting);前缓冲作为后缓冲,准备下一帧将要显示的画面。

  上述两个缓冲区组成交换链(Swap Chain)。在 Direct3D 中,交换链是由 IDXGISwapChain 接口表示。该接口存储前后缓冲的纹理,并且提供了设置缓冲区大小的函数 IDXGISwapChain::ResizeBuffers 和呈现函数 IDXGISwapChain::Present

  利用两个缓冲区(前后缓冲)组成交换链的方式叫做双重缓冲(double buffering),也就是说,交换链不是必须要用两个缓冲区才可以,也可以用两个数量以上的缓冲,但是通常情况下两个就已经绰绰有余了。

  尽管后缓冲区存储的是一个纹理,但是它却没有存储颜色信息——也就是说,它的每个数据元素并非是一个像素(pixel),而是一个“纹素(texel)”。

4.1.5 深度缓冲(Depth Buffering)

  深度缓冲同样是纹理,而且同样不包含图像信息,它包含像素有关“深度”的信息。深度值的范围在 0.0 与 1.0 之间,其中 0.0 表示是最接近显示器屏幕,1.0 是距离显示器屏幕最远,这样就能达到 3D 物体在 2D 屏幕上显示的遮盖以及近大远小等效果。深度缓冲存储的信息数目与分辨率相同,每一个像素都有属于自己的深度缓冲信息。

  由于深度缓冲属于纹理,所以它必须被特殊的数据格式来定义:

  1. DXGI_FORMAT_D32_FLOAT_S8X24_UINT:指定一个32位浮点数深度缓冲,保留8位(unsigned integer,[0, 255])为模版缓冲(stencil buffer)使用,其余的24位不用于填充。
  2. DXGI_FORMAT_D32_FLOAT:指定一个32位浮点数深度缓冲。
  3. DXGI_FORMAT_D24_UNORM_S8_UINT:指定一个无符号24位([0, 1])深度缓冲,8位(unsigned integer,[0, 255])为模版缓冲(stencil buffer)使用。
  4. DXGI_FORMAT_D16_UNORM:指定一个无符号16位([0, 1])的深度缓冲。

一个应用程序一般不需要模版缓冲(stencil buffer),但如果它一旦存在,它一定是附加到了深度缓冲中。例如 DXGI_FORMAT_D24_UNORM_S8_UINT 使用了24位为深度缓冲使用,而其余8位为模版缓冲使用,所以,深度缓冲的更好说法是“深度/模版缓冲(

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值