栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

文章目录
  • 作业要求
  • 代码实现
    • castRay
  • 绘制结果
  • 简单的思考

本文为闫令琪老师的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_enter和t_exit设初始值,当t_enter == t_exit == 0时, 三角形面被不正常地照亮了

修改后的代码如下:

inline bool Bounds3::IntersectP(const Ray& ray, const Vector3f& invDir,
                                const std::array& 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::min();
    float t_exit = std::numeric_limits::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是动画部分,暂且略过)。真心感谢这门课程,为我打开了图形学的大门。还有许多理解不到位的地方,未来继续学习。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1002109.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号