美文网首页
使用Dx11渲染纹理1——初始化

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

作者: 上官宏竹 | 来源:发表于2022-01-10 11:38 被阅读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可以查看初始化过程

    相关文章

      网友评论

          本文标题:使用Dx11渲染纹理1——初始化

          本文链接:https://www.haomeiwen.com/subject/fgehqrtx.html