You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 15:55:18