【问题标题】:Traversal a KDTree遍历 KDTree
【发布时间】:2016-10-21 23:59:11
【问题描述】:

当我尝试渲染场景时,我的渲染出现问题。

这是我的遍历算法:

bool KDTree::traverse(Ray &ray, Node &node, double &tMin, double     &tMax, double &tNear, double &u, double &v, Triangle* &hitObject)
{
if(node.tris.size() == 0) return 0;

bool current = false;
//bool intersected = false;
if(!node.isLeaf)
{
    int axis = node.split_axis;
    double tSplit = (node.split_pos - ray.orig[axis]) / ray.dir[axis];
    Node* nearNode = ray.orig[axis] < node.split_pos ? node.leftNode : node.rightNode;
    Node* farNode = ray.orig[axis] < node.split_pos ? node.rightNode : node.leftNode;

    if (tSplit > tMax)
        return traverse(ray, *nearNode , tMin, tMax, tNear, u, v, hitObject);//case A
    else if (tSplit < tMin)
    {
        if(tSplit>0)
            return traverse(ray, *farNode, tMin, tMax, tNear, u, v, hitObject);//case B
        else if(tSplit<0)
                return traverse(ray, *nearNode, tMin, tMax, tNear, u, v, hitObject);//case C
        else
        {//tSplit==0
            if(ray.dir[axis]<0)
                return traverse(ray, *farNode, tMin, tMax, tNear, u, v, hitObject);//case D
            else
                return traverse(ray, *nearNode, tMin, tMax, tNear, u, v, hitObject);//case E
        }
    }
    else
    {
        if(tSplit>0)
        {//case F
            current = traverse(ray, *nearNode, tMin, tSplit, tNear, u, v, hitObject);
            if (current != false)
                return current;
            else
                return traverse(ray, *farNode, tSplit, tMax, tNear, u, v, hitObject);
        }
        else
        {
            return traverse(ray, *nearNode,tSplit, tMax, tNear, u, v, hitObject);//case G
        }
    }
}
else
{
    tNear = 9999999;

    for(unsigned int i = 0; i < node.tris.size(); ++i)
    {
        double t = 9999999;
        if(node.tris[i]->intersect(ray, t, u, v) && t < tNear)
        {
            hitObject = node.tris[i];
            tNear = t;
        }
    }

    return (hitObject != nullptr);
}   
}

这是我的构建算法:

void KDTree::buildkdtree(Node &node)
{
std::cout << "stò inizializzando il nodo di profondità: " << node.depth << std::endl;
if(node.tris.size() <= 30 || node.depth >= 15)
{
    std::cout << "ho creato una foglia di livello: " << node.depth << " , con " << node.tris.size() << " triangoli" << std::endl;
    node.isLeaf = true;
    return;
}

int axis = (node.depth % 3);
std::vector<Vec3d> midPoints;
for(unsigned int i = 0; i < node.tris.size(); ++i)
{
    midPoints.push_back(node.tris[i]->getMidPoint());
}
std::vector<double> mid;
node.split_axis = axis;
node.rightNode = new struct Node;
node.leftNode = new struct Node;
double max, min, med;
switch(node.split_axis)
{
    case(0):
        std::cout << "splitto su x" << std::endl;
        for(unsigned int i = 0; i < midPoints.size(); ++i)
        {
            mid.push_back(midPoints[i].x);
        }

        std::sort(mid.begin(), mid.end());

        if(mid.size() % 2 == 0)
            med = (mid[mid.size()/2 - 1] + mid[mid.size()/2]) / 2;
        else
            med = mid[mid.size()/2];

        node.split_pos = med;

        std::cout << "l'intervallo e': (" << node.bbox->xMin << " ," << node.bbox->xMax << ")\n";
        std::cout << "split_pos = " << node.split_pos << std::endl;

        node.rightNode->bbox = new Bbox(node.bbox->xMax, node.split_pos, node.bbox->yMax, node.bbox->yMin, node.bbox->zMax, node.bbox->zMin);
        node.leftNode->bbox = new Bbox(node.split_pos, node.bbox->xMin, node.bbox->yMax, node.bbox->yMin, node.bbox->zMax, node.bbox->zMin);

        for(unsigned int i = 0; i < node.tris.size(); ++i)
        {
            node.tris[i]->getExtreme(max, min, axis);
            if(min <= node.split_pos)
                node.leftNode->tris.push_back(node.tris[i]);
            if(max >= node.split_pos)
                node.rightNode->tris.push_back(node.tris[i]);
        }
    break;

    case(1):
        std::cout << "splitto su y" << std::endl;
        for(unsigned int i = 0; i < midPoints.size(); ++i)
        {
            mid.push_back(midPoints[i].y);
        }

        std::sort(mid.begin(), mid.end());

        if(mid.size() % 2 == 0)
            med = (mid[mid.size()/2 - 1] + mid[mid.size()/2]) / 2;
        else
            med  = mid[mid.size()/2];

        node.split_pos = med;

        std::cout << "l'intervallo e': (" << node.bbox->yMin << " ," << node.bbox->yMax << ")\n";
        std::cout << "split_pos = " << node.split_pos << std::endl;

        node.rightNode->bbox = new Bbox(node.bbox->xMax, node.bbox->xMin, node.split_pos, node.bbox->yMin, node.bbox->zMax, node.bbox->zMin);
        node.leftNode->bbox = new Bbox(node.bbox->xMax, node.bbox->xMin, node.bbox->yMax, node.split_pos, node.bbox->zMax, node.bbox->zMin);

        for(unsigned int i = 0; i < node.tris.size(); ++i)
        {
            node.tris[i]->getExtreme(max, min, axis);
            if(min <= node.split_pos)
                node.leftNode->tris.push_back(node.tris[i]);
            if(max >= node.split_pos)
                node.rightNode->tris.push_back(node.tris[i]);
        }
    break;

    case(2):
        std::cout << "splitto su z" << std::endl;
        for(unsigned int i = 0; i < midPoints.size(); ++i)
        {
            mid.push_back(midPoints[i].z);
        }

        std::sort(mid.begin(), mid.end());

        if(mid.size() % 2 == 0)
            med = (mid[mid.size()/2 - 1] + mid[mid.size()/2]) / 2;
        else
            med  = mid[mid.size()/2];

        node.split_pos = med;

        std::cout << "l'intervallo e': (" << node.bbox->zMin << " ," << node.bbox->zMax << ")\n";
        std::cout << "split_pos = " << node.split_pos << std::endl;

        node.rightNode->bbox = new Bbox(node.bbox->xMax, node.bbox->xMin, node.bbox->yMax, node.bbox->yMin, node.split_pos, node.bbox->zMin);
        node.leftNode->bbox = new Bbox(node.bbox->xMax, node.bbox->xMin, node.bbox->yMax, node.bbox->yMin, node.bbox->zMax, node.split_pos);

        for(unsigned int i = 0; i < node.tris.size(); ++i)
        {
            node.tris[i]->getExtreme(max, min, axis);
            if(min <= node.split_pos)
                node.leftNode->tris.push_back(node.tris[i]);
            if(max >= node.split_pos)
                node.rightNode->tris.push_back(node.tris[i]);
        }
    break;

    default:
        std::cout << "Errore, non ho uno dei tre assi" << std::endl;
    break;
}

std::cout << "i " << node.tris.size() << " triangoli del padre sono stati divisi così\n";
std::cout << node.rightNode->tris.size() << " nel nodo di destra\n";
std::cout << node.leftNode->tris.size() << " nel nodo di sinistra\n" << std::endl;

node.rightNode->depth = node.depth + 1;
node.leftNode->depth = node.depth + 1;

std::cout << "sto processando figlio di destra del nodo di profondità: " << node.depth << std::endl;
buildkdtree(*(node.rightNode));
std::cout << "sto processando figlio di sinistra del nodo di profondità: " << node.depth << std::endl;
buildkdtree(*(node.leftNode));}

有人可以帮助我吗?

PS:这是我得到的图像:

【问题讨论】:

  • 有什么问题?
  • 如果你看左上角猴子的嘴附近,一些多边形不会变红,但如果我将相机设置更改为前视图,则没有问题
  • 你能贴一张更清晰/更大/更清晰的图片来说明问题吗?

标签: c++ raytracing tree-traversal kdtree


【解决方案1】:

我在编写光线追踪器时遇到了同样的问题。问题实际上可能出在您的构建代码或遍历代码中。考虑一下,如果你构建一棵坏树,“正确”的遍历也会导致工件。

我通过在光线追踪器上构建一个简单的 OpenGL 渲染器发现了这个问题。这涉及以下内容:

  1. 创建一个 OpenGL 渲染实例并将您的场景和相机信息提供给它。看起来你只有三角形和一两个灯,所以这应该很容易。 OpenGL 为我们的目的渲染了一个足够好的近似值。

  2. 使用 GLUT 创建一个输出窗口,并在连续渲染循环中显示 OpenGL 输出。修改输出窗口,使其接受用户输入(键盘、鼠标等)来移动相机的位置和方向。

  3. 修改您的 OpenGL 渲染器以绘制所有 KDNode 边界框。使边界框半透明。

  4. 创建包含树控件的第二个窗口。将您的 KDTree 绑定到树控件,以便 KDTree 中的每个元素都对应于树控件中的一个节点。您现在应该可以直观地检查您的 KDTree。

  5. 修改树形窗口,使其接受用户输入以选择、展开和折叠节点。

  6. 修改您的 OpenGL 渲染器,使当前选定的树节点 (KDNode) 的边界框以及分配给该 KDNode 的三角形以特殊颜色绘制。

现在,通过在树窗口中选择一个节点,您可以看到关联的 KDNode 的边界框,哪些三角形分配给了 KDNode,您可以四处移动相机以验证您认为的三角形是否分配给了 KDNode实际分配给节点。

当我第一次这样做时,我对树的心智模型与我的算法实际创建的模型有多么不同感到吃惊。使用此工具,您应该能够验证您的构建代码是否在执行您认为的操作。您还可以使用它来微调构建代码的参数以获得更高效的树。

你的输出窗口应该是这样的(礼貌Michele Bosi):

编辑:Another example由李怡宁提供

编辑:A third example由阿波罗·埃利斯提供

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-05
    • 2018-10-05
    • 2018-07-15
    • 2014-01-23
    相关资源
    最近更新 更多