DirectXMath之XMVECTOR :https://blog.csdn.net/BonChoix/article/details/8280596
DirectXMath之XMMATRIX :https://blog.csdn.net/BonChoix/article/details/8280617
Directx—-Vs2019环境配置
首先打开Vs2019—-工具—-扩展工具和功能勾选一下选项
下载安装完毕之后,新建项目可以看到Directx11项目
根据龙书教程我们可以不适用VS2019自带的Directx框架,新建一个空项目,然后右键项目—-属性
DirectX11初始化
DirectX初始化步骤总共分为:
1.使用 D3D11CreateDevice 方法创建 ID3D11Device 和 ID3D11DeviceContext。
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)。我们总是将该参数设为空值,因为我们使用硬件进行渲染。
- 可选参数,一般为NULL,可以设为D3D11_CREATE_DEVICE_DEBUG、D3D11_CREATE_DEVICE_SINGLETHREADED,或两者一起,前者让要用于调试时收集信息,后者在确定程序只在单线程下运行时设置为它,可以提高性能;
- pFeatureLevels:为我们提供给程序的特征等级的一个数组,下一个参数为数组中元素个数
- SDKVersion:始终设为 D3D11_SDK_VERSION。
- ppDevice:返回创建后的设备对象。
- pFeatureLevel : 返 回 pFeatureLevels 数 组 中 第 一 个 支 持 的 特 征 等 级 ( 如 果 pFeatureLevels 为 null,则返回可支持的最高等级)。
- 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;
- BufferDesc:该结构体描述了我们所要创建的后台缓冲区的属性。我们主要关注的属性有:宽度、高度和像素格式
- SampleDesc:多重采样数量和质量级别
- BufferUsage:设为 DXGI_USAGE_RENDER_TARGET_OUTPUT,因为我们要将场景渲染到后台缓冲区
- BufferCount:交换链中的后台缓冲区数量;我们一般只用一个后台缓冲区来实现双缓存。
- OutputWindow:我们将要渲染到的窗口的句柄。
- Windowed:当设为 true 时,程序以窗口模式运行;当设为 false 时,程序以全屏 (full-screen)模式运行。
- SwapEffect:设为 DXGI_SWAP_EFFECT_DISCARD,让显卡驱动程序选择最高效的显示模式。
- 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;
- Width:后台缓冲区宽度
- Height:后台缓冲区高度
- RefreshRate:显示刷新率
- 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);
得到结果