【GAMES101】作业7——路径追踪

作业内容:

castRay(const Ray ray,int depth):实现Path Tracing算法

作业实现:

输入参数:ray为视线看出去的射线,depth为递归的次数

若该视线没有与物体相交则返回空;

若该视线与光源相交则返回光源的emission;

若该视线与非光源物体相交则考虑两种情况:

i )与该交点与某个光源的连线没有遮挡物,利用以下公式计算(这一步需要对光源采样samplelight,或者光源位置与法线)

 其原理图如下

 ii)以一定概率RussianRoulette从x点采样发射射线递归(depth+1),若这条新的射线击中的物体为非光源(间接光照)则以下计算

 返回 i) ii)两部分L之和,实验文档的伪代码与代码如下Vector3f Scene::castRay(const Ray &ray, int depth) const

{
    //计算ray的交点
    Intersection  inter = Scene::intersect(ray);
    Vector3f L_dir(0, 0, 0);
    Vector3f L_indir(0, 0, 0);
    //如果没有交点返回空
    if (!inter.happened) {
        return Vector3f(0,0,0);
    } 
    //如果交点打到光源
    if (inter.m->hasEmission()) {
        if(depth==0){
            return inter.m->getEmission();
        }
        else return Vector3f(0,0,0);
    }
    //对光源进行采样
    Intersection lightInter;
    float lightPdf = 0.0f;
    sampleLight(lightInter, lightPdf);
    //物体表面的信息 n x
    Vector3f n = inter.normal;
    Vector3f x = inter.coords;
    //灯光表面信息 n' x'
    Vector3f nn = lightInter.normal;
    Vector3f xx = lightInter.coords;
    //求物体表面与灯光的连线 x->x'
    Vector3f w = xx - x;
    Vector3f lightDir = w.normalized();
    float lightDistance = w.x * w.x + w.y * w.y + w.z * w.z;
    //看x->x'过程中是否有遮挡,lightObjtoL为物体表面的交点向光源的射线
    Ray lightObjtoL(x, lightDir);
    Intersection objtoLInter = intersect(lightObjtoL);
    //击中的是光源的情况,利用交点与光源之差小于某个小值判断
    if (objtoLInter.happened && (objtoLInter.coords - xx).norm() < 5e-3) {
        L_dir = lightInter.emit * inter.m->eval(ray.direction, lightDir, n) * dotProduct(lightDir, n) * dotProduct(-lightDir, nn) / lightDistance / lightPdf;
    }
    //轮盘赌
    if (get_random_float() < RussianRoulette) {
        //随机在物体表面取反射方向
        Vector3f nextDir = inter.m->sample(ray.direction, n).normalized();
        Ray nextRay(x,nextDir);
        Intersection nextInter = intersect(nextRay);
        //下一条光线击中的不是光源时才加入
        if (nextInter.happened && !nextInter.m->hasEmission()) {
            float pdf = inter.m->pdf(ray.direction, nextDir, n);
            Vector3f f_r = inter.m->eval(ray.direction, nextDir, n);
            L_indir = castRay(nextRay, depth + 1) * f_r * dotProduct(nextDir, n) / pdf / RussianRoulette;
        }
    }
return L_dir + L_indir; // TO DO Implement Path Tracing Algorithm here }

结果:

SPP=16

 SPP=32

SPP=128

 

 

posted @ 2022-05-07 23:52  一只雷史莱姆  阅读(296)  评论(0编辑  收藏  举报