chapter 5:表面法线和多个物体

文章翻译

  首先,让我们得到球体表面法线,通过这个可以制造阴影。这是一个与球体表面垂直的向量,通常来说,是指向外面的。一个设计上的决策是,是否让这些法线为单位向量,为了能方便的制造阴影,我的回答是是的,但是我不强迫你们在代码里一定要这样。这可能会允许出现细微的错误,因此请注意这是个人的喜好,就如之前许多的设计决定那样。对于一个球体来说,法线的方向是光线击中点与球心相减:

houdini球形法线_搜索


  在地球上,这暗示着这个向量是地球中心到你的位置并竖直向上。让我们在代码里实现这个想法,并制造阴影。我们现在还没有任何光线和物体,所以就仅仅用彩色来可视化这个法线。一个可视化法线的常用技巧 (因为这是简单的,并本能的将N假设为单位向量——因此向量中每个坐标值都在-1~1之间) 是将每个坐标映射到0~1之间,并将x/y/z映射到r/g/b。为了得到法线,我们需要求出光线与球体的相交点,而非仅仅判断是否相交。让我们求出最近的相交点(最小的 t ),这些在代码中的改变能让我们计算并可视化法线 N

houdini球形法线_houdini球形法线_02


  这会得到这张图片:

houdini球形法线_houdini球形法线_03


  现在,如果是多个球体呢?虽然可以有个一球体数组,而一个十分清晰的解决方案是,为光线可能击中的事物制作一个抽象类,并让球体和存储球体的列表仅仅是判断光线是否击中的东西。这个被称为类的东西有点混乱,如果不是面向对象编程,称它为对象或许比较好。" 表面 "经常被使用,其缺点是我们可能会想要数量。"Hitable "类强调用功能函数将这些参数结合起来,我不喜欢这些,但我会选择"Hitable "类。

  这个hitable抽象类有一个以光线ray为参数的击中函数。大多数写光追的人发现为击中函数添加一个有效间隔tmin~tmax很方便,因此击中函数仅判断是否满足 tmin < t < tmax .一个设计上的问题是,如果光线击中事物,我们是否需要做些和计算法线那样的操作。光线击中最近的物体,将结束我们的搜索,我们也只需要最近这束光线击中的最近物体的法线。我们将得到简单的解,并计算出一系列值存储进结构体里。我知道我们想要在某些点上实现运动模糊,因此我添加了一个时间输入变量。下面这是抽象类:

houdini球形法线_抽象类_04


  下面这是球体类(请注意,我删掉了一些相互抵消的冗余)

houdini球形法线_抽象类_05


  下面是可以存储一系列物体:

houdini球形法线_搜索_06


  新的主函数如下:

houdini球形法线_解决方案_07


  这产生了一张图片,这确实可视化了球体及其表面的法向量。这也通常是一个好的方法,用来查看你的模型缺陷和特征。

houdini球形法线_c++_08

小结

  1.这一章节主要引用了法向量,目前还没具体用到,后面的散射方向需要根据法向量来计算.
  2.书中求根公式计算 t 的那部分,大家看了可能会有一点疑惑,其实书里面代码没错,是用数学化简后的结果,也可以按照高中学的公式来计算.
  3.书中嵌套了抽象类,看起来会比较模糊,这里来梳理一下:

对于单个球体来说,hit函数主要是判断光线与该球体是否相交,如果相交则把最近的相交点 P,交点法线 N,以及参数 t 存储进结构 hit_record 中,由于现实中有多个球体,如果一条视线上有多个物体,则我们只能看见前面的那部分,这时候引入了 hitable_listhit 函数将 最近的 球体相交部分对应信息记录下来,真正存储信息的是 hit_record

  4.球的颜色是根据法线来渐变的,上表面的渐变颜色是绿色,大小球对比可知