在 D3D12 中实现 GenerateMipmaps

目录

一、Render Target 的 Mipmap 需要数据

二、生成 Mipmap 数据方法的原理

 三、具体实现和优化

四、坑

 五、总结


一、Render Target 的 Mipmap 需要数据

        在纹理中使用 Mipmap 的方法很常见,其数据一般都是从纹理文件中读取而来。还有另一种带 Mipmap 的纹理,它就是 Render Target。在完成渲染到纹理之后,Render Target 可以被当成贴图再次使用。但是如果 Render Target 带有 Mipmap 则除了被渲染的那层 Mip 之外其他层都没有数据。在 D3D11 中提供了一个方法 ID3D11DeviceContext::GenerateMips 可以帮助 Render Target 生成指定 Mip 层的数据,但是这个好用的方法在 D3D12 中取消了,因为 D3D12 更底层,想要生成 Mipmap 的数据就需要自己动手。

二、生成 Mipmap 数据方法的原理

        从一张原图生成 Mipmap 数据的方法很多,做起来都非常耗时,看看 nVidia 给 PS 做的纹理插件就知道生成 Mipmap 有多少道道。但是 Render Target 生成 Mipmap 数据都是需要在运行时实时生成的,不可能像 PS 插件那么精细,时间和效率都耗不起。所以我们只要解决 Mipmap 数据的有无问题就行。

        一般来说 Render Target 分辨率最高的那层就是原图数据,其他每一层只要使用上一层的 Mipmap 作为纹理输入进行 Render To Texutre 就可以了,其实方法可以看作最简单后处理。注意,由于有 Cubemap 的存在,除了 Render Target 还需要对 Render Targe

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是使用DirectX 12实现图片渲染纹理数据的示例代码: ```cpp // 初始化纹理资源 ID3D12Resource* textureResource = nullptr; D3D12_RESOURCE_DESC textureDesc = {}; textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; textureDesc.Width = textureWidth; textureDesc.Height = textureHeight; textureDesc.DepthOrArraySize = 1; textureDesc.MipLevels = 1; textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; textureDesc.SampleDesc.Count = 1; textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE; ThrowIfFailed(device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &textureDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&textureResource))); // 创建上传堆 ID3D12Resource* textureUploadHeap = nullptr; ThrowIfFailed(device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(GetRequiredIntermediateSize(textureResource, 0, 1)), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&textureUploadHeap))); // 将纹理数据复制到上传堆 D3D12_SUBRESOURCE_DATA textureData = {}; textureData.pData = imageData; // 图像数据指针 textureData.RowPitch = textureWidth * 4; // 每行字节数 textureData.SlicePitch = textureData.RowPitch * textureHeight; UpdateSubresources(commandList, textureResource, textureUploadHeap, 0, 0, 1, &textureData); // 将纹理资源从复制目标状态转换为常量状态 CD3DX12_RESOURCE_BARRIER textureBarrier = CD3DX12_RESOURCE_BARRIER::Transition( textureResource, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); commandList->ResourceBarrier(1, &textureBarrier); // 创建纹理描述符堆 CD3DX12_DESCRIPTOR_HEAP_DESC textureHeapDesc(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE); ID3D12DescriptorHeap* textureDescriptorHeap = nullptr; ThrowIfFailed(device->CreateDescriptorHeap(&textureHeapDesc, IID_PPV_ARGS(&textureDescriptorHeap))); // 创建纹理资源视图 D3D12_SHADER_RESOURCE_VIEW_DESC textureViewDesc = {}; textureViewDesc.Format = textureDesc.Format; textureViewDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; textureViewDesc.Texture2D.MipLevels = 1; device->CreateShaderResourceView(textureResource, &textureViewDesc, textureDescriptorHeap->GetCPUDescriptorHandleForHeapStart()); ``` 这个示例代码包括以下步骤: 1. 创建纹理资源,使用R8G8B8A8_UNORM格式存储像素数据。 2. 创建上传堆,将像素数据复制到上传堆。 3. 使用`UpdateSubresources`函数将上传堆的数据复制到纹理资源。 4. 使用`CD3DX12_RESOURCE_BARRIER`将纹理资源从复制目标状态转换为常量状态。 5. 创建纹理描述符堆和纹理资源视图,使其在着色器可见。 请注意,这只是一个示例代码,并且需要根据您的具体需要进行修改。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值