欢迎光临散文网 会员登陆 & 注册

[光线追踪] 00 -- 前言 & 前置知识

2022-05-14 16:32 作者:nyasyamorina  | 我要投稿

前言

其实自己学习光追已经有挺长一段时间的了 (大概一年多?),  途中尝试过很多不同的光追模型和编程语言,  但都因为效率不太好所以一直没有写相关的专栏.  不过最近发现了一个效率挺高的模型,  就觉得用这个模型作为专栏里的主要部分了,  不过在介绍光追原理和大概结构的时候还会随便提提其他模型.

专栏里的主要编程语言就选用速度很快的 C++ 了,  但是由于 C++ 写起来还是挺麻烦的,  所以也许专栏里有部分代码会选用其他语言 (比如说 python) 作为示例,  不过实际上实现的最后还是 C++ 就是了.  不得不说明的一点,  自己真的不太会写 C++,  如果实际代码里有什么可以优化或者真的写得一团糟的地方,  非常欢迎指出.

关于排版的话,  因为屑阿b在一个专栏里只能放 100 张图片,  而数学公式也算是一张图片,  所以有些地方不得不使用 unicode 字符来代替 latex 公式了.  但是我发现有很多地方都不能显示 unicode 的上标箭头 (如下图所示),  所以向量就使用带颜色的粗体表示了:  %5Cvec%20u  u

关于光追有一个不得不说的东西:  这里讨论的光追是指一种渲染手段,  而不是对物理的模拟仿真.  也就是说为了追求模型的简便和计算的速度,  有某些地方需要进行必要的假设,  而这些假设会使渲染结果与真实的场景产生偏差.  所以如果是在追求对真实场景的模拟仿真的话,  这篇专栏是非常不合适的.  另外,  在专栏里进行这种会产生偏差的假设时,  会用红色大字标明.


前置知识

因为光追涉及到很多向量计算,  所以相应的向量知识是必须的 (下面会进行一个复习的动作).  而对推导光追模型的过程需要运用微积分的知识,  所以如果想知道具体数学细节的话,  看懂微积分是必须的,  但仅限于看懂就行了,  并不会涉及微积分的求解.  跟传统的光栅化渲染不一样的是,  在光追里线性代数不是必须的,  倒不如说基本上不会遇上.

复习:  

在三维空间里,  任意一个向量都有 3 个分量:  %5Cvec%20v%3D%5Bv_x%3Bv_y%3Bv_z%5D.

向量的模长定义为  %7C%5Cvec%20v%7C%3D%5Csqrt%7Bv_x%5E2%2Bv_y%5E2%2Bv_z%5E2%7D.

向量的归一化返回方向与原向量相同但模长为1的向量:  %5Cmathrm%7Bnorm%7D(%5Cvec%20v)%3D%5Cvec%20v%2F%7C%5Cvec%20v%7C.

两向量之间的点乘 dot 定义为向量之间逐元素乘积的和:  %5Cvec%20u%5Ccdot%5Cvec%20v%3Du_xv_x%2Bu_yv_y%2Bu_zy_z,  点乘与向量的模长和夹角有关:  %5Cvec%20u%5Ccdot%5Cvec%20v%3D%7C%5Cvec%20u%7C%5C%20%7C%5Cvec%20v%7C%5C%20%5Ccos%5Cangle_%7B%5Cvec%20u%2C%5Cvec%20v%7D.

两向量之间的叉乘 cross 返回一个向量,  并且返回向量与原来的两个向量垂直,  模长与原向量的模长和夹角有关:  %7C%5Cvec%20u%5Ctimes%5Cvec%20v%7C%3D%7C%5Cvec%20u%7C%20%5C%20%7C%5Cvec%20v%7C%5C%20%5Csin%5Cangle_%7B%5Cvec%20u%2C%5Cvec%20v%7D,  叉乘的计算为:  %5Cvec%20u%5Ctimes%5Cvec%20v%3D%5Bu_yv_z-u_zv_y%3Bu_zy_x-u_xy_z%3Bu_xv_y-u_yv_x%5D,  并且叉乘是不可以左右互换的.


几种基本的类型和方法

数学上的向量可以在编程里使用数组实现,  并且在一些编程语言里都自带实现了数组,  比如说 python 的 list 或 numpy 的 ndarray,  julia 的 Vector,  C++ 的 std::vector.  这些数组都是可以改变长度的,  但是向量本身是不变长的,  所以为了优化性能,  应该使用不可变长的数组作为向量类型.  在 julia 里可以使用 StaticArrays 包,  而在 C++ 里可以使用 glm 库 [github.com/g-truc/glm].  在这里我就多此一举自己实现了:

Vec2 是为了计算纹理或采样的,  Vec3 就是计算光追里最主要的类了.  这里使用双精度浮点数是因为计算光追的精度要求较高,  如果使用单精度浮点数虽然计算速度较快,  但会产生较大的误差,  从而造成渲染错误.

另外需要实现两个向量类的四则运算:

然后实现向量的几何运算:

为了某些增加某些计算的速度,  应该提供某些不饶远路的几何运算:  比如说 abs2 直接返回模长的平方,  亦即向量元素的平方和,  absnorm 修改向量的模长到1并且返回原来的模长:

另外别忘了还有球极坐标和相应的逆方法:


最后还有一个实用的东西:  因为有时候会在几何表面处计算临近的坐标,  所以在几何表面建立局部坐标系是很有用的.  一般来说几何表面会提供一个法向量:  法向量是一个垂直于表面并且模长为1的向量,  但是这样是不足以建立局部坐标系的,  所以还需要一个在表面上的纹理向量,  但纹理向量不存在时可以直接选取全局坐标的 x轴,  但如果法向量平衡与 x轴 计算会出问题,  这时候选取 y轴 就行,  下面是局部坐标系的实现:

其中 LocalCoord::at 是把局部坐标转为全局坐标.


最后,  储存渲染缓冲区和采样集都需要二维数组,  所以自己搓了一个 Buffer2D<T>,  大概是这个样子的

具体实现可以参考仓库里的 utils.  (仓库链接: github.com/nyasyamorina/nyasRT)

另外关于采样的实现也可以参考仓库里的 samples.



写了一大篇废话,  总之,  下一篇开始就是开始推导并实现光追算法了.


最后再推一下仓库: github.com/nyasyamorina/nyasRT

最最后再推一下弔图群:  274767696

[光线追踪] 00 -- 前言 & 前置知识的评论 (共 条)

分享到微博请遵守国家法律