如何在DirectX 12中调整窗口内的纹理位置
DirectX 12 实现纹理居中显示
核心思路
DirectX 12 没有DirectX 11中SetTransform这类直接设置2D变换的API,需要通过常量缓冲区传递变换矩阵,在顶点着色器中对顶点位置做变换,以此实现纹理的位置调整。你现有的纹理创建(CreateTexture)和更新(UpdateTextureResource)代码无需修改,只需添加变换相关逻辑并修改着色器。
具体实现步骤
1. 定义变换常量缓冲区
在CPU端和着色器端定义结构一致的常量缓冲区,用于传递平移变换数据:
// CPU端常量缓冲区结构 struct TransformConstants { XMFLOAT4X4 transformMatrix; };
// 着色器端常量缓冲区(放在顶点着色器开头) cbuffer TransformCB : register(b0) { float4x4 transformMatrix; };
2. 创建并初始化常量缓冲区
创建上传堆类型的资源,用于将CPU端的变换数据传递到GPU:
D3D12MA::Allocation* transformBufferAlloc = nullptr; ID3D12Resource* transformBuffer = nullptr; // 初始化常量缓冲区 void InitializeTransformBuffer() { D3D12_RESOURCE_DESC cbDesc = CD3DX12_RESOURCE_DESC::Buffer(sizeof(TransformConstants)); D3D12MA::ALLOCATION_DESC allocDesc = {}; allocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD; allocator->CreateResource( &allocDesc, &cbDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, &transformBufferAlloc, IID_PPV_ARGS(&transformBuffer) ); // 初始化为单位矩阵(无变换) TransformConstants* pConstants; transformBuffer->Map(0, nullptr, reinterpret_cast<void**>(&pConstants)); XMStoreFloat4x4(&pConstants->transformMatrix, XMMatrixIdentity()); transformBuffer->Unmap(0, nullptr); }
3. 计算居中变换矩阵
根据窗口尺寸和纹理尺寸,计算平移矩阵,让纹理中心与窗口中心对齐:
// 更新变换矩阵,传入窗口宽高、纹理宽高 void UpdateTransformMatrix(int windowWidth, int windowHeight, int textureWidth, int textureHeight) { // 转换为NDC坐标系下的偏移量(NDC范围:X/Y ∈ [-1, 1]) float offsetX = (windowWidth - textureWidth) / (float)windowWidth; // DirectX NDC坐标系Y轴向下,所以Y偏移取负 float offsetY = -(windowHeight - textureHeight) / (float)windowHeight; // 构建平移变换矩阵,并转置为着色器所需的列主序格式 XMMATRIX translateMatrix = XMMatrixTranslation(offsetX, offsetY, 0.0f); TransformConstants* pConstants; transformBuffer->Map(0, nullptr, reinterpret_cast<void**>(&pConstants)); XMStoreFloat4x4(&pConstants->transformMatrix, XMMatrixTranspose(translateMatrix)); transformBuffer->Unmap(0, nullptr); }
4. 修改顶点着色器
在顶点着色器中应用变换矩阵,调整顶点位置:
struct PSInput { float4 position : SV_POSITION; float2 uv : TEXCOORD; }; cbuffer TransformCB : register(b0) { float4x4 transformMatrix; }; Texture2D g_texture : register(t0); SamplerState g_sampler : register(s0); PSInput VSMain(float4 position : POSITION, float2 uv : TEXCOORD) { PSInput result; // 对顶点位置应用变换矩阵 result.position = mul(position, transformMatrix); result.uv = uv; return result; } float4 PSMain(PSInput input) : SV_TARGET { return g_texture.Sample(g_sampler, input.uv); }
5. 绑定常量缓冲区并绘制
确保你的根签名包含常量缓冲区的绑定槽(索引0),在绘制前绑定常量缓冲区:
// 在绘制纹理的代码中添加 CommandList->SetGraphicsRootConstantBufferView(0, transformBuffer->GetGPUVirtualAddress()); // 执行绘制命令(如DrawInstanced)
关键说明
- 若你使用的是全屏四边形作为绘制载体,上述变换会直接调整四边形位置,从而让纹理居中显示。
- 变换矩阵的转置是因为DirectX着色器默认使用列主序矩阵,而CPU端的XMMATRIX是行主序,需要转置后传递。
内容的提问来源于stack exchange,提问作者user11889309
相关产品推荐
相关产品推荐

