From 859b851842c2b884870c5f6ac711098224582e66 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Wed, 11 Mar 2026 20:52:56 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=85=A8=E5=B1=8F=E5=9B=9B?= =?UTF-8?q?=E8=BE=B9=E5=BD=A2=20Ray=20Marching=20=E4=BD=93=E7=A7=AF?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E5=9F=BA=E7=A1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 步骤 1 完成: 1. 创建全屏四边形顶点数据 2. 实现 Ray Marching 着色器: - 从相机发射光线 - 光线与边界框相交检测 - 固定密度采样 - Alpha 混合输出 3. 添加 CreateQuadPSO 函数 4. 更新渲染管线 验证结果: - 整个背景变成淡蓝色 - Ray marching 基础逻辑工作正常 --- BattleFireDirect.cpp | 64 +++++++++++++++++++++++++++++++++++++++ BattleFireDirect.h | 2 ++ Res/Shader/volume.hlsl | 68 +++++++++++++++++++++++++++++++----------- main.cpp | 60 +++++++++++++++++++++++++++---------- 4 files changed, 161 insertions(+), 33 deletions(-) diff --git a/BattleFireDirect.cpp b/BattleFireDirect.cpp index ee1561c9..d5916de9 100644 --- a/BattleFireDirect.cpp +++ b/BattleFireDirect.cpp @@ -281,6 +281,70 @@ ID3D12PipelineState* CreateVolumePSO(ID3D12RootSignature* inID3D12RootSignature, return d3d12PSO; } +ID3D12PipelineState* CreateQuadPSO(ID3D12RootSignature* inID3D12RootSignature, + D3D12_SHADER_BYTECODE inVertexShader, D3D12_SHADER_BYTECODE inPixelShader) { + D3D12_INPUT_ELEMENT_DESC vertexDataElementDesc[] = { + {"POSITION",0,DXGI_FORMAT_R32G32_FLOAT,0,0,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0}, + {"TEXCOORD",0,DXGI_FORMAT_R32G32_FLOAT,0,8,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0} + }; + D3D12_INPUT_LAYOUT_DESC vertexDataLayoutDesc = {}; + vertexDataLayoutDesc.NumElements = 2; + vertexDataLayoutDesc.pInputElementDescs = vertexDataElementDesc; + + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + psoDesc.pRootSignature = inID3D12RootSignature; + psoDesc.VS = inVertexShader; + 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_NONE; + psoDesc.RasterizerState.FrontCounterClockwise = FALSE; + psoDesc.RasterizerState.DepthBias = D3D12_DEFAULT_DEPTH_BIAS; + psoDesc.RasterizerState.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP; + psoDesc.RasterizerState.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; + psoDesc.RasterizerState.DepthClipEnable = TRUE; + psoDesc.RasterizerState.MultisampleEnable = FALSE; + psoDesc.RasterizerState.AntialiasedLineEnable = FALSE; + psoDesc.RasterizerState.ForcedSampleCount = 0; + psoDesc.RasterizerState.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; + + psoDesc.DepthStencilState.DepthEnable = TRUE; + psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; + psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS; + psoDesc.DepthStencilState.StencilEnable = FALSE; + + psoDesc.BlendState.AlphaToCoverageEnable = FALSE; + psoDesc.BlendState.IndependentBlendEnable = FALSE; + for (int i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) { + psoDesc.BlendState.RenderTarget[i].BlendEnable = TRUE; + psoDesc.BlendState.RenderTarget[i].LogicOpEnable = FALSE; + psoDesc.BlendState.RenderTarget[i].SrcBlend = D3D12_BLEND_SRC_ALPHA; + psoDesc.BlendState.RenderTarget[i].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; + psoDesc.BlendState.RenderTarget[i].BlendOp = D3D12_BLEND_OP_ADD; + psoDesc.BlendState.RenderTarget[i].SrcBlendAlpha = D3D12_BLEND_ONE; + psoDesc.BlendState.RenderTarget[i].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; + psoDesc.BlendState.RenderTarget[i].BlendOpAlpha = D3D12_BLEND_OP_ADD; + psoDesc.BlendState.RenderTarget[i].LogicOp = D3D12_LOGIC_OP_NOOP; + psoDesc.BlendState.RenderTarget[i].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + } + psoDesc.NumRenderTargets = 1; + ID3D12PipelineState* d3d12PSO = nullptr; + + HRESULT hResult = gD3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&d3d12PSO)); + if (FAILED(hResult)) { + printf("CreateQuadPSO failed: 0x%08X\n", hResult); + return nullptr; + } + return d3d12PSO; +} + bool InitD3D12(HWND inHWND, int inWidth, int inHeight) { HRESULT hResult; UINT dxgiFactoryFlags = 0; diff --git a/BattleFireDirect.h b/BattleFireDirect.h index 84c06698..c2bda888 100644 --- a/BattleFireDirect.h +++ b/BattleFireDirect.h @@ -24,6 +24,8 @@ ID3D12PipelineState* CreatePSO(ID3D12RootSignature* inID3D12RootSignature, D3D12_SHADER_BYTECODE inGSShader); ID3D12PipelineState* CreateVolumePSO(ID3D12RootSignature* inID3D12RootSignature, D3D12_SHADER_BYTECODE inVertexShader, D3D12_SHADER_BYTECODE inPixelShader); +ID3D12PipelineState* CreateQuadPSO(ID3D12RootSignature* inID3D12RootSignature, + D3D12_SHADER_BYTECODE inVertexShader, D3D12_SHADER_BYTECODE inPixelShader); bool InitD3D12(HWND inHWND, int inWidth, int inHeight); ID3D12GraphicsCommandList* GetCommandList(); ID3D12CommandAllocator* GetCommandAllocator(); diff --git a/Res/Shader/volume.hlsl b/Res/Shader/volume.hlsl index 4e5545ed..853fe862 100644 --- a/Res/Shader/volume.hlsl +++ b/Res/Shader/volume.hlsl @@ -4,47 +4,79 @@ cbuffer CB0 : register(b1) { - float4x4 _ViewProjection; + float4x4 _InverseViewProjection; float3 _CameraPos; float _DensityScale; + float3 _BBoxMin; + float _StepSize; + float3 _BBoxMax; + uint _MaxSteps; }; StructuredBuffer buf : register(t1); struct VSInput { - float3 position : POSITION; + float2 position : POSITION; + float2 texcoord : TEXCOORD0; }; struct PSInput { float4 position : SV_POSITION; - float3 worldPos : TEXCOORD0; + float2 texcoord : TEXCOORD0; + float3 worldPos : TEXCOORD1; }; PSInput MainVS(VSInput input) { PSInput output; - output.position = mul(_ViewProjection, float4(input.position, 1.0)); - output.worldPos = input.position; + output.position = float4(input.position, 0.0, 1.0); + output.texcoord = input.texcoord; + + float4 worldPosH = mul(_InverseViewProjection, float4(input.position, 0.5, 1.0)); + output.worldPos = worldPosH.xyz / worldPosH.w; + return output; } +bool intersectBox(float3 origin, float3 dir, float3 boxMin, float3 boxMax, out float tmin, out float tmax) +{ + float3 invDir = 1.0 / dir; + float3 t1 = (boxMin - origin) * invDir; + float3 t2 = (boxMax - origin) * invDir; + + tmin = max(max(min(t1.x, t2.x), min(t1.y, t2.y)), min(t1.z, t2.z)); + tmax = min(min(max(t1.x, t2.x), max(t1.y, t2.y)), max(t1.z, t2.z)); + + return tmax >= tmin && tmax > 0; +} + float4 MainPS(PSInput input) : SV_TARGET { - pnanovdb_grid_handle_t grid; - grid.address.byte_offset = 0; + float3 rayDir = normalize(input.worldPos - _CameraPos); - float3 worldBboxMin = float3( - (float)pnanovdb_grid_get_world_bbox(buf, grid, 0), - (float)pnanovdb_grid_get_world_bbox(buf, grid, 1), - (float)pnanovdb_grid_get_world_bbox(buf, grid, 2) - ); - float3 worldBboxMax = float3( - (float)pnanovdb_grid_get_world_bbox(buf, grid, 3), - (float)pnanovdb_grid_get_world_bbox(buf, grid, 4), - (float)pnanovdb_grid_get_world_bbox(buf, grid, 5) - ); + float tmin, tmax; + if (!intersectBox(_CameraPos, rayDir, _BBoxMin, _BBoxMax, tmin, tmax)) { + return float4(0, 0, 0, 0); + } - return float4(0.0, 1.0, 0.0, 1.0); + tmin = max(0, tmin); + + float3 color = float3(0, 0, 0); + float alpha = 0; + + for (uint i = 0; i < _MaxSteps; i++) { + float t = tmin + i * _StepSize; + if (t > tmax || alpha > 0.99) break; + + float3 pos = _CameraPos + rayDir * t; + + float density = 0.1; + + color += density * float3(0.5, 0.7, 1.0) * (1 - alpha); + alpha += density * (1 - alpha); + } + + return float4(color, alpha); } \ No newline at end of file diff --git a/main.cpp b/main.cpp index 8a70cd8a..0f5d47c4 100644 --- a/main.cpp +++ b/main.cpp @@ -112,6 +112,17 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi ID3D12Resource* cubeIBO = CreateBufferObject(commandList, cubeIndices, sizeof(cubeIndices), D3D12_RESOURCE_STATE_INDEX_BUFFER); printf("Cube mesh created\n"); + float quadVertices[] = { + -1.0f, -1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 0.0f, 1.0f, + }; + uint32_t quadIndices[] = { 0, 1, 2, 0, 2, 3 }; + ID3D12Resource* quadVBO = CreateBufferObject(commandList, quadVertices, sizeof(quadVertices), D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); + ID3D12Resource* quadIBO = CreateBufferObject(commandList, quadIndices, sizeof(quadIndices), D3D12_RESOURCE_STATE_INDEX_BUFFER); + printf("Quad mesh created\n"); + StaticMeshComponent staticMeshComponent; staticMeshComponent.InitFromFile(commandList, "Res/Model/Sphere.lhsm"); printf("Mesh loaded\n"); @@ -141,6 +152,13 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi printf("Volume PSO created: %p\n", volumePSO); } + ID3D12PipelineState* quadPSO = CreateQuadPSO(volumeRootSignature, volumeVS, volumePS); + if (!quadPSO) { + printf("Quad PSO creation failed!\n"); + } else { + printf("Quad PSO created: %p\n", quadPSO); + } + ID3D12Resource* volumeCB = CreateConstantBufferObject(65536); ID3D12Resource* cb = CreateConstantBufferObject(65536);//1024x64(4x4) @@ -253,29 +271,41 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi } staticMeshComponent.Render(commandList); - DirectX::XMMATRIX bboxScale = DirectX::XMMatrixScaling(bboxSize[0], bboxSize[1], bboxSize[2]); - DirectX::XMMATRIX bboxTranslate = DirectX::XMMatrixTranslation(0.0f, 0.0f, 80.0f); - DirectX::XMMATRIX bboxModel = bboxScale * bboxTranslate; - DirectX::XMMATRIX bboxViewProj = bboxModel * viewMatrix * projectionMatrix; - DirectX::XMFLOAT4X4 bboxViewProjMat; - DirectX::XMStoreFloat4x4(&bboxViewProjMat, bboxViewProj); - float volumeCBData[20]; - memcpy(volumeCBData, &bboxViewProjMat, sizeof(float) * 16); + DirectX::XMMATRIX viewProj = viewMatrix * projectionMatrix; + DirectX::XMMATRIX invViewProj = DirectX::XMMatrixInverse(nullptr, viewProj); + DirectX::XMFLOAT4X4 invViewProjMat; + DirectX::XMStoreFloat4x4(&invViewProjMat, invViewProj); + + float volumeCBData[32]; + memcpy(volumeCBData, &invViewProjMat, sizeof(float) * 16); volumeCBData[16] = 0.0f; volumeCBData[17] = 0.0f; volumeCBData[18] = -5.0f; volumeCBData[19] = 1.0f; - UpdateConstantBuffer(volumeCB, volumeCBData, sizeof(float) * 20); + volumeCBData[20] = bboxMin[0] - bboxCenter[0]; + volumeCBData[21] = bboxMin[1] - bboxCenter[1]; + volumeCBData[22] = bboxMin[2] - bboxCenter[2] + 80.0f; + volumeCBData[23] = 0.5f; + volumeCBData[24] = bboxMax[0] - bboxCenter[0]; + volumeCBData[25] = bboxMax[1] - bboxCenter[1]; + volumeCBData[26] = bboxMax[2] - bboxCenter[2] + 80.0f; + volumeCBData[27] = 128; + UpdateConstantBuffer(volumeCB, volumeCBData, sizeof(float) * 28); + if (frameCount == 1) { + printf("Volume BBox: [%.2f, %.2f, %.2f] - [%.2f, %.2f, %.2f]\n", + volumeCBData[20], volumeCBData[21], volumeCBData[22], + volumeCBData[24], volumeCBData[25], volumeCBData[26]); + } - if (volumePSO) { - commandList->SetPipelineState(volumePSO); + if (quadPSO) { + commandList->SetPipelineState(quadPSO); commandList->SetGraphicsRootSignature(volumeRootSignature); commandList->SetGraphicsRootConstantBufferView(0, volumeCB->GetGPUVirtualAddress()); commandList->SetGraphicsRootShaderResourceView(1, nanoVDBData.gpuBuffer->GetGPUVirtualAddress()); - commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST); - commandList->IASetVertexBuffers(0, 1, &D3D12_VERTEX_BUFFER_VIEW{ cubeVBO->GetGPUVirtualAddress(), sizeof(cubeVertices), sizeof(float) * 3 }); - commandList->IASetIndexBuffer(&D3D12_INDEX_BUFFER_VIEW{ cubeIBO->GetGPUVirtualAddress(), sizeof(cubeIndices), DXGI_FORMAT_R32_UINT }); - commandList->DrawIndexedInstanced(24, 1, 0, 0, 0); + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + commandList->IASetVertexBuffers(0, 1, &D3D12_VERTEX_BUFFER_VIEW{ quadVBO->GetGPUVirtualAddress(), sizeof(quadVertices), sizeof(float) * 4 }); + commandList->IASetIndexBuffer(&D3D12_INDEX_BUFFER_VIEW{ quadIBO->GetGPUVirtualAddress(), sizeof(quadIndices), DXGI_FORMAT_R32_UINT }); + commandList->DrawIndexedInstanced(6, 1, 0, 0, 0); } EndRenderToSwapChain(commandList);