Opengl 为访问体素的多个线程获取唯一缓冲区索引

Opengl 为访问体素的多个线程获取唯一缓冲区索引,opengl,glsl,voxel,opengl-4,voxels,Opengl,Glsl,Voxel,Opengl 4,Voxels,我正在尝试实现的一部分 基本上只是体素化,我已经完成了 以及“体素片段列表”的构建,基本上是几个预先分配的体素位置和属性缓冲区 使用原子计数器和原子comp交换或原子add创建位置缓冲区非常容易,以确保它只由一个线程写入 layout(r32ui, binding = 0) uniform coherent volatile uimage3D Voxels; layout(r32ui, binding = 1) uniform coherent volatile uimageBuffer

我正在尝试实现的一部分

基本上只是体素化,我已经完成了

以及“体素片段列表”的构建,基本上是几个预先分配的体素位置和属性缓冲区

使用原子计数器和原子comp交换或原子add创建位置缓冲区非常容易,以确保它只由一个线程写入

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位值存储在另一个缓冲区对象中


这听起来像是在描述原子计数器的缓冲区对象。为了保持简单(目前),我不会计算运行平均值(如本文所述),只是在渲染时将颜色相加并除以访问计数。

我不确定,但我认为不必使用imageAtomicAdd将具有相同坐标的体素存储到相同的体素片段中。 这意味着一些不同的体素片段可能具有相同的3d坐标

这是我的密码

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节点细分


我想知道自从你提交了这个帖子后,你是否有任何进展。

你说得对,我从作者那里得到了一些反馈。他的方法从不使用密集的3D纹理,而是增加每个体素片段的原子计数器,并附加到预先分配的“体素片段列表”。这意味着多个“体素片段”可以引用同一位置,并且像您所说的,在层次创建过程中合并。