DX11 Without DirectX SDK--01 DirectX11初始化
回到 DirectX11--使用Windows SDK来进行开发
由于个人觉得龙书里面第4章提供的Direct3D 初始化项目封装得比较好,而且DirectX SDK Samples里面的初始化程序过于精简,不适合后续使用,故选择了以Init Direct3D项目作为框架,然后还使用了微软提供的示例项目,两者结合到一起 。建议下载项目配合学习,这里不会贴出完整的项目源码。
链接静态库
这里的每一个项目都需要包含静态库: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.h
仅提供了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);
完成初始化后效果应该如下:
DX11 Without DirectX SDK--01 DirectX11初始化的更多相关文章
- DX11 Without DirectX SDK--使用Windows SDK来进行开发
在看龙书(Introduction to 3D Game Programming with Directx 11)的时候,里面所使用的开发工具包为Microsoft DirectX SDK(June ...
- DirectX11 With Windows SDK--01 DirectX11初始化
前言 由于个人觉得龙书里面第4章提供的Direct3D 初始化项目封装得比较好,而且DirectX SDK Samples里面的初始化程序过于精简,不适合后续使用,故选择了以Init Direct3D ...
- DX11 Without DirectX SDK--05 键盘和鼠标输入
回到 DirectX11--使用Windows SDK来进行开发 提供键鼠输入可以说是一个游戏的必备要素.在这里,我们不使用DirectInput,因为Windws SDK本身就不提供该头文件.这里我 ...
- DX11 Without DirectX SDK--06 DirectXMath数学库
回到 DirectX11--使用Windows SDK来进行开发 xnamath.h原本是位于DirectX SDK的一个数学库,但是现在Windows SDK包含的数学库已经抛弃掉原来的xnamat ...
- 从DirectX SDK升级到Windows SDK
原来的DirectX SDK到June 2010,微软就不更新了.之后新的版本被集成到了Windows SDK中. 在微软的博客里找到一篇升级指南:http://blogs.msdn.com/b/ch ...
- C#使用 DirectX SDK 9做视频播放器 并在视频画线添加文字 VMR9
视频图像处理系列 索引 VS2013下测试通过. 在百度中搜索关键字“DirectX SDk”,或者进入微软官网https://www.microsoft.com/en-us/download/det ...
- DirectX SDK版本与Visual Studio版本
对于刚刚接触 DirectShow 的人来说,安装配置是一个令人头疼的问题,经常出现的情况是最基本的 baseclass 就无法编译.一开始我也为此费了很大的功夫,比如说修改代码.修改编译选项使其编译 ...
- VS2012添加对DirectX SDK中需要文件的引用
error LNK2019: 无法解析的外部符号 _DirectDrawCreateEx@16,该符号在函数 "int __cdecl DD_Init(int,int,int)" ...
- 在VS2013、VS2015下如何配置DirectX SDK的开发环境
在Visual Studio 2013下配置DirectX SDK可以进行基于DirectX的3D大型应用程序的开发.如果在开发DirectX程序时不配置其开发环境会引起编译器报错, 下面就与大家分享 ...
随机推荐
- Spring揭秘 读书笔记 三 bean的scope与FactoryBean
本书可作为王富强所著<<Spring揭秘>>一书的读书笔记 第四章 BeanFactory的xml之旅 bean的scope scope有时被翻译为"作用域&quo ...
- mtk camera 移植步骤
mtk camera 移植步骤: 1, Kernel层驱动代码文件添加 /mediatek/custom/doov92_wet_tdd/kernel/imgsensor/下添加imx179_mipi_ ...
- LeetCode之“字符串”:最短回文子串
题目链接 题目要求: Given a string S, you are allowed to convert it to a palindrome by adding characters in f ...
- 在 Linux 下用 mkdir 命令来创建目录和子目录
mkdir 是什么呢 Mkdir 是一个用来在 Linux 系统下创建目录的命令.此命令属于内建命令. 运行 mkdir 命令 你可以在你的控制台直接键入 mkdir 来使用它. $ mkdir 默认 ...
- SharePoint 2013 页面访问,Url中间多一段"_layouts/15/start.aspx#"
问题描述: 我想访问如下页面 http://Host/_layouts/15/ManageFeatures.aspx 点击以后页面地址没有错,但是中间多了一段"_layouts/15/sta ...
- web报表工具FineReport的JS编辑框和URL地址栏语法简介
JS编辑框: 1.FineReport的js. 作为一款BS产品,browser端的JavaScript是必不可少的. FineReport中的js是已经调用了finereport.js的. 大家知道 ...
- linux中syscall调用号查看
可以用locate查找: locate unistd_32 //或者 locate unistd_64 以下是本猫在ubuntu下返回的结果: /usr/src/linux-headers-3.16. ...
- Java核心技术第四章——2.final 和 static
final实例域 实例域(对象的属性)可修饰为final.修饰为final后,在构建对象时必须初始化这个实例域.若没有在实例域进行初始化,那么必须在每个构造器内初始化这个实例域(否则会编译错误). 表 ...
- 智能合约最佳实践 之 Solidity 编码规范
每一门语言都有其相应的编码规范, Solidity 也一样, 下面官方推荐的规范及我的总结,供大家参考,希望可以帮助大家写出更好规范的智能合约. 命名规范 避免使用 小写的l,大写的I,大写的O 应该 ...
- WebService技术简介
今天继续阅读<.Net 大局观>时看到一段关于WebService支持技术的论述,真是简明扼要: Web services的另一个重要应用是B2B整合,一般来说它也依赖Internet,将 ...