C++ KDTree 3D通过使用中点分割:边界框交点提供了瑕疵

C++ KDTree 3D通过使用中点分割:边界框交点提供了瑕疵,c++,raytracing,bounding-box,kdtree,C++,Raytracing,Bounding Box,Kdtree,嗨,我正在写我的光线跟踪代码。我大部分时间都在做实验,现在正试图优化它以获得最佳速度。所以我实现KDTree并使用中点分割三角形。没有KDTree,我的结果很好,但是有了KDTree,我在输出中得到了一些工件。我不知道我哪里出了问题 在KDTree之前 在KDTree之后 我的KDTree代码如下: #include "sgrender.h" #ifndef KDNODE_H_ #define KDNODE_H_ using namespace std; struct KDNode {

嗨,我正在写我的光线跟踪代码。我大部分时间都在做实验,现在正试图优化它以获得最佳速度。所以我实现KDTree并使用中点分割三角形。没有KDTree,我的结果很好,但是有了KDTree,我在输出中得到了一些工件。我不知道我哪里出了问题

在KDTree之前

在KDTree之后

我的KDTree代码如下:

#include "sgrender.h"

#ifndef KDNODE_H_
#define KDNODE_H_

using namespace std;

struct KDNode {
    BoundingBox bbox;
    KDNode* left;
    KDNode* right;
    vector<Shape*> objects;

    KDNode() {
        bbox = BoundingBox();
    }

    void addObject(Shape*& obj) {
        objects.push_back(obj);
        bbox.expand(obj->bbox);
    }

    void build() {
        printf("Building\n");
        if(objects.size() <= 1)
            return;

        left = new KDNode();
        right = new KDNode();

        Vec midpt = Vec(0, 0, 0);
        for(int i = 0; i < objects.size(); i++)
            midpt = midpt + objects[i]->midpt;

        midpt = midpt * (1.0/ objects.size());

        int axis = bbox.longestAxis();

        for(int i = 0; i < objects.size(); i++) {
            switch(axis) {
                case 0:
                    if(midpt.x > objects[i]->midpt.x)
                        right->addObject(objects[i]);
                    else
                        left->addObject(objects[i]);
                    break;
                case 1:
                    if(midpt.y > objects[i]->midpt.y)
                        right->addObject(objects[i]);
                    else
                        left->addObject(objects[i]);
                    break;
                case 2:
                    if(midpt.z > objects[i]->midpt.z)
                        right->addObject(objects[i]);
                    else
                        left->addObject(objects[i]);
                    break;
            }
        }

        if(left->objects.size() && right->objects.size()) {
            left->build();
            right->build();
        }
    }

    Shape* intersect(Ray r, double &depth) {
        Shape *shape = NULL;

        if(DISABLE_KDTREE) {
            for(int i = 0; i < objects.size(); i++) {
                double d = objects[i]->intersect(r);
                if(d > 0 && d < depth) {
                    depth = d;
                    shape = objects[i];
                }
            }
        } else if(bbox.intersect(r)) {
            if((left && left->objects.size() > 0) || (right && right->objects.size() > 0)) {
                double d = depth;
                if(right && right->objects.size() > 0) {
                    Shape *rshape = right->intersect(r, d);
                    if(rshape && d > 0 && d < depth) {
                        shape = rshape;
                        depth = d;
                    }
                }
                if(left && left->objects.size() > 0) {
                    Shape *lshape = left->intersect(r, d);
                    if(lshape && d > 0 && d < depth) {
                        shape = lshape;
                        depth = d;
                    }
                }
            } else {
                for(int i = 0; i < objects.size(); i++) {
                    double d = objects[i]->intersect(r);
                    if(d > 0 && d < depth) {
                        depth = d;
                        shape = objects[i];
                    }
                }
            }
        }
        return shape;
    }
};

#endif
#包括“sgrender.h”
#ifndef KDU H_
#定义KDNODE_H_
使用名称空间std;
结构KDNode{
边界框bbox;
KDNode*左;
KDNode*对;
矢量对象;
KDNode(){
bbox=边界框();
}
void addObject(形状*&obj){
物体。推回(obj);
bbox.展开(obj->bbox);
}
void build(){
printf(“建筑”);
if(objects.size()midpt;
midpt=midpt*(1.0/objects.size());
int轴=bbox.longestAxis();
对于(int i=0;iobjects[i]->midpt.x)
右->添加对象(对象[i]);
其他的
左->添加对象(对象[i]);
打破
案例1:
if(midpt.y>objects[i]->midpt.y)
右->添加对象(对象[i]);
其他的
左->添加对象(对象[i]);
打破
案例2:
if(midpt.z>objects[i]->midpt.z)
右->添加对象(对象[i]);
其他的
左->添加对象(对象[i]);
打破
}
}
如果(左->对象.size()&右->对象.size()){
左->构建();
右->构建();
}
}
形状*相交(光线r、双色和深度){
Shape*Shape=NULL;
如果(禁用KDU树){
对于(int i=0;i相交(r);
如果(d>0&&d<深度){
深度=d;
形状=对象[i];
}
}
}else if(b框相交(r)){
if((左和左->对象.size()>0)| |(右和右->对象.size()>0)){
双d=深度;
if(right&&right->objects.size()>0){
形状*r形状=右->相交(r,d);
如果(形状和深度>0和深度<){
形状=形状;
深度=d;
}
}
if(left&&left->objects.size()>0){
形状*lshape=左->相交(r,d);
如果(形状和深度>0和深度<){
形状=L形状;
深度=d;
}
}
}否则{
对于(int i=0;i相交(r);
如果(d>0&&d<深度){
深度=d;
形状=对象[i];
}
}
}
}
返回形状;
}
};
#恩迪夫

终于在我的代码中找到了问题

1) 基于最长轴的拆分导致了缓慢的遍历。KDTree构造实际上没有有效地进行,或者在某些情况下根本没有进行


2) 边界框计算为我提供了工件。在从论文和书籍中尝试了许多不同的代码后,找到了测试算法。

最终在我的代码中找到了问题

1) 基于最长轴的拆分导致了缓慢的遍历。KDTree构造实际上没有有效地进行,或者在某些情况下根本没有进行


2) 边界框计算为我提供了工件。在从论文和书籍中尝试了许多不同的代码后,找到了测试算法。

我建议您使用智能指针,如shared_ptr。(我不是说这可以从那里得到,但它更好)@sop谢谢你的建议。我今天就试试。@sop我已经将代码更新为智能指针(shared\u ptr)。这一变化并没有解决工件问题,但从其他方面受益匪浅。递归中不再出现分段错误。谢谢你的宝贵建议。我建议你使用智能指针,比如共享的ptr。(我不是说这可以从那里得到,但它更好)@sop谢谢你的建议。我今天就试试。@sop我已经将代码更新为智能指针(shared\u ptr)。这一变化并没有解决工件问题,但从其他方面受益匪浅。递归中不再出现分段错误。谢谢你的宝贵建议。