在DirectX12中使用Texture

在DirectX12中使用Texture

这次让我们来看看如何在DirectX12中使用Texture。由于我们创建的texture最终是和const buffer一样,存放在同一个DescriptorHeap中的,所以有必要在之前的基础上扩充一下heap的大小:

	mCbvSrvHeapIncSize = mDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
	D3D12_DESCRIPTOR_HEAP_DESC cbvSrvHeapDesc;
	cbvSrvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
	cbvSrvHeapDesc.NumDescriptors = objCbCount + passCbCount + matCbCount + shaderResCount;
	cbvSrvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
	cbvSrvHeapDesc.NodeMask = 0;
	ThrowIfFailed(mDevice->CreateDescriptorHeap(&cbvSrvHeapDesc, IID_PPV_ARGS(&mCbvSrvHeap)));

接下来,我们知道,采样一个纹理有多种采样过滤模式,point,linear,anisotropic;寻址模式也有wrap,mirror,clamp等等。我们可以事先定义好用到的sampler:

		mStaticSamplers.push_back(CD3DX12_STATIC_SAMPLER_DESC(0, D3D12_FILTER_MIN_MAG_MIP_POINT, 
		D3D12_TEXTURE_ADDRESS_MODE_WRAP, D3D12_TEXTURE_ADDRESS_MODE_WRAP));
	mStaticSamplers.push_back(CD3DX12_STATIC_SAMPLER_DESC(1, D3D12_FILTER_MIN_MAG_MIP_POINT,
		D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP));
	mStaticSamplers.push_back(CD3DX12_STATIC_SAMPLER_DESC(2, D3D12_FILTER_MIN_MAG_MIP_LINEAR,
		D3D12_TEXTURE_ADDRESS_MODE_WRAP, D3D12_TEXTURE_ADDRESS_MODE_WRAP));
	mStaticSamplers.push_back(CD3DX12_STATIC_SAMPLER_DESC(3, D3D12_FILTER_MIN_MAG_MIP_LINEAR,
		D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP));
	mStaticSamplers.push_back(CD3DX12_STATIC_SAMPLER_DESC(4, D3D12_FILTER_ANISOTROPIC,
		D3D12_TEXTURE_ADDRESS_MODE_WRAP, D3D12_TEXTURE_ADDRESS_MODE_WRAP));
	mStaticSamplers.push_back(CD3DX12_STATIC_SAMPLER_DESC(5, D3D12_FILTER_ANISOTROPIC,
		D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP));

然后,在创建root signature的时候,将samplers作为参数传进去(存放于寄存器s0,s1,…)。由于这次需要传递texture资源给shader使用(存放于寄存器t0,t1,…),我们需要增加一个根参数:

	CD3DX12_DESCRIPTOR_RANGE cbvSrvTable[4];
	cbvSrvTable[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0);
	cbvSrvTable[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 1);
	cbvSrvTable[2].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 2);
	cbvSrvTable[3].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);

	CD3DX12_ROOT_PARAMETER rootParams[4];
	rootParams[0].InitAsDescriptorTable(1, &cbvSrvTable[0]);
	rootParams[1].InitAsDescriptorTable(1, &cbvSrvTable[1]);
	rootParams[2].InitAsDescriptorTable(1, &cbvSrvTable[2]);
	rootParams[3].InitAsDescriptorTable(1, &cbvSrvTable[3]);

	CD3DX12_ROOT_SIGNATURE_DESC sigDesc(_countof(rootParams), rootParams, mStaticSamplers.size(), 
		mStaticSamplers.data(), D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

这些准备工作做完之后,就可以正式去加载texture资源了,调用加载接口之后,不要忘记手动向GPU提交执行,否则这个texture就只能CPU看见,GPU还是一无所知。加载成功之后,还要记得创建对应的shader resource view,将资源绑定到descriptor heap上,并存放到正确的位置:

	ThrowIfFailed(mCommandAlloc->Reset());
	ThrowIfFailed(mCommandList->Reset(mCommandAlloc.Get(), nullptr));
	ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(mDevice.Get(), mCommandList.Get(), srcFile.c_str(), res, uploadHeap));
	ThrowIfFailed(mCommandList->Close());
	ID3D12CommandList *cmdList[] = { mCommandList.Get() };
	mCommandQueue->ExecuteCommandLists(_countof(cmdList), cmdList);
	FlushCommandQueue();

	D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
	srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
	srvDesc.Format = res->GetDesc().Format;
	srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
	srvDesc.Texture2D.MostDetailedMip = 0;
	srvDesc.Texture2D.MipLevels = res->GetDesc().MipLevels;
	srvDesc.Texture2D.ResourceMinLODClamp = 0.0f;

	CD3DX12_CPU_DESCRIPTOR_HANDLE handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(
		mCbvSrvHeap->GetCPUDescriptorHandleForHeapStart());
	UINT srvHeapIndex = objCbCount + passCbCount + matCbCount + texId;

	handle.Offset(srvHeapIndex, mCbvSrvHeapIncSize);
	mDevice->CreateShaderResourceView(res.Get(), &srvDesc, handle);
	return true;

最后,在绘制阶段,我们要显式地告诉GPU从哪儿读取texture资源加载到对应的寄存器上:

	UINT srvHeapIndex = objCbCount + passCbCount + matCbCount + object->mTexture->mTexId;
	CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle = CD3DX12_GPU_DESCRIPTOR_HANDLE(
		mCbvSrvHeap->GetGPUDescriptorHandleForHeapStart());
	srvHandle.Offset(srvHeapIndex, mCbvSrvHeapIncSize);
	mCommandList->SetGraphicsRootDescriptorTable(3, srvHandle);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R81fnQnK-1611381163972)(F:\Learning\blogs\在DirectX12中使用Texture1.png)]

这里,可能就有疑问了,为啥要把shader resource和const buffer都存放到一个descriptor heap上管理呢?分开用两个heap,各用各的不是更好吗?具体的解释可以参考这里。简单来说,首先SetDescriptorHeaps这个API同一类型的heap同时只能设置一个,而存放const buffer和shader resource的heap的type都是D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV 。其次,如果我们在绘制过程中频繁调用这个API去切换使用不同的heap,开销会非常高。所以,推荐的解决方法,就是使用一个大的heap,然后划分好不同的区域给const buffer和shader resource使用。

如果你觉得我的文章有帮助,欢迎关注我的微信公众号(大龄社畜的游戏开发之路-

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7DcpwA9L-1611381163976)(F:\Learning\blogs\qrcode_for_gh_16d0016744ab_258.jpg)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值