白纸一张

三十而立,四十而不惑

0%

练习项目(九):反射、折射相关计算

概述

反射、折射,在实现水面、玻璃等效果的时候,都多多少少会用到一些。本文主要简单介绍一些实现反射和折射的知识。使用天空盒来代表环境的信息。

一、简单的反射

反射,表现为物体反射它周围的环境。根据观察者的视角,反射会影响到物体本身的颜色表现。镜子就是一个反射性物体,它会根据观察者的视角反射它周围的环境。

在中学的物理课中,应该就学习过入射角、反射角等概念。反射的原理并不难,只是根据视角方向、法线方向,计算出反射方向,用来采样立方体贴图(此处是天空盒)。下图简单描述了这个过程:

已知视角方向viewDir、法线方向normal,现在要求的是反射方向reflectDir。这里,有一个内置函数reflect可以得到反射方向。注意上图,视角方向viewDir是从相机指向物体的。但是很多时候,我们计算得到的视角方向都是从物体指向相机的,这时候,使用reflect函数的话,需要对视角方向取反。

获得了反射方向后,就可以使用反射方向对立方体贴图采样,得到反射的环境信息。这一步没什么特别要介绍的,只是使用内置的SAMPLE_TEXTURECUBE函数采样立方体贴图。最后会得到如下的效果:

代码如下

二、光照计算与反射

上面得到了简单的反射效果,最后物体表现的完全是环境的信息。现在,我们想让体现一部分物体本身的信息。

主要的思路大概是:先计算环境光照、物体的漫反射颜色,得到物体的本身的颜色;然后计算反射环境的颜色。在二者之间做一个插值,这样,既可以体现物体本身的颜色,又可以体现反射的环境颜色。

代码如下

三、简单的折射

折射,与反射的原理比较相似。折射是光线由于传播介质的改变而产生的方向变化。在常见的类水表面上所产生的现象就是折射,光线不是直直地传播,而是弯曲了一点。比如将筷子插进水里面,看起来水下面的筷子好像弯了。

当给定入射方向时,我们可以根据斯涅耳定律(Snell's Law)来计算折射角,当光从介质1沿着和表面法线夹角为\(\theta_1\)的方向斜射入介质2时,我们可以使用如下公式计算折射光线与法线的夹角\(\theta_2\)\[ \eta_1 sin\theta_1 = \eta_2 sin\theta_2 \] 其中\(\eta_1\)\(\eta_2\)分别是两种介质的折射率。下图简单描述了这种关系:

方便的是,Unity内置的函数refract可以帮助我们计算得到折射的方向。

有了折射方向后,就可以像计算反射一样计算折射了。

代码如下

四、菲涅尔反射

在上面第二部分,只是简单地在物体本身颜色和环境的反射颜色之间进行插值。但其实为了得到更好的效果,我们一般会使用菲涅尔反射(Fresnel reflection)来根据视角方向控制反射的程度。

我们一般使用菲涅尔等式来计算菲涅尔反射,菲涅尔等式一般是近似公式,其中一个著名的近似公式就是Schlick菲涅尔近似等式: \[ F_{schlick}(v,n)=F_0+(1-F_0)(1-v\cdot n)^5 \] 其中,\(F_0\)是一个反射系数,用来控制菲涅尔反射的强度;\(v\)是视角方向;\(n\)是法线方向。

根据计算的数值,就可以在物体本身的颜色和反射的环境颜色之间进行插值了。

代码如下

五、总结

本篇文章,没有什么比较复杂的知识,只是简单介绍了反射、折射、菲涅尔方程等内容,用一个简单的过程来对相应的效果产生一个比较直观的印象。

参考

-------------本文结束感谢您的阅读-------------