概述
(准备篇提供Direct2D的基本操作,但是可能不会更新)
Direct2D 是一款笔者非常喜欢的图像API。在这里就写出D2D 1.1版本的笔记,方便大家也是方便自己。
网上有不少1.0版本的教程,但是几乎没有1.1版本的,很是可惜。希望本系列文章能帮助有需要的童鞋。
先说一下定位: Direct2D 1.1版本非常适合游戏开发,只有一个RenderTarget(以下简称RT)的继承实现,是D2D1DeviceContext,
而1.0版本自带了几个,其中HWNDRenderTarget(利用ID2D1Factory::CreateHwndRenderTarget)非常适合开发普通
Windows桌面程序,利用DxgiSurface创建的RT则也是适合游戏开发(使用ID2D1Factory::CreateDxgiSurfaceRenderTarget)。
再说一下系统要求,1.1版本系统要求是进行功能更新的Win7及其以上。看看吧,有一群人死守着XP,看你是否
为这些人单独设计还是使用其他接口。
1.0版本的D2D初始化非常简单,初始化COM就不多说了。
创建 ---> D2D工厂 --- 创建---> D2D RT
利用RT就可以渲染图形图像了。
在1.1版本就复杂了不少,先给张图吧:(这张图是面向Win8 应用商店程序的,不过也差不多)
本人的建议是: 大致看看这个流程,再看看在本文后面提供的模板即可。
以后开发应用直接利用这个模板即可,因为非常的定式化。
1. 创建D3D11 设备,也可以创建D3D10,不过D3D11更好。
D3D11CreateDevice
可以查看详细参数说明,唯一需要说明的是
创建flag 一定要有 D3D11_CREATE_DEVICE_BGRA_SUPPORT
比如:
<span style="font-size:14px;">UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
#ifdef _DEBUG
// Debug状态 有D3D DebugLayer就可以取消注释
//creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
D3D_FEATURE_LEVEL featureLevels[] = {
D3D_FEATURE_LEVEL_11_1,
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
};
// 创建设备
hr = D3D11CreateDevice(
// 设为空指针选择默认设备
pDxgiAdapter,
// 强行指定硬件渲染
D3D_DRIVER_TYPE_HARDWARE,
// 没有软件接口
nullptr,
// 创建flag
creationFlags,
// 欲使用的特性等级列表
featureLevels,
// 特性等级列表长度
lengthof(featureLevels),
// SDK 版本
D3D11_SDK_VERSION,
// 返回的D3D11设备指针
&pD3DDevice,
// 返回的特性等级
&m_featureLevel,
// 返回的D3D11设备上下文指针
&pD3DDeviceContext
);</span>
2. 获取 IDXGIDevice
<span style="font-size:14px;">hr = pD3DDevice->QueryInterface(__uuidof(IDXGIDevice1), (void **)&pDxgiDevice);</span>
3. 创建 D2D 工厂
<span style="font-size:14px;">hr = D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
__uuidof(ID2D1Factory1),
reinterpret_cast<void**>(&m_pD2DFactory)
);</span>
4. 创建D2D设备
<span style="font-size:14px;">hr = m_pD2DFactory->CreateDevice(pDxgiDevice, &m_pD2DDevice);</span>
5. 创建D2D设备上下文
<span style="font-size:14px;">hr = m_pD2DDevice->CreateDeviceContext(
D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
&m_pD2DDeviceContext
);</span>
理论上就初始化完毕了,但是这个D2D 设备上下文并没有渲染目标,
我们需要ID2D1DeviceContext::SetTarget设置一个渲染目标,这是一个什么目标呢。
可以是一个D2D位图(比如ID2D1Bitmap1),但是这样仅仅是在计算机里面做做运算,什么也不会显示。
我们可以创建一个窗口交换链,让这个窗口交换链承载渲染目标,这样我们就可以在窗口上面显示我们的图像了。
6. 获取Dxgi适配器 还可以可以获取该适配器信息,比如显卡型号
<span style="font-size:14px;">hr = pDxgiDevice->GetAdapter(&pDxgiAdapter);</span>
7. 利用适配器获取父对象: Dxgi工厂
<span style="font-size:14px;">hr = pDxgiAdapter->GetParent(IID_PPV_ARGS(&pDxgiFactory));</span>
8. 利用Dxgi工厂创建窗口交换链
<span style="font-size:14px;"> // 设置全屏参数(可以不要)
DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreenDesc;
// 设置刷新率60FPS
fullscreenDesc.RefreshRate.Numerator = 60;
fullscreenDesc.RefreshRate.Denominator = 1;
// 扫描方案
fullscreenDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
// 缩放方案
fullscreenDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
// 全屏显示
fullscreenDesc.Windowed = FALSE;
// 获取窗口大小
RECT rect;
::GetClientRect(m_hwnd, &rect);
rect.right -= rect.left;
rect.bottom -= rect.top;
// 交换链信息
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 };
swapChainDesc.Width = rect.right;
swapChainDesc.Height = rect.bottom;
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapChainDesc.Stereo = FALSE;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 2;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
// 应用商店程序
//swapChainDesc.Scaling = DXGI_SCALING_NONE;
//swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
// 桌面应用程序
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.Flags = 0;
// 利用窗口句柄创建交换链
hr = pDxgiFactory->CreateSwapChainForHwnd(
pD3DDevice,
m_hwnd,
&swapChainDesc,
false ? &fullscreenDesc : nullptr,
nullptr,
&m_pSwapChain
);</span>
请注意有行写的是:
false ? &fullscreenDesc : nullptr
也就是可要可不要的,看需求吧。反正调试起来,窗口模式更方便,而且2D游戏也适合窗口模式,
让玩家可以干干其他的事情。
8.5 确保安全, 保证DXGI队列里边不会超过一帧:
<span style="font-size:14px;">hr = pDxgiDevice->SetMaximumFrameLatency(1);</span>
9. 利用交换链获取其首个Dxgi表面:
<span style="font-size:14px;"> hr = m_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pDxgiBackBuffer));</span>
10. 利用Dxgi表面创建位图:
<span style="font-size:14px;"> D2D1_BITMAP_PROPERTIES1 bitmapProperties = D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
FIXED_DPI,
FIXED_DPI
);
hr = m_pD2DDeviceContext->CreateBitmapFromDxgiSurface(
pDxgiBackBuffer,
&bitmapProperties,
&m_pD2DTargetBimtap
);</span>
这个位图就是需要的呈现目标
11 设置目标 :
<span style="font-size:14px;">m_pD2DDeviceContext->SetTarget(m_pD2DTargetBimtap);</span>
11.5 (建议) 使用像素作为单位:
<span style="font-size:14px;">m_pD2DDeviceContext->SetUnitMode(D2D1_UNIT_MODE_PIXELS);</span>
请注意,ID2D1DeviceContext::SetTarget这个接口。这个接口提供了方便的渲染方法:
在位图上渲染图像,
我们仅需GetTarget获取当前接口,再设置一个位图,渲染图像,再设置回来。
就能获取一张渲染好的位图。
比如在游戏中提供一个设置提高亮度的选项。如果不使用这个方法,我们必须将每个渲染方法均需要修改亮度,
这很麻烦。
使用这个方法,我们先对换渲染对象,先使用一张位图承载渲染目标。渲染完毕后,
再换回来,背景清空,单独渲染刚刚的位图,不透明度就是(1-提高亮度),越透明就越量。
提交给交换链,简直方便。
还有就是根据自己的情况创建WIC工厂、DWrite工厂等等。
好了,现在送上模板(图片来源于网络,采用CC0授权):
下载地址
最后
以上就是奋斗大象为你收集整理的Direct2D 1.1 开发笔记 准备篇(一) 初始化的全部内容,希望文章能够帮你解决Direct2D 1.1 开发笔记 准备篇(一) 初始化所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复