以下是使用 DirectX 12 绘制彩虹色实心三角形的简单示例的项目结构:
```
RainbowTriangle/
├── RainbowTriangle.cpp
├── RainbowTriangle.h
├── Shader.hlsl
└── Resources/
├── Shaders/
│ ├── VS.hlsl
│ └── PS.hlsl
├── Textures/
└── Models/
```
其中,`RainbowTriangle.cpp` 和 `RainbowTriangle.h` 是 C++ 源代码文件,`Shader.hlsl` 是 HLSL 着色器文件,`Resources` 文件夹包含着色器、纹理和模型等资源。
下面是 `RainbowTriangle.cpp` 的示例代码,用于创建窗口、初始化 DirectX 12、设置顶点数据、编译着色器、创建管道和渲染三角形:
```cpp
#include <windows.h>
#include <d3d12.h>
#include <dxgi1_4.h>
#include <d3dx12.h>
#include <DirectXMath.h>
#include <iostream>
#pragma comment(lib, "d3d12.lib")
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "d3dcompiler.lib")
using namespace DirectX;
// 顶点结构体
struct Vertex
{
XMFLOAT3 position;
XMFLOAT4 color;
};
// 顶点数据
Vertex vertices[] =
{
{ XMFLOAT3(0.0f, 0.5f, 0.0f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
{ XMFLOAT3(0.5f, -0.5f, 0.0f), XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f) },
{ XMFLOAT3(-0.5f, -0.5f, 0.0f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) }
};
// HLSL 着色器代码
const char* vertexShaderCode =
"struct VertexInputType\n"
"{\n"
" float3 position : POSITION;\n"
" float4 color : COLOR;\n"
"};\n"
"struct PixelInputType\n"
"{\n"
" float4 position : SV_POSITION;\n"
" float4 color : COLOR;\n"
"};\n"
"PixelInputType main(VertexInputType input)\n"
"{\n"
" PixelInputType output;\n"
" output.position = float4(input.position, 1.0f);\n"
" output.color = input.color;\n"
" return output;\n"
"}";
const char* pixelShaderCode =
"struct PixelInputType\n"
"{\n"
" float4 position : SV_POSITION;\n"
" float4 color : COLOR;\n"
"};\n"
"float4 main(PixelInputType input) : SV_TARGET\n"
"{\n"
" return input.color;\n"
"}";
// 全局变量
HWND hWnd;
const UINT frameCount = 2;
UINT currentFrameIndex = 0;
ID3D12Device* device;
IDXGISwapChain3* swapChain;
ID3D12CommandQueue* commandQueue;
ID3D12CommandAllocator* commandAllocators[frameCount];
ID3D12GraphicsCommandList* commandList;
ID3D12DescriptorHeap* rtvDescriptorHeap;
ID3D12Resource* renderTargets[frameCount];
ID3D12RootSignature* rootSignature;
ID3D12PipelineState* pipelineState;
// 函数声明
bool InitWindow(HINSTANCE hInstance, int nCmdShow);
bool InitD3D();
void CreateRenderTargetViews();
void CreateCommandObjects();
void CreateRootSignature();
void CreatePipelineState();
void PopulateCommandList();
void WaitForPreviousFrame();
// WinMain 函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
if (!InitWindow(hInstance, nCmdShow))
{
return 1;
}
if (!InitD3D())
{
return 1;
}
// 主消息循环
MSG msg = {};
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
PopulateCommandList();
WaitForPreviousFrame();
}
}
return static_cast<int>(msg.wParam);
}
// 初始化窗口
bool InitWindow(HINSTANCE hInstance, int nCmdShow)
{
WNDCLASSEX wc = {};
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DefWindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.lpszClassName = L"RainbowTriangleClass";
RegisterClassEx(&wc);
RECT rect = { 0, 0, 640, 480 };
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
hWnd = CreateWindowEx(0, L"RainbowTriangleClass", L"Rainbow Triangle", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return false;
}
ShowWindow(hWnd, nCmdShow);
return true;
}
// 初始化 DirectX 12
bool InitD3D()
{
HRESULT hr;
// 创建设备
hr = D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device));
if (FAILED(hr))
{
return false;
}
// 创建命令队列和命令分配器
CreateCommandObjects();
// 创建交换链
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.BufferCount = frameCount;
swapChainDesc.Width = 640;
swapChainDesc.Height = 480;
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
IDXGISwapChain1* tempSwapChain;
hr = CreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG, IID_PPV_ARGS(&tempFactory));
if (FAILED(hr))
{
return false;
}
hr = tempFactory->CreateSwapChainForHwnd(commandQueue, hWnd, &swapChainDesc, nullptr, nullptr, &tempSwapChain);
if (FAILED(hr))
{
return false;
}
hr = tempSwapChain->QueryInterface(IID_PPV_ARGS(&swapChain));
if (FAILED(hr))
{
return false;
}
tempSwapChain->Release();
currentFrameIndex = swapChain->GetCurrentBackBufferIndex();
// 创建渲染目标视图
CreateRenderTargetViews();
// 创建根签名
CreateRootSignature();
// 创建管道状态
CreatePipelineState();
// 创建命令列表
hr = device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocators[currentFrameIndex], nullptr, IID_PPV_ARGS(&commandList));
if (FAILED(hr))
{
return false;
}
// 关闭命令列表
commandList->Close();
return true;
}
// 创建命令队列和命令分配器
void CreateCommandObjects()
{
HRESULT hr;
// 创建命令队列
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.NodeMask = 0;
hr = device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue));
if (FAILED(hr))
{
return;
}
// 创建命令分配器
for (UINT i = 0; i < frameCount; i++)
{
hr = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocators[i]));
if (FAILED(hr))
{
return;
}
}
}
// 创建渲染目标视图
void CreateRenderTargetViews()
{
HRESULT hr;
// 获取渲染目标视图描述符堆的大小
const UINT rtvDescriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
// 创建渲染目标视图描述符堆
D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
rtvHeapDesc.NumDescriptors = frameCount;
rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
hr = device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&rtvDescriptorHeap));
if (FAILED(hr))
{
return;
}
// 获取渲染目标视图描述符堆的起始句柄
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
// 创建渲染目标视图
for (UINT i = 0; i < frameCount; i++)
{
hr = swapChain->GetBuffer(i, IID_PPV_ARGS(&renderTargets[i]));
if (FAILED(hr))
{
return;
}
device->CreateRenderTargetView(renderTargets[i], nullptr, rtvHandle);
rtvHandle.Offset(1, rtvDescriptorSize);
}
}
// 创建根签名
void CreateRootSignature()
{
HRESULT hr;
// 根参数
CD3DX12_ROOT_PARAMETER rootParameters[1];
rootParameters[0].InitAsConstants(sizeof(XMFLOAT4X4) / 4, 0, 0, D3D12_SHADER_VISIBILITY_VERTEX);
// 根签名描述符
CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc;
rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW