追加缓冲区是一种特殊类型的缓冲区,用于在计算着色器中动态添加数据。与普通缓冲区不同,追加缓冲区允许在缓冲区末尾追加新的数据,而不会破坏原有的数据。每个线程可以向追加缓冲区中添加一个或多个元素,而不会影响其他线程添加的数据。
消费缓冲区是一种特殊类型的缓冲区,用于在计算着色器中读取追加缓冲区中的数据。与普通缓冲区不同,消费缓冲区只能读取追加缓冲区中已经存在的数据,而不能向其中添加新的数据。每个线程可以从消费缓冲区中读取一个或多个元素,而不会影响其他线程读取的数据。
假设我们通过下列结构体定义了一个存有粒子数据的缓冲区:
struct Particle
{
float3 Position;
float3 Velocity;
float3 Acceleration;
};
并且希望基于粒子的速度与恒定加速度在计算着色器中对其位置进行更新。此外,我们还假定不必考虑 粒子的更新顺序以及它们被写入输出缓冲区的顺序。消费结构化缓冲区(consume structured buffer, 一 种输入缓冲区)与追加结构化缓冲区(append structured buffer, 一种输出缓冲区)便是为这种场景而生的。若使用了这两种缓冲区,我们也就不必再在索引问题上花心思了:
struct Particle
{
float3 Position;
float3 Velocity;
float3 Acceleration;
};
float TimeStep = 1.0f / 60.0f;
ConsumestructuredBuffer<Particle> glnput;
AppendStructuredBuffer<Particle> gOutput;
[numthreads(16, 16, 1)]
void CS()
{
//对输入缓冲区中的数据元素之一进行处理(即“消费”,从缓冲区中移除一个元素)
Particle p = glnput.Consume();
p.Velocity += p.Acceleration*TimeStep;
p.Position += p.Velocity*TimeStep;
//将规范化向量追加到输出缓冲区
gOutput.Append( p );
}
数据元素一旦经过处理(即消费),其他线程就不能再对它进行任何操作了(事实上也就是从消费缓冲区中移除掉了)。而且,一个线程也只能处理一个数据元素。除此之外,我们无法知晓数据元素的具体 处理顺序与追加顺序。因此,一般来说,某元素位于输入缓冲区的位置与其处理后写入输出缓冲区的位 置(两种缓冲区中相同元素的排列顺序广并不是一一对应的。
追加结构化缓冲区的空间是不能动态扩展的。但是,它们一定有足够的空间来容纳我们要向其追加的所有元素。