Direct3D是一种低级别API,可用于绘制每帧的三角形、线条或点,或者在GPU上启动高度并行操作。Direct3D的初始化过程要熟悉一些基本的Direct3D类型和基本绘图概念。

一、DXGI概述

DXGI(Microsoft DirectX Graphics Infrastructure,Microsoft DirectX图形基础结构)主要目的是管理可独立于DirectX图形运行时的低级别任务,为未来图形组件提供了通用框架。DXGI的用途是与内核模式驱动程序和系统硬件进行通信,如下图所示。

DXGI甚至是位于用户模式之下的、基于COM。DXGI有一个基础接口IDXGIObject::IUnknownIDXGIFactory, IDXGIAdapter, IDXGIDeviceIDXGIOutput都继承于它。

Object的方法主要是,访问父对象GetParent,获得和设置私有数据Set/GetPrivateData,以及设置私有数据接口SetPrivateDataInterface。说到父对象,DXGI中各类型对象的从属关系如图:

一切都从Factory开始、创建Factory的方法和其他COM接口一样。

二、COM

COM(Component Object Model,组件对象模型)是基于Windows 平台的一套组件对象接口标准,由一组构造规范和组件对象库组成。一般的对象是由数据成员和作用在其上的方法组成,而组件对象和一般对象虽有相似性,但又有较大不同。组件对象不使用方法而用接口来描述自身。接口被定义为“在对象上实现的一组语义上相关的功能”,其实质是一组函数指针表,每个指针必须初始化指向某个具体的函数体。

COM使DirectX独立于任何编程语言,并具有版本向后兼容的特性。我们经常把COM对象称为接口,并把它当成一个普通的C++类来使用。当使用C++编写DirectX程序时,许多COM的底层细节都不必考虑。唯一需要知道的一件事情是,我们必须通过特定的函数或其他的COM接口方法来获取指向COM接口的指针,而不能用C++的new关键字来创建COM接口。另外,当我们不再使用某个接口时,必须调用它的Release方法来释放它(所有的COM接口都继承于IUnknown接口,而Release方法是IUnknown接口的成员),而不能用delete语句——COM对象在其自身内部实现所有的内存管理工作。

COM接口都以大写字母“I”为前缀。例如,表示2D纹理的接口为ID3D11Texture2D

三、纹理和数据资源格式

2D纹理(texture)是一种数据元素矩阵。2D纹理的用途之一是存储2D图像数据,在纹理的每个元素中存储一个像素颜色。但这不是纹理的唯一用途;例如, 有一种称为法线贴图映射(normal mapping)的高级技术在纹理元素中存储的不是颜色,而是3D向量。因此,从通常意义上讲,纹理用来存储图像数据,但是在实际应用中纹理可以有更广泛的用途。1D纹理类似于一个1D数据元素数组,3D 纹理类似于一个3D数据元素数组。纹理不仅仅是一个数据数组;纹理可以带有多级渐近纹理层(mipmap level),GPU可以在纹理上执行特殊运算,比如使用过滤器(filter)和多重采样(multisampling)。此外,不是任何类型的数据都能存储到纹理中的;纹理只支持特定格式的数据存储,这些格式由DXGI_FORMAT枚举类型描述。一些常用的格式如下:

  • DXGI_FORMAT_R32G32B32_FLOAT:每个元素包含3个32位浮点分量。
  • DXGI_FORMAT_R16G16B16A16_UNORM:每个元素包含4个16位分量,分量的取值范围在[0,1]区间内。
  • DXGI_FORMAT_R32G32_UINT:每个元素包含两个32位无符号整数分量。
  • DXGI_FORMAT_R8G8B8A8_UNORM:每个元素包含4个8位无符号分量,分量的取值范围在[0,1]区间内。
  • DXGI_FORMAT_R8G8B8A8_SNORM:每个元素包含4个8位有符号分量,分量的取值范围在[−1,1] 区间内。
  • DXGI_FORMAT_R8G8B8A8_SINT:每个元素包含4个8位有符号整数分量,分量的取值范围在[−128, 127] 区间内。
  • DXGI_FORMAT_R8G8B8A8_UINT:每个元素包含4个8位无符号整数分量,分量的取值范围在[0, 255]区间内

字母R、G、B、A分别表示red(红)、green(绿)、blue(蓝)和alpha(透明度)。每种颜色都是由红、绿、蓝三种基本颜色组成的。alpha通道(或alpha分量)用于控制透明度。纹理存储的不一定是颜色信息;例如,格式DXGI_FORMAT_R32G32B32_FLOAT包含3个浮点分量,可以存储一个使用浮点坐标的3D向量。

四、交换链

为了避免渲染实时图像时出现“撕裂”问题,最好的做法是在一个离屏(off-screen)纹理(后台)中执行所有的动画帧绘制工作,这个离屏纹理称为后台缓冲区(back buffer)。当我们在后台缓冲区中完成给定帧的绘制工作后,便可以将后台缓冲区作为一个完整的帧显示在屏幕上;使用这种方法,用户不会察觉到帧的绘制过程,只会看到完整的帧。从理论上讲,将一帧显示到屏幕上所消耗的时间小于屏幕的垂直刷新时间。硬件会自动维护两个内置的纹理缓冲区来实现这一功能,这两个缓冲区分别称为前台缓冲区(front buffer)和后台缓冲区。前台缓冲区存储了当前显示在屏幕上的图像数据,而动画的下一帧会在后台缓冲区中执行绘制。当后台缓冲区的绘图工作完成之后,前后两个缓冲区的作用会发生翻转:后台缓冲区会变为前台缓冲区, 而前台缓冲区会变为后台缓冲区,为下一帧的绘制工作提前做准备。前后缓冲区功能互换的行为称做呈现(presenting)。提交是一个运行速度很快的操作,因为它只是将前台缓冲区的指针和后台缓冲区的指针做了一个简单的交换。如图所示:

前后缓冲区形成了一个交换链(swap chain)。在Direct3D中,交换链由IDXGISwapChain接口表示。该接口保存了前后缓冲区纹理,并提供了用于调整缓冲区尺寸的方法(IDXGISwapChain::ResizeBuffers)和呈现方法(IDXGISwapChain::Present)。

五、深度缓冲区

【颜色缓冲区】

  颜色缓冲区(color buffer)就是帧缓冲区(frame buffer),你需要渲染的场景最终每一个像素都要写入该缓冲区,然后由它在渲染到屏幕上显示;

【深度缓冲区】

  深度缓冲区(depth buffer)与帧缓冲区对应,用于记录上面每个像素的深度值,通过深度缓冲区,我们可以进行深度测试,从而确定像素的遮挡关系,保证渲染正确;

【模板缓冲区】

  模版缓冲(stencil buffer)与深度缓冲大小相同,通过设置模版缓冲每个像素的值,我们可以指定在渲染的时候只渲染某些像素,从而可以达到一些特殊的效果。

(1)什么是深度

深度其实就是该象素点在3d世界中距离摄象机的距离(绘制坐标),深度缓存中存储着每个象素点(绘制在屏幕上的)的深度值。深度值(Z值)越大,则离摄像机越远。深度值是存贮在深度缓存里面的,我们用深度缓存的位数来衡量深度缓存的精度。深度缓存位数越高,则精确度越高。

(2)为什么需要深度

在不使用深度测试的时候,如果我们先绘制一个距离较近的物体,再绘制距离较远的物体,则距离远的物体因为后绘制,会把距离近的物体覆盖掉,这样的效果并不是我们所希望的。而有了深度缓冲以后,绘制物体的顺序就不那么重要了,都能按照远近(Z值)正常显示。

深度缓冲区用于为每个像素计算深度值和实现深度测试。深度测试通过比较像素深度来决定是否将该像素写入后台缓冲区的特定像素位置。只有离观察者最近的像素才会胜出,成为写入后台缓冲区的最终像素。这很容易理解,因为离观察者最近的像素会遮挡它后面的其他像素。

深度缓冲区是一个纹理,所以在创建它时必须指定一种数据格式。用于深度缓存的格式如下:

  • DXGI_FORMAT_D32_FLOAT_S8X24_UINT:32位浮点深度缓冲区。为模板缓冲区预留8位(无符号整数),每个模板值的取值范围为[0,255]。其余24位闲置。
  • DXGI_FORMAT_D32_FLOAT:32位浮点深度缓冲区。
  • DXGI_FORMAT_D24_UNORM_S8_UINT:无符号24位深度缓冲区,每个深度值的取值范围为[0,1]。为模板缓冲区预留8位(无符号整数),每个模板值的取值范围为[0,255]。
  • DXGI_FORMAT_D16_UNORM:无符号16位深度缓冲区,每个深度值的取值范围为[0,1]。

【注意】模板缓冲区对应用程序来说不是必须的,但是如果用到了模板缓冲区,那么模板缓冲区必定是与深度缓冲区存储在一起的。例如,32位格式DXGI_FORMAT_D24_UNORM_S8_UINT使用24位用于深度缓冲区,8位用于模板缓冲区。 所以,将深度缓冲区称为“深度/模板缓冲区”更为合适。

六、纹理资源视图

纹理可以被绑定到渲染管线(rendering pipeline)的不同阶段(stage);例如,比较常见的情况是将纹理作为渲染目标(即,Direct3D渲染到纹理)或着色器资源(即,在着色器中对纹理进行采样)。当创建用于这两种目的的纹理资源时,应使用绑定标志值:

D3D11_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE

指定纹理所要绑定的两个管线阶段。其实,资源不能被直接绑定到一个管线阶段;我们只能把与资源关联的资源视图绑定到不同的管线阶段。无论以哪种方式使用纹理,Direct3D始终要求我们在初始化时为纹理创建相关的资源视图(resource view),这样有助于提高运行效率。正如SDK文档指出的那样:“运行时环境与驱动程序可以在视图创建执行相应的验证和映射,减少绑定时的类型检查”。所以,当把纹理作为一个渲染目标和着色器资源时,我们要为它创建两种视图:渲染目标视图(ID3D11RenderTargetView)和着色器资源视图(ID3D11ShaderResourceView)。资源视图主要有两个功能:(1)告诉Direct3D如何使用资源(即,指定资源所要绑定的管线阶段);(2)如果在创建资源时指定的是弱类型(typeless)格式,那么在为它创建资源视图时就必须指定明确的资源类型。

对于弱类型格式,纹理元素可能会在一个管线阶段中视为浮点数,而在另一个管线阶段中视为整数。为了给资源创建一个特定视图,我们必须在创建资源时使用特定的绑定标志值。例如,如果在创建资源没有使用D3D11_BIND_DEPTH_STENCIL绑定标志值(该标志值表示纹理将作为一个深度/模板缓冲区绑定到管线上),那我们就无法为该资源创建ID3D11DepthStencilView视图。

七、多重采样

因为计算机显示器上的像素分辨率有限,所以当我们绘制一条任意直线时,会出现锯齿效应,当使用像素矩阵近似地表示一条直线时就会出现这种现象,类似的锯齿也会发生在三角形的边缘上。通过提高显示器的分辨率,缩小像素的尺寸,也可以有效地缓解一问题,使阶梯效应明显降低。

当无法提高显示器分辨率或分辨率不够高时,我们可以使用抗锯齿(antialiasing)技术。其中的一种技术叫做超级采样(supersampling),它把后台缓冲和深度缓冲的大小提高到屏幕分辨率的4倍。3D场景会以这个更大的分辨率渲染到后台缓存中,当在屏幕上呈现后台缓冲时,后台缓冲会将4个像素的颜色取平均值后得到一个像素的最终颜色。从效果上来说,超级采样的工作原理就是以软件的方式提升分辨率。

超级采样代价昂贵,因为它处理的像素数量和所需的内存数量增加为原来的4倍。Direct3D支持另一种称为多重采样(multisampling)的抗锯齿技术,它通过对一个像素的子像素进行采样计算出该像素的最终颜色,比超级采样节省资源。假如我们使用的是4X多重采样(每个像素采样4个邻接像素),多重采样仍然会使用屏幕分辨率4倍大小的后台缓冲和深度缓冲,但是,不像超级采样那样计算每个子像素的颜色,而是只计算像素中心颜色一次,然后基于子像素的可见性(基于子像素的深度/模板测试)和范围(子像素中心在多边形之外还是之内)共享颜色信息。下图展示了一个例子。

【注意】supersampling与multisampling的关键区别在于:使用supersampling时,图像的颜色需要通过每个子像素的颜色计算得来,而每个子像素颜色可能不同;使用multisampling时,每个像素的颜色只计算一次,这个颜色会填充到所有可见的、被多边形覆盖的子像素中,即这个颜色是共享的。因为计算图像的颜色是图形管线中最昂贵的操作之一,因此multisampling相比supersampling而言节省的资源是相当可观的。但是,supersampling更为精确,这是multisampling做不到的。

参考链接:

https://www.cnblogs.com/mumuliang/archive/2012/06/13/2548180.html

https://www.linuxidc.com/Linux/2014-07/104847.htm

https://enjoyphysics.cn/Article1467

【DirectX学习笔记】01_D3D初始化准备-基本绘图概念相关推荐

  1. OpenCV学习笔记(二十一)——绘图函数core OpenCV学习笔记(二十二)——粒子滤波跟踪方法 OpenCV学习笔记(二十三)——OpenCV的GUI之凤凰涅槃Qt OpenCV学习笔记(二十

    OpenCV学习笔记(二十一)--绘图函数core 在图像中,我们经常想要在图像中做一些标识记号,这就需要绘图函数.OpenCV虽然没有太优秀的GUI,但在绘图方面还是做得很完整的.这里就介绍一下相关 ...

  2. java 量化指标_量化投资学习笔记13——各种指标的绘图、计算及交易策略

    <量化投资:以python为工具>第五部分笔记 先来画k线图,要注意finance模块已经从matplotlib库中去除,现在要用mpl_finance库,单独安装. 其中有candles ...

  3. B站台湾大学郭彦甫|MATLAB 学习笔记|06 高阶绘图 Advanced Plot

    MATLAB学习笔记(06 高阶绘图 Advanced Plot) 如果想获得更好浏览体验的朋友可以转到下面链接 06 1. 对数图 (Logarithm Plots) x = logspace(-1 ...

  4. VBNET学习笔记---MS VBnet数据库访问技术,概念,介绍,发展历程.

    VBNET学习笔记---MS VBnet数据库访问技术,概念,介绍,发展历程. 2013-02-20 1.数据库访问技术 a.JET与DAO JET(Joint Engine Technology)数 ...

  5. cocos2d-x 学习笔记(2)cocos2d-x重要概念,项目结构及 CCDirector 导演控件

    cocos2d-x 学习笔记(2)cocos2d-x重要概念及项目结构 在cocos2d引擎中,有几个概念,分别是导演,场景,布景和人物角色. 导演(CCDirector)在cocos2d-x引擎中, ...

  6. Direct3D11学习:(二)基本绘图概念和基本类型

    转载请注明出处:http://www.cnblogs.com/Ray1024 一.概述 在正式开始学习D3D11之前,我们必需首先学习必要的基础知识. 在这篇文章中,我们将介绍一下Direct3D中常 ...

  7. 安全学习笔记(一):基础概念

    域名 什么是域名 域名(英语:Domain Name),又称网域,是由一串用点分隔的名字组成的Internet上某一台计算机或计算机组的名称,用于在数据传输时对计算机的定位标识(有时也指地理位置) 由 ...

  8. Linux C 应用编程学习笔记——(1)应用编程概念

    <[正点原子]I.MX6U嵌入式Linux C应用编程指南>学习笔记 系统调用 由操作系统实现提供的所有系统调用所构成的集合即程序接口或应用编程接口(Application Program ...

  9. DirectX学习笔记(九):模板缓存与镜面效果实现

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处.   文章链接: http://blog.csdn.net/zhmxy555/article/details/8632184 作者:毛星云( ...

  10. DirectX学习笔记(十五):粒子系统实现

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处.   文章链接:http://blog.csdn.net/zhmxy555/article/details/8744805 作者:毛星云(浅 ...

最新文章

  1. 烽火18台系列之十一:刚需中的刚需——网站篡改监控
  2. 这些Python常用的工具和学习资源你都知道么?
  3. 【刘汝佳可运行代码】Ordering Tasks UVA - 10305【两种解法】
  4. 我的工作日报 - 2020-9-16 星期三
  5. 7年老Android一次操蛋的面试经历,深度好文
  6. android webview 获取 title,【报Bug】app webview 安卓机 title显示问题
  7. 计算机网络技术期末应用试卷,中专学校2016年《计算机网络技术与应用》期末考试题(考试卷与答案)...
  8. 调试过程中需要使用的工具
  9. Silverlight:针式打印机文字模糊的改善办法
  10. 大航海时代4+伙伴加入条件和港口一览
  11. html中table分页显示,html中table表格分页
  12. VoLTE前台信令详析及注释说明
  13. html导航折叠与展开,html展开收起
  14. 56个民族HTML代码
  15. java做mmo服务器_MMO聊天服务器设计
  16. 【学习笔记】无限极分类学习
  17. 越南语常用的计数词,多少钱用越南语怎么说
  18. Xshell个人家庭免费版
  19. Soft Diffusion:谷歌新框架从通用扩散过程中正确调度、学习和采样
  20. 音视频编解码基础知识(1)- 音视频编解码过程

热门文章

  1. iOS导航控制器使用interactivePopGestureRecognizer导致导航栏标题可能层次错乱的问题解决
  2. React 入门学习
  3. 目标跟踪-按专题分类文章
  4. 高仿有赞微小店SplashView
  5. android vr sdk 架构,PowerVR图形SDK v4.0及工具终于问世
  6. 【软件构造】黑盒测试与白盒测试
  7. Golang面试题整理
  8. cdh6.3安装以及整合spark2、flink1.9
  9. uniapp获取用户数据昵称为“微信用户”(小程序)@杨章隐
  10. php 取出最后一数组元素,PHP取出数组中最后一个元素的方法汇总