Я работаю с opencl над разработкой механизма воксельного raycasting. Я пытаюсь сделать что-то похожее на Gigavoxels от Crassin. В этой статье они используют октодерево для хранения данных вокселей. На данный момент я просто пытаюсь спуститься внутрь октодерева, пока не достигну листа, содержащего данные рендеринга.
Я сделал две реализации: одну на OpenCl на GPU и другую на C++ на CPU. Проблема, с которой я сталкиваюсь, заключается в том, что на графическом процессоре алгоритм проходит неправильное количество уровней, пока не достигнет листа внутри октодерева. Версия CPU дает правильные результаты. Алгоритм для обеих версий одинаков и код почти аналогичен.
Ребята, вы знаете, в чем может быть проблема? Это может быть аппаратная проблема, проблема с OpenCl или я что-то не так делаю? Я получаю один и тот же результат на трех разных графических процессорах nVidia.
Вот код С++:
// 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;
}
С++ версия:
inline byte GetLeafBit(uint value)
{
value = value >> 0x1;
return value & 0x1;
}
inline uint GetChildAddress(uint value)
{
return value >> 0x2;
}
Привет, нашел кое-что интересное. Я попытался вручную протестировать различные переменные, сравнивая их версии процессора и графического процессора на одном точном пикселе, положении и ориентации камеры. В приведенном ниже коде, если я запускаю программу, как сейчас, пиксель печатается белым, а значение (> 5,5 совершенно неверно по сравнению с реализацией ЦП), но если я прокомментирую последнюю структуру 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;
}
}
extractOctreeNodeLeaf
. Возможно, это проблема доступа к структуре octreeNode. - person Nobody moving away from SE   schedule 11.06.2012extractOctreeNodeLeaf
возвращаетchar
изuint
вuint
? 2. Почему вы назначаетеvalue = value >> 1
, а не толькоreturn (value >> 1) & 1;
? - person Nobody moving away from SE   schedule 11.06.2012