使用Dx11渲染纹理1——初始化

2022-01-10  本文已影响0人  上官宏竹

新建Windows窗口工程

使用VS2019工程创建一个默认的窗口工程。


创建一个win32应用

创建交换链和设备及上下文

添加头文件和依赖库如下:

#include <d3d11.h>
#pragma comment(lib, "d3d11.lib")

我们要做的第一件事是填写交换链的描述。交换链是图形将被绘制到的前后缓冲区。通常,您使用单个后台缓冲区,对其进行所有绘图,然后将其交换到前台缓冲区,然后将其显示在用户屏幕上。这就是为什么它被称为交换链。
交换链描述DXGI_SWAP_CHAIN_DESC

D3D11CreateDeviceAndSwapChain创建

HRESULT D3D11CreateDeviceAndSwapChain(
  [in, optional]  IDXGIAdapter               *pAdapter,
                  D3D_DRIVER_TYPE            DriverType,
                  HMODULE                    Software,
                  UINT                       Flags,
  [in, optional]  const D3D_FEATURE_LEVEL    *pFeatureLevels,
                  UINT                       FeatureLevels,
                  UINT                       SDKVersion,
  [in, optional]  const DXGI_SWAP_CHAIN_DESC *pSwapChainDesc,
  [out, optional] IDXGISwapChain             **ppSwapChain,
  [out, optional] ID3D11Device               **ppDevice,
  [out, optional] D3D_FEATURE_LEVEL          *pFeatureLevel,
  [out, optional] ID3D11DeviceContext        **ppImmediateContext
);

pAdapter: 指向用来创建设备的显示适配器的指针。NULL表示使用默认的适配器
DriverType: 指定驱动类型,常用的有D3D_DRIVER_TYPE_HARDWARE,使用硬件驱动
Software: 实现软件光栅器的DLL的句柄。如果DriverTypeD3D_DRIVER_TYPE_SOFTWARE,Software不能为NULL
Flags: 运行时层标记
pFeatureLevels:指向D3D特性等级数组的指针,如果为NULL,则使用默认的特性等级数组,默认数组如下:

{
    D3D_FEATURE_LEVEL_11_0,
    D3D_FEATURE_LEVEL_10_1,
    D3D_FEATURE_LEVEL_10_0,
    D3D_FEATURE_LEVEL_9_3,
    D3D_FEATURE_LEVEL_9_2,
    D3D_FEATURE_LEVEL_9_1,
}

FeatureLevel: pFeatureLevels中的元素个数。
SDKVersion: SDK版本,使用D3D11_SDK_VERSION
pSwapChainDesc: 指向交换链描述的指针DXGI_SWAP_CHAIN_DESC

交换链描述

typedef struct DXGI_SWAP_CHAIN_DESC {
    DXGI_MODE_DESC   BufferDesc;
    DXGI_SAMPLE_DESC SampleDesc;
    DXGI_USAGE       BufferUsage;
    UINT             BufferCount;
    HWND             OutputWindow;
    BOOL             Windowed;
    DXGI_SWAP_EFFECT SwapEffect;
    UINT             Flags;
} DXGI_SWAP_CHAIN_DESC;

BufferDesc: 描述后缓冲的显示模式
SampleDesc: 描述多重采样参数
BufferUsage: 描述表面的用法和CPU访问后缓冲的操作。后缓冲用于着色器输入或渲染对象输出
BufferCount: 缓冲区个数,包括前缓冲
OutputWindow: 输出窗口句柄,不能为NULL
Windowed: true表示窗口模式,false表示全屏模式
SwapEffect: 枚举类型。描述了提交表面后处理缓冲区内容的可选方法
Flags: 枚举类型。描述交换链的行为

显示模式描述

typedef struct DXGI_MODE_DESC {
    UINT                     Width;
    UINT                     Height;
    DXGI_RATIONAL            RefreshRate;
    DXGI_FORMAT              Format;
    DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;
    DXGI_MODE_SCALING        Scaling;
} DXGI_MODE_DESC, *LPDXGI_MODE_DESC;

Width: 分辨率宽
Height: 分辨率高
RefreshRate: 结构类型。描述刷新频率
Format: 结构类型。描述显示模式
ScanlineOrdering: 枚举类型。描述扫描线绘制模式
Scaling: 枚举类型。描述缩放模式

示例代码

创建交换链及设备的代码如下:

DXGI_SWAP_CHAIN_DESC swapChainDesc; 
ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));

// 设置为单个后台缓冲区。
swapChainDesc.BufferCount = 1;

// 设置后台缓冲区的宽度和高度。
swapChainDesc.BufferDesc.Width = width;
swapChainDesc.BufferDesc.Height = height;

// 为后台缓冲区设置常规的32位表面。
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;

// 设置刷新率,设置让系统尽快刷新
swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;

// 设置后台缓冲区的使用目的
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;

// 设置要渲染到的窗口句柄
swapChainDesc.OutputWindow = hwnd;

// 关闭多重采样。
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;

// 设置为窗口模式
swapChainDesc.Windowed = true;

// 将扫描线排序和缩放设置为未指定。
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

// 呈现后丢弃后台缓冲区内容。
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

// 不要设置高级标志。
swapChainDesc.Flags = 0;

// 特征级别设置为 11.0,即 DirectX 11
D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0;

// 创建交换链、设备及上下文
D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, &featureLevel, 1,
    D3D11_SDK_VERSION, &swapChainDesc, &m_swapChain, &m_device, NULL, &m_deviceContext);

创建渲染目标

使用交换链后台缓存创建渲染目标。

ID3D11Texture2D* backBufferPtr;
HRESULT hr = m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferPtr);

hr = m_device->CreateRenderTargetView(backBufferPtr, NULL, &m_renderTargetView);
backBufferPtr->Release();

渲染

在消息循环中渲染,其中消息循环中取系统消息队列中的消息需要改用PeekMessage,如果没有消息时进行渲染操作。
在每次渲染前可以使用CreateRenderTargetView,将渲染目标使用指定的颜色清除其后台缓冲。

PeekMessage、GetMessage区别

  1. GetMessage的主要功能是从消息队列中“取出”消息,消息被取出以后,就从消息队列中将其删除;而PeekMessage的主要功能是“窥视”消息,如果有消息,就返回true,否则返回false。也可以使用PeekMessage从消息队列中取出消息,这要用到它的一个参数(UINT wRemoveMsg),如果设置为PM_REMOVE,消息则被取出并从消息队列中删除;如果设置为PM_NOREMOVE,消息就不会从消息队列中取出。
  2. 如果GetMessage从消息队列中取不到消息,则线程就会被操作系统挂起,等到OS重新调度该线程,GetMessage每次都会等待消息,直到取到消息才返回;而PeekMessage只是查询消息队列,没有消息就立即返回,从返回值判断是否取到了消息。

效果

image.png
完整代码见:使用git log可以查看初始化过程
上一篇 下一篇

猜你喜欢

热点阅读