ボクセル レイキャスティング エンジンを開発するために opencl を使用しています。Crassinの Gigavoxels に似たようなことをしようとしています。この論文では、ボクセル データを格納するために octree を使用しています。今のところ、レンダリング データを含むリーフに到達するまで、octree 内を下降しようとしています。
私は 2 つの実装を作成しました。1 つは GPU 上の OpenCl で、もう 1 つは CPU 上の C++ です。私が経験している問題は、GPU でアルゴリズムが octree 内の葉に到達するまで間違った数のレベルを通過していることです。CPU バージョンで正しい結果が得られます。両方のバージョンのアルゴリズムは同じで、コードはほとんど同じです。
何が問題なのか知っていますか?ハードウェアの問題か、OpenCl の問題か、それとも何か間違っているのでしょうか? 3 つの異なる nVidia GPU で同じ結果が発生しています。
C++ コードは次のとおりです。
// Calculate actual ray stepping position
glm::vec4 pos = eyeRay_o + eyeRay_d * t;
uint offset = 0;
//check if root is leaf
uint leafFlag = GetLeafBit(octreeNodes[0]);
//get children address of root
uint childrenAddress = GetChildAddress(octreeNodes[0]);
while (iterations < 30) {
iterations++;
// Calculate subdivision offset
offset = (uint)(pos.x * 2) + (uint)(pos.y * 2) * 2 + (uint)(pos.z * 2) * 4;
if (leafFlag == 1) {
//return some colour and exit the loop
break;
}
else
{
glm::uvec4 off = glm::uvec4(pos.x * 2, pos.y * 2, pos.z * 2, pos.w * 2);
pos.x = 2 * pos.x - off.x;
pos.y = 2 * pos.y - off.y;
pos.z = 2 * pos.z - off.z;
pos.w = 2 * pos.w - off.w;
}
// Extract node data from the children
finalAddress = childrenAddress + offset;
leafFlag = GetLeafBit(nodes[finalAddress]);
childrenAddress = GetChildAddress(nodes[finalAddress]);
}
OpenCL コードは次のとおりです。
// Calculate actual ray stepping position
float4 position = rayOrigin + rayDirection * t;
uint offset = 0;
//check if root is leaf
uint leafFlag = extractOctreeNodeLeaf(octreeNodes[0]);
//get children address of root
uint childrenAddress = extractOctreeNodeAddress(octreeNodes[0]);
//position will be in the [0, 1] interval
//size of octree is 1
while (iterations < 30) {
iterations++;
//calculate the index of the next child based on the position in the current subdivision
offset = (uint)(position.x * 2) + (uint)(position.y * 2) * 2 + (uint)(position.z * 2) * 4;
if (leafFlag == 1) {
//return some colour and exit the loop
break;
}
else
{
//transform the position inside the parent
//to the position inside the child subdivision
//size of child will be considered to be 1
uint4 off;
off.x = floor(position.x * 2);
off.y = floor(position.y * 2);
off.z = floor(position.z * 2);
off.w = floor(position.w * 2);
position = 2 * position - off;
}
// Extract node data from the children
finalAddress = childrenAddress + offset;
leafFlag = extractOctreeNodeLeaf(octreeNodes[finalAddress]);
//each node has an index to an array of 8 children - the index points to the first child
childrenAddress = extractOctreeNodeAddress(octreeNodes[finalAddress]);
}
要求に応じて、extractOctreeNodeAddress を次に示します。
どちらの関数も、いくつかのビット操作を行うだけです。
OpenCL バージョン:
inline char extractOctreeNodeLeaf(uint value) {
value = value >> 1;
return value & 1;
}
inline uint extractOctreeNodeAddress(uint value) {
return value >> 2;
}
C++ バージョン:
inline byte GetLeafBit(uint value)
{
value = value >> 0x1;
return value & 0x1;
}
inline uint GetChildAddress(uint value)
{
return value >> 0x2;
}
こんにちは、面白いものを見つけました。単一の正確なピクセルとカメラの位置と向きで CPU と GPU のバージョンを比較するさまざまな変数を手動でテストしようとしました。以下のコードでプログラムを実行すると、ピクセルが白く印刷され、値 (> 5.5 は CPU の実装と比較して完全に間違っています) のようになりますが、最後の if 構造をコメントし、最初の if 構造のコメントを外すと、私が得た結果は赤です....これは私には少し説明がつきません。何か案は?
if ((x == 265) && (y == 209)) {
/*float epsilon = 0.01f;
float4 stuff = (float4)(0.7604471f, 0.9088342f, 0.9999924f, 0);
if(fabs(pos.x - stuff.x) < epsilon)
temp = (float4)(1, 0, 0, 1);
else
temp = (float4)(1, 1, 1, 1);
break;*/
if(pos.x > 5.5)
{
temp = (float4)(1, 1, 1, 1);
break;
}
}