当前位置: 首页 > news >正文

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·摄像机 


http://www.mrgr.cn/news/41923.html

相关文章:

  • Git版本控制工具--关于命令
  • 武汉自闭症儿童寄宿学校:让孩子快乐成长
  • 易贝恩副总经理朱洪泽受邀为第四届中国项目经理大会演讲嘉宾
  • VirtulBOX Ubuntu22安装dpdk23.11
  • Ericsson EPSFB 通话掉话现象优化案例
  • 探索 aMQTT:Python中的AI驱动MQTT库
  • MySQL 实验 2:数据库的创建与管理
  • C++模版进阶
  • 统计学习理论之VC维究竟是什么
  • Go语言实现长连接并发框架 - 任务执行流上下文
  • Valhalla实现 -Docker部署利用OSM(Mapbox)地图实现路径规划可视化
  • 重生到现代之从零开始的C语言生活》—— 内存的存储
  • 深入理解 Solidity 中的支付与转账:安全高效的资金管理攻略
  • 吉他弹唱打谱软件哪个好用 吉他弹唱制谱教程
  • 抗生素治疗百病吗?
  • 工具的力量——提升工作效率的编程工具选择与运用
  • JavaScript(JS)学习笔记 6 常用的JS内置对象(FileReader对象 FormData对象 Promise对象)
  • Comparable接口和Comparator接口
  • SpringCloud微服务搭建实战
  • 华为云+WordPress+Puock主题搭建个人博客