0
我在gpu和cpu上實現了BVH遍歷方法。該代碼是相同的,可以在這裏找到:GPU和CPU上的相同代碼,但結果不同
GPU代碼:
bool insideCell(const __global UnstructDataset* dataset, const int cellIndex, const float4 point)
{
if(!inside(dataset->cell_box[cellIndex], point)) return false;
if (dataset->cell_point[dataset->cell_points_beg_index[cellIndex]] == 4)
{
float barycoords[4];
float4 cellpoints[4] = {
dataset->point[dataset->cell_point[dataset->cell_points_beg_index[cellIndex] + 1]],
dataset->point[dataset->cell_point[dataset->cell_points_beg_index[cellIndex] + 2]],
dataset->point[dataset->cell_point[dataset->cell_points_beg_index[cellIndex] + 3]],
dataset->point[dataset->cell_point[dataset->cell_points_beg_index[cellIndex] + 4]]
};
const float4 v1v0 = cellpoints[1] - cellpoints[0];
const float4 v2v0 = cellpoints[2] - cellpoints[0];
const float4 v3v2 = cellpoints[3] - cellpoints[2];
const float4 pv0 = point - cellpoints[0];
float tetvolumeinv = 1.0f/dot(v2v0, cross(v1v0, v3v2));
// calculate the barycentric coordinates
barycoords[0] = dot(cellpoints[2] - point, cross(cellpoints[1] - point, v3v2)) * tetvolumeinv;
barycoords[1] = dot(v2v0, cross(pv0, v3v2)) * tetvolumeinv;
barycoords[2] = dot(pv0, cross(v1v0, cellpoints[3] - point)) * tetvolumeinv;
barycoords[3] = 1.0f - barycoords[0] - barycoords[1] - barycoords[2];
// compute barycentric interpolation
return true;
}
}
// Locates the grid element which the point is residing in it.
int locateBVHElemIdx(
__global UnstructDataset* dataset,
__global BVHTree* bvh,
float4 point
) {
uint cell_index = 0;
int todoOffset = 0, nodeNum = 0;
int todo[64];
while(true){
// if the current node is an interior node
if(nodeNum >= 0){
const __global LinearBVHInteriorNode* node = &bvh->interior_nodes[nodeNum];
const bool insideLeftChild = inside(node->left_bound, point/*, node->splitAxis*/);
const bool insideRightChilld = inside(node->right_bound, point/*, node->splitAxis*/);
if(insideLeftChild && insideRightChilld){
todo[todoOffset++] = node->children[1];
nodeNum = node->children[0];
} else if(insideLeftChild && !insideRightChilld){
nodeNum = node->children[0];
} else if(insideRightChilld && !insideLeftChild){
nodeNum = node->children[1];
} else {
if(todoOffset == 0) break;
nodeNum = todo[--todoOffset];
}
} else {
const __global LinearBVHLeafNode* node = &bvh->leaf_nodes[-nodeNum - 1];
// return node->lowIdx;
// inside leaf node
for(int i = node->lowIdx; i < node->highIdx; i++){
if(insideCell(dataset, i, point))
return i;
}
if(todoOffset == 0) break;
nodeNum = todo[--todoOffset];
}
}
return 0;
}
CPU代碼:
bool UnstructDataset::insideCell(PrimitiveIndex cellIndex, const glm::vec3& point) const {
if (!m_cellBoxes[cellIndex].contains((float*)&point))
return false;
if (m_cellPoints[m_cellPointsBegIndices[cellIndex]] == 4)
{
float barycoords[4];
glm::vec3 cellpoints[4] = {
m_points[m_cellPoints[m_cellPointsBegIndices[cellIndex] + 1]],
m_points[m_cellPoints[m_cellPointsBegIndices[cellIndex] + 2]],
m_points[m_cellPoints[m_cellPointsBegIndices[cellIndex] + 3]],
m_points[m_cellPoints[m_cellPointsBegIndices[cellIndex] + 4]]
};
const glm::vec3 v1v0 = cellpoints[1] - cellpoints[0];
const glm::vec3 v2v0 = cellpoints[2] - cellpoints[0];
const glm::vec3 v3v2 = cellpoints[3] - cellpoints[2];
const glm::vec3 pv0 = point - cellpoints[0];
float tetvolumeinv = 1.0f/glm::dot(v2v0, glm::cross(v1v0, v3v2));
// calculate the barycentric coordinates
barycoords[0] = glm::dot(cellpoints[2] - point, glm::cross(cellpoints[1] - point, v3v2)) * tetvolumeinv;
barycoords[1] = glm::dot(v2v0, glm::cross(pv0, v3v2)) * tetvolumeinv;
barycoords[2] = glm::dot(pv0, glm::cross(v1v0, cellpoints[3] - point)) * tetvolumeinv;
barycoords[3] = 1.0f - barycoords[0] - barycoords[1] - barycoords[2];
// if the point is in the tetrahedron
if (barycoords[0] < 0.0f || barycoords[1] < 0.0f || barycoords[2] < 0.0f || barycoords[3] < 0.0f)
return false;
return true;
}
}
bool BVHTree::getBoundingPrimitiveIndex(const UnstructDataset* const datasetPtr, const float point[3], PrimitiveIndex& cell_index) {
uint32_t idx = 0;
int todoOffset = 0, nodeNum = 0;
int todo[64];
while(true){
// if the current node is an interior node
if(nodeNum >= 0){
const LinearBVHInteriorNode* node = &m_interior_nodes[nodeNum];
const bool insideLeftChild = node->leftBound.contains(point/*, node->splitAxis*/);
const bool insideRightChilld = node->rightBound.contains(point/*, node->splitAxis*/);
if(insideLeftChild && insideRightChilld){
todo[todoOffset++] = node->children[1];
nodeNum = node->children[0];
} else if(insideLeftChild && !insideRightChilld){
nodeNum = node->children[0];
} else if(insideRightChilld && !insideLeftChild){
nodeNum = node->children[1];
} else {
if(todoOffset == 0) break;
nodeNum = todo[--todoOffset];
}
} else {
const LinearBVHLeafNode* node = &m_leaf_nodes[-nodeNum - 1];
// inside leaf node
for(int i = node->lowIdx; i < node->highIdx; i++){
if(datasetPtr->insideCell(i, glm::vec3(point[0], point[1], point[2]))){
cell_index = i;
return true;
}
}
if(todoOffset == 0) break;
nodeNum = todo[--todoOffset];
}
}
return false;
}
問題是,當我使用的代碼,我會得到非常接近節點BVH。對我來說,看起來gpu和cpu上的浮點運算是不一樣的,這會導致算法產生不同的節點,而這兩個代碼工作正常。情況如何?
你的GPU代碼似乎並沒有使用重心座標來檢查點是四面體內部,像CPU代碼執行。 – jprice
@jprice你是對的!對於那個很抱歉!謝謝 – mmostajab