D3D11:HLSL 中可变数量的灯

D3D11: variable number of lights in HLSL

我正在使用 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
    }
}

这很好用。但如果我尝试:

cbuffer LIGHTS_COUNT : register(b13)
{
    int LightsCount;
}

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

有人知道如何解决这个问题吗?提前谢谢你。

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

想到了几种技巧:

  1. 如果您的数组很小,最简单的方法是传递一个常量缓冲区,其中包含 固定大小的数组当前大小 正如您所建议的那样。

  2. 几乎可以在任何硬件上工作的方法是将数据写入纹理并从着色器Sample or Load写入数据。您只能读取基本类型(floatfloat4 等),因此您需要对纹理实施适当的索引以读取复杂对象(structs)。

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

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

考虑到给定的问题,即经典光照,我会说我所见的 99% 都使用方法 1。大多数情况下,一个场景中的灯光实际上不会超过一打.