2012-09-25 32 views
3

我试图实现"Octree-Based Sparse Voxelization for Real-Time Global Illumination"的一部分。为多线程访问体素获取唯一缓冲区索引

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

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

它很容易创建使用原子计数器,要么原子 - 压缩 - 交换或原子添加,以确保它只能由一个线程

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位值。

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

回答

3

我不确定,但我想你不必使用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))); 

我还没有完成尚未实现,我可能是错的,但我认为有相同COORDS体素将在接下来的过程,是在22.5.4节点分区进行合并。

我想知道自从您提交此主题后是否有任何进展。

+1

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