一、创建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,但尚未确定相机看向的方向。



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



输入lookfrom,lookat,vup,vfov,aspect就能完全确定一个相机啦

十一、景深

在现实的相机中,为了增加图片的亮度,我们需要更大的光圈而不是现有模型中的理想小孔,而大光圈会造成图片散焦,进而模糊。

但是我们可以调节呈像的位置,以改变图片的清晰度。

在之前,呈像的位置是-w平面,引入景深后,呈像位置记为-focus_dist平面。由相似三角形知,图片的大小也被整体放大focus_dist,因此有:



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



Ray Tracing in one Weekend 阅读笔记的更多相关文章

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

     Preface 博主刚放假回家就进了医院,今天刚完事儿,来续写第二本书  Ready 我们来总结一下上一本书的笔记中我们的一些规定 1. 数学表达式 我们采用小写粗黑体代表向量,大写粗黑体代表矩阵, ...

  2. Three.js源码阅读笔记-5

    Core::Ray 该类用来表示空间中的“射线”,主要用来进行碰撞检测. THREE.Ray = function ( origin, direction ) { this.origin = ( or ...

  3. 《Ray Tracing in One Weekend》、《Ray Tracing from the Ground Up》读后感以及光线追踪学习推荐

    <Ray Tracing in One Weekend> 优点: 相对简单易懂 渲染效果相当好 代码简短,只看书上的代码就可以写出完整的程序,而且Github上的代码是将基类与之类写在一起 ...

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

    上一篇比较简单,很久才发是因为做了一些好玩的场景,后来发现这一章是专门写场景例子的,所以就安排到了这一篇 Preface 这一篇要介绍的内容有: 1. 自己做的光照例子 2. Cornell box画 ...

  5. 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-7 混合概率密度

     Preface 注:鉴于很多网站随意爬取数据,可能导致内容残缺以及引用失效等问题,影响阅读,请认准原创网址: https://www.cnblogs.com/lv-anchoret/category ...

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

     Preface 往后看了几章,对这本书有了新的理解 上一篇,我们第一次尝试把MC积分运用到了Lambertian材质中,当然,第一次尝试是失败的,作者发现它的渲染效果和现实有些出入,所以结尾处声明要 ...

  7. 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-4 基于重要性采样的材质初探

     Preface 我们今天来把第三本书从开局到现在讲的一大堆理论运用到我们的框架中,那么今天我们首先将原始的材质改为基于重要性采样原理的材质 这一篇是代码工程中进行MC理论应用的初步尝试篇  Read ...

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

     Preface 今天有两个东东,一个是体积烟雾,一个是封面图 下一篇我们总结项目代码 Chapter 8:Volumes 我们需要为我们的光线追踪器添加新的物体——烟.雾,也称为participat ...

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

    Chapter 6:Rectangles and Lights 今天,我们来学习长方形区域光照  先看效果 light 首先我们需要设计一个发光的材质 /// light.hpp // ------- ...

随机推荐

  1. Puppeteer: 鼠标移动

    文档 mouse.click 是 mouse.move,mouse.down 和 mouse.up 的快捷方式 main.js const pptr = require('puppeteer'); c ...

  2. vueJS+ES6开发移动端APP实战项目笔记

    一.什么是MVVM框架 MV*包括MVC.MVP.MVVM MVVM框架由Model.View.ViewModel构成. Model指的是数据,在前端对应的是JavaScript对象. View指的是 ...

  3. 「NGK每日快讯」11.18日NGK公链第15期官方快讯

  4. 为什么NGK推出的DEFI项目这么火热?

    进入到2020年的下半年,DeFi的锁仓量基本上是以日破新高的态势,不断的成为一个独角兽.DeFi逐渐形成一个独角兽的同时,也在不断的给区块链生态赋能,源源不断进行金融价值输送.所以加密货币体量的不断 ...

  5. PBN转弯保护区作图回顾

    假期的最后一天,是该小结一下的时候了. 风螺旋有了自己中式风格的Logo,大家是否喜欢? 过去的春节假期,我们从学习CAD入手,回顾了风螺旋在PBN中的多种情况,画了很多的图,写了不少的文字,或许现在 ...

  6. js实现element中可清空的输入框(2)

    接着上一篇的:js实现element中可清空的输入框(1)继续优化,感兴趣的可以去看看哟,直通车链接:https://www.cnblogs.com/qcq0703/p/14450001.html 实 ...

  7. tesseract-ocr和tesseract.exe is not installed or it's not in your path问题解决

    一.解决方案: 1.http://www.ddooo.com/softdown/94968.htm   打开下载的压缩包,找到"tesseract-ocr-setup-3.02.02.exe ...

  8. redis数据结构和对象一

    1. SDS:简单动态字符串(simple dynamic string) Redis没有直接使用C语言的字符串,而是自己构建了一种名为简单动态字符串类型,并将SDS用作Redis的默认字符串. SD ...

  9. 将MacOS Catalina 降级为 Mojave

    1.下载Mojave https://apps.apple.com/cn/app/macos-mojave/id1398502828?ls=1&mt=12 2.更改U盘格式和名称 3.制作U盘 ...

  10. 微信小程序封装请求接口

    var rootDocment = 'https://123.com';//你的域名 function postData(url, data, cb) { wx.request({ url: root ...