01 DirectX11初始化

由于个人觉得龙书里面第4章提供的Direct3D 初始化项目封装得比较好,而且Direct SDK Samples里面的初始化程序过于精简,不适合后续使用,故选择了结合两者的代码,并做进一部简化处理。

项目源码点此

链接静态库

这里的每一个项目都需要包含静态库:d3d11.lib,dxgi.lib,dxguid.lib,D3DCompiler.lib和winmm.lib。可以用下面语句:

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "D3DCompiler.lib")
#pragma comment(lib, "winmm.lib")

也可以在项目属性-链接器-输入-附加依赖项 添加上面的库。

移植新的dxerr.h和dxerr.cpp

directx-sdk-samples-master\DXUT\Core中可以找到dxerr.h和dxerr.cpp,把它们拉进我们的项目中。然后使用下面的宏来进行检查

#if defined(DEBUG) | defined(_DEBUG)
#ifndef HR
#define HR(x)                                              {                                                              HRESULT hr = (x);                                          if(FAILED(hr))                                             {                                                              DXTrace(__FILEW__, (DWORD)__LINE__, hr, L#x, true);    }                                                      }
#endif

#else
#ifndef HR
#define HR(x) (x)
#endif
#endif 

由于新的dxerr仅提供了DXTrace的Unicode字符集版本,需要将原来的__FILE__替换为__FILEW__,并在项目属性页中将字符集设置为Unicode。

COM组件智能指针

考虑到DirectX11的API是由一系列的COM组件来管理的,我们可以使用智能指针来管理这些对象,而无需过多担心内存的泄漏。

使用该智能指针需要包含头文件wrl/client.h,并且智能指针类模板ComPtr位于名称空间Microsoft::WRL内。我们主要关注下面这几个方法:

ComPtr<Interface>::Get方法返回Interface*

ComPtr<Interface>::GetAddressOf方法返回Interface**,也可以用重载的&运算符来获取

ComPtr<Interface>::Reset方法将对里面的对象调用Release方法,并将指针置为nullptr

初始化DirectX 11

现在假定你的电脑已经支持DirectX 11,但同时也有可能支持DirectX 11.1。因此我们在这使用的头文件是d3d11_1.h。

要初始化DirectX11,我们需要创建这三样东西:D3D设备、D3D设备上下文和DXGI交换链。

D3D设备包含了创建各种所需资源的方法。

D3D设备上下文负责对缓冲区进行渲染,绑定D3D设备创建的各种资源到不同的渲染管线。

DXGI交换链可以包含两个或多个缓冲区,通常一个用于前端显示,其余的用于后端渲染。前台缓冲区通常是只读的,而后备缓冲区则是我们主要进行渲染的场所。当后备缓冲区渲染完成后,通过呈现方式将前后台缓冲区交换,在屏幕上显示出原来刚绘制好的画面。

这三样东西对应的接口类为:ID3D11Device、ID3D11DeviceContext、IDXGISwapChain

而如果支持DirectX11.1的话,则对应的接口类为:ID3D11Device1、ID3D11DeviceContext1、IDXGISwapChain1,它们分别继承自上面的三个接口类,区别在于额外提供了少数新的接口。

创建D3D设备、D3D设备上下文使用如下函数:

HRESULT WINAPI D3D11CreateDevice(
    IDXGIAdapter* pAdapter,         // [InOpt]适配器
    D3D_DRIVER_TYPE DriverType,     // [In]驱动类型
    HMODULE Software,               // [In]若上面为D3D_DRIVER_TYPE_SOFTWARE则这里需要提供程序模块
    UINT Flags,                     // [In]使用D3D11_CREATE_DEVICE_FLAG枚举类型
    D3D_FEATURE_LEVEL* pFeatureLevels,  // [In]若为nullptr则为默认特性等级,否则需要提供特性等级数组
    UINT FeatureLevels,             // [In]特性等级数组的元素数目
    UINT SDKVersion,                // [In]SDK版本,默认D3D11_SDK_VERSION
    ID3D11Device** ppDevice,        // [Out]输出D3D设备
    D3D_FEATURE_LEVEL* pFeatureLevel,   // [Out]输出当前应用D3D特性等级
    ID3D11DeviceContext** ppImmediateContext ); //[Out]输出D3D设备上下文

该函数可以创建DirectX11.1或者DirectX11.0的设备与设备上下文,取决于最终应用的D3D特性等级。

首先需要创建驱动类型数组进行轮询,不过通常大多数情况都会支持D3D_DRIVER_TYPE_HARDWARE,以享受硬件加速带来的效益:

// 驱动类型数组
D3D_DRIVER_TYPE driverTypes[] =
{
    D3D_DRIVER_TYPE_HARDWARE,
    D3D_DRIVER_TYPE_WARP,
    D3D_DRIVER_TYPE_REFERENCE,
};
UINT numDriverTypes = ARRAYSIZE(driverTypes);

然后就是提供特性等级数组,这里只考虑DirectX11:

// 特性等级数组
D3D_FEATURE_LEVEL featureLevels[] =
{
    D3D_FEATURE_LEVEL_11_1,
    D3D_FEATURE_LEVEL_11_0,
};
UINT numFeatureLevels = ARRAYSIZE(featureLevels);

最后就会可以创建D3D设备和设备上下文了:

// 应用程序类中的DX11成员
Microsoft::WRL::ComPtr<ID3D11Device> md3dDevice;
Microsoft::WRL::ComPtr<ID3D11DeviceContext> md3dImmediateContext;
Microsoft::WRL::ComPtr<IDXGISwapChain> mSwapChain;
// 应用程序类中的DX11.1成员
Microsoft::WRL::ComPtr<ID3D11Device1> md3dDevice1;
Microsoft::WRL::ComPtr<ID3D11DeviceContext1> md3dImmediateContext1;
Microsoft::WRL::ComPtr<IDXGISwapChain1> mSwapChain1;

D3D_FEATURE_LEVEL featureLevel;
D3D_DRIVER_TYPE d3dDriverType;
for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++)
{
    d3dDriverType = driverTypes[driverTypeIndex];
    hr = D3D11CreateDevice(nullptr, d3dDriverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels,
        D3D11_SDK_VERSION, md3dDevice.GetAddressOf(), &featureLevel, md3dImmediateContext.GetAddressOf());

    if (hr == E_INVALIDARG)
    {
        // DirectX 11.0 平台不承认D3D_FEATURE_LEVEL_11_1所以我们需要尝试特性等级11.0
        hr = D3D11CreateDevice(nullptr, d3dDriverType, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1,
            D3D11_SDK_VERSION, md3dDevice.GetAddressOf(), &featureLevel, md3dImmediateContext.GetAddressOf());
    }

    if (SUCCEEDED(hr))
        break;
}

如果支持DirectX11.1的话,featureLevel的结果应该为D3D_FEATURE_LEVEL_11_1,并且md3dDevice指向的是一个包含ID3D11Device1接口的对象,以及md3dImmediateContext指向的是一个包含ID3D11DeviceContext1接口的对象;而如果只支持DirectX11.0的话则为D3D_FEATURE_LEVEL_11_0。

接下来是需要创建DXGI交换链。

如果是DirectX11.1的话,需要先填充DXGI_SWAP_CHAIN_DESC1和DXGI_SWAP_CHAIN_FULLSCREEN_DESC这两个结构体:

typedef struct DXGI_SWAP_CHAIN_DESC1
{
    UINT Width;                     // 缓冲区宽度
    UINT Height;                    // 缓冲区高度
    DXGI_FORMAT Format;             // 缓冲区数据格式
    BOOL Stereo;                    // 忽略
    DXGI_SAMPLE_DESC SampleDesc;    // 采样描述
    DXGI_USAGE BufferUsage;         // 缓冲区用途
    UINT BufferCount;               // 缓冲区数目
    DXGI_SCALING Scaling;           // 忽略
    DXGI_SWAP_EFFECT SwapEffect;    // 交换效果
    DXGI_ALPHA_MODE AlphaMode;      // 忽略
    UINT Flags;                     // 使用DXGI_SWAP_CHAIN_FLAG枚举类型
} DXGI_SWAP_CHAIN_DESC1;

typedef struct DXGI_SAMPLE_DESC
{
    UINT Count;                     // 采样数
    UINT Quality;                   // 质量等级
} DXGI_SAMPLE_DESC;

typedef struct DXGI_SWAP_CHAIN_FULLSCREEN_DESC
{
    DXGI_RATIONAL RefreshRate;                  // 刷新率
    DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;  // 忽略
    DXGI_MODE_SCALING Scaling;                  // 忽略
    BOOL Windowed;                              // 是否窗口化
} DXGI_SWAP_CHAIN_FULLSCREEN_DESC;

typedef struct DXGI_RATIONAL
{
    UINT Numerator;                 // 刷新率分子
    UINT Denominator;               // 刷新率分母
} DXGI_RATIONAL;

而如果是DirectX11.0的话,需要先填充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_FLAG枚举类型
}   DXGI_SWAP_CHAIN_DESC;

typedef struct DXGI_SAMPLE_DESC
{
    UINT Count;                     // 采样数
    UINT Quality;                   // 质量等级
} DXGI_SAMPLE_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;

typedef struct DXGI_RATIONAL
{
    UINT Numerator;                 // 刷新率分子
    UINT Denominator;               // 刷新率分母
} DXGI_RATIONAL;

接下来我们需要创建交换链。

DirectX11.0下使用的创建方法为IDXGIFactory::CreateSwapChain:

HRESULT IDXGIFactory::CreateSwapChain(
    IUnknown *pDevice,                  // [In]D3D设备
    DXGI_SWAP_CHAIN_DESC *pDesc,        // [In]交换链描述
    IDXGISwapChain **ppSwapChain);      // [Out]输出交换链对象

而DirectX11.1使用的创建方法为IDXGIFactory2::CreateSwapChainForHwnd:

HRESULT IDXGIFactory2::CreateSwapChainForHwnd(
    IUnknown *pDevice,                      // [In]D3D设备
    HWND hWnd,                              // [In]窗口句柄
    const DXGI_SWAP_CHAIN_DESC1 *pDesc,     // [In]交换链描述1
    const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc, // [In]交换链全屏描述,可选
    IDXGIOutput *pRestrictToOutput,         // [In]忽略
    IDXGISwapChain1 **ppSwapChain);         // [Out]输出交换链对象

但现在我们需要先拿到包含IDXGIFactory或者IDXGIFactory2接口的对象:

ComPtr<IDXGIDevice> dxgiDevice = nullptr;
ComPtr<IDXGIAdapter> dxgiAdapter = nullptr;
ComPtr<IDXGIFactory1> dxgiFactory1 = nullptr;

ComPtr<IDXGIDevice1> dxgiDevice1 = nullptr;
ComPtr<IDXGIAdapter1> dxgiAdapter1 = nullptr;
ComPtr<IDXGIFactory2> dxgiFactory2 = nullptr;

HR(md3dDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(dxgiDevice.GetAddressOf())));
HR(dxgiDevice->GetAdapter(dxgiAdapter.GetAddressOf()));
HR(dxgiAdapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(dxgiFactory1.GetAddressOf())));

这时候可以确定dxgiFactory1包含接口IDXGIFactory1,然后检查它是否包含接口IDXGIFactory2,包含的话就说明支持DirectX11.1,然后获取ID3D11Device1和ID3D11DeviceContext1接口对象并创建包含IDXGISwapChain1接口的对象,否则就创建IDXGISwapChain接口的对象:

// 如果包含,则说明支持DX11.1
if (dxgiFactory2 != nullptr)
{
    HR(md3dDevice->QueryInterface(__uuidof(ID3D11Device1), reinterpret_cast<void**>(md3dDevice1.GetAddressOf())));
    HR(md3dImmediateContext->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void**>(md3dImmediateContext1.GetAddressOf())));
    // 填充各种结构体用以描述交换链
    DXGI_SWAP_CHAIN_DESC1 sd;
    ZeroMemory(&sd, sizeof(sd));
    sd.Width = mClientWidth;
    sd.Height = mClientHeight;
    sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.SampleDesc.Count = 1;
    sd.SampleDesc.Quality = 0;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.BufferCount = 1;
    sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    sd.Flags = 0;

    DXGI_SWAP_CHAIN_FULLSCREEN_DESC fd;
    fd.RefreshRate.Numerator = 60;
    fd.RefreshRate.Denominator = 1;
    fd.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
    fd.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
    fd.Windowed = TRUE;
    // 为当前窗口创建交换链
    HR(dxgiFactory2->CreateSwapChainForHwnd(md3dDevice.Get(), mhMainWnd, &sd, &fd, nullptr, mSwapChain1.GetAddressOf()));
    mSwapChain1->QueryInterface(__uuidof(IDXGISwapChain), reinterpret_cast<void**>(mSwapChain.GetAddressOf()));
}
else
{
    // 填充DXGI_SWAP_CHAIN_DESC用以描述交换链
    DXGI_SWAP_CHAIN_DESC sd;
    ZeroMemory(&sd, sizeof(sd));
    sd.BufferDesc.Width = mClientWidth;
    sd.BufferDesc.Height = mClientHeight;
    sd.BufferDesc.RefreshRate.Numerator = 60;
    sd.BufferDesc.RefreshRate.Denominator = 1;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
    sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
    sd.SampleDesc.Count = 1;
    sd.SampleDesc.Quality = 0;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.BufferCount = 1;
    sd.OutputWindow = mhMainWnd;
    sd.Windowed = TRUE;
    sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    sd.Flags = 0;
    HR(dxgiFactory1->CreateSwapChain(md3dDevice.Get(), &sd, mSwapChain.GetAddressOf()));
}

这时候,如果支持DirectX11.1的话,md3dDevice和md3dDevice1其实都指向同一个对象,md3dImmediateContext和md3dImmediateContext1,mSwapChain和mSwapChain1也是一样的,区别仅仅在于后者实现了额外的一些接口,问题不大。因此不管是DirectX11.1还是DirectX11.0,后续都主要使用md3dDevice,md3dImmediateContext和mSwapChain来进行操作。

设置全屏

默认情况下按ALT+ENTER可以切换成全屏,如果不想要这种操作,可以使用刚才创建的dxgiFactory1,按照下面的方式来调用即可:

dxgiFactory1->MakeWindowAssociation(mhMainWnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES);

这样DXGI就不会监听Windows消息队列,并且屏蔽掉了对接收到ALT+ENTER消息的处理。

渲染目标视图(RenderTargetView)和深度模板视图(DepthStencilView)

接下来我们需要创建渲染目标视图(RenderTargetView)并绑定到渲染管线的输出合并阶段,使得交换链可以操作后备缓冲区。此时我们创建好的交换链已经包含1个后备缓冲区了,我们需要使用渲染目标视图来绑定这个后备缓冲区先。

使用IDXGISwapChain::GetBuffer来获取交换链的后备缓冲区:

HRESULT IDXGISwapChain::GetBuffer(
    UINT Buffer,        // [In]缓冲区索引号,从0到BufferCount - 1
    REFIID riid,        // [In]缓冲区的接口类型ID
    void **ppSurface);  // [Out]获取到的缓冲区

然后再使用下面的方法来获取渲染目标视图:

HRESULT ID3D11Device::CreateRenderTargetView(
    ID3D11Resource *pResource,                      // [In]缓冲区资源
    const D3D11_RENDER_TARGET_VIEW_DESC *pDesc,     // 忽略
    ID3D11RenderTargetView **ppRTView);             // [Out]获取渲染目标视图
// 重设交换链并且重新创建渲染目标视图
ComPtr<ID3D11Texture2D> backBuffer;
HR(mSwapChain->ResizeBuffers(1, mClientWidth, mClientHeight, DXGI_FORMAT_R8G8B8A8_UNORM, 0));
HR(mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(backBuffer.GetAddressOf())));
HR(md3dDevice->CreateRenderTargetView(backBuffer.Get(), 0, mRenderTargetView.GetAddressOf()));

除了渲染目标视图外,我们还需要创建深度缓冲区用于深度测试。通过D3D设备可以新建一个缓冲区,但在此之前我们需要先描述该缓冲区的信息:

typedef struct D3D11_TEXTURE2D_DESC
{
    UINT Width;         // 缓冲区宽度
    UINT Height;        // 缓冲区高度
    UINT MipLevels;     // Mip等级
    UINT ArraySize;     // 纹理数组中的纹理数量,默认1
    DXGI_FORMAT Format; // 缓冲区数据格式
    DXGI_SAMPLE_DESC SampleDesc;    // 忽略
    D3D11_USAGE Usage;  // 数据的CPU/GPU访问权限
    UINT BindFlags;     // 使用D3D11_BIND_FLAG枚举来决定该数据的使用类型
    UINT CPUAccessFlags;    // 使用D3D11_CPU_ACCESS_FLAG枚举来决定CPU访问权限
    UINT MiscFlags;     // 使用D3D11_RESOURCE_MISC_FLAG枚举,这里默认0
}   D3D11_TEXTURE2D_DESC;   

我们可以这样填充:

D3D11_TEXTURE2D_DESC depthStencilDesc;

depthStencilDesc.Width     = mClientWidth;
depthStencilDesc.Height    = mClientHeight;
depthStencilDesc.MipLevels = 1;
depthStencilDesc.ArraySize = 1;
depthStencilDesc.Format    = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilDesc.SampleDesc.Count   = 1;
depthStencilDesc.SampleDesc.Quality = 0;
depthStencilDesc.Usage          = D3D11_USAGE_DEFAULT;
depthStencilDesc.BindFlags      = D3D11_BIND_DEPTH_STENCIL;
depthStencilDesc.CPUAccessFlags = 0;
depthStencilDesc.MiscFlags      = 0;

这时候我们就可以用方法ID3D11Device::CreateTexture2D来创建2D纹理:

HRESULT ID3D11Device::CreateTexture2D(
    const D3D11_TEXTURE2D_DESC *pDesc,          // [In] 2D纹理描述信息
    const D3D11_SUBRESOURCE_DATA *pInitialData, // [In] 用于初始化的资源
    ID3D11Texture2D **ppTexture2D);             // [Out] 获取到的2D纹理

再通过方法ID3D11Device::CreateDepthStencilView来创建深度模板视图,绑定刚创建的深度缓冲区:

HRESULT ID3D11Device::CreateDepthStencilView(
    ID3D11Resource *pResource,                      // [In] 需要绑定的资源
    const D3D11_DEPTH_STENCIL_VIEW_DESC *pDesc,     // [In] 深度缓冲区描述
    ID3D11DepthStencilView **ppDepthStencilView);   // [Out] 获取到的深度模板视图

下面两句话演示了创建深度模板缓冲区和深度模板视图:

// 创建深度缓冲区以及深度模板视图
HR(md3dDevice->CreateTexture2D(&depthStencilDesc, 0, mDepthStencilBuffer.GetAddressOf()));
HR(md3dDevice->CreateDepthStencilView(mDepthStencilBuffer.Get(), 0, mDepthStencilView.GetAddressOf()));

最后,我们需要调用方法ID3D11DeviceContext::OMSetRenderTargets,将渲染目标视图和深度模板视图一同绑定到输出合并阶段:

void ID3D11DeviceContext::OMSetRenderTargets(
    UINT NumViews,                                      // [In] 视图数目
    ID3D11RenderTargetView *const *ppRenderTargetViews, // [In] 渲染目标视图数组
    ID3D11DepthStencilView *pDepthStencilView) = 0;     // [In] 深度模板视图

下面演示了这些操作:


md3dImmediateContext->OMSetRenderTargets(1, mRenderTargetView.GetAddressOf(), mDepthStencilView.Get());

视口

最终我们还需要决定将整个视图输出到特定的范围。因此我们需要使用D3D11_VIEWPORT来设置视口

typedef struct D3D11_VIEWPORT
{
    FLOAT TopLeftX;     // 屏幕左上角起始位置X
    FLOAT TopLeftY;     // 屏幕左上角起始位置Y
    FLOAT Width;        // 宽度
    FLOAT Height;       // 高度
    FLOAT MinDepth;     // 最小深度,必须为0.0f
    FLOAT MaxDepth;     // 最大深度,必须为1.0f
}   D3D11_VIEWPORT;

ID3D11DeviceContext::RSSetViewports方法将设置1个或多个视口:

void ID3D11DeviceContext::RSSetViewports(
    UINT  NumViewports,                     // 视口数目
    const D3D11_VIEWPORT *pViewports);      // 视口数组

将视图输出到整个屏幕需要进行下面的操作:

mScreenViewport.TopLeftX = 0;
mScreenViewport.TopLeftY = 0;
mScreenViewport.Width    = static_cast<float>(mClientWidth);
mScreenViewport.Height   = static_cast<float>(mClientHeight);
mScreenViewport.MinDepth = 0.0f;
mScreenViewport.MaxDepth = 1.0f;

md3dImmediateContext->RSSetViewports(1, &mScreenViewport);

画面绘制

在每一帧画面绘制的操作中,我们需要清理一遍渲染目标视图,

可以通过ID3D11DeviceContext::ClearRenderTargetView方法:

void ID3D11DeviceContext::ClearRenderTargetView(
    ID3D11RenderTargetView *pRenderTargetView,  // 渲染目标视图
    const FLOAT  ColorRGBA[4]);                 // 指定覆盖颜色

我们用蓝色进行清屏,即RGBA=(0.0,0.0,1.0,1.0)的值操作:

float blue[4] = {0.0f, 0.0f, 1.0f, 1.0f);
md3dImmediateContext->ClearRenderTargetView(mRenderTargetView.Get(), reinterpret_cast<const float*>(&blue));

然后我们还要使用ID3D11DeviceContext::ClearDepthStencilView来清空深度模板缓冲区:

void ID3D11DeviceContext::ClearDepthStencilView(
    ID3D11DepthStencilView *pDepthStencilView,  // 深度模板视图
    UINT ClearFlags,    // [In]D3D11_CLEAR_FLAG枚举
    FLOAT Depth,        // [In]深度
    UINT8 Stencil);     // [In]模板初始值

例如:

md3dImmediateContext->ClearDepthStencilView(mDepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

最后我们直接调用IDXGISwapChain::Present方法进行前后台交换的呈现:

mSwapChain->Present(0, 0);

完成初始化后效果应该如下:

原文地址:https://www.cnblogs.com/X-Jun/p/9028825.html

时间: 2024-10-20 20:43:45

01 DirectX11初始化的相关文章

01背包初始化的细节问题与循环下限的改进

转自:背包久讲 Tianyi Cui 初始化的细节问题 我们看到的求最优解的背包问题题目中,事实上有两种不太相同的问法.有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满.一种区别这两种问法的实现方法是在初始化的时候有所不同. 如果是第一种问法,要求恰好装满背包,那么在初始化时除了f[0]为0其它f[1..V]均设为-∞,这样就可以保证最终得到的f[N]是一种恰好装满背包的最优解. 如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0

DirectX11--使用Windows SDK来进行开发

在看龙书(Introduction to 3D Game Programming with Directx 11)的时候,里面所使用的开发工具包为Microsoft DirectX SDK(June 2010),该开发包到现在也已经经历了8年左右.而现在,微软其实已经将DX的相关组件随同Windows SDK一同更新,并不再对DirectX SDK做任何的更新.若你使用的是Visual Studio 2017,可能会发现系统库内已经默认包含了D3D11.h等DX11开发相关的头文件.对于之前龙书

01.组件版本和集群环境

01.系统初始化和全局变量 集群机器 kube-node1:192.168.1.106 kube-node2:192.168.1.107 kube-node3:192.168.1.108 本着测试的目的,etcd 集群.kubernetes master 集群.kubernetes node 均使用这三台机器. 若有安装 Vagrant 与 Virtualbox,这三台机器可以用本着提供的 Vagrantfile 来建置: $ cd vagrant $ vagrant up 主机名 设置永久主机

剖析ECMALL的登录机制

在ecmall.php文件中实例化控制器类,每一个控制器类,必须继承(extends)upload\admin\app\backend.base.php文件.在继承中调用方法是谁先被继承谁的方法被先调用. 以default为例,首先在公共入口文件index.php文件中包含eccore/ecmall.php文件,调用startup方法并把includes/global.lib.php,includes/libraries/time.lib.php,includes/ecapp.base.php,

深入JavaScript对象创建的细节

最近深入学习javascript后,有个体会:面向对象的方式编程才是高效灵活的编程,也是现在唯一可以让代码更加健壮的编程方式.如果我们抛开那些玄乎的抽象出类等等思想,我自己对面向对象的从写程序的角度理解就是:复用和封装.复用具体就是让你尽量少写重复代码,封装就是将一些耦合度很高的逻辑放到一个程序块里,而且尽量让里面内容不受外界影响.最后的结论是:优秀的javascript代码都是面向对象的.定州市科技工业局 如何构建javascript对象?ECMA-262对对象的定义是:无序属性的集合,其属性

FFmpeg SDK开发模型之三:muxer

简介 使用FFmpeg SDK实现的H.264码流合成MPEG2-TS文件 一.源代码 int main(int argc, char* argv[]) { const char* input = NULL; const char* output= NULL; /* Obtain input params */ if (argc <= 1) { printf("Usage:\n"); printf("%s <input_file.264> <outpu

学生管理系统管理系统

本系统是大一课程设计中课程设计做出来的! -----------------完成时间2013 06 08 1 /学生管理系统 完成时间2013 06 08 2 //大一第一次课程设计 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #define N 3 7 #define LEN (Student*) malloc(sizeof(Student)) 8 /* 学生数据结构 */ 9

Cocos2d-x中创建SQLite数据库

我们下边介绍如何通过SQLite3提供的API实现MyNotes数据库创建.创建数据库一般需要经过如下三个步骤.(1) 使用sqlite3_open函数打开数据库.(2) 使用sqlite3_exec函数执行Create Table语句,创建数据库表.(3) 使用sqlite3_close函数释放资源.在这个过程中,我们使用了三个SQLite3 API函数,它们都是纯C语言函数.在Cocos2d-x中通过C++调用C函数当然不是什么问题,NoteDAO.cpp中的NoteDAO::initDB(

FFmpeg SDK开发模型之一:解码器

简介 本例讲解了如何使用ffmpeg SDK解码媒体文件: 参考源码是ffmpeg 自带的apiexample.c 一.源代码 #include <stdlib.h> #include <stdio.h> #include <string.h> #include <math.h> #ifdef HAVE_AV_CONFIG_H #undef HAVE_AV_CONFIG_H #endif #include "libavcodec/avcodec.h