预备知识

1.DirectX:它是微软公司创建的多媒体编程接口,由显示部分(由负责2D显示的DirectDraw和3D显示的Direct3D组成)、声音部分(DirectSound)、输入部分(DirectInput)和网络部分(DirectPlay)组成。

2.Direct3D:它是DirectX中的重要组成部分,是编写高性能3D图形应用程序的渲染库。可以把它看作是一种介于程序员和图形硬件之间的桥梁。借此,程序员便可以通过调用Direct3D函数来实现把资源视图绑定到硬件渲染流水线,配置渲染流水线的输出以及绘制3D几何体等操作。

3.组件对象模型(COM)是一种可以令DirectX不依赖于特定语言且向后兼容的技术。Direct3D程序员不需知道COM的具体实现细节,也无需了解其工作原理,只需知晓如何获取和释放COM接口即可。为了辅助Direct3D程序员管理COM对象生命周期,Windows运行时库专门为此提供了ComPtr类,我们可以把它当做COM对象的智能指针。当一个ComPtr对象超出作用域范围时,它便会自动调用相应COM对象的Release方法,继而省掉手动调用的麻烦。ComPtr类中常用的方法如下所示:
1>.Get:返回一个指向此底层COM接口的指针。此方法常用于把原始的COM接口指针作为参数传递给函数。
2>.GetAddressOf:返回指向此底层COM接口指针的地址。凭此方法即可利用函数参数返回COM接口的指针。
3>.Reset:等价于将ComPtr对象赋值为nullptr。此方法释放ComPtr对象的所有引用(同时减少其底层COM接口的引用计数)。

4.1D,2D,3D纹理分别类似于由数据元素所构成的1D,2D,3D数组。具有以下特性:
1>.纹理的格式必定为DXGI_FORMAT枚举类型中的成员之一。
2>.纹理除了可以存储像素颜色外,还可以存储像素深度等其他类型数据。
3>.GPU可以对纹理进行特殊的操作,比如运用过滤器和进行多重采样。

5.为了避免动画中发生闪烁的问题,最好将动画帧完全绘制到一种称为后台缓冲区的离屏纹理中。只要依次行事,显示在屏幕上的就会是一个完整的动画帧,观者也就不会察觉到帧的绘制过程。当动画帧被绘制在后台缓冲区后,前台缓冲区与后台缓冲区的角色也就该互换了:为了显示下一帧动画,此前的后台缓冲区将变为前台缓冲区,而此前的前台缓冲区亦会变成后台缓冲区。后台和前台缓冲区交换角色的行为称为呈现。前台和后台缓冲区构成了交换链,在代码中通过IDXGISwapChain接口来表示。使用两个缓冲区(前台和后台)的情况称作双缓冲。

6.深度缓冲区中存储像素的深度值。该值的范围为0.0 ~ 1.0,其中0.0代表观察者在视椎体中能看到离自己最近的物体,1.0则代表观察者在视椎体中能看到离自己最远的物体。

7.深度测试用于判定操作像素的深度值是否小于等于深度缓冲区中存储的深度值,如果是就表示深度测试通过;否则就表示深度测试不通过。当深度测试通过时,就将操作像素的深度值写入到深度缓冲区中,并将操作像素的颜色值写入到后台缓冲区中。

8.深度缓冲技术就是一种利用深度测试来确定场景中离摄像机最近点的技术。通过这种技术,我们就不必担心场景中物体的绘制顺序了。

9.描述符也叫做视图。具有以下特性:
1>.在Direct3D中,资源不能直接与渲染流水线绑定。为此,我们需要为绘制调用时所引用的资源指定描述符。
2>.可以将描述符对象看作是GPU识别以及描述资源的一种轻量级结构。
3>.应用程序可以通过创建描述符堆来为描述符分配所需的内存。
4>.可以为同一种资源创建不同的描述符。如此一来,一种资源就可以具有多种用途。
5>.常见的描述符有CBV(constant buffer view)常量缓冲区视图,SRV(shader resource view)着色器资源视图,UAV(unordered access view)无序访问视图,RTV(render target view)渲染目标视图,DSV(depth / stencil view)深度 / 模板视图,采样器等。

10.ID3D12Device是Direct3D中重要的接口,我们可以把它看作是图形硬件设备的软件控制器。我们能够通过它来创建GPU资源以及其他用于控制图形硬件的特定接口。具有以下特性:
1>.通过CheckFeatureSupport函数来检测当前图形驱动对指定功能的支持。
2>.通过GetNodeCount函数来查询系统中GPU适配器节点的数量。
3>.通过MakeResident函数来指定资源数组中指定个数的资源驻留在显存中。
4>.通过Evict函数来指定资源数组中指定个数的资源从显存中清出。

11.锯齿指的是以像素矩阵逼近直线时所产生的阶梯效应。如图所示:
在这里插入图片描述
改善锯齿的方法如下所示:
1>.提高显示器的分辨率就能够缩小像素的大小,从而使阶梯效应在很大程度上不易被用户所察觉。如图所示:
在这里插入图片描述
2>.使用超级采样(SSAA)技术,它使用4倍于屏幕分辨率大小的后台缓冲区和深度缓冲区。3D场景将以这种更大的分辨率渲染到后台缓冲区中。当数据要从后台缓冲区调往屏幕显示的时候,会将后台缓冲区按四个像素为一组进行解析,通过每组求平均值的方法来得到一个相对平滑的像素颜色。
3>.使用多重采样(MSAA)技术,它计算一次像素中心处的颜色,再基于可视性(每个子像素经深度 / 模板测试的结果)和覆盖性(子像素的中心在多边形的里面还是外面)将得到的颜色信息分享给其他子像素。参考代码如下所示:

// 第一步:获取图像质量级别
typedef struct D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS {
	DXGI_FORMAT Format; // 纹理格式类型
	UINT SampleCount; // 每个像素的采样数量
	D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS Flags; // 多重采样标志
	UINT NumQualityLevels; // 输出图像质量级别
} D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS;

D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msQualityLevels;
msQualityLevels.Format = mBackBufferFormat;
msQualityLevels.SampleCount = 4;
SampleCount.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE;
SampleCount.NumQualityLevels = 0;
md3dDevice->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msQualityLevels, sizeof(msQualityLevels));

// 第二步:在创建交换链缓冲区(既是前后缓冲区)和深度缓冲区时需要填写DXGI_SAMPLE_DESC结构体。当采样数量设置为1以及质量级别为0时,就不使用多重采样。
typedef struct DXGI_SAMPLE_DESC {
	UINT Count; // 每个像素的采样数量
	UINT Quality; // 图像质量级别
} DXGI_SAMPLE_DESC;

12.功能级别为不同级别所支持的功能进行了严格的界定。如果用户的硬件不支持某特定功能级别,应用程序理当回退至版本更低的功能级别。参考代码如下所示:

enum D3D_FEATURE_LEVEL
{
	D3D_FEATURE_LEVEL_9_1 = 0x9100,
	D3D_FEATURE_LEVEL_9_2 = 0x9200,
	D3D_FEATURE_LEVEL_9_3 = 0x9300,
	D3D_FEATURE_LEVEL_10_0 = 0xa000,
	D3D_FEATURE_LEVEL_10_1 = 0xa100,
	D3D_FEATURE_LEVEL_11_0 = 0xb000,
	D3D_FEATURE_LEVEL_11_1 = 0xb100,
	D3D_FEATURE_LEVEL_12_0 = 0xc000,
	D3D_FEATURE_LEVEL_12_1 = 0xc100
};

13.DXGI(DirectX图形基础结构)是一种与Direct3D配合使用的API。具有以下特性:
1>.显示模式用DXGI_MODE_DESC结构体来表示。
2>.显示设备用IDXGIOutput接口来表示,其数据信息存储在DXGI_OUTPUT_DESC结构体中。
3>.适配器用IDXGIAdapter接口来表示,其数据信息存储在DXGI_ADAPTER_DESC结构体中。
4>.一个适配器可以与多个显示设备关联起来,一个显示设备都有一系列它所支持的显示模式。
5>.IDXGIFactory是DXGI中关键的接口之一,主要用于创建IDXGISwapChain接口以及枚举适配器。
6>.操作适配器,显示器以及显示模式的参考代码如下所示:

// 用IDXGIFactory对象mdxgiFactory调用EnumAdapters函数来枚举显示适配器
UINT i = 0;
IDXGIAdapter* adapter = nullptr;
while (mdxgiFactory->EnumAdapters(i, &adapter) != DXGI_ERROR_NOT_FOUND)
{
	DXGI_ADAPTER_DESC adapterDesc;
	adapter->GetDesc(&adapterDesc);
	cout << adapterDesc.Description;

	// 用IDXGIAdapter对象adapter调用EnumOutputs函数来枚举显示设备
	UINT j = 0;
	IDXGIOutput* output = nullptr;
	while (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND)
	{
		DXGI_OUTPUT_DESC outputDesc;
		output->GetDesc(&outputDesc);
		cout << output.DeviceName;

		// 用IDXGIOutput对象output调用GetDisplayModelList函数来取符合条件的显示模式数据。
		// 当第四个参数为nullptr时,获取显示模式的个数。
		// 当第四个参数为vector列表时,将显示模式存放在该列表中。
		UINT count = 0;
		UINT flags = 0;
		output->GetDisplayModelList(DXGI_FORMAT_B8G8R8A8_UNORM, flags, &count, nullptr);
		std::vector<DXGI_MODE_DESC> modeList(count);
		output->GetDisplayModelList(DXGI_FORMAT_B8G8R8A8_UNORM, flags, &count, &modeList[0]);
		for (auto& x : modeList)
		{
			cout << x.Width << "," << x.Height
		}
	}
}

14.性能计数器具有以下特性:
1>.性能计数器是一种高精度的计时器,它是测量微小时间差的一种有效工具。
2>.QueryPerformanceCounter函数用来获取性能计数器的当前计数值。
3>.QueryPerformanceFrequency函数用来获取性能计数器每秒的计数值。
4>.在调用QueryPerformanceCounter函数时,由于基本输入/输出系统(BIOS)或硬件抽象层(HAL)上的缺陷,导致了在不同的处理器上可能会得到不同的结果。对此,我们可以通过SetThreadAffinityMask函数,防止应用程序的主线程切换到其他的处理器上去执行指令,从而得到正确的计数值。
5>.通过统计时间段Δt内处理的帧数即可计算出每秒的平均帧数(FPS)。设n为时间Δt内处理的帧数,那么该时间段内每秒的平均帧数为FPSavg = n / Δt。采用帧率进行考量可能会对性能造成一些误判,相对而言,"处理一帧所花费时间"这个统计信息可能更加精准,直观。以秒为单位表示的每帧平均处理时间可以用帧率的倒数来计算,即 1 / FPSavg。

15.为了开启调试模式需要启用调试层。如此一来,Direct3D就会把调试信息发往VC++的输出窗口。参考代码如下所示:

// 启用D3D12的调试层
#if defined(DEBUG) || defined(_DEBUG)
{
	ComPtr<ID3D12Debug> debugController;
	ThrowIfFailed(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)));
	debugController->EnableDebugLayer();
}
#endif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值