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

如何在几何着色器中使用SV_ViewportArrayIndex?双视口渲染故障排查

多视口渲染第二个视口黑屏的问题修复

核心问题分析

你的双视口渲染失效主要有三个关键问题:

  1. 渲染数据未分配到第二个视口
    单次DrawIndexed调用只会输出一组顶点数据,默认对应第一个视口,没有为第二个视口提供独立的渲染数据或指令。

  2. 几何着色器视口索引逻辑无效

    • 顶点着色器中的CUSTOM_VIEWPORT_INDEX未赋值,几何着色器传递的是未初始化的垃圾值,GPU无法识别目标视口。
    • 即使索引有效,你也没有为第二个视口生成对应的变换后顶点数据(比如独立的投影矩阵),两个视口共用同一组顶点位置,无法实现分区域渲染。
  3. 视口与渲染状态未同步
    如果之前绑定过单个视口,RSSetViewports后需要确保光栅化状态已正确更新,避免旧状态覆盖新设置。


修复方案

1. 修正着色器视口索引与数据生成

顶点着色器(补充索引赋值)

struct VSOut
{
    float2 tex : TEXCOORD;
    float4 pos : SV_POSITION;
    uint viewportIndex : CUSTOM_VIEWPORT_INDEX; 
};

VSOut main_VS(float3 pos : POSITION, float2 tex : TEXCOORD)
{
    VSOut output;
    // 基础顶点模型视图变换
    output.pos = mul(float4(pos, 1.0), modelViewMatrix);
    output.tex = tex;
    // 可根据需求分配初始视口索引,或在GS中动态指定
    output.viewportIndex = 0;
    return output;
}

几何着色器(为双视口生成独立数据)

struct VSOut
{
    float2 tex : TEXCOORD;
    float4 pos : SV_POSITION;
    uint viewportIndex : CUSTOM_VIEWPORT_INDEX; 
};

struct GSOut
{
    float2 tex : TEXCOORD;
    float4 pos : SV_POSITION;
    uint viewportIndex : SV_ViewportArrayIndex; 
};

[maxvertexcount(6)] // 输出两个三角形,顶点数翻倍
void main_GS(triangle VSOut input[3], inout TriangleStream<GSOut> TriStream)
{
    GSOut output;

    // 渲染到第一个视口
    for (int i = 0; i < 3; ++i)
    {
        output.pos = mul(input[i].pos, viewport0ProjMatrix); // 视口0专属投影矩阵
        output.tex = input[i].tex;
        output.viewportIndex = 0; // 指定目标视口
        TriStream.Append(output);
    }
    TriStream.RestartStrip();

    // 渲染到第二个视口
    for (int i = 0; i < 3; ++i)
    {
        output.pos = mul(input[i].pos, viewport1ProjMatrix); // 视口1专属投影矩阵
        output.tex = input[i].tex;
        output.viewportIndex = 1; // 指定目标视口
        TriStream.Append(output);
    }
    TriStream.RestartStrip();
}

2. CPU端渲染指令修正

有两种可选的渲染提交方式:

方式1:用几何着色器自动分配视口(单次绘制)

D3D11_VIEWPORT viewports[2];
// 初始化视口数组(原有代码不变)
viewports[0].TopLeftX = 0;
viewports[0].TopLeftY = 0;
viewports[0].Width = width_ / 2;
viewports[0].Height = height_;
viewports[0].MinDepth = 0.0f;
viewports[0].MaxDepth = 1.0f;

viewports[1].TopLeftX = width_ / 2;
viewports[1].TopLeftY = 0;
viewports[1].Width = width_ / 2;
viewports[1].Height = height_;
viewports[1].MinDepth = 0.0f;
viewports[1].MaxDepth = 1.0f;

deviceContext->RSSetViewports(2, viewports);
// 绑定包含两个投影矩阵的常量缓冲区
deviceContext->VSSetConstantBuffers(1, 1, &viewportProjCB);
deviceContext->DrawIndexed(indicesSize, 0, 0);

方式2:分两次绘制(无需几何着色器)

D3D11_VIEWPORT viewports[2];
// 初始化视口数组(同上)

// 渲染第一个视口
deviceContext->VSSetConstantBuffers(0, 1, &viewport0CB); // 绑定视口0的常量缓冲区
deviceContext->RSSetViewports(1, &viewports[0]);
deviceContext->DrawIndexed(indicesSize, 0, 0);

// 渲染第二个视口
deviceContext->VSSetConstantBuffers(0, 1, &viewport1CB); // 绑定视口1的常量缓冲区
deviceContext->RSSetViewports(1, &viewports[1]);
deviceContext->DrawIndexed(indicesSize, 0, 0);

3. 验证渲染资源绑定

确保你的渲染目标视图(RTV)和深度模板视图(DSV)尺寸覆盖整个窗口,没有将第二个视口区域排除在渲染资源之外。


内容的提问来源于stack exchange,提问作者mercuric taylor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 23:35:02