【GAMES 101】作业7的实现和思考


本文为闫令琪老师的GAMES 101课程的作业7的个人实现,文中如有错漏欢迎指出。

作业要求

  • castRay(const Ray ray, int depth)in Scene.cpp: 在其中实现 Path Tracing 算法

可能用到的函数:

  • intersect(const Ray ray)in Scene.cpp: 求一条光线与场景的交点

  • sampleLight(Intersection pos, float pdf) in Scene.cpp: 在场景的所有光源上按面积 uniform 地 sample 一个点,并计算该 sample 的概率密度

  • sample(const Vector3f wi, const Vector3f N) in Material.cpp: 按照该材质的性质,给定入射方向与法向量,用某种分布采样一个出射方向

  • pdf(const Vector3f wi, const Vector3f wo, const Vector3f N) in Material.cpp: 给定一对入射、出射方向与法向量,计算该出射方向的概率密度

  • eval(const Vector3f wi, const Vector3f wo, const Vector3f N) in Material.cpp: 给定一对入射、出射方向与法向量,计算这种情况下的f_r

代码实现

Path Tracing的理论知识,在此不多赘述。下图为作业文档中提供的伪代码,我们要做的就是把它写成C++代码:

在这里插入图片描述

castRay

// Implementation of Path Tracing
Vector3f Scene::castRay(const Ray &ray, int depth) const
{
    Vector3f L_dir, L_indir;
    // TODO Implement Path Tracing Algorithm here
    // ray and scene intersect at p
    Intersection inter_p = intersect(ray);

    if (!inter_p.happened)
    {
        return Vector3f();
    }
    if (inter_p.m->hasEmission())
    {
        return inter_p.m->getEmission();
    }

    Vector3f& p = inter_p.coords;
    Vector3f& N = inter_p.normal;
    Vector3f wo = (ray.origin - p).normalized();
    Material* m = inter_p.m;

    // sample light
    Intersection inter;
    float pdf_light;
    sampleLight(inter, pdf_light);
    // Get x, ws, NN, emit from inter
    Vector3f& x = inter.coords;
    Vector3f& NN = inter.normal;
    Vector3f& emit = inter.emit;
    Vector3f ws = (x - p).normalized();
    float d = (x - p).norm();

    // Shoot a ray from p to x
    Ray r(p, ws);
    Intersection i = intersect(r);
    // If the ray is not blocked in the middle
    if (i.distance - d > -0.001)
    {
        L_dir = emit * m->eval(wo, ws, N) * dotProduct(ws, N) * 
            dotProduct(-ws, NN) / (d * d * pdf_light);
    }

    // Test Russian Roulette with probability RR
    float f = get_random_float();
    if (f < RussianRoulette)
    {
        Vector3f wi = m->sample(wo, N).normalized();
        // Trace a ray r(p, wi)
        Ray r(p, wi);
        Intersection i = intersect(r);
        // If ray r hit a non-emitting object at q
        if (i.happened && !i.m->hasEmission())
        {
            L_indir = castRay(r, depth + 1) * m->eval(wo, wi, N) *
                dotProduct(wi, N) / m->pdf(wo, wi, N) / RussianRoulette;
        }
    }
    return L_dir + L_indir;
} 

绘制结果

直接光+间接光:
在这里插入图片描述

只有直接光:
在这里插入图片描述

简单的思考

1.原来的判断条件为t_enter < t_exit,场景中有很多地方没被照亮
在这里插入图片描述

2.没有为t_entert_exit设初始值,当t_enter == t_exit == 0时, 三角形面被不正常地照亮了
在这里插入图片描述

修改后的代码如下:

inline bool Bounds3::IntersectP(const Ray& ray, const Vector3f& invDir,
                                const std::array<int, 3>& dirIsNeg) const
{
    // invDir: ray direction(x,y,z), invDir=(1.0/x,1.0/y,1.0/z), use this because Multiply is faster that Division
    // dirIsNeg: ray direction(x,y,z), dirIsNeg=[int(x>0),int(y>0),int(z>0)], use this to simplify your logic
    // TODO test if ray bound intersects
    float t_enter = std::numeric_limits<float>::min();
    float t_exit = std::numeric_limits<float>::max();

    for (int i = 0; i < 3; ++i)
    {
        float t_min = (pMin[i] - ray.origin[i]) * invDir[i];
        float t_max = (pMax[i] - ray.origin[i]) * invDir[i];
        if (!dirIsNeg[i])
        {
            std::swap(t_min, t_max);
        }
        t_enter = std::max(t_enter, t_min);
        t_exit = std::min(t_exit, t_max);
    }
    return (t_enter <= t_exit) && (t_exit >= 0);
}

赶在2022上半年的最后一天,完成了Games101的第7个作业。(作业8是动画部分,暂且略过)。真心感谢这门课程,为我打开了图形学的大门。还有许多理解不到位的地方,未来继续学习。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值