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

如何合并两个ID3D11Texture2D?最佳DirectX实现方案咨询

实现方案与DirectX特性选择

最佳方式:GPU端像素着色器混合

用Direct3D 11的像素着色器结合渲染管线完成纹理混合,这是效率最高、最符合DirectX设计思路的方案,完全利用GPU并行计算能力,比CPU端操作纹理数据快得多。从结果图来看,需求是将带透明通道的前景纹理(Texture2)叠加到背景纹理(Texture1)上,按alpha通道实现半透明混合。

需要用到的DirectX 11特性

  • ID3D11ShaderResourceView:将两个输入纹理绑定到着色器,让GPU可访问纹理数据
  • ID3D11PixelShader:自定义像素着色器实现alpha混合逻辑
  • ID3D11RenderTargetView:创建可写入的渲染目标纹理,作为混合结果的输出载体
  • 全屏渲染管线:用全屏四边形作为渲染载体,配合简单顶点着色器完成坐标传递

具体实现步骤

1. 创建渲染目标纹理

原纹理仅绑定了Shader Resource,无法直接作为渲染目标,需要创建一个支持渲染写入的纹理:

D3D11_TEXTURE2D_DESC rtDesc = desc; // 复用原纹理的宽高、格式等参数
rtDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; // 新增渲染目标绑定标志
ID3D11Texture2D* pResultTexture = nullptr;
HRESULT hr = pDevice->CreateTexture2D(&rtDesc, nullptr, &pResultTexture);

// 创建对应的渲染目标视图和着色器资源视图
ID3D11RenderTargetView* pRTV = nullptr;
pDevice->CreateRenderTargetView(pResultTexture, nullptr, &pRTV);
ID3D11ShaderResourceView* pResultSRV = nullptr;
pDevice->CreateShaderResourceView(pResultTexture, nullptr, &pResultSRV);

2. 准备全屏渲染的顶点数据

用覆盖整个纹理区域的四边形(两个三角形)作为渲染载体,顶点数据包含位置和纹理坐标:

struct FullscreenVertex {
    XMFLOAT3 pos;
    XMFLOAT2 uv;
};
FullscreenVertex vertices[] = {
    { { -1.0f,  1.0f, 0.0f }, { 0.0f, 0.0f } },
    { {  1.0f,  1.0f, 0.0f }, { 1.0f, 0.0f } },
    { { -1.0f, -1.0f, 0.0f }, { 0.0f, 1.0f } },
    { {  1.0f, -1.0f, 0.0f }, { 1.0f, 1.0f } }
};
// 按标准D3D11流程创建顶点缓冲区(省略缓冲区创建代码)

3. 编写着色器代码

顶点着色器(传递顶点与纹理坐标)

struct VSInput {
    float3 pos : POSITION;
    float2 uv : TEXCOORD0;
};

struct PSInput {
    float4 pos : SV_POSITION;
    float2 uv : TEXCOORD0;
};

PSInput VS(VSInput input) {
    PSInput output;
    output.pos = float4(input.pos, 1.0f);
    output.uv = input.uv;
    return output;
}

像素着色器(实现alpha混合)

采用标准混合公式:结果颜色 = 前景颜色 * 前景Alpha + 背景颜色 * (1 - 前景Alpha)

Texture2D background : register(t0);
Texture2D foreground : register(t1);
SamplerState samLinear : register(s0);

struct PSInput {
    float4 pos : SV_POSITION;
    float2 uv : TEXCOORD0;
};

float4 PS(PSInput input) : SV_TARGET {
    float4 bgColor = background.Sample(samLinear, input.uv);
    float4 fgColor = foreground.Sample(samLinear, input.uv);
    return float4(fgColor.rgb * fgColor.a + bgColor.rgb * (1.0f - fgColor.a), 1.0f);
}

4. 执行渲染流程

// 设置渲染目标与视口
pContext->OMSetRenderTargets(1, &pRTV, nullptr);
D3D11_VIEWPORT vp = { 0.0f, 0.0f, (float)desktop.right, (float)desktop.bottom, 0.0f, 1.0f };
pContext->RSSetViewports(1, &vp);

// 绑定纹理、采样器与着色器
pContext->PSSetShaderResources(0, 1, &pMyTexture1SRV); // 绑定背景纹理
pContext->PSSetShaderResources(1, 1, &pMyTexture2SRV); // 绑定前景纹理
pContext->PSSetSamplers(0, 1, &pSamLinear); // 绑定线性采样器(提前创建)
pContext->IASetVertexBuffers(0, 1, &pVertexBuffer, &stride, &offset);
pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
pContext->VSSetShader(pVS, nullptr, 0);
pContext->PSSetShader(pPS, nullptr, 0);

// 绘制全屏四边形完成混合
pContext->Draw(4, 0);

备选方案(不推荐):CPU端手动混合

若纹理尺寸极小,可将纹理转为D3D11_USAGE_STAGING类型,通过Map/Unmap读取CPU数据,手动计算混合后写入新纹理。但这种方式完全浪费GPU性能,仅适合极端小众场景。


内容的提问来源于stack exchange,提问作者Дмитрий Мизантропович

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 18:23:15