【Ray Tracing The Next Week 超详解】 光线追踪2-6 Cornell box

Chapter 6:Rectangles and Lights

今天,我们来学习长方形区域光照

 先看效果

light

首先我们需要设计一个发光的材质

/// light.hpp

// -----------------------------------------------------
// [author]        lv
// [begin ]        2019.1
// [brief ]        the areaLight-class for the ray-tracing project
//                from the 《ray tracing the next week》
// -----------------------------------------------------

#pragma once

namespace rt
{

//the statement of areaLight class

class areaLight :public material
    {
public:
    areaLight() {  }

    areaLight(texture* mat) :_emit(mat) {  }

    virtual bool scatter(const ray& InRay, const hitInfo& info, rtvec& attenuation, ray& scattered)const { return false; }

    virtual rtvec emitted(rtvar u, rtvar v, const rtvec& p)const { return _emit->value(u, v, p); }

private:
    texture* _emit;
    };

} // rt namespace

关于设计方面,我们需要把发光函数设为可继承虚函数,基类也要添加,但是不是所有的材质都需要发光,所以,基类中的发光函数并不需要设置为纯虚

/// material.hpp

// -----------------------------------------------------
// [author]        lv
// [begin ]        2018.12
// [brief ]        the material-class for the ray-tracing project
//                from the 《ray tracing in one week》
// -----------------------------------------------------

#pragma once

namespace rt
{

// the statement of material class

class material
    {
public:

    /*
    @brief: produce a scattered ray
    @param: InRay -> Incident light
            info -> the information of intersect-point(hit-point)
            attenuation -> when scattered, how much the ray should be attenuated by tis reflectance R
            scattered -> as we talk, it is a new sight; or
                         it is the scattered ray with the intersect-point
    @retur: the function calculate a scattered ray or not
    */
    virtual bool scatter(const ray& InRay, const hitInfo& info, rtvec& attenuation, ray& scattered)const = 0;

    /*
    @brief: 自发光
    @param: 纹理所需信息
    @retur: 纹理像素值
    */
    virtual rtvec emitted(rtvar u, rtvar v, const rtvec& p)const { return rtvec(); }

    };

}

这样的话,一般的材质继承之后,发光为黑色即不发光,较为合理

我们既然添加了光照,那么计算插值函数时候也要将它加进去

到此,我们的发光材质就设置妥当了

rectangle

我们定义的长方形均为平行于轴的

(引用书上一张图)

假设长方形位于 z = k 平面,x和y边界如上,交点为P(x,y,k)

我们如何确定光线参数t?

已知:

光线:p(t) = eye + t * direction

则,z方向的方程为:z(t) = eye.z + t * direction.z

那么,若满足z = k,则

t = (k - eye.z) / direction.z

同理可得x和y的等式

如果,得到的x坐标或者y坐标不在边界之内,那么就没有相交,反之则光线和长方形相交

上面的代码都比较简单,那个 hit 呢,就是,根据已知的一个分量求出t,然后,把这个解带入求出对应的其他两个分量,如果其他两个分量不在边界内,那么返回false

反之,我们求取该点的纹理坐标,以及其他碰撞点信息记录之

获取包围盒嘛,理论上面无厚薄,线无粗细,但是实际中面有厚薄,我们可以将厚度设置为0.0002,以此模拟理论厚度

这个没什么问题,我们就往下进行

我们来做Cornell box

相机参数设置:

得到的图如下:

有几个面是黑色的??也就是根本没画出来

我们细细看一下,发现,长方形的法向量是关键

比如画出来的红墙,对面与之平行的面的法线是朝左边的,展现在我们视线中的是背面

所以,我们有时候需要反转一下法向量

/// flip_normal.hpp

// -----------------------------------------------------
// [author]        lv
// [begin ]        2019.1
// [brief ]        the flip_normal-class for the ray-tracing project
//                from the 《ray tracing the next week》
// -----------------------------------------------------

#pragma once

namespace rt
{

class flip_normal: public intersect
    {
public:
    flip_normal(intersect * p) :_p(p) {  }

    virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const override
        {
        if (_p->hit(sight, t_min, t_max, info))
            {
            info._n = -info._n;
            return true;
            }
        return false;
        }

    virtual aabb getbox()const override
        {
        return _p->getbox();
        }

private:
    intersect* _p;
    };

} // rt namespace 

这样就可以了,我们改一下场景

如下:

此外,我们还需要注意的是,light对应的纹理中的数值越大光强越强

我们可以试一下

    material * light = new areaLight(new constant_texture(rtvec(20, 20, 20)));

如下:

可以看出来两张图对比之下,第二张亮多了

但是我们依旧看着很不舒服,好多黑点点,太难受了

我想啊想,为什么这么多黑点??可能是因为背景是黑色的,毕竟是漫反射,如果随机反射失败那就是黑色,所以随机反射点可能产生好多黑色小点,你千万别想着换成镜面材质,那个更无语

所以啊,我想了下,把背景改为白色,那样更好,毕竟色彩中掺杂一点白色,无伤大雅

如是,我改了下,效果可观

感谢您的阅读,生活愉快~

原文地址:https://www.cnblogs.com/lv-anchoret/p/10303112.html

时间: 2024-11-05 23:32:20

【Ray Tracing The Next Week 超详解】 光线追踪2-6 Cornell box的相关文章

【Ray Tracing in One Weekend 超详解】 光线追踪1-10

<Ray Tracing in One Weekend>完结篇 最近课程上机实验,封面图渲染时间也超长,所以写东西就落下了,见谅 这篇之后,我会继续<Ray Tracing The Next Week>,还请多多关注 这几天我在渲染这本书的封面图,封面图还没出,不算结束,刚好安排了10节 今天呢,有两件事: 1.阐述整个工程的文件组织即内容 2.阐述封面,完结 12.1工程文件组织 试过很多方法,问过很多老师,无奈,子类继承实现的父类纯虚函数实在无法和类声明分成两个文件(即声明放于

【Ray Tracing The Next Week 超详解】 光线追踪2-3

 Preface 终于到了激动人心的纹理章节了 然鹅,看了下,并不激动 因为我们之前就接触过 当初有一个 attenuation 吗? 对了,这就是我们的rgb分量过滤器,我们画出的红色.蓝色.绿色等等,都是通过它来控制的 专业点的词语叫做rgb衰减比例,比如rtvec(1.,0.,0.),最后呈现出来的是红色,因为r保留了100% 它是怎么控制的呢,我们来回顾一下这个过程 首先,我们创建一个材质球 后面那个rtvec(0.4,0.2,0.1)就是衰减比例(衰减到原来的百分之..) 之后 进入数

【Ray Tracing The Next Week 超详解】 光线追踪2-7 任意长方体 &amp;&amp; 场景案例

上一篇比较简单,很久才发是因为做了一些好玩的场景,后来发现这一章是专门写场景例子的,所以就安排到了这一篇 Preface 这一篇要介绍的内容有: 1. 自己做的光照例子 2. Cornell box画质问题及优化方案 3. 新的场景几何体——长方体 轴平行长方体 任意长方体 我们这一篇重实践轻理论阐述 ready 1. 需要上一章的知识 但是,上一章的Cornell box画质优化仅限于盒子本身,如果作为场景和其他物体放在一起就不能那么优化画质 即,Cornell box像素计算失败应该返回黑色

【Ray Tracing in One Weekend 超详解】 光线追踪1-7 Dielectric 半径为负,实心球体镂空技巧

今天讲这本书最后一种材质 Preface 水,玻璃和钻石等透明材料是电介质.当光线照射它们时,它会分裂成反射光线和折射(透射)光线. 处理方案:在反射或折射之间随机选择并且每次交互仅产生一条散射光线 (实施方法:随机取样,具体见后文) 调试最困难的部分是折射光线.如果有折射光线的话,我通常首先让所有的光折射.对于这个项目,我试图在我们的场景中放置两个玻璃球,我得到了这个:   上述图片是对的吗?显然,在实际生活中,那两个玻璃球看起来怪怪的,实际情况下,里面的内容应该将现在的进行上下颠倒,且没有黑

POJ 1659 Frogs&#39; Neighborhood(可图性判定—Havel-Hakimi定理)【超详解】

Frogs' Neighborhood Time Limit: 5000MS   Memory Limit: 10000K Total Submissions: 9897   Accepted: 4137   Special Judge Description 未名湖附近共有N个大小湖泊L1, L2, ..., Ln(其中包括未名湖),每个湖泊Li里住着一只青蛙Fi(1 ≤ i ≤ N).如果湖泊Li和Lj之间有水路相连,则青蛙Fi和Fj互称为邻居.现在已知每只青蛙的邻居数目x1, x2, ..

CentOS6启动过程超详解分析

CentOS 6 开机流程--linux由kernel和rootfs组成.kernel负责进程管理.内存管理.网络管理.驱动程序.文件系统.安全等;rootfs由程序和glibc组成,完善操作系统的功能.同时linux内核的特点是模块化,通过对模块装载卸载可以对内核功能自定义.linux内核文件:/boot/vmlinuz-2.6.32-696.el6.x86_64 整体的流程 BIOS/开机自检 MBR引导(Boot Loader) 启动内核 启动第一个进程init 一.BIOS/开机自检 1

【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-5 random direction &amp; ONB

 Preface 往后看了几章,对这本书有了新的理解 上一篇,我们第一次尝试把MC积分运用到了Lambertian材质中,当然,第一次尝试是失败的,作者发现它的渲染效果和现实有些出入,所以结尾处声明要通过实践,改进当前的效果 于是乎,就有了后面的章节,几乎整本书都在讲,如何一步一步地改进上一篇的画质,使其更加符合现实,上一篇其实是抛砖引玉 这本书的小标题名为the rest of your life 通过前面几章,我们可以更好地理解这句话:我们通过MC积分优化效果,采用的是pdf函数,之前说过,

高斯消元法(Gauss Elimination)【超详解&amp;模板】

高斯消元法,是线性代数中的一个算法,可用来求解线性方程组,并可以求出矩阵的秩,以及求出可逆方阵的逆矩阵.高斯消元法的原理是:若用初等行变换将增广矩阵 化为 ,则AX = B与CX = D是同解方程组. 所以我们可以用初等行变换把增广矩阵转换为行阶梯阵,然后回代求出方程的解. 1.线性方程组 1)构造增广矩阵,即系数矩阵A增加上常数向量b(A|b) 2)通过以交换行.某行乘以非负常数和两行相加这三种初等变化将原系统转化为更简单的三角形式(triangular form) 注:这里的初等变化可以通过

海量数据处理算法总结【超详解】

1. Bloom Filter [Bloom Filter]Bloom Filter(BF)是一种空间效率很高的随机数据结构,它利用位数组很简洁地表示一个集合,并能判断一个元素是否属于这个集合.它是一个判断元素是否存在集合的快速的概率算法.Bloom Filter有可能会出现错误判断,但不会漏掉判断.也就是Bloom Filter判断元素不再集合,那肯定不在.如果判断元素存在集合中,有一定的概率判断错误.因此,Bloom Filter不适合那些“零错误”的应用场合. 而在能容忍低错误率的应用场合