图形API学习工程(9):深度缓冲(Depth Buffering)

工程GIT地址:https://gitee.com/yaksue/yaksue-graphics

目标

如果不设置“深度缓冲”,场景中的图形将不能以正确的遮挡关系渲染。(见本篇的【无深度缓冲的情况】)

本篇目标是配置好工程中各个图形API的深度缓冲。

无深度缓冲的情况

现在将顶点数据变成一个立方体,并为每一个面都设置不同的颜色:

//作为测试的顶点缓冲数据:
std::vector<RawVertexData> vertices = {	
	//六个面,颜色各不同
	
	{ {-1.0f, 1.0f, -1.0f},		{1.0f, 0.0f, 0.0f, 1.0f} },
	{ {1.0f, 1.0f, -1.0f},		{1.0f, 0.0f, 0.0f, 1.0f} },
	{ {1.0f, 1.0f, 1.0f},		{1.0f, 0.0f, 0.0f, 1.0f} },
	{ {-1.0f, 1.0f, 1.0f},		{1.0f, 0.0f, 0.0f, 1.0f} },

	{ {-1.0f, -1.0f, -1.0f},	{0.0f, 1.0f, 0.0f, 1.0f} },
	{ {1.0f, -1.0f, -1.0f},		{0.0f, 1.0f, 0.0f, 1.0f} },
	{ {1.0f, -1.0f, 1.0f},		{0.0f, 1.0f, 0.0f, 1.0f} },
	{ {-1.0f, -1.0f, 1.0f},		{0.0f, 1.0f, 0.0f, 1.0f} },

	{ {-1.0f, -1.0f, 1.0f},		{0.0f, 0.0f, 1.0f, 1.0f} },
	{ {-1.0f, -1.0f, -1.0f},	{0.0f, 0.0f, 1.0f, 1.0f} },
	{ {-1.0f, 1.0f, -1.0f},		{0.0f, 0.0f, 1.0f, 1.0f} },
	{ {-1.0f, 1.0f, 1.0f},		{0.0f, 0.0f, 1.0f, 1.0f} },

	{ {1.0f, -1.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} },
	{ {1.0f, 1.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} },

	{ {-1.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, 1.0f} },
	{ {1.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, 1.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, 1.0f, 1.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, 1.0f, 1.0f} },
};
//作为测试的索引数据
std::vector<unsigned int> indices = {
	//六个面:

	3,1,0,
	2,1,3,

	6,4,5,
	7,4,6,

	11,9,8,
	10,9,11,

	14,12,13,
	15,12,14,

	19,17,16,
	18,17,19,

	22,20,21,
	23,20,22
};

效果:
在这里插入图片描述
可以看到,在没有设置深度缓冲的情况下,各个面没有正确的遮挡关系。


准确来说,也不是一定能看到这种情况。如果设置了剔除,即反向时针的三角形不被渲染,那么对于这个正方体,依旧能看到“正确”的渲染结果。

图中OpenGL版的错误,也代表着现在工程里的OpenGL版没有设置剔除,即两面都渲染了。
对于工程中目前的D3D11就设置了剔除,因此它看不到这种错误,要想看到这种错误,需要设置为不剔除,例如在D3D11中需要:

D3D11_RASTERIZER_DESC RasterizerState_desc;
ZeroMemory(&RasterizerState_desc, sizeof(D3D11_RASTERIZER_DESC));
RasterizerState_desc.FillMode = D3D11_FILL_SOLID;
RasterizerState_desc.CullMode = D3D11_CULL_NONE;//不剔除
ThrowIfFailed(Device->CreateRasterizerState(&RasterizerState_desc, &RasterizerState));
ImmediateContext->RSSetState(RasterizerState);

在D3D12中需要:

//光栅化状态
D3D12_RASTERIZER_DESC RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
RasterizerState.CullMode = D3D12_CULL_MODE_NONE;//不剔除
...
psoDesc.RasterizerState = RasterizerState;

工程中发现Vulkan版本似乎也没有剔除,所以不用设置。

设置深度缓冲

OpenGL

主要参考《深度测试 - LearnOpenGL CN》

对于OpenGL非常简单:

首先启用GL_DEPTH_TEST

glEnable(GL_DEPTH_TEST);

然后,Clear的时候附带上GL_DEPTH_BUFFER_BIT

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

D3D11

首先,需要两个成员:

ID3D11Texture2D* DepthStencil = NULL;
ID3D11DepthStencilView* DepthStencilView = NULL;

在初始化中创建他们:

//创建一个 深度/模板 贴图
D3D11_TEXTURE2D_DESC descDepth;
ZeroMemory(&descDepth, sizeof(descDepth));
descDepth.Width = WindowWidth;
descDepth.Height = WindowHeight;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
ThrowIfFailed(Device->CreateTexture2D(&descDepth, NULL, &DepthStencil));

//创建一个 深度/模板 view
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
ZeroMemory(&descDSV, sizeof(descDSV));
descDSV.Format = descDepth.Format;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;
ThrowIfFailed(Device->CreateDepthStencilView(DepthStencil, &descDSV, &DepthStencilView));

在OM阶段设置上DepthStencilView

//输出合并阶段(Output-Merger Stage)设置RenderTarget和DepthStencilView
ImmediateContext->OMSetRenderTargets(1, &RenderTargetView, DepthStencilView);

在Clear时:

//清理DepthStencilView
ImmediateContext->ClearDepthStencilView(DepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);

D3D12

D3D12的代码相对较多,概括起来:

  • 创建depth stencil view的Descriptor堆
  • 创建depth stencil view
  • OMSetRenderTargets中设置 depth stencil view
  • ClearDepthStencilView
  • 管线状态中 DepthEnable = true;等设置

Vulkan

Vulkan这部分的代码最多。
此部分主要参照《Depth buffering - Vulkan Tutorial》

效果:

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值