DirectX11入门笔记---DirectX初始化

image-20201217210042177

DirectXMath之XMVECTOR :https://blog.csdn.net/BonChoix/article/details/8280596

DirectXMath之XMMATRIX :https://blog.csdn.net/BonChoix/article/details/8280617

Directx—-Vs2019环境配置

首先打开Vs2019—-工具—-扩展工具和功能勾选一下选项

image-20201217210456000

下载安装完毕之后,新建项目可以看到Directx11项目

image-20201217210549337

根据龙书教程我们可以不适用VS2019自带的Directx框架,新建一个空项目,然后右键项目—-属性

image-20201217210732179

image-20201217210657134

DirectX11初始化

DirectX初始化步骤总共分为:

1.使用 D3D11CreateDevice 方法创建 ID3D11DeviceID3D11DeviceContext

2.使用 ID3D11Device::CheckMultisampleQualityLevels 方法检测设备支持的 4X 多重采样质量等级。

3.填充一个 IDXGI_SWAP_CHAIN_DESC 结构体,该结构体描述了所要创建的交换链的特性。

4.查询 IDXGIFactory 实例,这个实例用于创建设备和一个 IDXGISwapChain 实例。

5.为交换链的后台缓冲区创建一个渲染目标视图。

6.创建深度/模板缓冲区以及相关的深度/模板视图。

7.将渲染目标视图和深度/模板视图绑定到渲染管线的输出合并阶段,使它们可以被Direct3D 使用。

8.设置视口。

创建Device和Context

Device和Context是Direct3D最重要的接口,可以通过该接口与硬件进行交互,命令硬件件完成一些工作 (比如:在显存中分配资源、清空后台缓冲区、将资源绑定到各种管线阶段、绘制几何体)。

1. ID3D11Device 接口用于检测显示适配器功能和分配资源。

2. ID3D11DeviceContext 接口用于设置管线状态、将资源绑定到图形管线和生成渲染命令。

HRESULT  D3D11CreateDevice(
  __in   IDXGIAdapter *pAdapter,
  __in   D3D_DRIVER_TYPE DriverType,
  __in   HMODULE Software,
  __in   UINT Flags,
  __in   const D3D_FEATURE_LEVEL *pFeatureLevels,
  __in   UINT FeatureLevels,
  __in   UINT SDKVersion,
  __out  ID3D11Device **ppDevice,
  __out  D3D_FEATURE_LEVEL *pFeatureLevel,
  __out  ID3D11DeviceContext **ppImmediateContext
);

​ 1.pAdapter:指定要为哪个物理显卡创建设备对象。当该参数设为空值时,表示使用主显卡。

​ 2.DriverType:一般来讲,该参数总是指定为 D3D_DRIVER_TYPE_HARDWARE , 表示使用 3D 硬件来加快渲染速度。

​ 3.Software:用于支持软件光栅化设备(software rasterizer)。我们总是将该参数设为空值,因为我们使用硬件进行渲染。

  1. 可选参数,一般为NULL,可以设为D3D11_CREATE_DEVICE_DEBUGD3D11_CREATE_DEVICE_SINGLETHREADED,或两者一起,前者让要用于调试时收集信息,后者在确定程序只在单线程下运行时设置为它,可以提高性能;
  2. pFeatureLevels:为我们提供给程序的特征等级的一个数组,下一个参数为数组中元素个数
  3. SDKVersion:始终设为 D3D11_SDK_VERSION
  4. ppDevice:返回创建后的设备对象。
  5. pFeatureLevel : 返 回 pFeatureLevels 数 组 中 第 一 个 支 持 的 特 征 等 级 ( 如 果 pFeatureLevels 为 null,则返回可支持的最高等级)。
  6. ppImmediateContext:返回创建后的设备上下文。
    //DirectX设备
    ID3D11Device* DirectxDevice;
    //Directx上下文
    ID3D11DeviceContext* DirectxDeviceContext;

    //特征等级
    D3D_FEATURE_LEVEL featureLevels[3] =
    {
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
    };

    //当前特征等级
    D3D_FEATURE_LEVEL curLevel;

    //创建设备和上下文
    D3D11CreateDevice(
        0,        //默认显卡
        D3D_DRIVER_TYPE_HARDWARE,        //硬件加速
        0,        //硬件渲染,不适用软光栅化渲染器
        0,        //不需要收集调试信息
        featureLevels, 3,        //特征等级
        D3D11_SDK_VERSION,
        &DirectxDevice,        //获取返回的设备,特征等级,上下文
        &curLevel,
        &DirectxDeviceContext
    );

检测多重采样等级

//检查4X多重采样质量等级
    UINT m4xMsaaQualiy;
    DirectxDevice->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, 4, &m4xMsaaQualiy);

描述交换链

创建交换链前,我们需要填充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;
  1. BufferDesc:该结构体描述了我们所要创建的后台缓冲区的属性。我们主要关注的属性有:宽度、高度和像素格式
  2. SampleDesc:多重采样数量和质量级别
  3. BufferUsage:设为 DXGI_USAGE_RENDER_TARGET_OUTPUT,因为我们要将场景渲染到后台缓冲区
  4. BufferCount:交换链中的后台缓冲区数量;我们一般只用一个后台缓冲区来实现双缓存。
  5. OutputWindow:我们将要渲染到的窗口的句柄。
  6. Windowed:当设为 true 时,程序以窗口模式运行;当设为 false 时,程序以全屏 (full-screen)模式运行。
  7. SwapEffect:设为 DXGI_SWAP_EFFECT_DISCARD,让显卡驱动程序选择最高效的显示模式。
  8. Flags:可选参数,主要是全屏模式下的设置

DXGI_MODE_DESC是另外一个结构体

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;
  1. Width:后台缓冲区宽度
  2. Height:后台缓冲区高度
  3. RefreshRate:显示刷新率
  4. Format:后台缓冲区像素格式
    //描述交换链
    DXGI_SWAP_CHAIN_DESC chainDesc;
    chainDesc.BufferDesc.Width = 640;
    chainDesc.BufferDesc.Height = 480;
    chainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;        //设置缓冲区格式
    chainDesc.BufferDesc.RefreshRate.Numerator = 60;        //刷新率
    chainDesc.BufferDesc.RefreshRate.Denominator = 1;
    chainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;        //固定参数
    chainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

    chainDesc.BufferCount = 1;        //缓冲区个数
    chainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;        //为渲染目标Output
    chainDesc.Flags = 0;
    chainDesc.OutputWindow = hwnd;        //主窗口句柄
    chainDesc.SampleDesc.Count = 4;        //4x多重采样
    chainDesc.SampleDesc.Quality = m4xMsaaQualiy - 1;        //4x多重采样质量等级
    chainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;        //让显卡选择最高校显示模式
    chainDesc.Windowed = true;        //窗口模式

注意:如果你想在运行时改变多重采样的设置,那么必须销毁然后重新创建交换链。

注意:因为大多数显示器不支持超过 24 位以上的颜色,再多的颜色也是浪费,所以我们将后台缓冲区的像素格式设置为 DXGI_FORMAT_R8G8B8A8_UNORM(红、绿、蓝、 alpha 各 8 位)。额外的 8 位 alpha 并不会输出在显示器上,但在后台缓冲区中可以用于特定的用途。

创建交换链

通过IDXGIFactory::CreateSwapChain 方法创建交换链(IDXGISwapChain

HRESULT IDXGIFactory::CreateSwapChain( 
IUnknown *pDevice ,         // 指向 ID3D11Device 的指针 
DXGI_SWAP_CHAIN_DESC *pDesc,         // 指向一个交换链描述的指针 
IDXGISwapChain **ppSwapChain);         // 返回创建后的交换链

首先我们要通过COM查询来获得IDXGIFactory实例,然后再创建交换链,最后释放COM接口

    //创建交换链
    IDXGISwapChain* dxgiSwapChain(NULL);
    //首先要获取接口IDXGIFactory实例
    IDXGIDevice* dxgiDevice(NULL);
    DirectxDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice));
    IDXGIAdapter* dxgiAdapter(NULL);
    dxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&dxgiAdapter));
    IDXGIFactory* dxgiFactory(NULL);
    dxgiAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&dxgiFactory));
    dxgiFactory->CreateSwapChain(DirectxDevice, &chainDesc, &dxgiSwapChain);

    //释放COM接口
    dxgiDevice->Release();
    dxgiAdapter->Release();
    dxgiFactory->Release();

创建RenderTargetView

由于资源无法直接绑定到一个管线阶段,所以我们必须为资源创建资源视图,然后再把资源视图绑定到不同的管线阶段,尤其时把后台缓冲区绑定到管线输出合并阶段,我们必须要为后台缓冲区创建RenderTargetView

    //创建资源
    ID3D11Texture2D* backBuffer;
    //获取后台缓冲区地址
    dxgiSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBuffer));
    //创建RenderTargetView
    ID3D11RenderTargetView* renderTargetView;
    DirectxDevice->CreateRenderTargetView(backBuffer, 0, &renderTargetView);

IDXGISwapChain::GetBuffer函数

HRESULT GetBuffer(
  UINT   Buffer,    //获取Buffer的索引号,因为后台缓冲区数量可能会>1,所以必须说明索引号
  REFIID riid,        //缓冲区的接口类型,通常是ID3D11Texture2D
  void   **ppSurface        //指向后台缓冲区的指针
);

CreateRenderTargetView函数

HRESULT CreateRenderTargetView(
       ID3D11Resource *pResource,                //视图对应资源
       const D3D11_RENDER_TARGET_VIEW_DESC *pDesc,        //视图描述
       ID3D11RenderTargetView **ppRTView            //要创建的视图(指针的地址)
);

创建深度/模板缓冲区及其视图

深度缓冲区只是一个存储深度信息的2D纹理,创建纹理前,我们要填充D3D11_TEXTURE2D_DESC 结 构 体 来 描 述 所 要 创 建 的 纹 理 ,然后再调用 ID3D11Device::CreateTexture2D 方法。

typedef struct D3D11_TEXTURE2D_DESC {
  UINT             Width;
  UINT             Height;
  UINT             MipLevels;        //这里不需要mipmap,设为1
  UINT             ArraySize;        //纹理数组才用,这里为1
  DXGI_FORMAT      Format;        //数据格式,一般为DXGI_FORMAT_D24_UNORM_S8_UINT,24位用于深度,8位用于模板
  DXGI_SAMPLE_DESC SampleDesc;        //多重采样,如前,前后务必保持一致!
  D3D11_USAGE      Usage;        //Usage,对于只让GPU读、写,应为D3D11_USAGE_DEFAULT
  UINT             BindFlags;        //绑定类型,为D3D11_BIND_DEPTH_STENCIL
  UINT             CPUAccessFlags;    //CPU不可访问,设为0
  UINT             MiscFlags;        //设为0
} D3D11_TEXTURE2D_DESC;
    //描述深度模板纹理
    D3D11_TEXTURE2D_DESC DepthStencilDesc;
    DepthStencilDesc.Width = 640;
    DepthStencilDesc.Height = 480;
    DepthStencilDesc.MipLevels = 1;
    DepthStencilDesc.ArraySize = 1;
    DepthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    DepthStencilDesc.SampleDesc.Count = 4;
    DepthStencilDesc.SampleDesc.Quality = m4xMsaaQualiy - 1;
    DepthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
    DepthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    DepthStencilDesc.CPUAccessFlags = 0;
    DepthStencilDesc.MiscFlags = 0;

    //创建深度模板纹理
    ID3D11Texture2D* depthStencilBuffer;
    DirectxDevice->CreateTexture2D(&DepthStencilDesc, 0, &depthStencilBuffer);
    //创建深度模板视图
    ID3D11DepthStencilView* depthStencilView;
    DirectxDevice->CreateDepthStencilView(depthStencilBuffer, 0, &depthStencilView);


    //将视图绑定到管线的输出合并阶段
    DirectxDeviceContext->OMSetRenderTargets(1, &renderTargetView, depthStencilView);

设置视口Viewport

同样需要先设置D3D11_VIEWPORT属性

typedef struct D3D11_VIEWPORT {
  FLOAT TopLeftX;        //视口左上角在屏幕上x坐标,一般视口占满屏幕的,所以为0
  FLOAT TopLeftY;        //y坐标,同上
  FLOAT Width;            //视口宽度,一般与后缓冲区一致,以保持图像不变形
  FLOAT Height;            //高度,同上
  FLOAT MinDepth;        //最小深度值:0.0f
  FLOAT MaxDepth;        //最大深度值:1.0f
} D3D11_VIEWPORT;
    //最后设置Viewport阶段
    D3D11_VIEWPORT viewPort;
    viewPort.TopLeftX = 0.0f;
    viewPort.TopLeftY = 0.0f;
    viewPort.Width = static_cast<FLOAT>(640);
    viewPort.Height = static_cast<FLOAT>(480);
    viewPort.MinDepth = 0.0f;
    viewPort.MaxDepth = 1.0f;
    DirectxDeviceContext->RSSetViewports(1, &viewPort);

绘制场景

进入主循环渲染函数绘制场景

        //进入主循环绘制场景
        XMVECTORF32 color = { 0.0f,1.0f,0.0f,1.0f };
        DirectxDeviceContext->ClearRenderTargetView(renderTargetView, reinterpret_cast<float*>(&color));
        DirectxDeviceContext->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
        dxgiSwapChain->Present(0, 0);

得到结果

image-20201217205550695

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2015-2021 Opda
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信