refactor: 移除HelloEarth示例,统一使用D3D12最小可行系统

This commit is contained in:
2026-03-15 00:43:54 +08:00
parent 9a7a6102b5
commit d8882ab93f
17 changed files with 0 additions and 8722 deletions

View File

@@ -1,511 +0,0 @@
#include "BattleFireDirect.h"
ID3D12Device* gD3D12Device = nullptr;
ID3D12CommandQueue* gCommandQueue = nullptr;
IDXGISwapChain3* gSwapChain = nullptr;
ID3D12Resource* gDSRT = nullptr, * gColorRTs[2];
int gCurrentRTIndex = 0;
ID3D12DescriptorHeap* gSwapChainRTVHeap = nullptr;
ID3D12DescriptorHeap* gSwapChainDSVHeap = nullptr;
UINT gRTVDescriptorSize = 0;
UINT gDSVDescriptorSize = 0;
ID3D12CommandAllocator* gCommandAllocator = nullptr;
ID3D12GraphicsCommandList* gCommandList = nullptr;
ID3D12Fence* gFence = nullptr;
HANDLE gFenceEvent = nullptr;
UINT64 gFenceValue = 0;
ID3D12RootSignature* InitRootSignature() {
//1110001110101111111111111111111111
D3D12_ROOT_PARAMETER rootParameters[4];
rootParameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
rootParameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
rootParameters[1].Constants.RegisterSpace = 0;
rootParameters[1].Constants.ShaderRegister = 0;
rootParameters[1].Constants.Num32BitValues = 4;
rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
rootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
rootParameters[0].Descriptor.RegisterSpace = 0;
rootParameters[0].Descriptor.ShaderRegister = 1;//cbv
D3D12_DESCRIPTOR_RANGE descriptorRange[1];
descriptorRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
descriptorRange[0].RegisterSpace = 0;
descriptorRange[0].BaseShaderRegister = 0;//t0
descriptorRange[0].NumDescriptors = 1;
descriptorRange[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
rootParameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
rootParameters[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
rootParameters[2].DescriptorTable.pDescriptorRanges = descriptorRange;
rootParameters[2].DescriptorTable.NumDescriptorRanges = _countof(descriptorRange);//cbv
rootParameters[3].ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;
rootParameters[3].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
rootParameters[3].Descriptor.RegisterSpace = 1;
rootParameters[3].Descriptor.ShaderRegister = 0;//srv
D3D12_STATIC_SAMPLER_DESC samplerDesc[1];
memset(samplerDesc, 0,sizeof(D3D12_STATIC_SAMPLER_DESC)*_countof(samplerDesc));
samplerDesc[0].Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc[0].AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
samplerDesc[0].AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
samplerDesc[0].AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
samplerDesc[0].BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK;
samplerDesc[0].MaxLOD = D3D12_FLOAT32_MAX;
samplerDesc[0].RegisterSpace = 0;
samplerDesc[0].ShaderRegister = 0;//s0
samplerDesc[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {};
rootSignatureDesc.NumParameters = _countof(rootParameters);
rootSignatureDesc.pParameters = rootParameters;
rootSignatureDesc.NumStaticSamplers = _countof(samplerDesc);
rootSignatureDesc.pStaticSamplers = samplerDesc;
rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
//64 DWORD -> float 128 WORD -> 16bit
ID3DBlob* signature;
HRESULT hResult = D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, nullptr);
ID3D12RootSignature* d3d12RootSignature;
gD3D12Device->CreateRootSignature(
0, signature->GetBufferPointer(), signature->GetBufferSize(),
IID_PPV_ARGS(&d3d12RootSignature));
return d3d12RootSignature;
}
void CreateShaderFromFile(
LPCTSTR inShaderFilePath,
const char* inMainFunctionName,
const char* inTarget,//"vs_5_0","ps_5_0","vs_4_0"
D3D12_SHADER_BYTECODE* inShader) {
ID3DBlob* shaderBuffer = nullptr;
ID3DBlob* errorBuffer = nullptr;
HRESULT hResult = D3DCompileFromFile(inShaderFilePath, nullptr, nullptr,
inMainFunctionName, inTarget, D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION,
0, &shaderBuffer, &errorBuffer);
if (FAILED(hResult)) {
char szLog[1024] = {0};
strcpy(szLog, (char*)errorBuffer->GetBufferPointer());
printf("CreateShaderFromFile error : [%s][%s]:[%s]\n", inMainFunctionName, inTarget, szLog);
errorBuffer->Release();
return;
}
inShader->pShaderBytecode = shaderBuffer->GetBufferPointer();
inShader->BytecodeLength = shaderBuffer->GetBufferSize();
}
ID3D12Resource* CreateConstantBufferObject(int inDataLen) {
D3D12_HEAP_PROPERTIES d3dHeapProperties = {};
d3dHeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;//cpu,gpu
D3D12_RESOURCE_DESC d3d12ResourceDesc = {};
d3d12ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
d3d12ResourceDesc.Alignment = 0;
d3d12ResourceDesc.Width = inDataLen;
d3d12ResourceDesc.Height = 1;
d3d12ResourceDesc.DepthOrArraySize = 1;
d3d12ResourceDesc.MipLevels = 1;
d3d12ResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
d3d12ResourceDesc.SampleDesc.Count = 1;
d3d12ResourceDesc.SampleDesc.Quality = 0;
d3d12ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
d3d12ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
ID3D12Resource* bufferObject = nullptr;
gD3D12Device->CreateCommittedResource(
&d3dHeapProperties,
D3D12_HEAP_FLAG_NONE,
&d3d12ResourceDesc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&bufferObject)
);
return bufferObject;
}
void UpdateConstantBuffer(ID3D12Resource* inCB, void* inData, int inDataLen) {
D3D12_RANGE d3d12Range = { 0 };
unsigned char* pBuffer = nullptr;
inCB->Map(0, &d3d12Range, (void**)&pBuffer);
memcpy(pBuffer, inData, inDataLen);
inCB->Unmap(0, nullptr);
}
ID3D12PipelineState* CreatePSO(ID3D12RootSignature* inID3D12RootSignature,
D3D12_SHADER_BYTECODE inVertexShader, D3D12_SHADER_BYTECODE inPixelShader,
D3D12_SHADER_BYTECODE inGSShader) {
D3D12_INPUT_ELEMENT_DESC vertexDataElementDesc[] = {
{"POSITION",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,0,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0},
{"TEXCOORD",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,sizeof(float) * 4,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0},
{"NORMAL",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,sizeof(float) * 8,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0},
{"TANGENT",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,sizeof(float) * 12,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0}
};
D3D12_INPUT_LAYOUT_DESC vertexDataLayoutDesc = {};
vertexDataLayoutDesc.NumElements = 4;
vertexDataLayoutDesc.pInputElementDescs = vertexDataElementDesc;
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.pRootSignature = inID3D12RootSignature;
psoDesc.VS = inVertexShader;
psoDesc.GS = inGSShader;
psoDesc.PS = inPixelShader;
psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
psoDesc.DSVFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
psoDesc.SampleDesc.Count = 1;
psoDesc.SampleDesc.Quality = 0;
psoDesc.SampleMask = 0xffffffff;
psoDesc.InputLayout = vertexDataLayoutDesc;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
psoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK;
psoDesc.RasterizerState.DepthClipEnable = TRUE;
psoDesc.DepthStencilState.DepthEnable = true;
psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
psoDesc.BlendState = { 0 };
D3D12_RENDER_TARGET_BLEND_DESC rtBlendDesc = {
FALSE,FALSE,
D3D12_BLEND_SRC_ALPHA,D3D12_BLEND_INV_SRC_ALPHA,D3D12_BLEND_OP_ADD,
D3D12_BLEND_SRC_ALPHA,D3D12_BLEND_INV_SRC_ALPHA,D3D12_BLEND_OP_ADD,
D3D12_LOGIC_OP_NOOP,
D3D12_COLOR_WRITE_ENABLE_ALL,
};
for (int i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
psoDesc.BlendState.RenderTarget[i] = rtBlendDesc;
psoDesc.NumRenderTargets = 1;
ID3D12PipelineState* d3d12PSO = nullptr;
HRESULT hResult = gD3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&d3d12PSO));
if (FAILED(hResult)) {
return nullptr;
}
return d3d12PSO;
}
bool InitD3D12(HWND inHWND, int inWidth, int inHeight) {
HRESULT hResult;
UINT dxgiFactoryFlags = 0;
#ifdef _DEBUG
{
ID3D12Debug* debugController = nullptr;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
debugController->EnableDebugLayer();
dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
}
}
#endif
IDXGIFactory4* dxgiFactory;
hResult = CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&dxgiFactory));
if (FAILED(hResult)) {
return false;
}
IDXGIAdapter1* adapter;
int adapterIndex = 0;
bool adapterFound = false;
while (dxgiFactory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND) {
DXGI_ADAPTER_DESC1 desc;
adapter->GetDesc1(&desc);
if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
continue;
}
hResult = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), nullptr);
if (SUCCEEDED(hResult)) {
adapterFound = true;
break;
}
adapterIndex++;
}
if (false == adapterFound) {
return false;
}
hResult = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&gD3D12Device));
if (FAILED(hResult)) {
return false;
}
D3D12_COMMAND_QUEUE_DESC d3d12CommandQueueDesc = {};
hResult = gD3D12Device->CreateCommandQueue(&d3d12CommandQueueDesc, IID_PPV_ARGS(&gCommandQueue));
if (FAILED(hResult)) {
return false;
}
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
swapChainDesc.BufferCount = 2;
swapChainDesc.BufferDesc = {};
swapChainDesc.BufferDesc.Width = inWidth;
swapChainDesc.BufferDesc.Height = inHeight;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.OutputWindow = inHWND;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.Windowed = true;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
IDXGISwapChain* swapChain = nullptr;
dxgiFactory->CreateSwapChain(gCommandQueue, &swapChainDesc, &swapChain);
gSwapChain = static_cast<IDXGISwapChain3*>(swapChain);
D3D12_HEAP_PROPERTIES d3dHeapProperties = {};
d3dHeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
D3D12_RESOURCE_DESC d3d12ResourceDesc = {};
d3d12ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
d3d12ResourceDesc.Alignment = 0;
d3d12ResourceDesc.Width = inWidth;
d3d12ResourceDesc.Height = inHeight;
d3d12ResourceDesc.DepthOrArraySize = 1;
d3d12ResourceDesc.MipLevels = 1;
d3d12ResourceDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
d3d12ResourceDesc.SampleDesc.Count = 1;
d3d12ResourceDesc.SampleDesc.Quality = 0;
d3d12ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
d3d12ResourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
D3D12_CLEAR_VALUE dsClearValue = {};
dsClearValue.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
dsClearValue.DepthStencil.Depth = 1.0f;
dsClearValue.DepthStencil.Stencil = 0;
gD3D12Device->CreateCommittedResource(&d3dHeapProperties,
D3D12_HEAP_FLAG_NONE,
&d3d12ResourceDesc,
D3D12_RESOURCE_STATE_DEPTH_WRITE,
&dsClearValue,
IID_PPV_ARGS(&gDSRT)
);
//RTV,DSV,alloc
D3D12_DESCRIPTOR_HEAP_DESC d3dDescriptorHeapDescRTV = {};
d3dDescriptorHeapDescRTV.NumDescriptors = 2;
d3dDescriptorHeapDescRTV.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
gD3D12Device->CreateDescriptorHeap(&d3dDescriptorHeapDescRTV, IID_PPV_ARGS(&gSwapChainRTVHeap));
gRTVDescriptorSize = gD3D12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
D3D12_DESCRIPTOR_HEAP_DESC d3dDescriptorHeapDescDSV = {};
d3dDescriptorHeapDescDSV.NumDescriptors = 1;
d3dDescriptorHeapDescDSV.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
gD3D12Device->CreateDescriptorHeap(&d3dDescriptorHeapDescDSV, IID_PPV_ARGS(&gSwapChainDSVHeap));
gDSVDescriptorSize = gD3D12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
D3D12_CPU_DESCRIPTOR_HANDLE rtvHeapStart = gSwapChainRTVHeap->GetCPUDescriptorHandleForHeapStart();
for (int i = 0; i < 2; i++) {
gSwapChain->GetBuffer(i, IID_PPV_ARGS(&gColorRTs[i]));
D3D12_CPU_DESCRIPTOR_HANDLE rtvPointer;
rtvPointer.ptr = rtvHeapStart.ptr + i * gRTVDescriptorSize;
gD3D12Device->CreateRenderTargetView(gColorRTs[i], nullptr, rtvPointer);
}
D3D12_DEPTH_STENCIL_VIEW_DESC d3dDSViewDesc = {};
d3dDSViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
d3dDSViewDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
gD3D12Device->CreateDepthStencilView(gDSRT, &d3dDSViewDesc, gSwapChainDSVHeap->GetCPUDescriptorHandleForHeapStart());
gD3D12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&gCommandAllocator));
gD3D12Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, gCommandAllocator, nullptr, IID_PPV_ARGS(&gCommandList));
gD3D12Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&gFence));
gFenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
return true;
}
ID3D12CommandAllocator* GetCommandAllocator() {
return gCommandAllocator;
}
ID3D12GraphicsCommandList* GetCommandList() {
return gCommandList;
}
void WaitForCompletionOfCommandList() {
if (gFence->GetCompletedValue() < gFenceValue) {
gFence->SetEventOnCompletion(gFenceValue, gFenceEvent);
WaitForSingleObject(gFenceEvent, INFINITE);
}
}
void EndCommandList() {
gCommandList->Close();//
ID3D12CommandList* ppCommandLists[] = { gCommandList };
gCommandQueue->ExecuteCommandLists(1, ppCommandLists);
//CommandList
gFenceValue += 1;
gCommandQueue->Signal(gFence, gFenceValue);//
}
void BeginRenderToSwapChain(ID3D12GraphicsCommandList* inCommandList) {
gCurrentRTIndex = gSwapChain->GetCurrentBackBufferIndex();
D3D12_RESOURCE_BARRIER barrier = InitResourceBarrier(gColorRTs[gCurrentRTIndex], D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
inCommandList->ResourceBarrier(1, &barrier);
D3D12_CPU_DESCRIPTOR_HANDLE colorRT, dsv;
dsv.ptr = gSwapChainDSVHeap->GetCPUDescriptorHandleForHeapStart().ptr;
colorRT.ptr = gSwapChainRTVHeap->GetCPUDescriptorHandleForHeapStart().ptr + gCurrentRTIndex * gRTVDescriptorSize;
inCommandList->OMSetRenderTargets(1, &colorRT, FALSE, &dsv);
D3D12_VIEWPORT viewport = { 0.0f,0.0f,1280.0f,720.0f };
D3D12_RECT scissorRect = { 0,0,1280,720 };
inCommandList->RSSetViewports(1, &viewport);
inCommandList->RSSetScissorRects(1, &scissorRect);
const float clearColor[] = { 0.0f,0.0f,0.0f,1.0f };
inCommandList->ClearRenderTargetView(colorRT, clearColor, 0, nullptr);
inCommandList->ClearDepthStencilView(dsv, D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
}
void EndRenderToSwapChain(ID3D12GraphicsCommandList* inCommandList) {
D3D12_RESOURCE_BARRIER barrier = InitResourceBarrier(gColorRTs[gCurrentRTIndex], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
inCommandList->ResourceBarrier(1, &barrier);
}
void SwapD3D12Buffers() {
gSwapChain->Present(0, 0);
}
ID3D12Resource* CreateBufferObject(ID3D12GraphicsCommandList* inCommandList,
void* inData, int inDataLen, D3D12_RESOURCE_STATES inFinalResourceState) {
D3D12_HEAP_PROPERTIES d3dHeapProperties = {};
d3dHeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;//gpu
D3D12_RESOURCE_DESC d3d12ResourceDesc = {};
d3d12ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
d3d12ResourceDesc.Alignment = 0;
d3d12ResourceDesc.Width = inDataLen;
d3d12ResourceDesc.Height = 1;
d3d12ResourceDesc.DepthOrArraySize = 1;
d3d12ResourceDesc.MipLevels = 1;
d3d12ResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
d3d12ResourceDesc.SampleDesc.Count = 1;
d3d12ResourceDesc.SampleDesc.Quality = 0;
d3d12ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
d3d12ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
ID3D12Resource* bufferObject = nullptr;
gD3D12Device->CreateCommittedResource(
&d3dHeapProperties,
D3D12_HEAP_FLAG_NONE,
&d3d12ResourceDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(&bufferObject)
);
d3d12ResourceDesc = bufferObject->GetDesc();
UINT64 memorySizeUsed = 0;
UINT64 rowSizeInBytes = 0;
UINT rowUsed = 0;
D3D12_PLACED_SUBRESOURCE_FOOTPRINT subresourceFootprint;
gD3D12Device->GetCopyableFootprints(&d3d12ResourceDesc, 0, 1, 0,
&subresourceFootprint, &rowUsed, &rowSizeInBytes, &memorySizeUsed);
// 3 x 4 x 4 = 48bytes,32bytes,24bytes + 24bytes
ID3D12Resource* tempBufferObject = nullptr;
d3dHeapProperties = {};
d3dHeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;//cpu,gpu
gD3D12Device->CreateCommittedResource(
&d3dHeapProperties,
D3D12_HEAP_FLAG_NONE,
&d3d12ResourceDesc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&tempBufferObject)
);
BYTE* pData;
tempBufferObject->Map(0, nullptr, reinterpret_cast<void**>(&pData));
BYTE* pDstTempBuffer = reinterpret_cast<BYTE*>(pData + subresourceFootprint.Offset);
const BYTE* pSrcData = reinterpret_cast<BYTE*>(inData);
for (UINT i = 0; i < rowUsed; i++) {
memcpy(pDstTempBuffer + subresourceFootprint.Footprint.RowPitch * i, pSrcData + rowSizeInBytes * i, rowSizeInBytes);
}
tempBufferObject->Unmap(0, nullptr);
inCommandList->CopyBufferRegion(bufferObject, 0, tempBufferObject, 0, subresourceFootprint.Footprint.Width);
D3D12_RESOURCE_BARRIER barrier = InitResourceBarrier(bufferObject, D3D12_RESOURCE_STATE_COPY_DEST, inFinalResourceState);
inCommandList->ResourceBarrier(1, &barrier);
return bufferObject;
}
D3D12_RESOURCE_BARRIER InitResourceBarrier(
ID3D12Resource* inResource, D3D12_RESOURCE_STATES inPrevState,
D3D12_RESOURCE_STATES inNextState) {
D3D12_RESOURCE_BARRIER d3d12ResourceBarrier;
memset(&d3d12ResourceBarrier, 0, sizeof(d3d12ResourceBarrier));
d3d12ResourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
d3d12ResourceBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
d3d12ResourceBarrier.Transition.pResource = inResource;
d3d12ResourceBarrier.Transition.StateBefore = inPrevState;
d3d12ResourceBarrier.Transition.StateAfter = inNextState;
d3d12ResourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
return d3d12ResourceBarrier;
}
ID3D12Resource* CreateTexture2D(ID3D12GraphicsCommandList* inCommandList,
const void* inPixelData, int inDataSizeInBytes, int inWidth, int inHeight,
DXGI_FORMAT inFormat) {
D3D12_HEAP_PROPERTIES d3dHeapProperties = {};
d3dHeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
D3D12_RESOURCE_DESC d3d12ResourceDesc = {};
d3d12ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
d3d12ResourceDesc.Alignment = 0;
d3d12ResourceDesc.Width = inWidth;
d3d12ResourceDesc.Height = inHeight;
d3d12ResourceDesc.DepthOrArraySize = 1;
d3d12ResourceDesc.MipLevels = 1;
d3d12ResourceDesc.Format = inFormat;
d3d12ResourceDesc.SampleDesc.Count = 1;
d3d12ResourceDesc.SampleDesc.Quality = 0;
d3d12ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
d3d12ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
ID3D12Resource* texture = nullptr;
gD3D12Device->CreateCommittedResource(&d3dHeapProperties,
D3D12_HEAP_FLAG_NONE,
&d3d12ResourceDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(&texture)
);
d3d12ResourceDesc = texture->GetDesc();
UINT64 memorySizeUsed = 0;
UINT64 rowSizeInBytes = 0;
UINT rowUsed = 0;
D3D12_PLACED_SUBRESOURCE_FOOTPRINT subresourceFootprint;
gD3D12Device->GetCopyableFootprints(&d3d12ResourceDesc, 0, 1, 0,
&subresourceFootprint, &rowUsed, &rowSizeInBytes, &memorySizeUsed);
// 3 x 4 x 4 = 48bytes,32bytes,24bytes + 24bytes
ID3D12Resource* tempBufferObject = nullptr;
D3D12_HEAP_PROPERTIES d3dTempHeapProperties = {};
d3dTempHeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;//cpu,gpu
D3D12_RESOURCE_DESC d3d12TempResourceDesc = {};
d3d12TempResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
d3d12TempResourceDesc.Alignment = 0;
d3d12TempResourceDesc.Width = memorySizeUsed;
d3d12TempResourceDesc.Height = 1;
d3d12TempResourceDesc.DepthOrArraySize = 1;
d3d12TempResourceDesc.MipLevels = 1;
d3d12TempResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
d3d12TempResourceDesc.SampleDesc.Count = 1;
d3d12TempResourceDesc.SampleDesc.Quality = 0;
d3d12TempResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
d3d12TempResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
gD3D12Device->CreateCommittedResource(
&d3dTempHeapProperties,
D3D12_HEAP_FLAG_NONE,
&d3d12TempResourceDesc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&tempBufferObject)
);
BYTE* pData;
tempBufferObject->Map(0, nullptr, reinterpret_cast<void**>(&pData));
BYTE* pDstTempBuffer = reinterpret_cast<BYTE*>(pData + subresourceFootprint.Offset);
const BYTE* pSrcData = reinterpret_cast<const BYTE*>(inPixelData);
for (UINT i = 0; i < rowUsed; i++) {
memcpy(pDstTempBuffer + subresourceFootprint.Footprint.RowPitch * i, pSrcData + rowSizeInBytes * i, rowSizeInBytes);
}
tempBufferObject->Unmap(0, nullptr);
D3D12_TEXTURE_COPY_LOCATION dst = {};
dst.pResource = texture;
dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dst.SubresourceIndex = 0;
D3D12_TEXTURE_COPY_LOCATION src = {};
src.pResource = tempBufferObject;
src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
src.PlacedFootprint = subresourceFootprint;
inCommandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);
D3D12_RESOURCE_BARRIER barrier = InitResourceBarrier(texture,
D3D12_RESOURCE_STATE_COPY_DEST,D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
inCommandList->ResourceBarrier(1, &barrier);
return texture;
}
ID3D12Device* GetD3DDevice() {
return gD3D12Device;
}

View File

@@ -1,35 +0,0 @@
#pragma once
#include <d3d12.h>
#include <dxgi1_4.h>
#include <d3dcompiler.h>
#include <DirectXMath.h>
#include <stdio.h>
D3D12_RESOURCE_BARRIER InitResourceBarrier(
ID3D12Resource* inResource, D3D12_RESOURCE_STATES inPrevState,
D3D12_RESOURCE_STATES inNextState);
ID3D12RootSignature* InitRootSignature();
void CreateShaderFromFile(
LPCTSTR inShaderFilePath,
const char* inMainFunctionName,
const char* inTarget,//"vs_5_0","ps_5_0","vs_4_0"
D3D12_SHADER_BYTECODE* inShader);
ID3D12Resource* CreateConstantBufferObject(int inDataLen);
void UpdateConstantBuffer(ID3D12Resource* inCB, void* inData, int inDataLen);
ID3D12Resource* CreateBufferObject(ID3D12GraphicsCommandList* inCommandList,
void* inData, int inDataLen, D3D12_RESOURCE_STATES inFinalResourceState);
ID3D12PipelineState* CreatePSO(ID3D12RootSignature* inID3D12RootSignature,
D3D12_SHADER_BYTECODE inVertexShader, D3D12_SHADER_BYTECODE inPixelShader,
D3D12_SHADER_BYTECODE inGSShader);
bool InitD3D12(HWND inHWND, int inWidth, int inHeight);
ID3D12GraphicsCommandList* GetCommandList();
ID3D12CommandAllocator* GetCommandAllocator();
void WaitForCompletionOfCommandList();
void EndCommandList();
void BeginRenderToSwapChain(ID3D12GraphicsCommandList* inCommandList);
void EndRenderToSwapChain(ID3D12GraphicsCommandList* inCommandList);
void SwapD3D12Buffers();
ID3D12Resource* CreateTexture2D(ID3D12GraphicsCommandList* inCommandList,
const void*inPixelData,int inDataSizeInBytes,int inWidth,int inHeight,
DXGI_FORMAT inFormat);
ID3D12Device* GetD3DDevice();

View File

@@ -1,29 +0,0 @@
cmake_minimum_required(VERSION 3.15)
project(HelloEarth)
add_executable(HelloEarth
WIN32
main.cpp
BattleFireDirect.cpp
StaticMeshComponent.cpp
Utils.cpp
stbi/stb_image.cpp
)
target_compile_definitions(HelloEarth PRIVATE
UNICODE
_UNICODE
)
target_include_directories(HelloEarth PRIVATE
${CMAKE_SOURCE_DIR}/mvs/HelloEarth
${CMAKE_SOURCE_DIR}/mvs/HelloEarth/stbi
)
target_link_libraries(HelloEarth PRIVATE
d3d12
dxgi
d3dcompiler
winmm
)

View File

@@ -1,114 +0,0 @@
# HelloEarth
基础 DirectX 12 渲染示例项目,展示如何搭建基本的渲染管线。
## 简介
HelloEarth 是 XCEngine 项目的入门级示例,通过渲染一个带纹理的球体,帮助理解 DirectX 12 的核心概念和渲染流程。
## 技术栈
- **渲染 API**: DirectX 12
- **语言**: C++17
- **构建系统**: CMake
- **依赖库**: DirectX 12 SDK, stb_image
## 项目结构
```
HelloEarth/
├── main.cpp # 程序入口
├── BattleFireDirect.cpp/h # DirectX 12 核心渲染实现
├── StaticMeshComponent.cpp/h # 静态网格组件
├── Utils.cpp/h # 工具函数
├── stbi/ # 图像加载库
│ ├── stb_image.h
│ └── stb_image.cpp
└── Res/ # 资源文件
├── Shader/
│ ├── gs.hlsl # 几何着色器
│ └── ndctriangle.hlsl # 三角形着色器
├── Model/
│ └── Sphere.lhsm # 球体模型
└── Image/
└── earth_d.jpg # 地球纹理
```
## 构建方法
### 前置要求
- Windows 10/11
- Visual Studio 2019 或更高版本
- CMake 3.15+
### 构建步骤
```bash
# 创建并进入构建目录
mkdir build && cd build
# 配置项目
cmake ..
# 编译
cmake --build . --config Release
```
### 运行
编译完成后运行 `HelloEarth.exe`(如果生成了可执行文件)
## 功能特性
### 渲染管线
- DirectX 12 渲染环境初始化
- 命令队列和命令列表管理
- 资源转换和同步
### 着色器
- 顶点着色器VS
- 几何着色器GS
- 像素着色器PS
### 资源管理
- 静态网格加载和渲染
- 纹理加载(支持 JPG/PNG
- 常量缓冲区管理
- 着色器资源视图SRV
### 数学运算
- 投影矩阵Perspective Projection
- 视图矩阵View Matrix
- 模型矩阵Model Matrix
- 法线矩阵计算
## 核心概念
### 渲染流程
1. 初始化 D3D12 设备和命令队列
2. 创建命令分配器和命令列表
3. 加载着色器(编译 HLSL
4. 创建根签名和 PSO 管道状态
5. 加载网格模型和纹理
6. 创建常量缓冲区并更新数据
7. 渲染循环:
- 重置命令分配器和列表
- 设置渲染目标
- 设置根签名和 PSO
- 设置描述符堆
- 绑定常量缓冲和纹理
- 提交绘制命令
- 呈现交换链
### 关键接口
- `InitD3D12` - 初始化 DirectX 12
- `CreateShaderFromFile` - 从文件加载着色器
- `CreatePSO` - 创建管道状态对象
- `StaticMeshComponent::Render` - 渲染网格
## 资源说明
- 模型文件格式:`.lhsm`(自定义格式)
- 纹理支持PNG、JPG
- 着色器HLSLShader Model 5.1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

View File

@@ -1,99 +0,0 @@
struct VertexData{
float4 position:POSITION;
float4 texcoord:TEXCOORD0;
float4 normal:NORMAL;
float4 tangent:TANGENT;
};
struct VSOut{
float4 position:SV_POSITION;
float4 normal:NORMAL;
float4 texcoord:TEXCOORD0;
};
static const float PI=3.141592;
cbuffer globalConstants:register(b0){
float4 misc;
};
Texture2D T_DiffuseTexture:register(t0);
SamplerState samplerState:register(s0);
struct MaterialData{
float r;
};
StructuredBuffer<MaterialData> materialData:register(t0,space1);
cbuffer DefaultVertexCB:register(b1){
float4x4 ProjectionMatrix;
float4x4 ViewMatrix;
float4x4 ModelMatrix;
float4x4 IT_ModelMatrix;
float4x4 ReservedMemory[1020];
};
VSOut MainVS(VertexData inVertexData){
VSOut vo;
vo.normal=mul(IT_ModelMatrix,inVertexData.normal);
float4 positionWS=mul(ModelMatrix,inVertexData.position);
float4 positionVS=mul(ViewMatrix,positionWS);
vo.position=mul(ProjectionMatrix,positionVS);
//vo.position=float4(positionWS.xyz+vo.normal.xyz*sin(misc.x)*0.2f,1.0f);
vo.texcoord=inVertexData.texcoord;
return vo;
}
[maxvertexcount(4)]
void MainGS(triangle VSOut inPoint[3],uint inPrimitiveID:SV_PrimitiveID,
inout TriangleStream<VSOut> outTriangleStream){
outTriangleStream.Append(inPoint[0]);
outTriangleStream.Append(inPoint[1]);
outTriangleStream.Append(inPoint[2]);
/*VSOut vo;
float3 positionWS=inPoint[0].position.xyz;
float3 N=normalize(inPoint[0].normal.xyz);
vo.normal=float4(N,0.0f);
float3 helperVec=abs(N.y)>0.999?float3(0.0f,0.0f,1.0f):float3(0.0f,1.0f,0.0f);
float3 tangent=normalize(cross(N,helperVec));//u
float3 bitangent=normalize(cross(tangent,N));//v
float scale=materialData[inPrimitiveID].r;
float3 p0WS=positionWS-(bitangent*0.5f-tangent*0.5f)*scale;//left bottom
float4 p0VS=mul(ViewMatrix,float4(p0WS,1.0f));
vo.position=mul(ProjectionMatrix,p0VS);
vo.texcoord=float4(0.0f,1.0f,0.0f,0.0f);
outTriangleStream.Append(vo);
float3 p1WS=positionWS-(bitangent*0.5f+tangent*0.5f)*scale;//right bottom
float4 p1VS=mul(ViewMatrix,float4(p1WS,1.0f));
vo.position=mul(ProjectionMatrix,p1VS);
vo.texcoord=float4(1.0f,1.0f,0.0f,0.0f);
outTriangleStream.Append(vo);
float3 p2WS=positionWS+(bitangent*0.5f+tangent*0.5f)*scale;//left top
float4 p2VS=mul(ViewMatrix,float4(p2WS,1.0f));
vo.position=mul(ProjectionMatrix,p2VS);
vo.texcoord=float4(0.0f,0.0f,0.0f,0.0f);
outTriangleStream.Append(vo);
float3 p3WS=positionWS+(bitangent*0.5f-tangent*0.5f)*scale;//right top
float4 p3VS=mul(ViewMatrix,float4(p3WS,1.0f));
vo.position=mul(ProjectionMatrix,p3VS);
vo.texcoord=float4(1.0f,0.0f,0.0f,0.0f);
outTriangleStream.Append(vo);*/
}
float4 MainPS(VSOut inPSInput):SV_TARGET{
float3 N=normalize(inPSInput.normal.xyz);
float3 bottomColor=float3(0.1f,0.4f,0.6f);
float3 topColor=float3(0.7f,0.7f,0.7f);
float theta=asin(N.y);//-PI/2 ~ PI/2
theta/=PI;//-0.5~0.5
theta+=0.5f;//0.0~1.0
float ambientColorIntensity=1.0;
float3 ambientColor=lerp(bottomColor,topColor,theta)*ambientColorIntensity;
float4 diffuseColor=T_DiffuseTexture.Sample(samplerState,inPSInput.texcoord.xy);
float3 surfaceColor=diffuseColor.rgb;
return float4(surfaceColor,1.0f);
}

View File

@@ -1,65 +0,0 @@
struct VertexData{
float4 position:POSITION;
float4 texcoord:TEXCOORD0;
float4 normal:NORMAL;
float4 tangent:TANGENT;
};
struct VSOut{
float4 position:SV_POSITION;
float4 normal:NORMAL;
float4 texcoord:TEXCOORD0;
float4 positionWS:TEXCOORD1;
};
static const float PI=3.141592;
cbuffer globalConstants:register(b0){
float4 misc;
};
cbuffer DefaultVertexCB:register(b1){
float4x4 ProjectionMatrix;
float4x4 ViewMatrix;
float4x4 ModelMatrix;
float4x4 IT_ModelMatrix;
float4x4 ReservedMemory[1020];
};
VSOut MainVS(VertexData inVertexData){
VSOut vo;
vo.normal=mul(IT_ModelMatrix,inVertexData.normal);
float3 positionMS=inVertexData.position.xyz+vo.normal*sin(misc.x);
float4 positionWS=mul(ModelMatrix,float4(positionMS,1.0));
float4 positionVS=mul(ViewMatrix,positionWS);
vo.position=mul(ProjectionMatrix,positionVS);
vo.positionWS=positionWS;
vo.texcoord=inVertexData.texcoord;
return vo;
}
float4 MainPS(VSOut inPSInput):SV_TARGET{
float3 N=normalize(inPSInput.normal.xyz);
float3 bottomColor=float3(0.1f,0.4f,0.6f);
float3 topColor=float3(0.7f,0.7f,0.7f);
float theta=asin(N.y);//-PI/2 ~ PI/2
theta/=PI;//-0.5~0.5
theta+=0.5f;//0.0~1.0
float ambientColorIntensity=0.2;
float3 ambientColor=lerp(bottomColor,topColor,theta)*ambientColorIntensity;
float3 L=normalize(float3(1.0f,1.0f,-1.0f));
float diffuseIntensity=max(0.0f,dot(N,L));
float3 diffuseLightColor=float3(0.1f,0.4f,0.6f);
float3 diffuseColor=diffuseLightColor*diffuseIntensity;
float3 specularColor=float3(0.0f,0.0f,0.0f);
if(diffuseIntensity>0.0f){
float3 cameraPositionWS=float3(0.0f,0.0f,0.0f);
float3 V=normalize(cameraPositionWS.xyz-inPSInput.positionWS.xyz);
float3 R=normalize(reflect(-L,N));
float specularIntensity=pow(max(0.0f,dot(V,R)),128.0f);
specularColor=float3(1.0f,1.0f,1.0f)*specularIntensity;
}
float3 surfaceColor=ambientColor+diffuseColor+specularColor;
return float4(surfaceColor,1.0f);
}

View File

@@ -1,90 +0,0 @@
#include "StaticMeshComponent.h"
#include "BattleFireDirect.h"
#include <stdio.h>
void StaticMeshComponent::SetVertexCount(int inVertexCount) {
mVertexCount = inVertexCount;
mVertexData = new StaticMeshComponentVertexData[inVertexCount];
memset(mVertexData, 0, sizeof(StaticMeshComponentVertexData)*inVertexCount);
}
void StaticMeshComponent::SetVertexPosition(int inIndex, float inX, float inY, float inZ, float inW /* = 1.0f */) {
mVertexData[inIndex].mPosition[0] = inX;
mVertexData[inIndex].mPosition[1] = inY;
mVertexData[inIndex].mPosition[2] = inZ;
mVertexData[inIndex].mPosition[3] = inW;
}
void StaticMeshComponent::SetVertexTexcoord(int inIndex, float inX, float inY, float inZ, float inW /* = 1.0f */) {
mVertexData[inIndex].mTexcoord[0] = inX;
mVertexData[inIndex].mTexcoord[1] = inY;
mVertexData[inIndex].mTexcoord[2] = inZ;
mVertexData[inIndex].mTexcoord[3] = inW;
}
void StaticMeshComponent::SetVertexNormal(int inIndex, float inX, float inY, float inZ, float inW /* = 1.0f */) {
mVertexData[inIndex].mNormal[0] = inX;
mVertexData[inIndex].mNormal[1] = inY;
mVertexData[inIndex].mNormal[2] = inZ;
mVertexData[inIndex].mNormal[3] = inW;
}
void StaticMeshComponent::SetVertexTangent(int inIndex, float inX, float inY, float inZ, float inW /* = 1.0f */) {
mVertexData[inIndex].mTangent[0] = inX;
mVertexData[inIndex].mTangent[1] = inY;
mVertexData[inIndex].mTangent[2] = inZ;
mVertexData[inIndex].mTangent[3] = inW;
}
void StaticMeshComponent::InitFromFile(ID3D12GraphicsCommandList* inCommandList, const char* inFilePath) {
FILE* pFile = nullptr;
errno_t err = fopen_s(&pFile, inFilePath, "rb");
if (err == 0) {
int temp = 0;
fread(&temp, 4, 1, pFile);
mVertexCount = temp;
mVertexData = new StaticMeshComponentVertexData[mVertexCount];
fread(mVertexData, 1, sizeof(StaticMeshComponentVertexData) * mVertexCount, pFile);
mVBO=CreateBufferObject(inCommandList,mVertexData,
sizeof(StaticMeshComponentVertexData) * mVertexCount,
D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
mVBOView.BufferLocation = mVBO->GetGPUVirtualAddress();
mVBOView.SizeInBytes = sizeof(StaticMeshComponentVertexData) * mVertexCount;
mVBOView.StrideInBytes = sizeof(StaticMeshComponentVertexData);
while (!feof(pFile)) {
fread(&temp, 4, 1, pFile);
if (feof(pFile)) {
break;
}
char name[256] = {0};
fread(name, 1, temp, pFile);
fread(&temp, 4, 1, pFile);
SubMesh* submesh = new SubMesh;
submesh->mIndexCount = temp;
unsigned int *indexes = new unsigned int[temp];
fread(indexes, 1, sizeof(unsigned int) * temp, pFile);
submesh->mIBO = CreateBufferObject(inCommandList, indexes,
sizeof(unsigned int) * temp,
D3D12_RESOURCE_STATE_INDEX_BUFFER);
submesh->mIBView.BufferLocation = submesh->mIBO->GetGPUVirtualAddress();
submesh->mIBView.SizeInBytes = sizeof(unsigned int) * temp;
submesh->mIBView.Format = DXGI_FORMAT_R32_UINT;
mSubMeshes.insert(std::pair<std::string, SubMesh*>(name,submesh));
delete[]indexes;
}
fclose(pFile);
}
}
void StaticMeshComponent::Render(ID3D12GraphicsCommandList* inCommandList) {
D3D12_VERTEX_BUFFER_VIEW vbos[] = {
mVBOView
};
inCommandList->IASetVertexBuffers(0, 1, vbos);
if (mSubMeshes.empty()) {
inCommandList->DrawInstanced(mVertexCount, 1, 0, 0);
}
else {
for (auto iter = mSubMeshes.begin();
iter != mSubMeshes.end(); iter++) {
inCommandList->IASetIndexBuffer(&iter->second->mIBView);
inCommandList->DrawIndexedInstanced(iter->second->mIndexCount, 1, 0, 0, 0);
}
}
}

View File

@@ -1,31 +0,0 @@
#pragma once
#include <d3d12.h>
#include <unordered_map>
#include <string>
struct StaticMeshComponentVertexData {
float mPosition[4];
float mTexcoord[4];
float mNormal[4];
float mTangent[4];
};
struct SubMesh {
ID3D12Resource* mIBO;
D3D12_INDEX_BUFFER_VIEW mIBView;
int mIndexCount;
};
class StaticMeshComponent{
public:
ID3D12Resource* mVBO;
D3D12_VERTEX_BUFFER_VIEW mVBOView;
StaticMeshComponentVertexData* mVertexData;
int mVertexCount;
std::unordered_map<std::string, SubMesh*> mSubMeshes;
void SetVertexCount(int inVertexCount);
void SetVertexPosition(int inIndex, float inX, float inY, float inZ, float inW = 1.0f);
void SetVertexTexcoord(int inIndex, float inX, float inY, float inZ, float inW = 1.0f);
void SetVertexNormal(int inIndex, float inX, float inY, float inZ, float inW = 1.0f);
void SetVertexTangent(int inIndex, float inX, float inY, float inZ, float inW = 1.0f);
void InitFromFile(ID3D12GraphicsCommandList*inCommandList,const char* inFilePath);
void Render(ID3D12GraphicsCommandList* inCommandList);
};

View File

@@ -1,10 +0,0 @@
#include "Utils.h"
#include <math.h>
#include <algorithm>
float srandom() {
float number = float(rand())/float(RAND_MAX);//0.0~1.0f
number *= 2.0f;//0.0~2.0
number -= 1.0f;//-1.0f~1.0f;
return number;
}

View File

@@ -1,3 +0,0 @@
#pragma once
float srandom();//-1.0f~1.0f

View File

@@ -1,188 +0,0 @@
#include <windows.h>
#include "BattleFireDirect.h"
#include "StaticMeshComponent.h"
#include "stbi/stb_image.h"
#include "Utils.h"
#pragma comment(lib,"d3d12.lib")
#pragma comment(lib,"dxgi.lib")
#pragma comment(lib,"d3dcompiler.lib")
#pragma comment(lib,"winmm.lib")
LPCTSTR gWindowClassName = L"BattleFire";
LRESULT CALLBACK WindowProc(HWND inHWND, UINT inMSG, WPARAM inWParam, LPARAM inLParam) {
switch (inMSG) {
case WM_CLOSE:
PostQuitMessage(0);//enqueue WM_QUIT
break;
}
return DefWindowProc(inHWND, inMSG, inWParam, inLParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int inShowCmd) {
//register
WNDCLASSEX wndClassEx;
wndClassEx.cbSize = sizeof(WNDCLASSEX);
wndClassEx.style = CS_HREDRAW | CS_VREDRAW;
wndClassEx.cbClsExtra = NULL;//class
wndClassEx.cbWndExtra = NULL;//instance
wndClassEx.hInstance = hInstance;
wndClassEx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClassEx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClassEx.hbrBackground = NULL;
wndClassEx.lpszMenuName = NULL;
wndClassEx.lpszClassName = gWindowClassName;
wndClassEx.lpfnWndProc = WindowProc;
if (!RegisterClassEx(&wndClassEx)) {
MessageBox(NULL, L"Register Class Failed!", L"Error", MB_OK | MB_ICONERROR);
return -1;
}
//create
int viewportWidth = 1280;
int viewportHeight = 720;
RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = viewportWidth;
rect.bottom = viewportHeight;
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
int windowWidth = rect.right - rect.left;
int windowHeight = rect.bottom - rect.top;
HWND hwnd = CreateWindowEx(NULL,
gWindowClassName,
L"My Render Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
windowWidth, windowHeight,
NULL,
NULL,
hInstance,
NULL);
if (!hwnd) {
MessageBox(NULL, L"Create Window Failed!", L"Error", MB_OK | MB_ICONERROR);
return -1;
}
//show
InitD3D12(hwnd, 1280, 720);
ID3D12GraphicsCommandList* commandList = GetCommandList();
ID3D12CommandAllocator* commandAllocator = GetCommandAllocator();
StaticMeshComponent staticMeshComponent;
staticMeshComponent.InitFromFile(commandList, "Res/Model/Sphere.lhsm");
ID3D12RootSignature* rootSignature = InitRootSignature();
D3D12_SHADER_BYTECODE vs,gs,ps;
CreateShaderFromFile(L"Res/Shader/gs.hlsl", "MainVS", "vs_5_1", &vs);
CreateShaderFromFile(L"Res/Shader/gs.hlsl", "MainGS", "gs_5_1", &gs);
CreateShaderFromFile(L"Res/Shader/gs.hlsl", "MainPS", "ps_5_1", &ps);
ID3D12PipelineState*pso=CreatePSO(rootSignature, vs, ps, gs);
ID3D12Resource* cb = CreateConstantBufferObject(65536);//1024x64(4x4)
DirectX::XMMATRIX projectionMatrix=DirectX::XMMatrixPerspectiveFovLH(
(45.0f*3.141592f)/180.0f,1280.0f/720.0f,0.1f,1000.0f);
DirectX::XMMATRIX viewMatrix = DirectX::XMMatrixIdentity();
DirectX::XMMATRIX modelMatrix = DirectX::XMMatrixTranslation(0.0f,0.0f,5.0f);
//modelMatrix *= DirectX::XMMatrixRotationZ(90.0f*3.141592f/180.0f);
DirectX::XMFLOAT4X4 tempMatrix;
float matrices[64];
DirectX::XMStoreFloat4x4(&tempMatrix, projectionMatrix);
memcpy(matrices, &tempMatrix, sizeof(float) * 16);
DirectX::XMStoreFloat4x4(&tempMatrix, viewMatrix);
memcpy(matrices+16, &tempMatrix, sizeof(float) * 16);
DirectX::XMStoreFloat4x4(&tempMatrix, modelMatrix);
memcpy(matrices + 32, &tempMatrix, sizeof(float) * 16);;
DirectX::XMVECTOR determinant;
DirectX::XMMATRIX inverseModelMatrix = DirectX::XMMatrixInverse(&determinant, modelMatrix);
if (DirectX::XMVectorGetX(determinant) != 0.0f) {
DirectX::XMMATRIX normalMatrix = DirectX::XMMatrixTranspose(inverseModelMatrix);
DirectX::XMStoreFloat4x4(&tempMatrix, modelMatrix);
memcpy(matrices + 48, &tempMatrix, sizeof(float) * 16);;
}
UpdateConstantBuffer(cb, matrices, sizeof(float) * 64);
ID3D12Resource* sb = CreateConstantBufferObject(65536);//1024x64(4x4)
struct MaterialData {
float r;
};
MaterialData* materialDatas = new MaterialData[3000];
for (int i=0;i<3000;i++){
materialDatas[i].r = srandom() * 0.1f + 0.1f;//0.0~1.0
}
UpdateConstantBuffer(sb, materialDatas, sizeof(MaterialData) * 3000);
int imageWidth, imageHeight,imageChannel;
//stbi_set_flip_vertically_on_load(true);
stbi_uc* pixels = stbi_load("Res/Image/earth_d.jpg", &imageWidth, &imageHeight, &imageChannel, 4);
ID3D12Resource* texture = CreateTexture2D(commandList, pixels,
imageWidth * imageHeight * imageChannel, imageWidth, imageHeight,DXGI_FORMAT_R8G8B8A8_UNORM);
delete[]pixels;
ID3D12Device* d3dDevice = GetD3DDevice();
ID3D12DescriptorHeap* srvHeap = nullptr;
D3D12_DESCRIPTOR_HEAP_DESC d3dDescriptorHeapDescSRV = {};
d3dDescriptorHeapDescSRV.NumDescriptors = 3;
d3dDescriptorHeapDescSRV.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
d3dDescriptorHeapDescSRV.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
d3dDevice->CreateDescriptorHeap(&d3dDescriptorHeapDescSRV, IID_PPV_ARGS(&srvHeap));
ID3D12DescriptorHeap* descriptorHeaps[] = {srvHeap};
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = 1;
D3D12_CPU_DESCRIPTOR_HANDLE srvHeapPtr = srvHeap->GetCPUDescriptorHandleForHeapStart();
d3dDevice->CreateShaderResourceView(texture, &srvDesc, srvHeapPtr);
srvHeapPtr.ptr += d3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
EndCommandList();
WaitForCompletionOfCommandList();
ShowWindow(hwnd, inShowCmd);
UpdateWindow(hwnd);
float color[] = {0.5f,0.5f,0.5f,1.0f};
MSG msg;
DWORD last_time = timeGetTime();
DWORD appStartTime = last_time;
while (true){
ZeroMemory(&msg, sizeof(MSG));
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
//rendering
WaitForCompletionOfCommandList();
DWORD current_time = timeGetTime();//ms
DWORD frameTime = current_time - last_time;
DWORD timeSinceAppStartInMS = current_time - appStartTime;
last_time = current_time;
float frameTimeInSecond = float(frameTime) / 1000.0f;//second
float timeSinceAppStartInSecond = float(timeSinceAppStartInMS) / 1000.0f;
color[0] = timeSinceAppStartInSecond;
commandAllocator->Reset();
commandList->Reset(commandAllocator, nullptr);
BeginRenderToSwapChain(commandList);
//draw
commandList->SetPipelineState(pso);
commandList->SetGraphicsRootSignature(rootSignature);
commandList->SetDescriptorHeaps(_countof(descriptorHeaps),descriptorHeaps);
commandList->SetGraphicsRootConstantBufferView(0, cb->GetGPUVirtualAddress());
commandList->SetGraphicsRoot32BitConstants(1, 4, color, 0);
commandList->SetGraphicsRootDescriptorTable(2, srvHeap->GetGPUDescriptorHandleForHeapStart());
commandList->SetGraphicsRootShaderResourceView(3, sb->GetGPUVirtualAddress());
commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
staticMeshComponent.Render(commandList);
EndRenderToSwapChain(commandList);
EndCommandList();
SwapD3D12Buffers();
}
}
return 0;
}

View File

@@ -1,2 +0,0 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

File diff suppressed because it is too large Load Diff

View File

@@ -1,351 +0,0 @@
# XCEngine 渲染引擎 - 第二阶段计划
> **目标**: 构建 RHI 抽象层,将 HelloEarth 的 D3D12 最小可行系统封装为引擎基础设施
> **版本**: 1.0
> **日期**: 2026-03-13
> **前置依赖**: 第一阶段数学库、Core基础类型、线程系统、内存管理、容器库、日志系统
---
## 阶段背景
本阶段基于以下代码基础进行构建:
1. **HelloEarth 最小可行渲染系统** (`mvs/HelloEarth/`)
- 已实现完整的 D3D12 渲染流程
- 包含窗口创建、设备初始化、Shader 加载、网格渲染、纹理绑定
- 可直接运行并渲染地球模型
2. **XCEngine 架构设计书** (`docs/XCEngine渲染引擎架构设计.md`)
- 定义了 RHI 抽象层接口规范
- 定义了渲染资源封装接口
- 定义了渲染管线基础架构
---
## 阶段目标
将 HelloEarth 中散落的 D3D12 代码重构为引擎的 RHI 抽象层,建立可复用的渲染基础设施,为第三阶段的 Component/GameObject 体系提供渲染支撑。
---
## 模块规划
### 2.1 RHI 公共定义 (RHIDefines)
| 项目 | 内容 |
|------|------|
| **优先级** | P0 |
| **预计工作量** | 1天 |
| **包含内容** | 枚举定义 (`Format`, `ShaderStage`, `ResourceState`, `PrimitiveTopology` 等)、公共结构体 (`Viewport`, `Rect`)、DXGI/D3D12 类型映射 |
| **参考来源** | `docs/XCEngine渲染引擎架构设计.md` 4.1 节 |
### 2.2 RHI 接口层
| 项目 | 内容 |
|------|------|
| **优先级** | P0 |
| **预计工作量** | 2天 |
| **包含接口** | `IRHIDevice`, `ICommandList`, `ICommandAllocator`, `ICommandQueue`, `IFence`, `ISwapChain`, `IDescriptorHeap`, `IRootSignature`, `IPipelineState` |
| **功能要求** | 跨平台抽象接口定义,不包含平台特定实现 |
| **补充说明** | 必须包含 `SetPrimitiveTopology()` 图元类型设置接口 |
| **参考来源** | `docs/XCEngine渲染引擎架构设计.md` 4.1 节 RHI 接口定义 |
### 2.3 D3D12 后端实现
| 项目 | 内容 |
|------|------|
| **优先级** | P0 |
| **预计工作量** | 4天 |
| **包含内容** | `D3D12Device` 实现 `IRHIDevice` 接口、`D3D12CommandList``D3D12CommandAllocator``D3D12Fence``D3D12SwapChain``D3D12DescriptorHeap``D3D12RootSignature``D3D12PipelineState` |
| **迁移参考** | `mvs/HelloEarth/BattleFireDirect.h/cpp` 中的全局函数封装为类接口 |
| **依赖** | RHI 接口层 |
**迁移映射表**
| HelloEarth 原有实现 | 新架构 RHI 接口 |
|---------------------|-----------------|
| `InitD3D12()` | `D3D12Device::Initialize()` |
| `GetD3DDevice()` | `IRHIDevice::GetNativeDevice()` |
| `GetCommandList()` | `ICommandList` |
| `GetCommandAllocator()` | `ICommandAllocator` |
| `InitRootSignature()` | `D3D12RootSignature` |
| `CreatePSO()` | `D3D12PipelineState` |
| `SwapD3D12Buffers()` | `ISwapChain::Present()` |
| `CreateBufferObject()` | `IVertexBuffer` / `IIndexBuffer` |
| `CreateConstantBufferObject()` | `IConstantBuffer` |
| `CreateTexture2D()` | `ITexture2D` |
### 2.4 渲染资源封装
| 项目 | 内容 |
|------|------|
| **优先级** | P0 |
| **预计工作量** | 2天 |
| **包含内容** | `VertexBuffer`, `IndexBuffer`, `ConstantBuffer`, `Texture2D`, `Sampler` |
| **功能要求** | 封装 RHI 资源创建/更新/绑定逻辑 |
| **参考来源** | `docs/XCEngine渲染引擎架构设计.md` 4.0 节渲染资源类型定义 |
| **迁移参考** | `mvs/HelloEarth/main.cpp` 中的 VB/IB/CB/Texture 创建逻辑 |
### 2.5 RenderTarget / DepthStencil 管理
| 项目 | 内容 |
|------|------|
| **优先级** | P0 |
| **预计工作量** | 1天 |
| **包含内容** | `RenderTarget`, `DepthStencil`, 交换链缓冲管理、Resource Barrier 状态转换、SRV/RTV/DSV 创建 |
| **功能要求** | 渲染目标创建、深度模板缓冲管理、状态转换 (Present ↔ RenderTarget)、视图创建 |
| **补充说明** | 必须包含纹理完整创建流程SRV 创建 + Copy 过程 + Barrier 转换ClearRenderTarget/ClearDepthStencil 命令 |
| **迁移参考** | `mvs/HelloEarth/BattleFireDirect.cpp` 中的 `gDSRT`, `gColorRTs` 管理逻辑、`InitResourceBarrier()` 函数、`CreateTexture2D()` 中的 SRV 创建和资源复制逻辑 |
### 2.6 Shader / PSO 管理
| 项目 | 内容 |
|------|------|
| **优先级** | P1 |
| **预计工作量** | 2天 |
| **包含内容** | `Shader` 加载编译、`PipelineState` 缓存管理、`InputLayout` 顶点布局定义、`BlendState`/`DepthStencilState`/`RasterizerState` 渲染状态 |
| **功能要求** | HLSL 文件加载、编译、PSO 创建与缓存、顶点布局定义 |
| **补充说明** | 必须定义渲染状态结构BlendState (混合模式)、DepthStencilState (深度测试)、RasterizerState (光栅化) |
| **迁移参考** | `mvs/HelloEarth/main.cpp``CreateShaderFromFile()``CreatePSO()` 逻辑PSO 中的硬编码状态 |
### 2.7 渲染上下文 (RenderContext)
| 项目 | 内容 |
|------|------|
| **优先级** | P1 |
| **预计工作量** | 2天 |
| **包含内容** | 渲染上下文管理、SwapChain 渲染循环封装、Viewport/Scissor 设置、Clear 命令 |
| **功能要求** | 帧开始/结束、渲染目标切换、视口裁剪设置、背景清除、Present |
| **补充说明** | 必须包含 ClearRenderTargetView 和 ClearDepthStencilView 命令 |
| **迁移参考** | `mvs/HelloEarth/main.cpp` 中渲染循环逻辑、`BeginRenderToSwapChain()` / `EndRenderToSwapChain()` 中的 Clear 调用 |
### 2.8 静态网格组件 (StaticMeshComponent)
| 项目 | 内容 |
|------|------|
| **优先级** | P1 |
| **预计工作量** | 1天 |
| **包含内容** | 网格加载 (.lhsm 格式)、顶点/索引缓冲绑定、渲染调用 |
| **功能要求** | 模型文件加载、顶点数据上传、DrawCall 封装 |
| **迁移参考** | `mvs/HelloEarth/StaticMeshComponent.h/cpp` |
### 2.9 CMake 构建配置
| 项目 | 内容 |
|------|------|
| **优先级** | P1 |
| **预计工作量** | 1天 |
| **包含内容** | RHI/D3D12 子目录 CMakeLists.txt、引擎库配置更新 |
| **功能要求** | 添加 D3D12 后端到构建系统、链接 DirectX 库 |
### 2.10 Demo 整合验证
| 项目 | 内容 |
|------|------|
| **优先级** | P1 |
| **预计工作量** | 1天 |
| **包含内容** | 使用新 RHI 架构重写 HelloEarth Demo |
| **验证目标** | 渲染效果与原 HelloEarth 一致,验证 RHI 层功能完整 |
---
## 目录结构
```
engine/include/XCEngine/
├── RHI/
│ ├── RHIDefines.h # 公共枚举定义
│ ├── IRHIDevice.h # 抽象设备接口
│ ├── ICommandList.h # 命令列表接口
│ ├── ICommandAllocator.h # 命令分配器接口
│ ├── ICommandQueue.h # 命令队列接口
│ ├── IFence.h # 同步围栏接口
│ ├── ISwapChain.h # 交换链接口
│ ├── IDescriptorHeap.h # 描述符堆接口
│ ├── IRootSignature.h # 根签名接口
│ ├── IPipelineState.h # PSO 接口
│ ├── IRenderTargetView.h # RTV 接口
│ ├── IDepthStencilView.h # DSV 接口
│ ├── IShaderResourceView.h # SRV 接口
│ └── RHISystem.h # RHI 系统入口
├── Rendering/
│ ├── Buffer.h # 缓冲区基类
│ ├── VertexBuffer.h # 顶点缓冲区
│ ├── IndexBuffer.h # 索引缓冲区
│ ├── ConstantBuffer.h # 常量缓冲区
│ ├── Texture.h # 纹理
│ ├── RenderTarget.h # 渲染目标
│ ├── DepthStencil.h # 深度模板缓冲
│ ├── Shader.h # Shader 抽象
│ ├── Sampler.h # 采样器
│ ├── InputLayout.h # 顶点输入布局
│ ├── RenderState.h # 渲染状态 (Blend/Depth/Rasterizer)
│ ├── StaticMeshComponent.h # 静态网格组件
│ └── RenderContext.h # 渲染上下文
engine/src/
├── RHI/
│ ├── CMakeLists.txt # RHI 构建配置
│ └── D3D12/
│ ├── CMakeLists.txt # D3D12 构建配置
│ ├── D3D12Device.cpp
│ ├── D3D12CommandList.cpp
│ ├── D3D12CommandAllocator.cpp
│ ├── D3D12CommandQueue.cpp
│ ├── D3D12Fence.cpp
│ ├── D3D12SwapChain.cpp
│ ├── D3D12DescriptorHeap.cpp
│ ├── D3D12RootSignature.cpp
│ ├── D3D12PipelineState.cpp
│ ├── D3D12Resource.cpp
│ └── D3D12Texture.cpp
└── Rendering/
├── CMakeLists.txt # Rendering 构建配置
├── Buffer.cpp
├── Texture.cpp
├── RenderTarget.cpp
├── Shader.cpp
├── RenderState.cpp
├── StaticMeshComponent.cpp
└── RenderContext.cpp
```
---
## 时间安排
| 天数 | 内容 |
|------|------|
| 第1天 | RHI 公共定义 |
| 第2-3天 | RHI 接口层定义 |
| 第4-7天 | D3D12 后端实现 |
| 第8-9天 | 渲染资源封装 (VB/IB/CB/Texture) |
| 第10天 | RenderTarget/DepthStencil 管理 |
| 第11-12天 | Shader / PSO 管理 + InputLayout |
| 第13-14天 | 渲染上下文 (RenderContext) |
| 第15天 | StaticMeshComponent 迁移 |
| 第16天 | CMake 构建配置 |
| 第17-18天 | Demo 整合验证 + 调试修复 |
> 注:总计约 18 个工作日,可根据实际情况调整
---
## 依赖关系
```
第一阶段 (已完成)
├──▶ RHI 公共定义 (无依赖)
│ │
│ ├──▶ RHI 接口层 (依赖 RHI 公共定义)
│ │
│ └──▶ D3D12 后端 (依赖 RHI 接口层, 复用 HelloEarth 实现)
├──▶ 渲染资源封装 (依赖 RHI 接口层, 复用 HelloEarth 资源创建逻辑)
│ │
│ └──▶ RenderTarget/DepthStencil (依赖 RHI 接口层)
├──▶ Shader/PSO 管理 (依赖 RHI 接口层, 复用 HelloEarth 编译逻辑)
├──▶ 渲染上下文 (依赖 RHI 接口层, 渲染资源, 复用 HelloEarth 渲染循环)
├──▶ StaticMeshComponent (依赖 RHI 接口层, 渲染资源)
└──▶ CMake 构建配置 (依赖引擎构建系统)
```
---
## 验收标准
- [ ] RHI 接口编译通过
- [ ] D3D12 后端完整实现 RHI 接口
- [ ] 可创建 VertexBuffer/IndexBuffer/ConstantBuffer/Texture2D
- [ ] RenderTarget/DepthStencil 创建与管理正常
- [ ] Resource Barrier 状态转换正常
- [ ] Shader 加载编译正常工作
- [ ] PipelineState 创建与管理正常
- [ ] InputLayout 顶点布局定义正确
- [ ] 渲染状态 (Blend/Depth/Rasterizer) 定义正确
- [ ] PrimitiveTopology 图元类型设置正常
- [ ] 纹理 SRV/RTV/DSV 视图创建正常
- [ ] ClearRenderTarget/ClearDepthStencil 清除命令正常
- [ ] Viewport/Scissor 设置正常
- [ ] 渲染上下文帧循环正常
- [ ] StaticMeshComponent 网格加载与渲染正常
- [ ] CMake 构建配置完整
- [ ] 新架构 Demo 运行效果与原 HelloEarth 一致
- [ ] 窗口/渲染/退出流程无崩溃
---
## 测试方案
### 测试用例设计
| 模块 | 测试类别 | 测试用例示例 |
|------|---------|-------------|
| **RHI** | 设备初始化 | D3D12 设备创建成功、获取适配器信息 |
| **RHI** | 命令列表 | Reset/Close/Begin 流程正常、PrimitiveTopology 设置 |
| **RHI** | 同步 | Fence Signal/Wait 正常工作 |
| **RHI** | 交换链 | Present/Resize 正常工作 |
| **Resources** | 缓冲区 | VB/IB 创建、数据更新、绑定正确 |
| **Resources** | 纹理 | 2D 纹理创建、Mipmap 生成、SRV 绑定、资源状态转换 |
| **Resources** | 视图 | RTV/DSV 创建正确 |
| **Shader** | 编译 | VS/PS/GS 编译成功、错误信息正确 |
| **Pipeline** | PSO | 图形 PSO 创建成功、渲染状态配置正确 |
| **Pipeline** | 渲染状态 | Blend/Depth/Rasterizer 状态正确应用 |
| **RenderContext** | 渲染循环 | 帧循环正常、Clear 命令正常、资源释放正确 |
### 执行命令
```bash
# 编译引擎
cmake --build build --target XCEngine
# 编译 Demo
cmake --build build --target HelloEarth
# 运行 Demo
./build/bin/HelloEarth.exe
```
---
## 迁移对照表
以下表格详细说明 HelloEarth 原有实现到新架构的映射关系:
| 功能 | HelloEarth 实现 | 新架构实现 | 接口位置 |
|------|----------------|-----------|----------|
| 初始化 D3D12 | `InitD3D12(hwnd, width, height)` | `device->Initialize(windowHandle, desc)` | `IRHIDevice` |
| 获取 D3D12 设备 | `GetD3DDevice()` | `device->GetNativeDevice()` | `IRHIDevice` |
| 命令分配器 | `GetCommandAllocator()` | `device->CreateCommandAllocator()` | `IRHIDevice` |
| 命令列表 | `GetCommandList()` | `device->CreateCommandList()` | `IRHIDevice` |
| 创建根签名 | `InitRootSignature()` | `device->CreateRootSignature()` | `IRHIDevice` |
| 创建 PSO | `CreatePSO(rs, vs, ps, gs)` | `device->CreatePipelineState()` | `IRHIDevice` |
| 创建顶点缓冲 | `CreateBufferObject()` | `device->CreateVertexBuffer()` | `IRHIDevice` |
| 创建常量缓冲 | `CreateConstantBufferObject()` | `device->CreateConstantBuffer()` | `IRHIDevice` |
| 创建纹理 | `CreateTexture2D()` | `device->CreateTexture2D()` | `IRHIDevice` |
| 纹理 SRV 创建 | `CreateShaderResourceView()` | `texture->CreateSRV()` | `ITexture` |
| 资源状态转换 | `InitResourceBarrier()` | `ICommandList::ResourceBarrier()` | `ICommandList` |
| 设置图元类型 | `IASetPrimitiveTopology()` | `ICommandList::SetPrimitiveTopology()` | `ICommandList` |
| 清除渲染目标 | `ClearRenderTargetView()` | `ICommandList::ClearRenderTargetView()` | `ICommandList` |
| 清除深度模板 | `ClearDepthStencilView()` | `ICommandList::ClearDepthStencilView()` | `ICommandList` |
| 渲染到交换链 | `BeginRenderToSwapChain()` | `context->BeginFrame()` | `RenderContext` |
| 结束渲染 | `EndRenderToSwapChain()` | `context->EndFrame()` | `RenderContext` |
| 呈现 | `SwapD3D12Buffers()` | `swapChain->Present()` | `ISwapChain` |
| 等待 GPU | `WaitForCompletionOfCommandList()` | `fence->Wait()` | `IFence` |
| 网格渲染 | `StaticMeshComponent::Render()` | `StaticMeshComponent::Render()` | `StaticMeshComponent` |
---
## 备注
1. **DirectX Math**: 本阶段继续使用 `DirectX::XMMatrix` 等数学库,待第三阶段替换为 XCEngine Math
2. **HelloEarth 复用**: HelloEarth 的 Shader 文件 (`Res/Shader/*.hlsl`)、模型文件 (`Res/Model/*.lhsm`)、纹理文件 (`Res/Image/*`) 均可直接复用
3. **后续阶段**: Component/GameObject 体系在第三阶段实现,届时将整合渲染组件