2015-07-13 139 views
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上的浮點運算是不一樣的,這會導致算法產生不同的節點,而這兩個代碼工作正常。情況如何?

+2

你的GPU代碼似乎並沒有使用重心座標來檢查點是四面體內部,像CPU代碼執行。 – jprice

+0

@jprice你是對的!對於那個很抱歉!謝謝 – mmostajab

回答

0

由於@jprice在評論中提到的,在代碼的bug。所以,我沒有檢查重心座標在0.0到1.0之間,看看這個點是否真的在單元格中。修復這個bug後,兩個結果都是一樣的。

相關問題