D3D11:HLSL 中可变数量的灯

fea*_*ped 4 c++ shader lighting hlsl direct3d11

我正在使用 C++ 和 Direct3D11 开发游戏引擎,现在我想向场景中添加可变数量的灯光。迄今为止,我设法添加和渲染了在着色器程序中已知和编码的计数的简单灯光。

在 shader.fx 中:

static const int LightsCount= 4;

struct NF3D_LIGHT
{
    // Members...
};

cbuffer Light : register(b5)
{
    NF3D_LIGHT light[LightsCount];
};

...

// And the pixel shader function:
float4 PS(PS_INPUT input) : SV_Target
{
    for(int i = 0; i < LightsCount; i++)
    {
        // Process each light and return the final pixel colour
    }
}
Run Code Online (Sandbox Code Playgroud)

这工作正常。但如果我尝试:

cbuffer LIGHTS_COUNT : register(b13)
{
    int LightsCount;
}
Run Code Online (Sandbox Code Playgroud)

要根据游戏中发生的情况使灯的数量发生变化,这是行不通的。我知道我可以LightsCount在应用程序开始时给出一个很大的值并向阵列添加灯光,但我发现这种方法复杂、固定且效率低下。

有谁知道如何解决这个问题?先感谢您。

Iva*_*rop 6

从着色器访问可变大小数组(具有运行时定义的大小)的一般问题可能会以不同的方式解决,具体取决于数组大小、数据更改频率和您的目标硬件。

有几种技术可以想到:

  1. 如果您的数组很小,最简单的方法是按照您的建议传递具有固定大小数组当前大小的常量缓冲区。

  2. 适用于几乎任何硬件的方法是将数据写入纹理并从着色器采样加载它。您只能读取原始类型(floatfloat4等),因此您需要对纹理实施适当的索引以读出复杂对象(structs)。

  3. 在 Shader Model 5 硬件(以及某些 SM 4 上),您可以使用UAVs 和StructuredBuffers 从缓冲区读取结构化数据。

  4. 如果您有涉及数组的非常复杂的计算,并且如果目标硬件允许您这样做,您可能希望将处理转移到计算着色器甚至 OpenCL 或 CUDA 内核。

考虑到给定的问题,即经典光照,我会说我所看到的 99% 的情况都使用方法 1。无论如何,在大多数情况下,场景中实际上并没有超过 12 盏灯。