D3D11:HLSL中可变数量的灯光变量

4
我正在使用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个回答

6

访问运行时定义大小的 变量大小数组(variable size array)可能会因数组大小、数据更改频率和面向的硬件而有不同的解决方法。

以下是几种可供选择的技术:

  1. 如果你的数组很小,最简单的方法是传递一个带有固定大小数组和当前大小的常量缓冲区,就像你建议的那样。

  2. 几乎在任何硬件上都可以使用的方法是将数据写入纹理中,并从着色器中SampleLoad它。你只能读取基本类型(如floatfloat4等),因此你需要实现适当的索引来从纹理中读取复杂对象(如struct)。

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

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

考虑到所给问题,即经典照明,我认为我见过的99%都使用方法1。大多数情况下,场景中实际上没有超过十几个灯光。


嗯...我没有预料到这些答案,但它们正是我最需要的。非常感谢您提供如此必要的帮助。 - featherless biped
通常,一个给定的对象会使用“n”个最近/最强的光源进行渲染。通常只有角色在实时中受到少量灯光(3-4),而房间则由光照贴图或其他预计算光照模型照亮。你当然可以在前向渲染中使用大量灯光和多次渲染,但这通常是不必要的。或者,你可以使用延迟渲染器并绘制数十个或数百个通道。 - Chuck Walbourn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接