Ray_Tracing_In_One_Weekend下

1·Lambertian漫反射材质

一个物体的材质,可以分成两部分来看,因为物体没有绝对光滑和绝对粗糙

漫反射:由于物体粗糙,那么对于微小平面,光线会向四周反射,光源的一部分光线传回人眼

镜面反射:假设物体绝对光滑,那么反射方向都是一致的,因此当特定角度观察,光线很大一部分传到人眼

物体越粗糙,漫反射材质部分占比越大

步骤:

为了模拟漫反射材质,我们生成随机反射方向,这个方向根据,交点的法线终点坐标为中心的单位球体内,生成随机点,求得反射光线(随机点 - 交点)

如何在单位球体生成随机点?

首先根据在一个-1---1的单位立方体内,生成随机点,如果这个点在球外(向量长度>1,超出了单位球的半径)就重新生成直到该点在球内:

然后 ,交点法线 + 随机点向量 = 反射方向

vec3 random_in_unit_sphere() {
    while (true) {
        auto p = vec3::random(-1,1);
        if (p.length_squared() >= 1) continue;
        return p;
    }
}

递归求光线颜色

  • 如果有交点,生成随机反射光线,递归 * 0.5,因此次数越多会越暗
  • 如果递归超过50次,那么返回0,防止一直有有交点不断反射的情况
  • 如果没有交点,返回背景颜色

结果:

2·伽马校正(gamma corrected)

 我们看到的球体比较暗,这其实和计算的数据不符合,因为屏幕CRT2.2会自动校正颜色,因此我们应该进行gamma校正(1/2.2次幂),让我们看到实际颜色值

这里简单的应用x^1/2次幂,也就是 sqrt(x)

3`优化

为了防止自相交,t==0.000……1的情况 ,我们将t的范围控制在>0.001

我们生成的随机点是单位球体积内, 这样生成的向量大概率上会和法线方向相近, 并且极小概率会沿着入射方向反射回去。

但是真正的反射分布率会更加均衡。这是因为我们选取的是单位球面上的点。我们可以通过在单位球内选取一个随机点, 然后将其单位化来获得该点。

vec3 random_unit_vector() {
    auto a = random_double(0, 2*pi);
    auto z = random_double(-1, 1);
    auto r = sqrt(1 - z*z);
    return vec3(r*cos(a), r*sin(a), z);
}

兰伯特球体: 

还有一种方式,选取随机反射方向:通过在交点取单位球体的随机方向,然后再和物体的normal点乘,判断是否在物体表面的半球 

4·金属材质

我们将材质类抽象出来,虚函数scatter散射函数,它会返回反射率(albedo),和散射光线

Lambertian材质继承material材质基类,散射光线是随机生成的

另外创建一个新的metal材质继承material材质基类,散射光线遵守反射定律,通过:

首先点乘vn,因为n是单位向量,点乘表示向量v在这个单位向量方向n上的投影长度,||v||costheta(三角函数)

因为vn方向相反,因此点乘cos结果为负数,即在n的反向方向的投影,因此需要加符号

反射向量 = v + 2(v在n 的投影长度)

vec3 reflect(const vec3& v, const vec3& n) {
    return v - 2*dot(v,n)*n;
}

可以让金属模糊,方法是以反射向量终点为单位球心,生成随机点,用这个点作为最终的反射方向 

通过fuzz变量控制模糊程度,随机向量 * fuzz,fuzz越大随机球的半径越大

可以看到越来越接近漫反射材质,左边0.3,右边1.0

5·绝缘体材质

 透明的材料, 例如水, 玻璃, 和钻石都是绝缘体。当光线击中这类材料时, 一条光线会分成两条, 一条发生反射, 一条发生折射。我们假设它每次要么是反射,要么是折射

斯内尔定律/折射定律:eta和eta prime是折射率,theta和theta prime是入射光线与折射光线距离法相的夹角

我们要表示折射向量,首先将折射向量Rprimer分解为,两个投影方向的加法,下面是一个经过推导后的结论,其中costheta(- 入射向量 * 法线)

 根据这个结论,写出refract折射函数,返回折射向量,

创建一个新的dielectric绝缘体材质,ref_idx是入射介质折射率,如果法线是正面的,那么eta / eta prime = 1 / ref_idx(空气折射率为1),否则法线反面,代表光线从物体内部折射出去,也就是ref_idx / 1 = ref_idx

设置散射光线为折射光线,但是这是会出现黑点,这是由于eta > eta prime导致的,比如从玻璃1.3进入空气,如果eta /  eta prime * sintheta >1,也就是sintheta primer>1这根本不可能求解,

因此无法计算折射光线的结果,我们应该在不会发生折射时进行反射

全内反射:所有的光线都不发生折射, 转而发生了反射,它经常在实心物体的内部发生

double cos_theta = ffmin(dot(-unit_direction, rec.normal), 1.0);
double sin_theta = sqrt(1.0 - cos_theta*cos_theta);
if (etai_over_etat * sin_theta > 1.0)
{
    vec3 reflected = reflect(unit_direction, rec.normal);
    scattered = ray(rec.p, reflected);
    return true;
}

优化:

最左侧是玻璃材质,这和现实世界的玻璃还不同,现实世界中的玻璃, 发生折射的概率会随着入射角而改变,从一个很狭窄的角度去看玻璃窗, 它会变成一面镜子

有个数学上近似的等式, 它是由Christophe Schlick提出的(几何函数:微平面间相互遮蔽的比率):

其中如果光线和物体法线,以一定角度观察,也会执行反射

double schlick(double cosine, double ref_idx) {
    auto r0 = (1-ref_idx) / (1+ref_idx);
    r0 = r0*r0;
    return r0 + (1-r0)*pow((1 - cosine),5);
}
double reflect_prob = schlick(cos_theta, etai_over_etat);
if (random_double() < reflect_prob)
{
    vec3 reflected = reflect(unit_direction, rec.normal);
    scattered = ray(rec.p, reflected);
    return true;
}

对于想要渲染通透的玻璃,需要两个球体,把一个小球套在大球里,半径设置为负数

6·摄像机 

优化我们的摄像机类,使得在创建相机时,可以轻松调整高度方向的视角fov theta,并且指定aspect 屏幕宽高比,和调整摄像机位置和旋转

那么屏幕(摄像机)一半高度可以由这两个参数表示 ==  half_height(==tan(fov theta / 2) == h / z,假设-z为1时省略,z越大,h越大        ),一半宽度 == aspect  * half_height

 调整摄像机位置和旋转,为了描述位置,我们建立lookfrom摄像机的位置,lookat看向的点,为了描述旋转,建立正上方向向量vup,可以绕着lookfrom--lookat轴旋转

class camera
{
public:
    camera(
        vec3 lookfrom, vec3 lookat, vec3 vup, /* 摄像机位置,屏幕的中心,上向量 */
        double vfov,                          /* 高度视角 */
        double aspect)                        /* 宽高比 */
    {
        origin = lookfrom; /* 摄像机原点 */
        vec3 u, v, w;
        /* 根据fov视角,计算宽高的长度 */
        auto theta = degrees_to_radians(vfov);
        auto half_height = tan(theta / 2);
        auto half_width = aspect * half_height;

        w = unit_vector(lookfrom - lookat); /* lookfrom-lookat */
        u = unit_vector(cross(vup, w));     /* 屏幕x坐标方向 */
        v = cross(w, u);                    /* 屏幕y坐标方向 */
        /*
            摄像机起点到屏幕平面形成锥形区域,我们计算左下点向量,实际是从摄像机向屏幕左下的向量
            左下角:屏幕一半的宽高分别*uv向量,有了两个从lookfrom出发的向量
            origin - 宽向量,向量取反,  -高向量,获得从uv平面lookfrom指向左下的向量,
            -w获得从lookfrom指向以lookat为中心屏幕的左下角
         */
        lower_left_corner = origin - (half_width * u) - (half_height * v) - w; /* */

        horizontal = 2 * half_width * u; /* 水平和垂直向量 */
        vertical = 2 * half_height * v;
    }

    ray get_ray(double s, double t)
    {
        /*
            向量位置无关性,那么为什么摄像机的origin的位置会影响渲染结果?
            因为ray的创建指定了origin,在世界空间从origin位置发射光线,求这个光线的交点
         */
        /*
            左下向量 + s向量 + t向量 获得从origin为起点,指向新的像素坐标
         */
        return ray(origin, lower_left_corner + (s * horizontal) + (t * vertical) - origin);
    }

public:
    vec3 origin;            /* 原点 */
    vec3 lower_left_corner; /* 左下 */
    vec3 horizontal;        /* 宽度 */
    vec3 vertical;          /* 高度 */
};

不同fov大小 

 

7·depth of field景深 / 散焦模糊(defocus blur)

我们原来相机是针孔相机,无法模拟景深,因此不再从lookfrom发射光线,而是指定aperture孔径大小,模拟薄片透镜相机来实现景深效果

我们只要从一个虚拟的透镜范围中发射光线到我们的摄像机平面(成像平面)就能模拟了,这个透镜与平面的距离成为焦距(focus_dist)

我们通过从随机球面生成lookfrom光线起点方向来模拟透镜

vec3 random_in_unit_disk() {
    while (true) {
        auto p = vec3(random_double(-1,1), random_double(-1,1), 0);
        if (p.length_squared() >= 1) continue;
        return p;
    }
}

我们定义一些属性:aperture光圈/透镜直径,lens_radius光圈半径,focus_dist焦距

首先生成单位球内随机点,然后*radius变为光圈大小,我们的偏移后的向量(透镜)对齐UV成像平面的方向

vec3 rd = lens_radius * random_in_unit_disk();
vec3 offset = u * rd.x() + v * rd.y();

然后从一定的(光圈范围)偏移位置发射光线,

return ray(
       origin + offset,lower_left_corner + s*horizontal + t*vertical - origin - offset
);

 结果:

8·渲染大场景

利用之前所有的框架,渲染多个球体,使用不同的材质,设置球体大小和位置

室内可见光通信射线追踪是一种模拟室内环境中可见光信号传输的方法。它利用光线追踪技术对光的传输进行详细建模和模拟,以便了解光在室内环境中的行为,进而优化室内通信系统的设计。 室内可见光通信射线追踪能够模拟光在室内环境中的传输路径、传输损耗以及干扰等因素。通过建立室内场景的模型,包括光源、障碍物、接收器等元素,并对光线在空气和材料中的衰减、反射、折射进行追踪,可以得出不同位置的光信号接收强度、光束走向等信息。 室内可见光通信射线追踪有助于优化室内通信系统的设计和布局。通过模拟和分析不同的光源位置、接收器位置和障碍物配置,可以评估可见光通信系统的传输性能。根据射线追踪结果,可以优化光源的位置、选择适当的光源功率和接收灵敏度等参数,提高通信质量和可靠性。 此外,室内可见光通信射线追踪对于解决干扰问题也具有重要作用。通过模拟室内环境中的光传播路径,可以了解到其他光源对通信系统的干扰情况,进而采取一些干扰抑制措施,如选取合适的通信频率、设计合理的编码方式等,提高系统的抗干扰性能。 综上所述,室内可见光通信射线追踪是一种用于模拟室内环境中可见光信号传输的方法。它可以帮助优化通信系统的设计和布局,改善传输性能,解决干扰问题,为高效的室内通信提供支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值