GAMES101学习笔记 lecture14 作业6

**

lecture14 光线追踪加速

**

原因:对于一条光线,我没有必要对场景所有的三角面求交,那样太慢。

想法:构建包围盒,如果没有命中,则没有必要取对包围盒内的三角面求交。

KD-Tree 划分空间,每次选一个轴,对空间进行划分。可能存在有一个三角面被多个包围盒记录。

BVH:划分物体的三角面。同样的,每次选一个轴,之后可以采用取包围盒中心,中位数等方法进行划分。分布较为均匀。

细节就不多说了,作业里有。

**

作业6

**

包围盒求交

inline bool Bounds3::IntersectP(const Ray& ray, const Vector3f& invDir,
                                const std::array<int, 3>& dirIsNeg) const
{
    Vector3f ttop = (pMax - ray.origin) * invDir;
    Vector3f tbot = (pMin - ray.origin) * invDir;
    Vector3f tmin = Vector3f::Min(ttop,tbot);
    Vector3f tmax = Vector3f::Max(ttop,tbot);

    float t0 = std::max(tmin.x , std::max(tmin.y,tmin.z));
    float t1 = std::min(tmax.x , std::min(tmax.y,tmax.z));
    
    return t0 <= t1 && t1 > 0;
}

BVH求交

Intersection BVHAccel::getIntersection(BVHBuildNode* node, const Ray& ray) const
{
    Intersection mIntersection;

    if(node == nullptr || !node->bounds.IntersectP(ray,ray.direction_inv,{0,0,0})) 
        return mIntersection;

    if(node->left == nullptr && node->right == nullptr)
    {
        mIntersection = node->object->getIntersection(ray);
        return mIntersection;
    }

    Intersection hit1,hit2;
    hit1 = getIntersection(node->left,ray);
    hit2 = getIntersection(node->right,ray);
    mIntersection = hit1.distance <= hit2.distance? hit1:hit2;

    return mIntersection;
}

SVH构建

BVHBuildNode* BVHAccel::recursiveBuild(std::vector<Object*> objects)
{
    BVHBuildNode* node = new BVHBuildNode();
    // Compute bounds of all primitives in BVH node
    Bounds3 bounds;
    for (int i = 0; i < objects.size(); ++i)
        bounds = Union(bounds, objects[i]->getBounds());
    if (objects.size() == 1) {
        // Create leaf _BVHBuildNode_
        node->bounds = objects[0]->getBounds();
        node->object = objects[0];
        node->left = nullptr;
        node->right = nullptr;
        return node;
    }
    else if (objects.size() == 2) {
        node->left = recursiveBuild(std::vector{objects[0]});
        node->right = recursiveBuild(std::vector{objects[1]});

        node->bounds = Union(node->left->bounds, node->right->bounds);
        return node;
    }
    else {
        const int bucketSize = 16;
        if(objects.size() < bucketSize / 4){
            Bounds3 centroidBounds;
            for (int i = 0; i < objects.size(); ++i)
                centroidBounds =
                    Union(centroidBounds, objects[i]->getBounds().Centroid());
            int dim = centroidBounds.maxExtent();//max axis 0:x 1:y 2:z
            switch (dim) {
            case 0:
                std::sort(objects.begin(), objects.end(), [](auto f1, auto f2) {
                    return f1->getBounds().Centroid().x <
                            f2->getBounds().Centroid().x;
                });
                break;
            case 1:
                std::sort(objects.begin(), objects.end(), [](auto f1, auto f2) {
                    return f1->getBounds().Centroid().y <
                            f2->getBounds().Centroid().y;
                });
                break;
            case 2:
                std::sort(objects.begin(), objects.end(), [](auto f1, auto f2) {
                    return f1->getBounds().Centroid().z <
                            f2->getBounds().Centroid().z;
                });
                break;
            }

            auto beginning = objects.begin();
            auto middling = objects.begin() + (objects.size() / 2);
            auto ending = objects.end();

            auto leftshapes = std::vector<Object*>(beginning, middling);
            auto rightshapes = std::vector<Object*>(middling, ending);

            assert(objects.size() == (leftshapes.size() + rightshapes.size()));

            node->left = recursiveBuild(leftshapes);
            node->right = recursiveBuild(rightshapes);

            node->bounds = Union(node->left->bounds, node->right->bounds);
        }
        else
        {
            Bounds3 centroidBounds;
            for (int i = 0; i < objects.size(); ++i)
                centroidBounds = Union(centroidBounds, objects[i]->getBounds().Centroid());
            int dim = centroidBounds.maxExtent();//max axis 0:x 1:y 2:z

            float bucketMin, bucketMax;
            switch (dim)
            {
                case 0:
                {
                    bucketMin = centroidBounds.pMin.x;
                    bucketMax = centroidBounds.pMax.x;
                    break;
                }
                case 1:
                {
                    bucketMin = centroidBounds.pMin.y;
                    bucketMax = centroidBounds.pMax.y;
                    break;
                }
                case 2:
                {
                    bucketMin = centroidBounds.pMin.z;
                    bucketMax = centroidBounds.pMax.z;
                    break;
                }
            }

            Bucket buckets[bucketSize];
            for(int i = 0 ; i < objects.size();++i){
                int index = caculateIndex(objects[i]->getBounds().Centroid().get(dim),bucketMin,bucketMax,bucketSize);
                buckets[index].count ++;
                buckets[index].bounds = Union(buckets[index].bounds,objects[i]->getBounds());                
            }

            Bounds3 leftBounds; int leftCount = 0;
            float minCost , UArea; int minLeftIndex;
            minCost = std::numeric_limits<float>::max();
            for(int left = 0;left < bucketSize - 1; ++left)
            {
                leftBounds = Union(leftBounds,buckets[left].bounds);
                leftCount += buckets[left].count;

                Bounds3 rightBounds; int rightCount = 0;
                for(int right = left + 1; right < bucketSize ; ++right)
                {
                    rightBounds = Union(rightBounds,buckets[right].bounds);
                    rightCount += buckets[right].count;
                }

                UArea = Union(leftBounds,rightBounds).SurfaceArea();
                float currentCost = (leftCount * leftBounds.SurfaceArea() + rightCount * rightBounds.SurfaceArea()) / UArea;
                if(currentCost < minCost){
                    minCost = currentCost;
                    minLeftIndex = left;
                } 
            }

            std::vector<Object*> leftshapes,rightshapes;
            for(int i = 0 ; i < objects.size();++i)
            {
                int index = caculateIndex(objects[i]->getBounds().Centroid().get(dim),bucketMin,bucketMax,bucketSize);
                if(index <= minLeftIndex)
                    leftshapes.emplace_back(objects[i]);
                else
                    rightshapes.emplace_back(objects[i]);
            }
            //std::cout<<leftshapes.size() << " " << rightshapes.size()<<std::endl;
            
            node->left = recursiveBuild(leftshapes);
            node->right = recursiveBuild(rightshapes);

            node->bounds = Union(node->left->bounds, node->right->bounds);
        }
        

    }

    return node;
}

值得注意的是,在构建的时候划分时根据重心进行划分。SVH的思想就是在当前划分的时候,我构建一个Cost,这个cost的定义就是命中左侧的概率 * 左侧三角面个数+命中右侧的概率 * 右侧三角面个数。这个命中率用左侧包围盒的面积 / 总的包围盒面积表示。这里构建了Buckets这个数据结构,把需要进行划分的空间划分为多个桶。当包围盒内三角面个数较少时,采用之前的中位数划分的办法。

这个方法,运行时间是8s,BVH是9s,快了一点。。一开始纠结的一点是,这个cost是否需要递归,因为cost的定义还包括了访问到这个节点的cost,定义为一个常数。后来我认为这个方法是基于当前的最优解,因此也没有必要递归那样也太复杂了。。于是计算的时候把这个常数丢了。我不知道这个结果是不是最终解,如果有大神还请指点下。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值