Browse Source

feat: 添加几何模型代码

nicetry12138 1 year ago
parent
commit
edc06e9c81

+ 26 - 5
图形学/DirectX学习/README.md

@@ -1859,16 +1859,37 @@ mCommandList->SetPipllineState(mPso2.Get());
 #### 几何图形辅助函数
 
 ```cpp
+// 结构体定义了一个几何子网格
 struct SubmeshGeometry
 {
-	UINT IndexCount = 0;
-	UINT StartIndexLocation = 0;
-	INT BaseVertexLocation = 0;
+	UINT IndexCount = 0;				// 需要绘制的索引数量
+	UINT StartIndexLocation = 0;		// 在索引缓冲区中,绘制操作应该开始读取索引的起始位置
+	INT BaseVertexLocation = 0;			// 顶点缓冲区中的基础顶点位置
 
-	DirectX::BoundingBox Bounds;
+	DirectX::BoundingBox Bounds;		// 此子网格的边界盒,在进行如视锥裁剪等操作时非常有用
 };
 ```
 
 ```cpp
+// 存储和管理与一组几何数据相关的所有资源和状态的容器
+struct MeshGeometry
+    std::string Name;		// 几何体的名称,用于通过名称索引查找具体的几何体
+
+    Microsoft::WRL::ComPtr<ID3DBlob> VertexBufferCPU = nullptr;				// 顶点和索引数据的系统内存副本,方便CPU访问
+    Microsoft::WRL::ComPtr<ID3DBlob> IndexBufferCPU = nullptr;				// 
+
+    Microsoft::WRL::ComPtr<ID3D12Resource> VertexBufferGPU = nullptr;		// 上传到GPU的顶点和索引缓冲区
+    Microsoft::WRL::ComPtr<ID3D12Resource> IndexBufferGPU = nullptr;		// 
+	
+    Microsoft::WRL::ComPtr<ID3D12Resource> VertexBufferUploader = nullptr;		// 将数据从CPU传输到GPU的上传缓冲区
+    Microsoft::WRL::ComPtr<ID3D12Resource> IndexBufferUploader = nullptr;		// 将数据从CPU传输到GPU的上传缓冲区
+
+    UINT VertexByteStride = 0;													// 缓冲区的布局和格式
+    UINT VertexBufferByteSize = 0;												// 	
+    DXGI_FORMAT IndexFormat = DXGI_FORMAT_R16_UINT;								// 					
+    UINT IndexBufferByteSize = 0;												// 	
+
+    std::unordered_map<std::string, SubmeshGeometry> DrawArgs;					// 按名称访问各个子网格,每个子网格可以单独绘制
+}
+```
 
-```

+ 110 - 10
图形学/DirectX学习/src/D3DBox/D3DBox/D3DBox.cpp

@@ -18,6 +18,9 @@ bool D3DBox::Initialize()
 	if (!D3DApp::Initialize())
 		return false;
 
+	// Reset the command list to prep for initialization commands.
+	ThrowIfFailed(mCommandList->Reset(mCommandAllocator.Get(), nullptr));
+
 	BuildDescriptorHeaps();
 	BuildConstantBuffers();
 	BuildRootSignature();
@@ -25,21 +28,88 @@ bool D3DBox::Initialize()
 	BuildBoxGeometry();
 	BuildPSO();
 
+	// Execute the initialization commands.
+	ThrowIfFailed(mCommandList->Close());
+	ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
+	mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
+
+	// Wait until initialization is complete.
+	FlushCommandQueue();
+
 	return true;
 }
 
 void D3DBox::OnResize()
 {
 	D3DApp::OnResize();
+
+	XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f * MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
+	XMStoreFloat4x4(&mProj, P);
 }
 
 void D3DBox::Update(const GameTimer& gt)
-{	
-	
+{
+	float x = mRadius * sinf(mPhi) * cosf(mTheta);
+	float z = mRadius * sinf(mPhi) * sinf(mTheta);
+	float y = mRadius * cosf(mPhi);
+
+	// Build the view matrix.
+	XMVECTOR pos = XMVectorSet(x, y, z, 1.0f);
+	XMVECTOR target = XMVectorZero();
+	XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
+
+	XMMATRIX view = XMMatrixLookAtLH(pos, target, up);
+	XMStoreFloat4x4(&mView, view);
+
+	XMMATRIX world = XMLoadFloat4x4(&mWorld);
+	XMMATRIX proj = XMLoadFloat4x4(&mProj);
+	XMMATRIX worldViewProj = world * view * proj;
+
+	ObjectConstants objConstants;
+	XMStoreFloat4x4(&objConstants.WorldViewProj, XMMatrixTranspose(worldViewProj));
+	mObjectCB->CopyData(0, objConstants);
 }
 
 void D3DBox::Draw(const GameTimer& gt)
 {
+	ThrowIfFailed(mCommandAllocator->Reset());
+
+	ThrowIfFailed(mCommandList->Reset(mCommandAllocator.Get(), mPSO.Get()));
+
+	mCommandList->RSSetViewports(1, &mScreenViewport);
+	mCommandList->RSSetScissorRects(1, &mScissorRect);
+
+	mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
+
+	mCommandList->ClearRenderTargetView(CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr);
+	mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
+
+	mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
+
+	ID3D12DescriptorHeap* descriptorHeaps[] = { mCbvHeap.Get() };
+	mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);
+
+	mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
+
+	mCommandList->IASetVertexBuffers(0, 1, &mBoxGeo->VertexBufferView());
+	mCommandList->IASetIndexBuffer(&mBoxGeo->IndexBufferView());
+	mCommandList->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+
+	mCommandList->SetGraphicsRootDescriptorTable(0, mCbvHeap->GetGPUDescriptorHandleForHeapStart());
+
+	mCommandList->DrawIndexedInstanced(mBoxGeo->DrawArgs["box"].IndexCount, 1, 0, 0, 0);
+
+	mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
+
+	ThrowIfFailed(mCommandList->Close());
+
+	ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
+	mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
+
+	ThrowIfFailed(mSwapChain->Present(0, 0));
+	mCurrentBackBuffer = (mCurrentBackBuffer + 1) % SwapChainBufferCount;
+
+	FlushCommandQueue();
 }
 
 void D3DBox::OnMouseDown(WPARAM btnState, int x, int y)
@@ -57,10 +127,10 @@ void D3DBox::OnMouseMove(WPARAM btnStae, int x, int y)
 void D3DBox::BuildDescriptorHeaps()
 {
 	D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc;
-	cbvHeapDesc.NodeMask = 0;
 	cbvHeapDesc.NumDescriptors = 1;
-	cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
 	cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
+	cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
+	cbvHeapDesc.NodeMask = 0;
 	md3dDevice->CreateDescriptorHeap(&cbvHeapDesc, IID_PPV_ARGS(&mCbvHeap));
 }
 
@@ -124,24 +194,30 @@ void D3DBox::BuildShaderAndInputLayout()
 void D3DBox::BuildPSO()
 {
 	D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc;
-
 	ZeroMemory(&psoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
 	psoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
 	psoDesc.pRootSignature = mRootSignature.Get();
-	psoDesc.VS = { mVSByteCode->GetBufferPointer(), mVSByteCode->GetBufferSize() };
-	psoDesc.PS = { mPSByteCode->GetBufferPointer(), mPSByteCode->GetBufferSize() };
+	psoDesc.VS =
+	{
+		reinterpret_cast<BYTE*>(mVSByteCode->GetBufferPointer()),
+		mVSByteCode->GetBufferSize()
+	};
+	psoDesc.PS =
+	{
+		reinterpret_cast<BYTE*>(mPSByteCode->GetBufferPointer()),
+		mPSByteCode->GetBufferSize()
+	};
 	psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
 	psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
 	psoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
-	psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
 	psoDesc.SampleMask = UINT_MAX;
+	psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
 	psoDesc.NumRenderTargets = 1;
 	psoDesc.RTVFormats[0] = mBackBufferFormat;
 	psoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
 	psoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
 	psoDesc.DSVFormat = mDepthStencilFormat;
-
-	md3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&mPSO));
+	ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&mPSO)));
 }
 
 void D3DBox::BuildBoxGeometry()
@@ -190,6 +266,30 @@ void D3DBox::BuildBoxGeometry()
 
 	mBoxGeo = std::make_unique<MeshGeometry>();
 	mBoxGeo->Name = "boxGeo";
+
+	ThrowIfFailed(D3DCreateBlob(vbByteSize, &mBoxGeo->VertexBufferCPU));
+	CopyMemory(mBoxGeo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
+
+	ThrowIfFailed(D3DCreateBlob(ibByteSize, &mBoxGeo->IndexBufferCPU));
+	CopyMemory(mBoxGeo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
+
+	mBoxGeo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
+		mCommandList.Get(), vertices.data(), vbByteSize, mBoxGeo->VertexBufferUploader);
+
+	mBoxGeo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
+		mCommandList.Get(), indices.data(), ibByteSize, mBoxGeo->IndexBufferUploader);
+
+	mBoxGeo->VertexByteStride = sizeof(Vertex);
+	mBoxGeo->VertexBufferByteSize = vbByteSize;
+	mBoxGeo->IndexFormat = DXGI_FORMAT_R16_UINT;
+	mBoxGeo->IndexBufferByteSize = ibByteSize;
+
+	SubmeshGeometry submesh;
+	submesh.IndexCount = (UINT)indices.size();
+	submesh.StartIndexLocation = 0;
+	submesh.BaseVertexLocation = 0;
+
+	mBoxGeo->DrawArgs["box"] = submesh;
 }
 
 

+ 1 - 0
图形学/DirectX学习/src/D3DBox/D3DBox/D3DBox.vcxproj

@@ -150,6 +150,7 @@
     <ClCompile Include="D3DBox.cpp" />
     <ClCompile Include="D3DUtil.cpp" />
     <ClCompile Include="GameTimer.cpp" />
+    <ClCompile Include="MathHelper.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="D3DBox.rc" />

+ 3 - 0
图形学/DirectX学习/src/D3DBox/D3DBox/D3DBox.vcxproj.filters

@@ -68,6 +68,9 @@
     <ClCompile Include="GameTimer.cpp">
       <Filter>源文件</Filter>
     </ClCompile>
+    <ClCompile Include="MathHelper.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="D3DBox.rc">

+ 1 - 1
图形学/DirectX学习/src/D3DBox/D3DBox/D3DBox.vcxproj.user

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
-    <ShowAllFiles>true</ShowAllFiles>
+    <ShowAllFiles>false</ShowAllFiles>
   </PropertyGroup>
 </Project>

+ 78 - 0
图形学/DirectX学习/src/D3DBox/D3DBox/MathHelper.cpp

@@ -0,0 +1,78 @@
+#include "MathHelper.h"
+#include <float.h>
+#include <cmath>
+
+using namespace DirectX;
+
+const float MathHelper::Infinity = FLT_MAX;
+const float MathHelper::Pi = 3.1415926535f;
+
+float MathHelper::AngleFromXY(float x, float y)
+{
+	float theta = 0.0f;
+
+	// Quadrant I or IV
+	if (x >= 0.0f)
+	{
+		// If x = 0, then atanf(y/x) = +pi/2 if y > 0
+		//                atanf(y/x) = -pi/2 if y < 0
+		theta = atanf(y / x); // in [-pi/2, +pi/2]
+
+		if (theta < 0.0f)
+			theta += 2.0f * Pi; // in [0, 2*pi).
+	}
+
+	// Quadrant II or III
+	else
+		theta = atanf(y / x) + Pi; // in [0, 2*pi).
+
+	return theta;
+}
+
+XMVECTOR MathHelper::RandUnitVec3()
+{
+	XMVECTOR One = XMVectorSet(1.0f, 1.0f, 1.0f, 1.0f);
+	XMVECTOR Zero = XMVectorZero();
+
+	// Keep trying until we get a point on/in the hemisphere.
+	while (true)
+	{
+		// Generate random point in the cube [-1,1]^3.
+		XMVECTOR v = XMVectorSet(MathHelper::RandF(-1.0f, 1.0f), MathHelper::RandF(-1.0f, 1.0f), MathHelper::RandF(-1.0f, 1.0f), 0.0f);
+
+		// Ignore points outside the unit sphere in order to get an even distribution 
+		// over the unit sphere.  Otherwise points will clump more on the sphere near 
+		// the corners of the cube.
+
+		if (XMVector3Greater(XMVector3LengthSq(v), One))
+			continue;
+
+		return XMVector3Normalize(v);
+	}
+}
+
+XMVECTOR MathHelper::RandHemisphereUnitVec3(XMVECTOR n)
+{
+	XMVECTOR One = XMVectorSet(1.0f, 1.0f, 1.0f, 1.0f);
+	XMVECTOR Zero = XMVectorZero();
+
+	// Keep trying until we get a point on/in the hemisphere.
+	while (true)
+	{
+		// Generate random point in the cube [-1,1]^3.
+		XMVECTOR v = XMVectorSet(MathHelper::RandF(-1.0f, 1.0f), MathHelper::RandF(-1.0f, 1.0f), MathHelper::RandF(-1.0f, 1.0f), 0.0f);
+
+		// Ignore points outside the unit sphere in order to get an even distribution 
+		// over the unit sphere.  Otherwise points will clump more on the sphere near 
+		// the corners of the cube.
+
+		if (XMVector3Greater(XMVector3LengthSq(v), One))
+			continue;
+
+		// Ignore points in the bottom hemisphere.
+		if (XMVector3Less(XMVector3Dot(n, v), Zero))
+			continue;
+
+		return XMVector3Normalize(v);
+	}
+}