日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【DirectX12】1.基本组件创建和绘图流程

發(fā)布時(shí)間:2024/9/30 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【DirectX12】1.基本组件创建和绘图流程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

基本組件的創(chuàng)建和繪圖流程

1.頭文件

2.類型名字

3.檢測(cè)XMath支持

4.開啟調(diào)試層

4.創(chuàng)建DXGI的Factory接口

5.獲取硬件適配器

6.輸出顯卡信息(可選)

7.創(chuàng)建Device

8.創(chuàng)建命令隊(duì)列(command queue)

9.創(chuàng)建交換鏈(swap chain)

10.禁止alt+enter的功能

11.記錄當(dāng)前后背緩沖索引

12.創(chuàng)建繪制表面視圖(rtv)堆描述符

?13.創(chuàng)建深度模板視圖(dsv)堆描述符

14.獲取堆描述符偏移大小

15.創(chuàng)建rtv

16.創(chuàng)建命令分配器(command allocator)

17.創(chuàng)建dsv

18.創(chuàng)建命令列表(command list)

19.創(chuàng)建用于同步的資源

20.創(chuàng)建根簽名(root signature)

21.創(chuàng)建輸入布局(input element)

22.編譯shader

23.創(chuàng)建管道狀態(tài)對(duì)象(pipeline state object)

光柵(rasterizer)狀態(tài)

混合(blend)狀態(tài)

深度模板(depth stencil)狀態(tài)

最終創(chuàng)建PSO

24.創(chuàng)建采樣器

25.創(chuàng)建索引緩沖(index buffer)

填充內(nèi)存

創(chuàng)建默認(rèn)堆(heap default)

?上載堆(heap upload)的創(chuàng)建

轉(zhuǎn)換資源狀態(tài)

?創(chuàng)建索引緩沖視圖(ibv)

26.執(zhí)行命令列表

27.繪制流水線

重置命令分配器和命令列表

rtv、stv清屏

繪制

轉(zhuǎn)換rtv狀態(tài)

關(guān)閉命令列表并執(zhí)行

呈現(xiàn)并進(jìn)行下一幀

28.繪圖流程

29.代碼倉庫


基本組件的創(chuàng)建和繪圖流程


1.頭文件

#include <d3d12.h>? ? ?最基本的dx12頭文件
#include "d3dx12.h"? ?d3dx12與以往的不同,現(xiàn)在只有一個(gè)頭文件,去官方示例里復(fù)制一份即可
#include <dxgi1_6.h>??dxgi相關(guān)
#include <D3DCompiler.h>著色器編譯相關(guān)
#include <DirectXMath.h>數(shù)學(xué)庫

2.類型名字

? ? ? ? 使用DirectX命名空間,然后typedef一些DXGI的類型,方便以后替換。

using namespace DirectX;typedef IDXGIFactory7 _IDXGIFactory; typedef IDXGIAdapter4 _IDXGIAdapter; typedef IDXGISwapChain4 _IDXGISwapChain;

3.檢測(cè)XMath支持

if (!XMVerifyCPUSupport()) {dnd_debug(DL::DAMAGE, L"DirectXMath不支持!");return; }

4.開啟調(diào)試層

? ? ? ? 開啟調(diào)試層后,在出現(xiàn)錯(cuò)誤時(shí),被DX庫檢測(cè)到,就會(huì)輸出原因。

#if defined(_DEBUG)// Enable the D3D12 debug layer.com_ptr<ID3D12Debug> debugController;hr = D3D12GetDebugInterface(IID_PPV_ARGS(&debugController));if (FAILED(hr)){dnd_debug(DL::DAMAGE, L"創(chuàng)建調(diào)試層失敗!");return;}debugController->EnableDebugLayer(); #endif

4.創(chuàng)建DXGI的Factory接口

? ? ? ?IDXGIFactory是DXGI的基礎(chǔ)接口,我們需要用com_ptr保存它的指針。可能你還看到其他人用ComPtr,這是偏舊一些的代碼。

//.h com_ptr<_IDXGIFactory> _factory; //.cpp hr = CreateDXGIFactory1(__uuidof(_IDXGIFactory), (void**)(&_factory)); if (FAILED(hr)) {dnd_debug(DL::DAMAGE, L"F創(chuàng)建DXGI接口失敗!");return; }

5.獲取硬件適配器

? ? ? ? IDXGIAdapter是顯卡的抽象,但不一定是硬件的。通過GetHardwareAdapter函數(shù)返回硬件適配器,并attach賦予指針?biāo)袡?quán)給com_ptr<_IDXGIAdapter>。

//.h com_ptr<_IDXGIAdapter> _adapter; //.cpp _IDXGIAdapter* adapter; GetHardwareAdapter(_factory.get(), &adapter); if (adapter == nullptr) {dnd_debug(DL::DAMAGE, L"獲取硬件適配器失敗!");return; } _adapter.attach(adapter); void GetHardwareAdapter(_IDXGIFactory* pFactory, _IDXGIAdapter** ppAdapter) {*ppAdapter = nullptr;for (UINT adapterIndex = 0; ; ++adapterIndex){_IDXGIAdapter* pAdapter = nullptr;if (DXGI_ERROR_NOT_FOUND == pFactory->EnumAdapterByGpuPreference(adapterIndex,DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, _uuidof(_IDXGIAdapter), (void**)&pAdapter)){// No more adapters to enumerate.break;}// Check to see if the adapter supports Direct3D 12, but don't create the// actual device yet.if (SUCCEEDED(D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))){*ppAdapter = pAdapter;return;}pAdapter->Release();} }

6.輸出顯卡信息(可選)

//輸出顯卡信息 DXGI_ADAPTER_DESC adapter_desc; _adapter->GetDesc(&adapter_desc);dnd_debug(DL::MSG, adapter_desc.Description); dnd_debug(DL::MSG, L"顯卡內(nèi)存:" + to_wstring(int(adapter_desc.DedicatedVideoMemory / 1024 / 1024))); dnd_debug(DL::MSG, L"獨(dú)占內(nèi)存:" + to_wstring(int(adapter_desc.DedicatedSystemMemory / 1024 / 1024))); dnd_debug(DL::MSG, L"共享內(nèi)存:" + to_wstring(int(adapter_desc.SharedSystemMemory / 1024 / 1024)));

7.創(chuàng)建Device

? ? ? ? 其中D3D_FEATURE_LEVEL_11_0是最低要求顯卡支持的特性等級(jí)(feature level),注意在GetHardwareAdapter函數(shù)里,我們也是填的這個(gè)值。這是官方文檔的方法,應(yīng)該不能填再低于它的值。

hr = D3D12CreateDevice(_adapter.get(),D3D_FEATURE_LEVEL_11_0,IID_PPV_ARGS(&_device)); if (FAILED(hr)) {dnd_debug(DL::DAMAGE, L"創(chuàng)建Device失敗!");return; }

8.創(chuàng)建命令隊(duì)列(command queue)

? ? ? ? 命令隊(duì)列用于執(zhí)行命令列表(command list),簡單情況只需要?jiǎng)?chuàng)建一個(gè)。

D3D12_COMMAND_QUEUE_DESC desc; desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; desc.NodeMask = 0; desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;hr = _device->CreateCommandQueue(&desc, IID_PPV_ARGS(&_commandQueue)); if (FAILED(hr)) {dnd_debug(DL::DAMAGE, L"創(chuàng)建命令隊(duì)列失敗!");return; }

9.創(chuàng)建交換鏈(swap chain)

基礎(chǔ)字段
SwapEffect交換模型DirectX12應(yīng)該使用DXGI_SWAP_EFFECT_FLIP_DISCARD交換模型
BufferCount緩沖數(shù)量翻轉(zhuǎn)丟棄模型,此值必須大于2
BufferUsage緩沖標(biāo)記作為繪制表面(render target)應(yīng)該填DXGI_USAGE_RENDER_TARGET_OUTPUT
OutputWindow窗口句柄填入窗口句柄hwnd
Windowed窗口模式這個(gè)值最好為TRUE,切換全屏是之后的事
Flag標(biāo)記填入DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH讓DXGI可以自行修改緩沖大小,由于不需要響應(yīng)alt+enter操作,直接填0
BufferDesc
Format顏色格式統(tǒng)一使用DXGI_FORMAT_R8G8B8A8_UNORM
Width緩沖寬度比如800
Height緩沖高度比如600

????????BufferDesc其余的刷新率、掃描方式字段如下填默認(rèn)值即可,因?yàn)槿聊J?#xff0c;還需要匹配這些信息。

? ? ? ? 而SamleDesc多重采樣(MSAA)字段,Count填1,Quality填0即可。因?yàn)榉D(zhuǎn)丟棄模型不支持多重采樣。

com_ptr<IDXGISwapChain> swapChain;DXGI_SWAP_CHAIN_DESC descSwapChain; descSwapChain.BufferCount = SWAP_CHAIN_BUFFER_COUNT; descSwapChain.BufferDesc.Format = DXGI_FORMAT_TYPE; descSwapChain.BufferDesc.Height = h; descSwapChain.BufferDesc.RefreshRate.Denominator = 0; descSwapChain.BufferDesc.RefreshRate.Numerator = 0; descSwapChain.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; descSwapChain.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; descSwapChain.BufferDesc.Width = w; descSwapChain.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; descSwapChain.Flags = 0;// DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; descSwapChain.OutputWindow = g_system.GetHwnd(); descSwapChain.SampleDesc.Count = 1; descSwapChain.SampleDesc.Quality = 0; descSwapChain.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; descSwapChain.Windowed = TRUE;hr = _factory->CreateSwapChain(_commandQueue.get(),&descSwapChain,swapChain.put() ); if (FAILED(hr)) {dnd_debug(DL::DAMAGE, L"創(chuàng)建交換鏈?zhǔn)?#xff01;");return; } swapChain.as(_swapChain);

10.禁止alt+enter的功能

? ? ? ? 創(chuàng)建交換鏈關(guān)聯(lián)窗口后調(diào)用才有效。

_factory->MakeWindowAssociation(g_system.GetHwnd(), DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER);

11.記錄當(dāng)前后背緩沖索引

UINT _frameIndex = _swapChain->GetCurrentBackBufferIndex();

12.創(chuàng)建繪制表面視圖(rtv)堆描述符

? ? ? ? 繪制表面視圖(render target view),縮寫rtv。

? ? ? ? 堆描述符(heap descriptor),用于描述多個(gè)資源的抽象。所以我們創(chuàng)建了一個(gè)_rtvHeap來表示對(duì)rtv的引用,其中NumDescriptors字段和創(chuàng)建交換鏈時(shí)填入的緩沖數(shù)量一致。

D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; rtvHeapDesc.NodeMask = 0; rtvHeapDesc.NumDescriptors = SWAP_CHAIN_BUFFER_COUNT;// rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;hr = _device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&_rtvHeap));if (FAILED(hr)) {dnd_debug(DL::DAMAGE, L"創(chuàng)建RTV堆描述符失敗!");return; }

?13.創(chuàng)建深度模板視圖(dsv)堆描述符

? ? ? ? 深度緩沖用作深度測(cè)試,而模板緩沖可作為鏡子效果。為了創(chuàng)建深度模板視圖(depth stencil view),首先需要?jiǎng)?chuàng)建堆描述符。這里NumDescriptors字段填1,因?yàn)橹恍枰?個(gè)。

D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {}; dsvHeapDesc.NumDescriptors = 1; dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; hr = _device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(&_dsvHeap));if (FAILED(hr)) {dnd_debug(DL::DAMAGE, L"創(chuàng)建深度模板緩存堆描述符失敗!");return; }

14.獲取堆描述符偏移大小

? ? ? ? 其中常量緩沖視圖(constant buffer view)、無序訪問視圖(unordered access view)和dsv的堆描述符偏移大小是一樣的。

_sizeDescriptorRtv = _device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); _sizeDescriptorCbvSrv = _device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

? ? ? ? 一個(gè)堆描述符描述了多個(gè)資源,這個(gè)偏移就是用于確定某個(gè)資源所在的位置。比如我們創(chuàng)建了包含N個(gè)紋理的著色器資源視圖(shader resource view)堆描述符,通過以下方式切換紋理:

CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandleTex(_srvHeap->GetGPUDescriptorHandleForHeapStart(), index, g_dx._sizeDescriptorCbvSrv); _commandList->SetGraphicsRootDescriptorTable(0, srvHandleTex);

15.創(chuàng)建rtv

? ? ? ? 前面創(chuàng)建了rtv的堆描述符,那個(gè)時(shí)候就確定了描述資源的數(shù)量(開始填入的SWAP_CHAIN_BUFFER_COUNT)。這時(shí)實(shí)際的創(chuàng)建rtv,由于它需要?jiǎng)討B(tài)修改(需要響應(yīng)窗口大小發(fā)生改變),我們寫成可反復(fù)調(diào)用的形式:

void DirectX::_create_rtv(LONG w, LONG h) {CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(_rtvHeap->GetCPUDescriptorHandleForHeapStart());// Create a RTV for each frame.for (UINT n = 0; n < SWAP_CHAIN_BUFFER_COUNT; n++){HRESULT hr = _swapChain->GetBuffer(n, IID_PPV_ARGS(&_renderTargets[n]));if (FAILED(hr)){dnd_debug(DL::ERR, L"從交換鏈獲取后背緩沖失敗!");continue;}_device->CreateRenderTargetView(_renderTargets[n].get(), nullptr, rtvHandle);rtvHandle.Offset(1, _sizeDescriptorRtv);} }

? ? ? ? 這里構(gòu)造了一個(gè)rtvHandle變量,然后每個(gè)緩沖創(chuàng)建一個(gè)RTV,循環(huán)的末尾調(diào)用了rtvHandle.Offset(1, _sizeDescriptorRtv);進(jìn)行偏移。

16.創(chuàng)建命令分配器(command allocator)

? ? ? ? 命令分配器用于記錄命令列表執(zhí)行過的操作。它的數(shù)量等于交換鏈的緩沖數(shù)量。

for (UINT n = 0; n < SWAP_CHAIN_BUFFER_COUNT; n++) {hr = _device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&_commandAllocator[n]));if (FAILED(hr)){dnd_debug(DL::DAMAGE, L"創(chuàng)建命令分配器失敗!");return;} }

17.創(chuàng)建dsv

? ? ? ? 先通過CreateCommittedResource在顯存上創(chuàng)建資源,再調(diào)用CreateDepthStencilView和前面dsvHeap綁定關(guān)系。

? ? ? ? 因?yàn)槲視簳r(shí)只使用了深度測(cè)試,所以DepthStencil.Stencil字段為0,而DepthStencil.Depth字段我設(shè)為的是1.0f,這個(gè)值只能在[0, 1]的范圍。在構(gòu)建投影矩陣時(shí),所有頂點(diǎn)的z值都會(huì)被變換到這個(gè)范圍。而2d繪制使用的是正交投影矩陣,我們手動(dòng)設(shè)置z值在此范圍即可,這也是精靈的遮擋關(guān)系。

? ? ? ? 并且每幀都需要重置dsv的緩沖值,類似于清屏。

? ? ? ? 它依賴于交換鏈緩沖的大小,所以需要多次調(diào)用,寫成函數(shù)的形式。

void DirectX::_create_dsv(LONG w, LONG h) {D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilDesc = {};depthStencilDesc.Format = DXGI_FORMAT_D32_FLOAT;depthStencilDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;depthStencilDesc.Flags = D3D12_DSV_FLAG_NONE;D3D12_CLEAR_VALUE depthOptimizedClearValue = {};depthOptimizedClearValue.Format = DXGI_FORMAT_D32_FLOAT;depthOptimizedClearValue.DepthStencil.Depth = DEPTH_VALUE_START;depthOptimizedClearValue.DepthStencil.Stencil = 0;HRESULT hr = _device->CreateCommittedResource(pointer(CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT)),D3D12_HEAP_FLAG_NONE,pointer(CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_D32_FLOAT, w, h, 1, 0, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)),D3D12_RESOURCE_STATE_DEPTH_WRITE,&depthOptimizedClearValue,IID_PPV_ARGS(&_depthStencil));if (FAILED(hr)){dnd_debug(DL::DAMAGE, L"創(chuàng)建dsv失敗!");return;}_device->CreateDepthStencilView(_depthStencil.get(), &depthStencilDesc, _dsvHeap->GetCPUDescriptorHandleForHeapStart());}

18.創(chuàng)建命令列表(command list)

? ? ? ? 在命令分配器的基礎(chǔ)上創(chuàng)建命令列表,通過_frameIndex只需要?jiǎng)?chuàng)建1個(gè)。

hr = _device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, _commandAllocator[_frameIndex].get(), nullptr, IID_PPV_ARGS(&_commandList)); if (FAILED(hr)) {dnd_debug(DL::DAMAGE, L"創(chuàng)建命令列表失敗!");return; }

19.創(chuàng)建用于同步的資源

? ? ? ? 當(dāng)命令列表的操作被命令隊(duì)列執(zhí)行時(shí),這時(shí)從內(nèi)存向顯卡傳輸資源,但這是異步的,需要時(shí)間來完成這些操作。通過同步資源我們可以知道,何時(shí)顯卡完成了操作,此時(shí)就可以釋放內(nèi)存資源等等。

//.h HANDLE _fenceEvent; com_ptr<ID3D12Fence> _fence; UINT64 _fenceValues[SWAP_CHAIN_BUFFER_COUNT] = {};//.cpp // Create synchronization objects and wait until assets have been uploaded to the GPU. hr = _device->CreateFence(_fenceValues[_frameIndex], D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&_fence)); _fenceValues[_frameIndex]++;// Create an event handle to use for frame synchronization. _fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (_fenceEvent == nullptr) {//hr = HRESULT_FROM_WIN32(GetLastError()));dnd_debug(DL::DAMAGE, L"創(chuàng)建同步事件失敗!");return; }

? ? ? ? 等待GPU完成操作的函數(shù)。

void DirectX::WaitForGpu() {HRESULT hr = E_FAIL;// Schedule a Signal command in the queue.hr = _commandQueue->Signal(_fence.get(), _fenceValues[_frameIndex]);if (FAILED(hr)){dnd_debug(DL::ERR, L"命令隊(duì)列Signal失敗!");return;}// Wait until the fence has been processed.hr = _fence->SetEventOnCompletion(_fenceValues[_frameIndex], _fenceEvent);if (FAILED(hr)){dnd_debug(DL::ERR, L"圍欄設(shè)置同步對(duì)象失敗!");return;}WaitForSingleObjectEx(_fenceEvent, INFINITE, FALSE);// Increment the fence value for the current frame._fenceValues[_frameIndex]++; }

20.創(chuàng)建根簽名(root signature)

? ? ? ? 根簽名簡單理解,需要與shader的資源一致。最常見的需要紋理、矩陣這兩種資源,紋理歸于srv,而矩陣屬于cbv。還需要?jiǎng)?chuàng)建一個(gè)動(dòng)態(tài)的采樣器(sampler)資源,采樣器也可以是靜態(tài)的。

// Create the root signature. D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {};// This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this. featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1;if (FAILED(g_dx._device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData)))) {featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0; }CD3DX12_DESCRIPTOR_RANGE1 ranges[3]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);//紋理資源 ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0);//采樣器 ranges[2].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);//常量區(qū)CD3DX12_ROOT_PARAMETER1 rootParameters[3]; rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL); rootParameters[1].InitAsDescriptorTable(1, &ranges[1], D3D12_SHADER_VISIBILITY_PIXEL); rootParameters[2].InitAsDescriptorTable(1, &ranges[2], D3D12_SHADER_VISIBILITY_ALL);//所有可見CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);com_ptr<ID3DBlob> signature; com_ptr<ID3DBlob> error; hr = D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, signature.put(), error.put()); if (FAILED(hr)) {dnd_debug(DL::DAMAGE, L"序列化根簽名失敗:" + String::Mbtowc((char*)error->GetBufferPointer(), false));return; } hr = g_dx._device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&_rootSignature)); if (FAILED(hr)) {dnd_debug(DL::DAMAGE, L"創(chuàng)建根簽名失敗!");return; }

? ? ? ? 可以看到,0為srv,1為sampler,2為cbv。這與shader文件一致:

//2d.hlsl cbuffer cb0 : register(b0) {float4x4 g_mWorldViewProj; };Texture2D g_txDiffuse : register(t0); SamplerState g_sampler : register(s0);

????????只有cbv標(biāo)記了全部可見(D3D12_SHADER_VISIBILITY_ALL ),因?yàn)?span style="color:#be191c;">頂點(diǎn)著色器(vertex shader)需要進(jìn)行頂點(diǎn)變換:

//2d.hlsl PSInput VSMain(VSInput input) {PSInput result;result.position = mul(float4(input.position, 1.0f), g_mWorldViewProj);result.color = input.color;result.uv = input.uv;return result; }

? ? ? ? 而像素著色器(pixel shader)使用了紋理和采樣器:

//2d.hlsl float4 PSMain(PSInput input) : SV_TARGET {float4 Color = g_txDiffuse.Sample(g_sampler, input.uv) * input.color;clip(Color.a - 0.004f);return Color; }

21.創(chuàng)建輸入布局(input element)

? ? ? ? 輸入布局描述了與頂點(diǎn)的結(jié)構(gòu),分別是位置、顏色、UV。

D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = {{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, };

? ? ? ? 這是2d繪圖需要的頂點(diǎn),3d繪圖則可能不需要頂點(diǎn)的顏色,但需要加上法線、切線等屬性通過光照混合紋理來計(jì)算它的顏色。

struct Vertex {XMFLOAT3 _pos;XMFLOAT4 _color;XMFLOAT2 _t; };

22.編譯shader

com_ptr<ID3DBlob> vertexShader;com_ptr<ID3DBlob> pixelShader;#if defined(_DEBUG)// Enable better shader debugging with the graphics debugging tools.UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #elseUINT compileFlags = 0; #endifID3DBlob* errors = nullptr;hr = D3DCompileFromFile(L"2d.hlsl", nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, vertexShader.put(), &errors);if (errors != nullptr){dnd_debug(Debug::Level::INFO, String::Mbtowc((char*)errors->GetBufferPointer(), false));errors->Release();}if (FAILED(hr)){dnd_debug(DL::DAMAGE, L"編譯vs失敗!");return;}hr = D3DCompileFromFile(L"2d.hlsl", nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, pixelShader.put(), &errors);if (errors != nullptr){dnd_debug(Debug::Level::INFO, String::Mbtowc((char*)errors->GetBufferPointer(), false));errors->Release();}if (FAILED(hr)){dnd_debug(DL::DAMAGE, L"編譯ps失敗!");return;}

? ? ? ? 簡單的2d.hlsl文件如下:

struct VSInput {float3 position : POSITION;float4 color : COLOR;float2 uv : TEXCOORD0; };struct PSInput {float4 position : SV_POSITION;float4 color : COLOR;float2 uv : TEXCOORD0; };cbuffer cb0 : register(b0) {float4x4 g_mWorldViewProj; };Texture2D g_txDiffuse : register(t0); SamplerState g_sampler : register(s0);PSInput VSMain(VSInput input) {PSInput result;result.position = mul(float4(input.position, 1.0f), g_mWorldViewProj);result.color = input.color;result.uv = input.uv;return result; }float4 PSMain(PSInput input) : SV_TARGET {float4 Color = g_txDiffuse.Sample(g_sampler, input.uv) * input.color;clip(Color.a - 0.004f);return Color; }

23.創(chuàng)建管道狀態(tài)對(duì)象(pipeline state object)

光柵(rasterizer)狀態(tài)

? ? ? ? 由于2d繪圖不需要通過頂點(diǎn)繞序判斷正面與背面,CullMode設(shè)置為NONE或許能減少GPU的消耗。

CD3DX12_RASTERIZER_DESC rasterizerStateDesc(D3D12_DEFAULT); rasterizerStateDesc.CullMode = D3D12_CULL_MODE_NONE;

混合(blend)狀態(tài)

? ? ? ? 使用如下的混合方式可以進(jìn)行半透明物體的正常繪制,但BlendEnable字段現(xiàn)在設(shè)置的暫時(shí)是false,即未開啟顏色混合。

D3D12_BLEND_DESC blend_desc; blend_desc.AlphaToCoverageEnable = FALSE; blend_desc.IndependentBlendEnable = FALSE;//false只使用RenderTarget[0]blend_desc.RenderTarget[0].BlendEnable = FALSE; blend_desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; blend_desc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA; blend_desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;//兩個(gè)透明物體混合,其透明度應(yīng)該是較不透明者 blend_desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_MAX; blend_desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA; blend_desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_DEST_ALPHA;blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; blend_desc.RenderTarget[0].LogicOpEnable = FALSE;

深度模板(depth stencil)狀態(tài)

? ? ? ? 這里打開了深度測(cè)試,但關(guān)閉了模板測(cè)試。D3D12_COMPARISON_FUNC_LESS標(biāo)記會(huì)使繪制時(shí),z值小于當(dāng)前像素z值的才被寫入。

D3D12_DEPTH_STENCIL_DESC depth_stencil_desc; //小于時(shí)成功 depth_stencil_desc.DepthEnable = TRUE; depth_stencil_desc.DepthFunc = D3D12_COMPARISON_FUNC_LESS; depth_stencil_desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;depth_stencil_desc.StencilEnable = FALSE;

最終創(chuàng)建PSO

? ? ? ? 創(chuàng)建PSO依賴從20節(jié)(創(chuàng)建根簽名)到前面所創(chuàng)建的資源,通過修改一些字段,我們創(chuàng)建了兩個(gè)PSO。一個(gè)用于非透明精靈的繪制、一個(gè)用于半透明精靈的繪制。非透明精靈的繪制關(guān)閉了顏色混合,半透明精靈的繪制打開了顏色混合,并且深度測(cè)試函數(shù)改為了小于等于時(shí)成功(D3D12_COMPARISON_FUNC_LESS_EQUAL),因?yàn)榘胪该骶`必須后繪制,遇到z值相同的非透明像素依舊需要寫入。

D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };psoDesc.pRootSignature = _rootSignature.get();psoDesc.VS = { reinterpret_cast<UINT8*>(vertexShader->GetBufferPointer()), vertexShader->GetBufferSize() };psoDesc.PS = { reinterpret_cast<UINT8*>(pixelShader->GetBufferPointer()), pixelShader->GetBufferSize() };psoDesc.RasterizerState = rasterizerStateDesc;psoDesc.BlendState = blend_desc;//CD3DX12_BLEND_DESC(D3D12_DEFAULT);psoDesc.DepthStencilState = depth_stencil_desc;psoDesc.SampleMask = UINT_MAX;psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;psoDesc.NumRenderTargets = 1;psoDesc.RTVFormats[0] = DXGI_FORMAT_TYPE;psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT;psoDesc.SampleDesc.Count = 1;//非透明任然需要深度測(cè)試,但不需要alpha混合hr = g_dx._device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&_pipelineState[PsoType::NORMAL]));if (FAILED(hr)){dnd_debug(DL::DAMAGE, L"創(chuàng)建PSO(normal)失敗!");return;}psoDesc.BlendState.RenderTarget[0].BlendEnable = TRUE;//相等也必須混合,因?yàn)楸尘翱赡苁遣煌该魑矬w,在DrawCall里,一定是后畫的psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;hr = g_dx._device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&_pipelineState[PsoType::TRANSLUCENT]));if (FAILED(hr)){dnd_debug(DL::DAMAGE, L"創(chuàng)建PSO(translucent)失敗!");return;}

24.創(chuàng)建采樣器

? ? ? ? 先創(chuàng)建堆描述符,再創(chuàng)建采樣器資源:

// Describe and create a sampler descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC samplerHeapDesc = {}; samplerHeapDesc.NumDescriptors = 1; samplerHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; samplerHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; hr = g_dx._device->CreateDescriptorHeap(&samplerHeapDesc, IID_PPV_ARGS(&_samplerHeap)); if (FAILED(hr)) {dnd_debug(DL::DAMAGE, L"創(chuàng)建采樣器堆描述符失敗!");return; }// Describe and create a sampler. D3D12_SAMPLER_DESC samplerDesc = {}; samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP; samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP; samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP; samplerDesc.MinLOD = 0; samplerDesc.MaxLOD = D3D12_FLOAT32_MAX; samplerDesc.MipLODBias = 0.0f; samplerDesc.MaxAnisotropy = 1; samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS; g_dx._device->CreateSampler(&samplerDesc, _samplerHeap->GetCPUDescriptorHandleForHeapStart());

25.創(chuàng)建索引緩沖(index buffer)

填充內(nèi)存

? ? ? ? 這里使用了vector,如果使用數(shù)組,由于數(shù)組太大可能會(huì)棧溢出。一個(gè)精靈(四邊形)有四個(gè)頂點(diǎn),劃分為兩個(gè)三角形,則需要6個(gè)索引。

? ? ? ? 頂點(diǎn)繞序?yàn)?012、023,如下圖所示:

vector<UINT32> indices; indices.resize(Constant::NUM_2D_INDICES);UINT32 n = 0; for (UINT32 i = 0; i < Constant::NUM_2D_INDICES; i += 6) {indices[i + 0] = 0 + n;indices[i + 1] = 1 + n;indices[i + 2] = 2 + n;indices[i + 3] = 0 + n;indices[i + 4] = 2 + n;indices[i + 5] = 3 + n;n += 4; }

創(chuàng)建默認(rèn)堆(heap default)

? ? ? ? 我們需要在顯存上創(chuàng)建索引緩沖資源,通過以下方式創(chuàng)建:

CD3DX12_HEAP_PROPERTIES heapProps2(D3D12_HEAP_TYPE_DEFAULT); auto desc2 = CD3DX12_RESOURCE_DESC::Buffer(Constant::NUM_2D_INDICES * sizeof(UINT32));hr = g_dx._device->CreateCommittedResource(&heapProps2,D3D12_HEAP_FLAG_NONE,&desc2,D3D12_RESOURCE_STATE_COPY_DEST,nullptr,IID_PPV_ARGS(&_indexBuffer)); if (FAILED(hr)) {dnd_debug(DL::DAMAGE, L"創(chuàng)建索引緩存失敗(DEFAULT)!");return; }

? ? ? ?通過標(biāo)記 D3D12_HEAP_TYPE_DEFAULT創(chuàng)建的CD3DX12_HEAP_PROPERTIES 結(jié)構(gòu)說明資源在顯存上,再通過?CD3DX12_RESOURCE_DESC::Buffer(size);指定了緩沖區(qū)的大小。D3D12_RESOURCE_STATE_COPY_DEST指定資源的狀態(tài)是復(fù)制目標(biāo)(copy dest)狀態(tài),資源必須是這個(gè)狀態(tài)才能通過內(nèi)存上傳資源。

????????通過標(biāo)記 D3D12_HEAP_TYPE_DEFAULT創(chuàng)建的資源叫默認(rèn)堆,它是沒有CPU訪問權(quán)限的,只能通過上載堆給它上傳資源,這個(gè)過程就是內(nèi)存到顯存的過程。

?上載堆(heap upload)的創(chuàng)建

? ? ? ? ?同樣上載堆是類似的創(chuàng)建方式,只不過堆類型改為了D3D12_HEAP_TYPE_UPLOAD,然后資源的狀態(tài)必須填D3D12_RESOURCE_STATE_GENERIC_READ,這是規(guī)定。它是可以被CPU訪問的,也就是存在于某片內(nèi)存上。

com_ptr<ID3D12Resource> indexBufferUploadHeap; CD3DX12_HEAP_PROPERTIES heapProps3(D3D12_HEAP_TYPE_UPLOAD); auto desc3 = CD3DX12_RESOURCE_DESC::Buffer(Constant::NUM_2D_INDICES * sizeof(UINT32));hr = g_dx._device->CreateCommittedResource(&heapProps3,D3D12_HEAP_FLAG_NONE,&desc3,D3D12_RESOURCE_STATE_GENERIC_READ,nullptr,IID_PPV_ARGS(&indexBufferUploadHeap)); if (FAILED(hr)) {dnd_debug(DL::DAMAGE, L"創(chuàng)建索引緩存失敗(Upload)!");return; }

? ? ? ? 可以通過MapCopyBufferRegion等接口來寫入,但d3dx12有封裝好的函數(shù),簡單的整體復(fù)制我們直接使用即可,先不考慮那么多(寫入一部分、寫入紋理等不盡相同)。

// Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the index buffer. D3D12_SUBRESOURCE_DATA indexData = {}; indexData.pData = (void*)indices.data(); indexData.RowPitch = Constant::NUM_2D_INDICES * sizeof(UINT32); indexData.SlicePitch = indexData.RowPitch;UpdateSubresources<1>(g_dx._commandList.get(), _indexBuffer.get(), indexBufferUploadHeap.get(), 0, 0, 1, &indexData);

? ? ? ? 這里使用到了命令列表,說明這個(gè)操作需要GPU同步,可以理解,從內(nèi)存復(fù)制到顯存,必然是需要顯卡告訴我們完成了此操作。

? ? ? ? 但命令列表的執(zhí)行,只是記錄了操作,并沒有實(shí)際的執(zhí)行操作,等到命令隊(duì)列執(zhí)行它,才真正的開始,那個(gè)時(shí)候我們才需要等待GPU完成操作。因?yàn)関ector<UINT32> indices;和com_ptr<ID3D12Resource> indexBufferUploadHeap;都是局部變量,生命周期結(jié)束后,內(nèi)存也就失效了。但顯然這時(shí)候內(nèi)存失效是錯(cuò)誤的,因?yàn)橘Y源還沒從內(nèi)存全部復(fù)制到顯存。

轉(zhuǎn)換資源狀態(tài)

? ? ? ? 前面創(chuàng)建的索引緩沖默認(rèn)堆一開始是D3D12_RESOURCE_STATE_COPY_DEST狀態(tài),要作為索引緩沖資源,還需要通過資源轉(zhuǎn)換屏障轉(zhuǎn)換到D3D12_RESOURCE_STATE_INDEX_BUFFER狀態(tài)。因?yàn)樯厦娴膭?chuàng)建,并沒有出現(xiàn)index buffer相關(guān)的標(biāo)記,顯卡不知道這個(gè)資源的用途是索引緩沖。

auto num_barrier1 = CD3DX12_RESOURCE_BARRIER::Transition(_indexBuffer.get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER); g_dx._commandList->ResourceBarrier(1, &num_barrier1);

?創(chuàng)建索引緩沖視圖(ibv)

D3D12_INDEX_BUFFER_VIEW _indexBufferView;// Describe the index buffer view. _indexBufferView.BufferLocation = _indexBuffer->GetGPUVirtualAddress(); _indexBufferView.Format = DXGI_FORMAT_R32_UINT; _indexBufferView.SizeInBytes = Constant::NUM_2D_INDICES * sizeof(UINT32);? ???

? ? ? ? 在繪制時(shí),通過_commandList->IASetIndexBuffer(&_indexBufferView);即可設(shè)置要使用索引緩沖。

26.執(zhí)行命令列表

? ? ? ? 命令列表記錄完操作后,需要Close表示完成記錄,再提交給命令隊(duì)列執(zhí)行。在最后使用WaitForGpu等待顯卡完成操作。

//關(guān)閉并 添加到命令隊(duì)列 // Close the command list and execute it to begin the initial GPU setup. hr = g_dx._commandList->Close(); if (FAILED(hr)) {dnd_debug(DL::DAMAGE, L"命令列表Close失敗!");return; }ID3D12CommandList* ppCommandLists[] = { g_dx._commandList.get() }; g_dx._commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);//這里必須等待資源上傳到GPU g_dx.WaitForGpu();

27.繪制流水線

? ? ? ? 到這里,所有基礎(chǔ)組件就創(chuàng)建完成了,接下來是幀函數(shù)循環(huán)調(diào)用的繪制部分。

重置命令分配器和命令列表

? ? ? ? 在創(chuàng)建命令列表時(shí),我們就依賴于命令分配器。這里每幀重新記錄,都需要Reset。

//重新記錄需要reset hr = _commandAllocator[_frameIndex]->Reset(); if (FAILED(hr)) {dnd_debug(DL::ERR, L"命令分配器Reset失敗!");return; }// However, when ExecuteCommandList() is called on a particular command // list, that command list can then be reset at any time and must be before // re-recording. hr = _commandList->Reset(_commandAllocator[_frameIndex].get(), _2d._pipelineState[Dx2D::PsoType::NORMAL].get()); if (FAILED(hr)) {dnd_debug(DL::ERR, L"命令列表Reset失敗!");return; }

rtv、stv清屏

? ? ? ?將rtv從呈現(xiàn)狀態(tài)(D3D12_RESOURCE_STATE_PRESENT),轉(zhuǎn)換到繪制目標(biāo)狀態(tài)(D3D12_RESOURCE_STATE_RENDER_TARGET),以進(jìn)行接下來的清屏與繪制操作。順便也將dsv清空到初始值。

//資源屏障 呈現(xiàn) -> 繪制目標(biāo) // Indicate that the back buffer will be used as a render target. auto res_barrier0 = CD3DX12_RESOURCE_BARRIER::Transition(_renderTargets[_frameIndex].get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET); _commandList->ResourceBarrier(1, &res_barrier0);//設(shè)置 當(dāng)前繪制目標(biāo) CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(_rtvHeap->GetCPUDescriptorHandleForHeapStart(), _frameIndex, _sizeDescriptorRtv); CD3DX12_CPU_DESCRIPTOR_HANDLE dsvHandle(_dsvHeap->GetCPUDescriptorHandleForHeapStart()); _commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);//清屏 // Record commands. const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f }; _commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr); _commandList->ClearDepthStencilView(_dsvHeap->GetCPUDescriptorHandleForHeapStart(), D3D12_CLEAR_FLAG_DEPTH, DEPTH_VALUE_START, 0, 0, nullptr);

繪制

? ? ? ? 這一步放在后面再講。

轉(zhuǎn)換rtv狀態(tài)

? ? ? ? 完成繪制后,反過來操作一遍,將rtv從繪制目標(biāo)狀態(tài)轉(zhuǎn)換到呈現(xiàn)狀態(tài)。

// Indicate that the back buffer will now be used to present. auto res_barrier1 = CD3DX12_RESOURCE_BARRIER::Transition(_renderTargets[_frameIndex].get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT); _commandList->ResourceBarrier(1, &res_barrier1);

關(guān)閉命令列表并執(zhí)行

//關(guān)閉 hr = _commandList->Close(); if (FAILED(hr)) {dnd_debug(DL::ERR, L"命令列表關(guān)閉失敗!");return; }// 執(zhí)行命令列表 ID3D12CommandList* ppCommandLists[] = { _commandList.get() }; _commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);

呈現(xiàn)并進(jìn)行下一幀

HRESULT hr = _swapChain->Present(_bVsync ? 1 : 0, 0); if (FAILED(hr)) {dnd_debug(DL::ERR, L"Present失敗!");return; }MoveToNextFrame(); void DirectX::MoveToNextFrame() {HRESULT hr = E_FAIL;// Schedule a Signal command in the queue.const UINT64 currentFenceValue = _fenceValues[_frameIndex];hr = _commandQueue->Signal(_fence.get(), currentFenceValue);if (FAILED(hr)){dnd_debug(DL::ERR, L"命令隊(duì)列Signal失敗!");return;}// Update the frame index._frameIndex = _swapChain->GetCurrentBackBufferIndex();// If the next frame is not ready to be rendered yet, wait until it is ready.if (_fence->GetCompletedValue() < _fenceValues[_frameIndex]){hr = _fence->SetEventOnCompletion(_fenceValues[_frameIndex], _fenceEvent);if (FAILED(hr)){dnd_debug(DL::ERR, L"圍欄設(shè)置同步對(duì)象失敗!");return;}WaitForSingleObjectEx(_fenceEvent, INFINITE, FALSE);}// Set the fence value for the next frame._fenceValues[_frameIndex] = currentFenceValue + 1; }

28.繪圖流程

//設(shè)置根簽名 _commandList->SetGraphicsRootSignature(_rootSignature.get());//設(shè)置使用的堆描述符 ID3D12DescriptorHeap* ppHeaps[] = { _cbvSrvHeap.get() ,_samplerHeap.get() }; _commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);//設(shè)置采樣器 _commandList->SetGraphicsRootDescriptorTable(1, _samplerHeap->GetGPUDescriptorHandleForHeapStart());//設(shè)置PSO _commandList->SetPipelineState(_pipelineState[PsoType::NORMAL].get());//設(shè)置視口 _commandList->RSSetViewports(1, &g_dx._viewport);//設(shè)置裁剪 _commandList->RSSetScissorRects(1, &g_dx._scissorRect);//設(shè)置srv偏移 CD3DX12_GPU_DESCRIPTOR_HANDLE cbvSrvHandleTex(_cbvSrvHeap->GetGPUDescriptorHandleForHeapStart(), INT(iter._canvas->_id), g_dx._sizeDescriptorCbvSrv); _commandList->SetGraphicsRootDescriptorTable(0, cbvSrvHandleTex);//設(shè)置cbv偏移 CD3DX12_GPU_DESCRIPTOR_HANDLE cbvSrvHandleMat(_cbvSrvHeap->GetGPUDescriptorHandleForHeapStart(), INT(_vecCanvas.size() + mat_id), g_dx._sizeDescriptorCbvSrv); _commandList->SetGraphicsRootDescriptorTable(2, cbvSrvHandleMat);//設(shè)置繪制圖元 _commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);//設(shè)置索引緩存 _commandList->IASetIndexBuffer(&_indexBufferView);//設(shè)置頂點(diǎn)緩存 _commandList->IASetVertexBuffers(0, 1, &iter._canvas->_vertexBufferView);//繪制 _commandList->DrawIndexedInstanced(UINT((iter._end - iter._beg) / 2 * 3), 1, 0, INT(iter._beg), 0);

29.代碼倉庫

? ? ? ? 完整的2d繪圖封裝,可以參考我的倉庫,我還將實(shí)現(xiàn)圖像加載、音效、文本、網(wǎng)絡(luò)、ui等等一系列游戲相關(guān)的組件,歡迎提出bug,或參與進(jìn)來。

DND3D: 基于DirectX12的3D引擎,嘗試。

總結(jié)

以上是生活随笔為你收集整理的【DirectX12】1.基本组件创建和绘图流程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 18男女无套免费视频 | 日日夜夜免费 | 国产女主播喷水视频在线观看 | 一级黄色大片视频 | 欧美 丝袜 自拍 制服 另类 | 女人被男人躁得好爽免费视频 | 人人搞人人| 日韩欧美自拍 | 欧美激情一区二区三区p站 欧美mv日韩mv国产网站app | 欧美视频一区二区在线观看 | 精品一二三区久久aaa片 | 伊人开心网| 最新99热 | 久久天天躁狠狠躁夜夜av | 午夜在线观看影院 | 色妞视频| 日韩少妇内射免费播放 | 好吊色欧美一区二区三区视频 | 欧美一区二区三区久久成人精品 | 不卡中文字幕在线观看 | 午夜少妇久久久久久久久 | 国产av无码国产av毛片 | 久一久久| 高清视频在线免费观看 | 驯服少爷漫画免费观看下拉式漫画 | 国产午夜成人久久无码一区二区 | 亚洲人成电影网站 | 久久国产视频一区 | 欧美在线导航 | 91久久久久久久 | 亚洲区久久 | 久久精品国产99国产精品 | 欧洲视频一区二区 | 亚洲成a | 日韩在线视屏 | 蜜桃视频污 | 午夜精品久久久久久久久久久久久 | 午夜大片 | 办公室大战高跟丝袜秘书经理ol | 黄瓜视频在线播放 | 成长快手短视频在线观看 | 国产又粗又猛又爽又黄 | 蜜臀99久久精品久久久久久软件 | 中文字幕久久网 | 国产xx在线观看 | av动态| 中文字幕第31页 | 999热精品| 奴性白洁会所调教 | 先锋影音中文字幕 | 久久久久久蜜桃 | 嫩草社区| 国产不卡在线视频 | 国产中文字幕91 | 成人在线免费播放 | 欧美日韩精品三区 | 国产精品美女久久久久av超清 | 欧美人人爽 | 自拍偷拍国产视频 | 国产精品白虎 | 亚洲精品1区 | 黄色一及毛片 | 色多多入口 | 久久亚洲AV成人无码一二三 | 看了让人下面流水的视频 | 亚洲乱码国产乱码精品精 | 欧美日韩国产成人精品 | 欧美丰满熟妇bbbbbb | 少妇太爽了太深了太硬了 | 足疗店女技师按摩毛片 | 亚洲女人天堂网 | 亚洲国产精品人人爽夜夜爽 | 高清av免费观看 | 欧美黑人又粗又大高潮喷水 | 魔女鞋交玉足榨精调教 | 国产精品调教 | 少妇一级淫片免费播放 | 久久久久久网址 | 久久久久国产视频 | 午夜免费一区 | sm一区二区三区 | 影音先锋人妻啪啪av资源网站 | 久久久久国产精品国产 | 麻豆视频网址 | www色天使 | 日本不卡视频 | 永久免费未满蜜桃 | 乱人伦av| 国产精品中文久久久久久 | 亚洲国产精品久久 | 中文字幕1区2区3区 www.com黄色片 | 伊人天天操 | 亚洲一卡二卡 | а√天堂资源官网在线资源 | 欧美jizz18性欧美 | 亚洲欧美自拍另类 | 美女在线观看视频 | 天天射天天干天天 | 一本之道高清无码视频 |