我正在尝试实现“用于实时全局照明的基于八叉树的稀疏体素化”的一部分。
基本上只是体素化,我已经完成了。还有“体素片段列表”构造,它基本上是体素位置和属性的几个预先分配的缓冲区。
使用原子计数器和原子补偿交换或原子添加来创建位置缓冲区非常容易,以确保它仅由一个线程写入
layout(r32ui, binding = 0) uniform coherent volatile uimage3D Voxels;
layout(r32ui, binding = 1) uniform coherent volatile uimageBuffer positionBuffer;
void writeVoxels(ivec3 coord)
{
uint voxelVal = imageAtomicCompSwap(Voxels, coord, 0, 1);
if(voxelVal == 0)
{
int index = 3*int(atomicCounterIncrement(voxelCounter));
imageStore(positionBuffer, index+0, uvec4(coord.x));
imageStore(positionBuffer, index+1, uvec4(coord.y));
imageStore(positionBuffer, index+2, uvec4(coord.z));
}
}
但是,在多个线程写入同一体素位置的情况下,如何确保所有线程获得适当的索引?如上所示,正确的索引仅对 1 个线程有效。
类似下面的内容
#extension GL_NV_shader_atomic_float : require
layout(r32ui, binding = 0) uniform coherent volatile uimage3D Voxels;
layout(r32ui, binding = 1) uniform coherent volatile uimageBuffer positionBuffer;
layout(r32f, binding = 2) uniform coherent volatile imageBuffer colorBuffer;
void writeVoxels(ivec3 coord, vec3 color)
{
uint voxelVal = imageAtomicAdd(Voxels, coord, 1);
int index;
if(voxelVal == 0) //This ensure that only 1 thread performs the
{ //atomicCounterIncrement
index = 3*int(atomicCounterIncrement(voxelCounter));
imageStore(positionBuffer, index+0, uvec4(coord.x));
imageStore(positionBuffer, index+1, uvec4(coord.y));
imageStore(positionBuffer, index+2, uvec4(coord.z));
}
//Need index to be valid here
imageAtomicAdd(colorBuffer, index+0, color.x);
imageAtomicAdd(colorBuffer, index+1, color.y);
imageAtomicAdd(colorBuffer, index+2, color.z);
}
我尝试了很多不同的方法。论文中唯一的提示是
为了管理(体素片段)列表,我们将下一个可用条目的索引(也是列表中体素片段数量的计数器)作为单个 32 位值存储在另一个缓冲区对象中。这听起来像是只是描述原子计数器的缓冲区对象。为了让事情保持简单(目前),我没有计算运行平均值(如论文中所述),只是在渲染时将颜色相加并除以访问计数。
这是我的代码:
const uint VOXEL_FRAGMENT_SIZE = 3;
layout(r32ui, binding = 0) uniform coherent volatile writeonly uimageBuffer voxelFragmentBuffer;
layout(binding=0, offset=0) uniform atomic_uint voxelIndexCounter;
// ...
int voxelIndex = int(atomicCounterIncrement( voxelIndexCounter ))* VOXEL_FRAGMENT_SIZE;
imageStore( voxelFragmentBuffer, voxelIndex+0, uvec4( convIVec3ToR32UI( voxelPosition ) ) );
imageStore( voxelFragmentBuffer, voxelIndex+1, uvec4( convVec4ToRGBA8( vec4( normal*127, 2.0 ) ) ) );
imageStore( voxelFragmentBuffer, voxelIndex+2, uvec4( convVec4ToRGBA8( color*255 ) ) );
我还没有完成实现,我可能是错的,但我认为具有相同坐标的体素将在下一个过程中合并,即22.5.4节点细分中。