计算机图形学

作业

课程设计

#include "../../Common/d3dApp.h" // 基本d3d结构
#include "../../Common/MathHelper.h" // 基本数学包装
#include "../../Common/UploadBuffer.h" // 上传缓冲区包装
#include "../../Common/GeometryGenerator.h" // 生成模型包装
#include "FrameResource.h" // 帧资源包装
#include "Waves.h" // 生成波纹

#pragma comment(lib, "d3dcompiler.lib")
#pragma comment(lib, "D3D12.lib")

//帧资源数
const int NumFrameResources = 3;

//渲染项
struct RenderItem
{
	RenderItem() = default;

	// 世界坐标
	DirectX::XMFLOAT4X4 World = MathHelper::Identity4x4();

	// 指示对象数据已更改
	int NumFramesDirty = NumFrameResources;

	// 常量缓冲区索引
	UINT ObjCBIndex = -1;

	// 材质
	Material* Mat = nullptr;

	// 模型
	MeshGeometry* Geo = nullptr;

	// 拓扑结构
	D3D12_PRIMITIVE_TOPOLOGY PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;

	// 绘制索引总数
	UINT IndexCount = 0;

	// 绘制索引开始
	UINT StartIndexLocation = 0;

	// 绘制索引偏移
	int BaseVertexLocation = 0;
};

//渲染层
enum class RenderLayer : int
{
	Opaque = 0,
	Count
};

//主类
class LitWavesApp final : public D3DApp
{
public:
	LitWavesApp() = delete;
	explicit LitWavesApp(HINSTANCE hInstance);

	LitWavesApp(const LitWavesApp& rhs) = delete;
	LitWavesApp(LitWavesApp&& rhs) = delete;

	LitWavesApp& operator=(const LitWavesApp& rhs) = delete;
	LitWavesApp& operator=(LitWavesApp&& rhs) = delete;

	~LitWavesApp();

	// 初始化
	bool Initialize() override;

private:
	// 窗口缩放
	void OnResize() override;
	
	// 更新
	void Update(const GameTimer& gt) override;
	
	// 绘制
	void Draw(const GameTimer& gt) override;

	// 处理鼠标按下
	void OnMouseDown(WPARAM btnState, int x, int y) override;

	// 处理鼠标抬起
	void OnMouseUp(WPARAM btnState, int x, int y) override;

	// 处理鼠标移动
	void OnMouseMove(WPARAM btnState, int x, int y) override;

	// 处理键盘输入
	void OnKeyboardInput(const GameTimer& gt);

	// 更新摄像机
	void UpdateCamera(const GameTimer& gt);

	// 更新物体常量缓冲区
	void UpdateObjectCBs(const GameTimer& gt);

	// 更新材质常量缓冲区
	void UpdateMaterialCBs(const GameTimer& gt);

	// 更新Pass常量缓冲区
	void UpdateMainPassCB(const GameTimer& gt);

	// 更新波浪
	void UpdateWaves(const GameTimer& gt) const;

	// 创建根签名
	void BuildRootSignature();

	// 创建着色器和输入层
	void BuildShadersAndInputLayout();

	// 创建陆地模型
	void BuildLandGeometry();

	// 创建波浪模型缓冲区
	void BuildWavesGeometryBuffers();

	// 创建流水线状态对象
	void BuildPSOs();

	// 创建帧资源
	void BuildFrameResources();

	// 创建材质
	void BuildMaterials();

	// 创建渲染项
	void BuildRenderItems();

	// 绘制所有渲染项
	void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems) const;

	// 获取地形高度
	static float GetHillsHeight(float x, float z);

	// 获取地形法线
	DirectX::XMFLOAT3 GetHillsNormal(float x, float z) const;

	// 帧资源
	std::vector<std::unique_ptr<FrameResource>> mFrameResources;

	// 当前帧资源
	FrameResource* mCurrFrameResource = nullptr;

	// 当前帧资源索引
	int mCurrFrameResourceIndex = 0;

	// 描述符的大小
	UINT mCbvSrvDescriptorSize = 0;

	// 根签名
	Microsoft::WRL::ComPtr<ID3D12RootSignature> mRootSignature = nullptr;

	// 模型
	std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
	
	// 材质
	std::unordered_map<std::string, std::unique_ptr<Material>> mMaterials;

	// 着色器
	std::unordered_map<std::string, Microsoft::WRL::ComPtr<ID3DBlob>> mShaders;

	// 流水线状态对象
	std::unordered_map<std::string, Microsoft::WRL::ComPtr<ID3D12PipelineState>> mPSOs;

	// 输入布局 
	std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;

	// 水的渲染项
	RenderItem* mWavesRitem = nullptr;

	// 所有的渲染项
	std::vector<std::unique_ptr<RenderItem>> mAllRitems;

	// 渲染层
	std::vector<RenderItem*> mRitemLayer[static_cast<int>(RenderLayer::Count)];

	// 波纹
	std::unique_ptr<Waves> mWaves;

	// main pass
	PassConstants mMainPassCB;

	// 观察矩阵
	DirectX::XMFLOAT3 mEyePos = {0.0f, 0.0f, 0.0f};
	DirectX::XMFLOAT4X4 mView = MathHelper::Identity4x4();
	DirectX::XMFLOAT4X4 mProj = MathHelper::Identity4x4();
	float mTheta = 1.5f * DirectX::XM_PI;
	float mPhi = DirectX::XM_PIDIV2 - 0.1f;
	float mRadius = 50.0f;

	// 光源
	float mSunTheta = 1.25f * DirectX::XM_PI;
	float mSunPhi = DirectX::XM_PIDIV4;

	// 鼠标位置
	POINT mLastMousePos{};
};

LitWavesApp::LitWavesApp(const HINSTANCE hInstance) : D3DApp(hInstance)
{
}

LitWavesApp::~LitWavesApp()
{
	if (md3dDevice != nullptr)
		FlushCommandQueue();
}

bool LitWavesApp::Initialize()
{
	// 初始化Windows窗口 和 Direct3D 12
	if (!D3DApp::Initialize()) return false;

	// 重置命令队列
	ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));

	// 获取描述符的大小
	mCbvSrvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

	// 产生波浪模拟
	mWaves = std::make_unique<Waves>(128, 128, 1.0f, 0.03f, 4.0f, 0.2f);

	// 创建根签名
	BuildRootSignature();

	// 创建着色器和输入层
	BuildShadersAndInputLayout();

	// 创建陆地模型
	BuildLandGeometry();

	// 创建波浪模型缓冲区
	BuildWavesGeometryBuffers();

	// 创建材质
	BuildMaterials();

	// 创建渲染项
	BuildRenderItems();
	
	// 创建帧资源
	BuildFrameResources();
	
	// 创建流水线状态对象
	BuildPSOs();

	// 初始化命令队列
	ThrowIfFailed(mCommandList->Close());
	ID3D12CommandList* cmdsLists[] = {mCommandList.Get()};
	mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);

	// 等待命令队列初始化完成
	FlushCommandQueue();

	return true;
}

void LitWavesApp::OnResize()
{
	D3DApp::OnResize();

	// 更改投影矩阵
	const auto p = DirectX::XMMatrixPerspectiveFovLH(0.25f * MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
	XMStoreFloat4x4(&mProj, p);
}

void LitWavesApp::Update(const GameTimer& gt)
{
	OnKeyboardInput(gt);
	UpdateCamera(gt);

	// 循环遍历循环帧资源数组
	mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % NumFrameResources;
	mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();

	// 等待GPU处理
	if (mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
	{
		const auto eventHandle = CreateEventEx(nullptr, nullptr, false, EVENT_ALL_ACCESS);
		ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
		WaitForSingleObject(eventHandle, INFINITE);
		CloseHandle(eventHandle);
	}

	// 更新常量缓冲区
	UpdateObjectCBs(gt);
	UpdateMaterialCBs(gt);
	UpdateMainPassCB(gt);
	UpdateWaves(gt);
}

void LitWavesApp::Draw(const GameTimer& gt)
{
	auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;

	// 重置命令队列
	ThrowIfFailed(cmdListAlloc->Reset());
	ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].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(),
		DirectX::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());

	// 设置根签名
	mCommandList->SetGraphicsRootSignature(mRootSignature.Get());

	// 指定pass
	auto passCB = mCurrFrameResource->PassCB->Resource();
	mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());

	// 绘制所有渲染项
	DrawRenderItems(mCommandList.Get(), mRitemLayer[static_cast<int>(RenderLayer::Opaque)]);

	// 设置资源状态
	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));
	mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;

	// 设置围栏
	mCurrFrameResource->Fence = ++mCurrentFence;
	mCommandQueue->Signal(mFence.Get(), mCurrentFence);
}

void LitWavesApp::OnMouseDown(WPARAM btnState, const int x, const int y)
{
	mLastMousePos.x = x;
	mLastMousePos.y = y;
	SetCapture(mhMainWnd);
}

void LitWavesApp::OnMouseUp(WPARAM btnState, int x, int y)
{
	ReleaseCapture();
}

void LitWavesApp::OnMouseMove(const WPARAM btnState, const int x, const int y)
{
	// 左键
	if ((btnState & MK_LBUTTON) != 0)
	{
		const auto dx = DirectX::XMConvertToRadians(0.25f * static_cast<float>(x - mLastMousePos.x));
		const auto dy = DirectX::XMConvertToRadians(0.25f * static_cast<float>(y - mLastMousePos.y));
		mTheta += dx;
		mPhi += dy;
		mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi - 0.1f);
	}
	else if ((btnState & MK_RBUTTON) != 0) // 右键
	{
		float dx = 0.2f * static_cast<float>(x - mLastMousePos.x);
		float dy = 0.2f * static_cast<float>(y - mLastMousePos.y);
		mRadius += dx - dy;
		mRadius = MathHelper::Clamp(mRadius, 5.0f, 150.0f);
	}

	mLastMousePos.x = x;
	mLastMousePos.y = y;
}

void LitWavesApp::OnKeyboardInput(const GameTimer& gt)
{
	const auto dt = gt.DeltaTime();

	if (GetAsyncKeyState(VK_LEFT) & 0x8000)
		mSunTheta -= 1.0f * dt;

	if (GetAsyncKeyState(VK_RIGHT) & 0x8000)
		mSunTheta += 1.0f * dt;

	if (GetAsyncKeyState(VK_UP) & 0x8000)
		mSunPhi -= 1.0f * dt;

	if (GetAsyncKeyState(VK_DOWN) & 0x8000)
		mSunPhi += 1.0f * dt;

	mSunPhi = MathHelper::Clamp(mSunPhi, 0.1f, DirectX::XM_PIDIV2);
}

void LitWavesApp::UpdateCamera(const GameTimer& gt)
{
	// 将球面坐标转换为笛卡尔坐标
	mEyePos.x = mRadius * sinf(mPhi) * cosf(mTheta);
	mEyePos.z = mRadius * sinf(mPhi) * sinf(mTheta);
	mEyePos.y = mRadius * cosf(mPhi);

	// 构建视图矩阵
	const auto pos = DirectX::XMVectorSet(mEyePos.x, mEyePos.y, mEyePos.z, 1.0f);
	const auto target = DirectX::XMVectorZero();
	const auto up = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
	const auto view = DirectX::XMMatrixLookAtLH(pos, target, up);
	XMStoreFloat4x4(&mView, view);
}

void LitWavesApp::UpdateObjectCBs(const GameTimer& gt)
{
	auto currObjectCB = mCurrFrameResource->ObjectCB.get();
	for (auto& e : mAllRitems)
	{
		if (e->NumFramesDirty > 0)
		{
			const auto world = XMLoadFloat4x4(&e->World);
			ObjectConstants objConstants;
			XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
			currObjectCB->CopyData(e->ObjCBIndex, objConstants);
			e->NumFramesDirty--;
		}
	}
}

void LitWavesApp::UpdateMaterialCBs(const GameTimer& gt)
{
	auto currMaterialCB = mCurrFrameResource->MaterialCB.get();
	for (auto& e : mMaterials)
	{
		const auto mat = e.second.get();
		if (mat->NumFramesDirty > 0)
		{
			MaterialConstants matConstants;
			matConstants.DiffuseAlbedo = mat->DiffuseAlbedo;
			matConstants.FresnelR0 = mat->FresnelR0;
			matConstants.Roughness = mat->Roughness;
			currMaterialCB->CopyData(mat->MatCBIndex, matConstants);
			mat->NumFramesDirty--;
		}
	}
}

void LitWavesApp::UpdateMainPassCB(const GameTimer& gt)
{
	// 更新投影矩阵
	using DirectX::operator-;
	const auto view = XMLoadFloat4x4(&mView);
	const auto proj = XMLoadFloat4x4(&mProj);
	const auto viewProj = XMMatrixMultiply(view, proj);
	const auto invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
	const auto invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
	const auto invViewProj = XMMatrixInverse(&XMMatrixDeterminant(viewProj), viewProj);
	XMStoreFloat4x4(&mMainPassCB.View, XMMatrixTranspose(view));
	XMStoreFloat4x4(&mMainPassCB.InvView, XMMatrixTranspose(invView));
	XMStoreFloat4x4(&mMainPassCB.Proj, XMMatrixTranspose(proj));
	XMStoreFloat4x4(&mMainPassCB.InvProj, XMMatrixTranspose(invProj));
	XMStoreFloat4x4(&mMainPassCB.ViewProj, XMMatrixTranspose(viewProj));
	XMStoreFloat4x4(&mMainPassCB.InvViewProj, XMMatrixTranspose(invViewProj));
	mMainPassCB.EyePosW = mEyePos;
	mMainPassCB.RenderTargetSize = DirectX::XMFLOAT2(static_cast<float>(mClientWidth), static_cast<float>(mClientHeight));
	mMainPassCB.InvRenderTargetSize = DirectX::XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
	mMainPassCB.NearZ = 1.0f;
	mMainPassCB.FarZ = 1000.0f;
	mMainPassCB.TotalTime = gt.TotalTime();
	mMainPassCB.DeltaTime = gt.DeltaTime();
	mMainPassCB.AmbientLight = {0.25f, 0.25f, 0.35f, 1.0f};

	// 更新光源位置
	const auto lightDir = -MathHelper::SphericalToCartesian(1.0f, mSunTheta, mSunPhi);

	XMStoreFloat3(&mMainPassCB.Lights[0].Direction, lightDir);
	mMainPassCB.Lights[0].Strength = {1.0f, 1.0f, 0.9f};

	auto currPassCB = mCurrFrameResource->PassCB.get();
	currPassCB->CopyData(0, mMainPassCB);
}

void LitWavesApp::UpdateWaves(const GameTimer& gt) const
{
	// 随机生成波浪
	static auto tBase = 0.0f;
	if (mTimer.TotalTime() - tBase >= 0.25f)
	{
		tBase += 0.25f;
		const auto i = MathHelper::Rand(4, mWaves->RowCount() - 5);
		const auto j = MathHelper::Rand(4, mWaves->ColumnCount() - 5);
		const float r = MathHelper::RandF(0.2f, 0.5f);
		mWaves->Disturb(i, j, r);
	}

	mWaves->Update(gt.DeltaTime());

	// 更新波浪的顶点缓冲区
	auto currWavesVB = mCurrFrameResource->WavesVB.get();
	for (int i = 0; i < mWaves->VertexCount(); ++i)
	{
		Vertex v{};
		v.Pos = mWaves->Position(i);
		v.Normal = mWaves->Normal(i);
		currWavesVB->CopyData(i, v);
	}
	mWavesRitem->Geo->VertexBufferGPU = currWavesVB->Resource();
}

void LitWavesApp::BuildRootSignature()
{
	// 根参数
	CD3DX12_ROOT_PARAMETER slotRootParameter[3];

	// 创建常量缓冲区视图
	for (auto i = 0; i < 3; ++i) slotRootParameter[i].InitAsConstantBufferView(i);

	// 创建根签名描述
	CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(
		3,
		slotRootParameter,
		0,
		nullptr,
		D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

	// 创建根签名指针
	Microsoft::WRL::ComPtr<ID3DBlob> serializedRootSig = nullptr;

	// 错误指针
	Microsoft::WRL::ComPtr<ID3DBlob> errorBlob = nullptr;

	// 序列化根签名
	const auto hr = D3D12SerializeRootSignature(
		&rootSigDesc,
		D3D_ROOT_SIGNATURE_VERSION_1, 
		serializedRootSig.GetAddressOf(),
		errorBlob.GetAddressOf());

	// 输出错误
	if (errorBlob != nullptr)
	{
		OutputDebugStringA(static_cast<char*>(errorBlob->GetBufferPointer()));
	}
	ThrowIfFailed(hr);

	//创建根签名
	ThrowIfFailed(md3dDevice->CreateRootSignature(
		0,
		serializedRootSig->GetBufferPointer(),
		serializedRootSig->GetBufferSize(),
		IID_PPV_ARGS(mRootSignature.GetAddressOf())));
}

void LitWavesApp::BuildShadersAndInputLayout()
{
	// 编译顶点着色器和片元着色器
	mShaders["standardVS"] = d3dUtil::CompileShader(
		L"D:\\Default.hlsl",
		nullptr,
		"VS",
		"vs_5_0");
	mShaders["opaquePS"] = d3dUtil::CompileShader(
		L"D:\\Default.hlsl", 
		nullptr,
		"PS",
		"ps_5_0");

	// 定于着色器输入布局
	mInputLayout =
	{
		{
			"POSITION",
			0,
			DXGI_FORMAT_R32G32B32_FLOAT,
			0,
			0,
			D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
			0
		},
		{
			"NORMAL",
			0,
			DXGI_FORMAT_R32G32B32_FLOAT,
			0,
			12,
			D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
			0
		}
	};
}

void LitWavesApp::BuildLandGeometry()
{
	// 创建网格
	GeometryGenerator geoGen;
	auto grid = geoGen.CreateGrid(160.0f, 160.0f, 50, 50);

	std::vector<Vertex> vertices(grid.Vertices.size());
	for (size_t i = 0; i < grid.Vertices.size(); ++i)
	{
		auto& p = grid.Vertices[i].Position;
		vertices[i].Pos = p;
		vertices[i].Pos.y = GetHillsHeight(p.x, p.z);
		vertices[i].Normal = GetHillsNormal(p.x, p.z);
	}

	// 顶点缓冲大小
	const UINT vbByteSize = static_cast<UINT>(vertices.size()) * sizeof(Vertex);

	// 索引缓冲大小
	auto indices = grid.GetIndices16();
	const UINT ibByteSize = static_cast<UINT>(indices.size()) * sizeof(std::uint16_t);

	// 构建模型
	auto geo = std::make_unique<MeshGeometry>();
	geo->Name = "landGeo";
	ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
	CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
	ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
	CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
	geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(
		md3dDevice.Get(),
		mCommandList.Get(),
		vertices.data(),
		vbByteSize,
	    geo->VertexBufferUploader);
	geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(
		md3dDevice.Get(),
		mCommandList.Get(),
		indices.data(),
		ibByteSize,
		geo->IndexBufferUploader);
	geo->VertexByteStride = sizeof(Vertex);
	geo->VertexBufferByteSize = vbByteSize;
	geo->IndexFormat = DXGI_FORMAT_R16_UINT;
	geo->IndexBufferByteSize = ibByteSize;

	// 创建子模型
	SubmeshGeometry submesh;
	submesh.IndexCount = static_cast<UINT>(indices.size());
	submesh.StartIndexLocation = 0;
	submesh.BaseVertexLocation = 0;

	geo->DrawArgs["grid"] = submesh;

	mGeometries["landGeo"] = std::move(geo);
}

void LitWavesApp::BuildWavesGeometryBuffers()
{
	// 为每个面创建3个索引
	std::vector<std::uint16_t> indices(3 * mWaves->TriangleCount());
	assert(mWaves->VertexCount() < 0x0000ffff);

	// 创建面
	const auto m = mWaves->RowCount();
	const auto n = mWaves->ColumnCount();
	auto k = 0;
	for (auto i = 0; i < m - 1; ++i)
	{
		for (auto j = 0; j < n - 1; ++j)
		{
			indices[k] = i * n + j;
			indices[k + 1] = i * n + j + 1;
			indices[k + 2] = (i + 1) * n + j;
			indices[k + 3] = (i + 1) * n + j;
			indices[k + 4] = i * n + j + 1;
			indices[k + 5] = (i + 1) * n + j + 1;
			k += 6;
		}
	}

	// 构建动态模型
	const UINT vbByteSize = mWaves->VertexCount() * sizeof(Vertex);
	const UINT ibByteSize = static_cast<UINT>(indices.size()) * sizeof(std::uint16_t);
	auto geo = std::make_unique<MeshGeometry>();
	geo->Name = "waterGeo";
	geo->VertexBufferCPU = nullptr;
	geo->VertexBufferGPU = nullptr;
	ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
	CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
	geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(
		md3dDevice.Get(),
	    mCommandList.Get(),
		indices.data(),
		ibByteSize,
		geo->IndexBufferUploader);
	geo->VertexByteStride = sizeof(Vertex);
	geo->VertexBufferByteSize = vbByteSize;
	geo->IndexFormat = DXGI_FORMAT_R16_UINT;
	geo->IndexBufferByteSize = ibByteSize;

	// 构建子模型
	SubmeshGeometry submesh;
	submesh.IndexCount = static_cast<UINT>(indices.size());
	submesh.StartIndexLocation = 0;
	submesh.BaseVertexLocation = 0;

	geo->DrawArgs["grid"] = submesh;

	mGeometries["waterGeo"] = std::move(geo);
}

void LitWavesApp::BuildPSOs()
{
	// 创建流水线状态对象描述符
	D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
	ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
	// 输入布局描述
	opaquePsoDesc.InputLayout = {mInputLayout.data(), static_cast<UINT>(mInputLayout.size())};
	// 根签名指针
	opaquePsoDesc.pRootSignature = mRootSignature.Get();
	// 顶点着色器
	opaquePsoDesc.VS =
	{
		reinterpret_cast<BYTE*>(mShaders["standardVS"]->GetBufferPointer()),
		mShaders["standardVS"]->GetBufferSize()
	};
	// 像素着色器
	opaquePsoDesc.PS =
	{
		reinterpret_cast<BYTE*>(mShaders["opaquePS"]->GetBufferPointer()),
		mShaders["opaquePS"]->GetBufferSize()
	};
	// 光栅器状态
	opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
	// 混合状态
	opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
	// 深度模版缓冲状态
	opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
	// 采样情况掩码
	opaquePsoDesc.SampleMask = UINT_MAX;
	// 图元拓扑类型
	opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
	// 同时用的渲染目标个数
	opaquePsoDesc.NumRenderTargets = 1;
	// 渲染目标格式数组
	opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
	// 采样数量
	opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
	// 采样质量
	opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
	// 深度/模版缓冲级别
	opaquePsoDesc.DSVFormat = mDepthStencilFormat;
	// 创建图形流水线状态机
	ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&mPSOs["opaque"])));
}

void LitWavesApp::BuildFrameResources()
{
	for (auto i = 0; i < NumFrameResources; ++i)
	{
		mFrameResources.push_back(std::make_unique<FrameResource>(
			md3dDevice.Get(),
			1,
			static_cast<UINT>(mAllRitems.size()),
			static_cast<UINT>(mMaterials.size()),
			mWaves->VertexCount()));
	}
}

void LitWavesApp::BuildMaterials()
{
	// 创建草
	auto grass = std::make_unique<Material>();
	grass->Name = "grass";
	grass->MatCBIndex = 0;
	grass->DiffuseAlbedo = DirectX::XMFLOAT4(0.2f, 0.6f, 0.2f, 1.0f);
	grass->FresnelR0 = DirectX::XMFLOAT3(0.01f, 0.01f, 0.01f);
	grass->Roughness = 0.125f;

	// 创建简单水
	auto water = std::make_unique<Material>();
	water->Name = "water";
	water->MatCBIndex = 1;
	water->DiffuseAlbedo = DirectX::XMFLOAT4(0.0f, 0.2f, 0.6f, 1.0f);
	water->FresnelR0 = DirectX::XMFLOAT3(0.1f, 0.1f, 0.1f);
	water->Roughness = 0.0f;

	mMaterials["grass"] = std::move(grass);
	mMaterials["water"] = std::move(water);
}

void LitWavesApp::BuildRenderItems()
{
	// 创建水
	auto wavesRitem = std::make_unique<RenderItem>();
	wavesRitem->World = MathHelper::Identity4x4();
	wavesRitem->ObjCBIndex = 0;
	wavesRitem->Mat = mMaterials["water"].get();
	wavesRitem->Geo = mGeometries["waterGeo"].get();
	wavesRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
	wavesRitem->IndexCount = wavesRitem->Geo->DrawArgs["grid"].IndexCount;
	wavesRitem->StartIndexLocation = wavesRitem->Geo->DrawArgs["grid"].StartIndexLocation;
	wavesRitem->BaseVertexLocation = wavesRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
	mWavesRitem = wavesRitem.get();
	mRitemLayer[static_cast<int>(RenderLayer::Opaque)].push_back(wavesRitem.get());

	// 创建陆地
	auto gridRitem = std::make_unique<RenderItem>();
	gridRitem->World = MathHelper::Identity4x4();
	gridRitem->ObjCBIndex = 1;
	gridRitem->Mat = mMaterials["grass"].get();
	gridRitem->Geo = mGeometries["landGeo"].get();
	gridRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
	gridRitem->IndexCount = gridRitem->Geo->DrawArgs["grid"].IndexCount;
	gridRitem->StartIndexLocation = gridRitem->Geo->DrawArgs["grid"].StartIndexLocation;
	gridRitem->BaseVertexLocation = gridRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
	mRitemLayer[static_cast<int>(RenderLayer::Opaque)].push_back(gridRitem.get());

	mAllRitems.push_back(std::move(wavesRitem));
	mAllRitems.push_back(std::move(gridRitem));
}

void LitWavesApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems) const
{
	const auto objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
	const auto matCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(MaterialConstants));

	auto objectCB = mCurrFrameResource->ObjectCB->Resource();
	auto matCB = mCurrFrameResource->MaterialCB->Resource();

	for (auto ri : ritems)
	{
		cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
		cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
		cmdList->IASetPrimitiveTopology(ri->PrimitiveType);

		const auto objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex * objCBByteSize;
		const auto matCBAddress = matCB->GetGPUVirtualAddress() + ri->Mat->MatCBIndex * matCBByteSize;

		cmdList->SetGraphicsRootConstantBufferView(0, objCBAddress);
		cmdList->SetGraphicsRootConstantBufferView(1, matCBAddress);

		cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
	}
}

float LitWavesApp::GetHillsHeight(const float x, const float z)
{
	return 0.3f * (z * sinf(0.1f * x) + x * cosf(0.1f * z));
}

DirectX::XMFLOAT3 LitWavesApp::GetHillsNormal(const float x, const float z) const
{
	// n = (-df/dx, 1, -df/dz)
	DirectX::XMFLOAT3 n(
		-0.03f * z * cosf(0.1f * x) - 0.3f * cosf(0.1f * z),
		1.0f,
		-0.3f * sinf(0.1f * x) + 0.03f * x * sinf(0.1f * z));
	const auto unitNormal = DirectX::XMVector3Normalize(XMLoadFloat3(&n));
	XMStoreFloat3(&n, unitNormal);
	return n;
}

//主程序
int WINAPI WinMain(const HINSTANCE hInstance, HINSTANCE, PSTR, int)
{
	// 检测内存泄露
#if defined(DEBUG) | defined(_DEBUG)
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
	try
	{
		LitWavesApp theApp(hInstance);
		if (!theApp.Initialize())
			return 0;

		return theApp.Run();
	}
	catch (DxException& e)
	{
		MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
		return 0;
	}
}

 

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注