Ray Tracing in one Weekend 阅读笔记
一、创建Ray类,实现背景
从相机到画布的每一个像素,创建一条Ray,每个像素点都有属于自己的Ray,并且根据自己的Ray计算出自身颜色。

可以看到Ray方向的y分量越多,像素越蓝,y分量越少则越白
下面是效果图

二、加入一个球
光线如果和球有交点,后面的背景则会被遮挡,显示球的颜色。求交的方式是:
用A*t+B表示直线上某一点,如果这个点到球心的距离等于球的半径,则有交点,可以列出方程式:

t有解,则有交点。
化简之后,就是一个二次方程,求根公式即可


计算每个像素颜色时(color(ray)),先判断和球是否交,没有交再渲染背景颜色

则结果:

三、让球的颜色和其法线信息相关
球面上的法线=球面上的点坐标-球心坐标
但是有时候会和球面交有两点,因此需要舍去背面的点,才能得到正确的法线。

让球的颜色和法线相关

四、多种形状,多个碰撞体
sphere,hitable_list继承hitable抽象类
之前创建sphere,是直接在Color函数里面,加入了球形的碰撞检测

现在有很多个hitable object,可以在main中创建他们,封装成list,再传给color函数

每个hitable的子类都继承hit方法
bool hit(const ray& r, float t_min, float t_max, hit_record& rec)
t_min,t_max指定了t的求解范围,只在直线的一定范围内判断是否有交点。
rec用于返回碰撞信息:

五、封装相机类
之前创建每个像素对应的光线是:

其中origin为相机投影屏中心,uv为屏幕坐标系下的横纵坐标
可以把光线创建封装到camera类中

在main函数中调用

六、抗锯齿
一个像素内随机取ns个点,ns个点颜色的平均值,作为该点颜色。

这样边缘像素的颜色,有一部分是前景的,有一部分是背景的。看起来更加自然。

七、漫发射
光线在一个碰撞点发生碰撞,部分吸收,部分反射,并且反射的方向是随机的。
反射出的光线可以用于二次颜色计算(递归调用color)

在与碰撞点P相切的圆中随机取一个点S。PS即为一条新的光线。
随机取点的方法:
先在随机生成[-1,1],范围内的点,再保留在球内部的即可。
得到的坐标是球心为(0,0,0)的坐标,S的世界坐标还需加上球心的世界坐标(P+n)
现在把法线相关的颜色信息替换成漫反射:


不论递归多少次,最终终止时,返回的颜色都是背景的蓝色。再层层乘0.5,表示每次反射都有50%的光线被吸收。
光线被层层吸收后,最后上图的漫反射看上去很暗,进行gama校正即可,gama校正本质是一种图像幂率变换

γ<1图像将变亮
γ>1变暗
这里不妨取1/2:


回顾之前的hit函数:
hit(const ray& r, const float t_min, const float t_max, hit_record& rec)
我们指定了t_ min,t_max限制t的范围。
理论上从相机发出的光线,不接受t<0的交点,因为交点位于视线后方,但由于浮点数的缘故,计算的t并不是完全的精确,所以t_min取0.001更加保险。
原文描述为:This gets rid of the shadow acne problem. (暂时不是很理解为什么)
八、抽象出材料类(编写metal类)
将求反射光线的部分放到了材质类的Scatter(),输入入射光线,碰撞信息,衰减强度,反射光线用scattered返回:

attenuation 代表了衰减强弱,之前的案例是50%,这里是vec3,和color的每个分量对应相乘即可。
attenuation是物体表面材质信息,如果绿色,红色吸收的多(r,g分量数值较小),那么该物体就会呈现蓝色。如果三个分量数值相等,则会呈现灰色。
下面的(0.8,0.6,0.2)则呈现黄色。
我们将之前写的diffuse材料抽象到Lambertian类中,作为material的子类。
对于铁而言,并不像漫反射一样,反射的光方向随机散开。如果将铁视为纯反射,则满足光的反射定律:

反射光的方向计算如下:

因此铁的class为:

其中return的值,测试反射光的方向,和法向量是否成锐角(成钝角就指向表面内部了,显然不合理)
返回为false则不会参与颜色计算。

scattered光线衰减后,再进入二次计算,depth记录了递归的深度,递归次数小于50次。
color和main更新如下



但铁并不是完全的镜面反射,反射方向可以有部分的偏移。

fuzzier是上图球的半径大小


把左边改成
list[3] = new sphere(vec3(-1, 0, -1), 0.5, new metal(vec3(0.3, 0.3, 0.3),0.3));
结果还是不够真实。
铁的高光反射范围应该更狭小,高光强度应该更高,其他物体映射在表面的投影不应该如此明显,需要如何修改呢?

九、介质材料(折射光)
这里的“介质”是指光可以通过的物质。比如,水,玻璃等。也就是我们常说的具有一定透明度的物质。
入射透明材料的光线,部分折射,部分反射,折射满足Snell’s law


满足下面条件时,发生全反射(无折射,Snell’s law无解):
- 光从光密介质入射光疏介质;
- 入射角大于等于临界角。
求解折射光线的函数:

以上函数推导过程详见:
https://blog.csdn.net/Pabebe/article/details/83308190
这里的scatter只选取折射或者反射的一种

如果不发生全反射,则只产生反射光,否则只产生折射光。
考虑到可能是入射透明物体,也可能是出射透明物体,故需要用入射方向与法线方向的夹角进行判断,调节法线方向和折射比率。
此处全部发生折射:

可以发现透过介质球看到的像的位置和球背后景的位置是上下颠倒的,原因如图:

https://blog.csdn.net/libing_zeng/article/details/54428732
在右侧的介质球完全看不到蓝球的反射,为什么呢?
我们目前所有的散射光(折射、反射)都是由scatter函数计算的

而scattered函数的返回,只有一条光线scattered,意味着反射,折射只能取其中一条,这里似乎全部选择了折射。
来看看refract函数:

选择反射的条件是,Snell’s law无解,即发生全反射的条件,我们可以推导该条件:
https://blog.csdn.net/Pabebe/article/details/83308190
顺着此链接的推导步骤,发生反射的条件是,根号下的式子小于0

易得,要满足根号下小于0的条件,首先n2/n1需要小于1,因为sinα1<1,即需从光密介质入射光疏介质,其次α1需要大于arcsin(n2/n1),和全反射的发生条件一致。
由于从空气入射介质,往往是从光疏介质入射光密介质,因此不满足全反射条件,故此处全为折射。
但在真实世界里,折射和反射往往是并存的,只是这里由于模型的局限性无法实现。
下面再画一个位置形状材质都相同,但|半径|略小,且半径为负值的介质球。半径为负值,意味着外表面的填充,即表面法线方向指向球心。
这样我们就有了一个空心介质球。相当于再画一个,让倒着的成像正过来。

十、可指定位置的相机
目前我们在main中创建相机,仅用:
camera cam;
相机的属性,已经提前写好在相机类中了
class camera {
public:
vec3 origin;
vec3 lower_left_corner;
vec3 horizontal;
vec3 vertical;
camera()
{
lower_left_corner = vec3(-2.0, -1.0, -1.0);
horizontal = vec3(4.0, 0.0, 0.0);
vertical = vec3(0.0, 2.0, 0.0);
origin = vec3(0.0, 0.0, 0.0);
}
ray get_ray(float s, float t) {
return ray(origin, lower_left_corner + s * horizontal + t * vertical - origin);
}
};
如果我们希望指定这些属性,则需要更多的工作。
这里选择输入vfov和aspect来计算horizontal,vertical,vfov是纵向张角,aspect是横纵比。

下面的构造函数中给出了计算方法

绘制结果如图

上面的代码让我们确定了horizontal和vertical,但尚未确定相机看向的方向。

确定相机方向,需有lookfrom,lookat,但如果只确定lookfrom,lookat,相机可以绕着lookfrom,lookat的轴,进行旋转,得到的视野仍不是确定的,因而还需要第三个分量vup,指定相机的上方。

输入lookfrom,lookat,vup,vfov,aspect就能完全确定一个相机啦
十一、景深
在现实的相机中,为了增加图片的亮度,我们需要更大的光圈而不是现有模型中的理想小孔,而大光圈会造成图片散焦,进而模糊。
但是我们可以调节呈像的位置,以改变图片的清晰度。
在之前,呈像的位置是-w平面,引入景深后,呈像位置记为-focus_dist平面。由相似三角形知,图片的大小也被整体放大focus_dist,因此有:

同时由于小孔成像,变为光圈成像,光线的起点和终点会在光圈半径的范围内偏移,故有:


Ray Tracing in one Weekend 阅读笔记的更多相关文章
- 【Ray Tracing The Next Week 超详解】 光线追踪2-1
Preface 博主刚放假回家就进了医院,今天刚完事儿,来续写第二本书 Ready 我们来总结一下上一本书的笔记中我们的一些规定 1. 数学表达式 我们采用小写粗黑体代表向量,大写粗黑体代表矩阵, ...
- Three.js源码阅读笔记-5
Core::Ray 该类用来表示空间中的“射线”,主要用来进行碰撞检测. THREE.Ray = function ( origin, direction ) { this.origin = ( or ...
- 《Ray Tracing in One Weekend》、《Ray Tracing from the Ground Up》读后感以及光线追踪学习推荐
<Ray Tracing in One Weekend> 优点: 相对简单易懂 渲染效果相当好 代码简短,只看书上的代码就可以写出完整的程序,而且Github上的代码是将基类与之类写在一起 ...
- 【Ray Tracing The Next Week 超详解】 光线追踪2-7 任意长方体 && 场景案例
上一篇比较简单,很久才发是因为做了一些好玩的场景,后来发现这一章是专门写场景例子的,所以就安排到了这一篇 Preface 这一篇要介绍的内容有: 1. 自己做的光照例子 2. Cornell box画 ...
- 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-7 混合概率密度
Preface 注:鉴于很多网站随意爬取数据,可能导致内容残缺以及引用失效等问题,影响阅读,请认准原创网址: https://www.cnblogs.com/lv-anchoret/category ...
- 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-5 random direction & ONB
Preface 往后看了几章,对这本书有了新的理解 上一篇,我们第一次尝试把MC积分运用到了Lambertian材质中,当然,第一次尝试是失败的,作者发现它的渲染效果和现实有些出入,所以结尾处声明要 ...
- 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-4 基于重要性采样的材质初探
Preface 我们今天来把第三本书从开局到现在讲的一大堆理论运用到我们的框架中,那么今天我们首先将原始的材质改为基于重要性采样原理的材质 这一篇是代码工程中进行MC理论应用的初步尝试篇 Read ...
- 【Ray Tracing The Next Week 超详解】 光线追踪2-8 Volume
Preface 今天有两个东东,一个是体积烟雾,一个是封面图 下一篇我们总结项目代码 Chapter 8:Volumes 我们需要为我们的光线追踪器添加新的物体——烟.雾,也称为participat ...
- 【Ray Tracing The Next Week 超详解】 光线追踪2-6 Cornell box
Chapter 6:Rectangles and Lights 今天,我们来学习长方形区域光照 先看效果 light 首先我们需要设计一个发光的材质 /// light.hpp // ------- ...
随机推荐
- NGK底层技术如何助力SPC子币VAST高价与安全并行?
NGK近来使用了新的侧链技术推出了新的SPC侧链代币,以及SPC的子币VAST---维萨币. NGK使用去中心化和开源区块链数据分布式协议,不断打造高倍币,力求成为生态建设参与者们所信赖的高倍币孵化器 ...
- NGK公链DeFi发力,Baccarat项目引爆流动性挖矿热潮
DeFi市值屡创新高,在这条康庄大道上,人们摩拳擦掌,就像90年代美国西部淘金热一般.DeFi带来的流动性挖矿构成了今年加密货币一道靓丽的风景线,而人们手握的不再是当年的锄头铲子,而是一串代码. 随着 ...
- ToolBar 用法
xml中的设置: <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_wi ...
- Windows开发常用快捷键
毕业后一直在从事Windows开发工作,掌握些常用的Windows快捷键可以大大的提升工作效率,同时还能秀一波操作.本文记录在工作中常用的Windows快捷键,以及VS常用快捷键.掌握了这些键盘操作, ...
- 后端程序员之路 30、webapi测试工具的一点想法
有了webapi,对应的,也就要有各种语言的sdk,有时候,还要有一个好用的api测试工具.sdk和api测试工具在功能上有一些异同,有时候测试工具会直接基于sdk来制作. 它们通常包含: 1.htt ...
- 关于VsCode创建Vue基础项目的步骤以及相关问题
项目创建步骤: 1. 全局安装vue-cli 安装命令: npm install -g vue-cli 在vscode上打开一个终端,然后输入此命令(下为截图): 2. 安装webpack,打包js ...
- 痞子衡嵌入式:FlexSPI复位方式不当会导致i.MXRT系列下OTFAD加密启动失败
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是FlexSPI复位方式不当会导致i.MXRT系列下OTFAD加密启动失败问题. 本篇是<系统时钟配置不当会导致i.MXRT1xxx ...
- 剑指 Offer 52. 两个链表的第一个公共节点 + 链表 + 第一个公共结点 + 双指针
剑指 Offer 52. 两个链表的第一个公共节点 Offer_52 题目详情 题解分析 可以使用两个指针 node1,node2 分别指向两个链表 headA,headB 的头结点,然后同时分别逐结 ...
- CentOS7 安装 MySQL Cluster 7.6.7
引用自:http://lemonlone.com/posts/mysql-ndb-cluster-install/ 仅做备份和配置文件更改 1.先在VMware中安装 CentOS-7-x86_64- ...
- Java-for循环打印九九乘法表
Java打印九九乘法表 public class forDemo04 { public static void main(String[] args) { //练习3:打印九九乘法表 /* 1*1=1 ...