如何从大尺寸D3D12Resource提取指定区域生成640x640资源?
D3D12大尺寸资源截取640x640区域的正确实现方法
针对你需要从任意尺寸D3D12Resource中提取640x640区域(不缩放)的需求,以下两种方案可以解决问题,同时纠正你之前使用视口和裁剪矩形的错误思路:
方案一:通过渲染管线绘制指定区域到目标资源
你之前的错误在于混淆了视口、裁剪矩形的作用:视口负责将顶点NDC坐标映射到渲染目标的像素空间,裁剪矩形仅限制渲染目标上的绘制范围,二者都无法直接选择输入资源的采样区域。正确的做法是让视口匹配目标资源尺寸,通过着色器调整UV来精准采样输入资源的指定区域。
步骤与代码示例
- 准备目标资源:创建640x640的D3D12Resource,确保格式与输入资源一致(如
DXGI_FORMAT_R8G8B8A8_UNORM),并将其设置为渲染目标。 - 设置视口与裁剪矩形:完全匹配目标资源尺寸,确保绘制内容填满整个目标资源:
// 目标资源为640x640,视口和裁剪矩形均对应此尺寸 CD3DX12_VIEWPORT viewport(0.0f, 0.0f, 640.0f, 640.0f); CD3DX12_RECT scissorRect(0, 0, 640, 640); pCommandList->RSSetViewports(1, &viewport); pCommandList->RSSetScissorRects(1, &scissorRect);
- 在着色器中调整采样UV:以截取输入资源
(640, 0)-(1024, 640)区域为例,计算UV的偏移与缩放系数,精准定位采样范围:
Texture2D inputTex : register(t0); SamplerState inputSampler : register(s0); float4 PSMain(float4 pos : SV_POSITION, float2 uv : TEXCOORD0) : SV_TARGET { // 输入资源尺寸为1024x1024,计算目标区域的UV参数 const float inputWidth = 1024.0f; const float inputHeight = 1024.0f; const float startX = 640.0f; const float startY = 0.0f; const float targetWidth = 640.0f; const float targetHeight = 640.0f; // 转换UV到目标区域范围 float2 uvOffset = float2(startX / inputWidth, startY / inputHeight); float2 uvScale = float2(targetWidth / inputWidth, targetHeight / inputHeight); float2 adjustedUV = uv * uvScale + uvOffset; return inputTex.Sample(inputSampler, adjustedUV); }
方案二:使用CopySubresourceRegion直接复制像素区域
如果不需要经过渲染管线处理,直接复制像素区域的性能更高,适合批量切片场景。
步骤与代码示例
- 创建目标资源:生成多个640x640的D3D12Resource,将资源状态设置为
D3D12_RESOURCE_STATE_COPY_DEST。 - 计算源区域坐标:根据输入资源尺寸,确定每个640x640切片的起始坐标(如1024x1024资源可切出
(0,0)、(0,640)两个完整切片,剩余区域可按需补黑或忽略)。 - 执行复制操作:调用
CopySubresourceRegion完成区域复制:
// 输入资源:pInputResource(状态为D3D12_RESOURCE_STATE_COPY_SOURCE) // 目标资源:pTargetResource(640x640,状态为D3D12_RESOURCE_STATE_COPY_DEST) // 要截取的源区域起始坐标(startX, startY) const UINT startX = 0; const UINT startY = 640; D3D12_COPY_SUBRESOURCE_REGION copyRegion = {}; copyRegion.srcSubresource = 0; copyRegion.srcX = startX; copyRegion.srcY = startY; copyRegion.srcZ = 0; copyRegion.dstSubresource = 0; copyRegion.dstX = 0; copyRegion.dstY = 0; copyRegion.dstZ = 0; copyRegion.Width = 640; copyRegion.Height = 640; // 执行区域复制 pCommandList->CopySubresourceRegion( pTargetResource, 0, 0, 0, 0, pInputResource, 0, ©Region ); // 复制完成后,将目标资源转换为后续需要的状态(如SHADER_RESOURCE) CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition( pTargetResource, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_SHADER_RESOURCE ); pCommandList->ResourceBarrier(1, &barrier);
内容的提问来源于stack exchange,提问作者Anna Maule
相关产品推荐
相关产品推荐

