跳转至

构建渲染器准备

1.输出格式

使用最简单的格式ppm(几行、几列、像素最大颜色、像素点)

  • 实现方式非常简单,两层循环遍历即可 https://www.cs.rhodes.edu/welshc/COMP141_F16/ppmReader.html

2.cmake构建文件

使用优化的构建,将exe重定向到iamge.ppm文件中

3.进度指示器

clog

4.向量运算类vec3

  • using取别名,区分point3和color
  • 默认构造
  • 带参构造
  • x、y、z获取
  • 重载负号、下标获取、下标修改
  • +=,* =, /=
  • 模长length()
  • 输出<<
  • 加减
  • 向量点乘(内积)
  • 标量乘向量(左右两种情况)
  • 标量/
  • 点积dot()
  • 叉积cross()
  • 单位向量 Pasted image 20240719232921.png

5.颜色实用程序函数

  • 可以引用向量类后新建个color.h
  • using取color别名
  • 写颜色(将rgb的01转换为0255)

光追器准备

1.光线Ray类

起点p、方向v、长度t

2.渲染图像设置

  • 通过设置aspect_radio来设置图像宽高比,注意高度至少为1

3.光线创建

  • 相机中心,了解焦距,uv
  • 坐标轴(右手系:y上,x右、z负)
  • 由于y图像应该与轴方向相反(左上(0,0)),使用边缘向量和像素增量 从左到右,从上到小扫描像素
  • 创建场景光线:对场景中的每一个像素点,发送一条光线。

添加球体

1.射线球交点

推导:

求交:利用

可以获得三种求交情况

2.曲面法线和多对象

最近表面光线 = 判别式负号的那一个 法线 = 表面-圆中心

3.区分正面和背面

使用光线和向外的法向量进行计算,若点乘之和小于0,则为异方向,为正面 * 设计一个类来记录相交hit * 设计可命中对象列表

4.可命中的抽象

  • hittable作为父类,提供常用命中抽象
  • 先使用一个球体作为基类

4.可命中对象列表

  • 需要用到我们的只能指针了

6.新的一些C++特性

  • vector
  • sharedPtr

7.常用常量和实用函数类

  • rtweekend.h 公共标头
  • 最后改一下主文件,删去一些重复的引用就可以了
  • 设置一些无穷大、pi、角度转弧度、随机数[0,1),两值间的随机数等 两个球的效果

8.An Interval Class 区间类

  • 将之前代码中的min,max(光线)用interval类来表示
  • size = max-min
  • contains包含
  • surround 包围
  • empty
  • universe

9.移动相机到类 camera.h

几乎所有代码都转移到camera,主函数留下世界构造 * 把ray_color放在相机中

抗锯齿

吐槽,这么计算采样不是每个像素算了100次?

1.添加随机数方法

用于设置采样点

2.添加区间类的Clamp方法

防止超出界限的代码造成抗锯齿颜色的错误计算

3.修改颜色代码

确保颜色被限制

4.相机实现采样

多次取平均值

漫反射

1. 生成随机矢量的方法

2. rejection method使用拒绝方法生成理想向量

1.在单位球体内生成一个随机向量 2. 归一化此向量 3.如果归一化向量落在错误的半球上,则反转它

3.将输出的法线改为输出颜色

4.限制递归次数

无限反弹极有可能炸毁堆栈

5.修复阴影痤疮Shadow acne

if(world.hit(r, interval(0.0001, infinity), rec)){ 如果光线的原点就在表面下方,0有可能导致再次光线相交 0变成0.001

6.True Lambertian Reflection 兰伯特反射模型

normal再加随机射出方向,可以比较明显的看出来画面的提亮(偏天空蓝色),而阴影处更加明显

伽马测试(从0到1,颜色逐渐提升)

反射率0.1的gamma图像前后对比

材质--金属

1.材质抽象类

  • 先定义hittable类,等待后面实现

2.hittable类,描述射线-物体交集的数据结构

  • 描述射线-物体交集的数据结构
  • 子类sphere也要添加上材质了(智能指针)

3.Scatter&Reflectance散射与反射

  • albedo反照率:描述部分反射(会随着颜色和入射发生变化)
  • 构建新的lambertion材料类

4.临界处理

  • 和法线相反方向时,光线投射矢量会逼近于0,这会导致临意外的错误
  • 新增方向,逼近于0时,向量默认为法线向量

5.镜面反射

* 反射向量计算函数reflect() * 添加新的金属材质,并进行光线反射计算 * 修改RayColor,可以根据材质提供散射反射率 * 修改sphere构造,可以传入材质

6.金属球的场景

添加四个材质,再添加到4个球上

7.模糊反射 Fuzzy Reflection

原理很简单,在反射光线处再加一个随机向量,并乘以模糊因子来控制反射。 1. 构造增添模糊度(金属度) 2. 原金属反射向量归一化(方便控制fuzz) 3. 加上fuzz计算新的反射向量 4. 给金属材质传入(模糊)金属度 实际上,当fuzz为一的时候,金属模型就很接近lambertain模型了

模糊度0.3,0.9

材质-电介质Dielectrics(Water、Glass、Diamond)

1.Refraction 折射

  • 由Snell 定律描述

* 将折射光拆分成平面方向和法向 * 那么我们可以求解得到 Pasted image 20240730221324.png * cosθ怎么计算? -R·n(限制为单位向量) * 将整个计算工时作为向量vec3.h的一个公式 * 新增材料子类,添加新的透明材质。 * * Pasted image 20240730225015.png

2.全内反射 Total Internal Reflection

  • 棘手的问题是,存在无法使用斯涅尔定律解决的射线角
  • 当光线以足够的掠视角度进入折射率较低的介质时,它可以以大于 90° 的角度折射。
  • 算出来的折射角会大于90度,sinθ’的值也不能大于1。因此等式两边之间的等式就被打破了,不存在则必须反射光线
  • 1.00/1.33(水里)比较

3. Schlick Approximation 斯科利近似

真正的玻璃具有随角度变化的反射率,但是方程非常丑陋且复杂 * Schlick的廉价方程能有有效的模拟近似这种效果

static double reflectance(double cosine, double refraction_idx) {  
    // Use Schlick's approximation for reflectance.  
    auto r0 = (1 - refraction_idx) / (1 + refraction_idx);  
    r0 = r0 * r0;  
    return r0 + (1 - r0) * pow((1 - cosine), 5);  
}

4.中空玻璃球建模

  • 实则就是在中间再造一个半径较小的圆,但是折射率和外面的圆相反

可定位相机

1.相机视野几何体

  • 确定Fov,焦距,可算出高度的比率

2.确定相机的位置和定向

  • 设置相机起始点lookfrom,相机视野朝向lookat,相机上面的方向vup
  • 设置相机渲染帧基础向量u、v、w
  • 焦距变为起始点和朝向之差的长度
  • w为(起始点-朝向)的反向
  • u、v通过vup、w、u等进行叉乘计算
  • 边缘向量viewport-u、v也是通过u,-v乘上视野宽度进行计算
  • 左上角的点也通过focal_length和w的改变而改变 最终 Pasted image 20240730234806.png

Zoom in; Pasted image 20240731095225.png

Defocus Blur散焦模糊(景深)

注意区分焦距focal distance 和focal length的区别(虽然这里确实当一样的实现了) * 摄像机需要”光圈“,而虚拟相机可以实现完美传感器,只有散焦模糊时需要模拟

1.A Thin Lens Approximation 薄透镜近似

Pasted image 20240731131026.png

Pasted image 20240731131437.png

2.生产采样射线

  • defocus disk 散焦盘(半径为1的圆,z = 0)里随机取点
  • 设置散焦角度--即我们相机中的光圈
  • 根据散焦角度,计算出散焦盘半径
  • 散焦uv向量:则等于散焦半径 * uv
  • 那么散焦返回的光点位置,则等于我们随机取点的位置X散焦uv+相机原点位置
  • 最后我们就可以根据光圈大小(散焦角度),就能判定是否使用景深了。

大光圈散焦10.0,焦距3.0

Pasted image 20240731224136.png

无散焦

Pasted image 20240731224340.png

大焦距10.0

Pasted image 20240731224632.png

中焦距4.0

Pasted image 20240731225223.png

小焦距1.0

Pasted image 20240731224754.png 可以看到过近或者过远,都会导致结果的模糊