「リアルタイム グローバル イルミネーションのための Octree ベースのスパース ボクセル化」の一部を実装しようとしています。
基本的にボクセル化だけで、すでに完了しています。
そして、「ボクセル フラグメント リスト」構造は、基本的に、ボクセルの位置と属性の事前に割り当てられたいくつかのバッファーです。
アトミックカウンターとアトミックコンプスワップまたはアトミック追加のいずれかを使用して位置バッファーを作成するのは非常に簡単で、1つのスレッドによってのみ書き込まれるようにします
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 ビット値として格納します。
これは、アトミック カウンターのバッファー オブジェクトを記述しているように思えます。物事をシンプルに保つために (今のところ)、移動平均 (論文で説明されているように) を計算するのではなく、単純に色を合計し、レンダリング時にアクセス数で割っています。