第三种方法比较特殊,前面两张方法都是使用定义好的贴图,制作出来的立方体纹理也是全局共享的。而第三种方法不使用准备好的图像,而是依赖于脚本,由物体在不同的位置生成。核心方法为 Camera.RenderToCubeMap ,这个方法可以从任意位置观察到的图像存储到 6 张图像中,从而创建当前位置的立方体纹理。我们可以在 Unity 官方脚本手册中找到其解释及用法。
当然需要注意的是:
Camera.RenderToCubeMap (Cubemap cubemap, int faceMask)是 “静态” 的方法。当场景变化时,立方体纹理不会变化,从效果上看,类似 “烘焙”。
RenderToCubemap (RenderTexture cubemap, int faceMask) 是 “动态” 的方法,能够实时渲染,但同时也需要注意资源的消耗。
对于这种方法实现的立方体纹理,我不打算在这里赘述了,因为本文重点在后文,感兴趣的读者可以自行实现一下。
二. 光线反射
2.1 何为光线反射
反射是光现象中最为常见的一种,且遵循光的反射定律,即光射到一个界面时,其入射光线与反射光线成相同角度。光入射到不同介质的界面上会发生折射,如图
反射时会出现以下情况:
反射线跟入射线和法线在同一平面
反射线和入射线分居法线两侧,并且与界面法线的夹角(分别叫做入射角和反射角)相等
反射角等于入射角
前文介绍了如何制作立方体纹理,现在我们需要用上它来实现一些效果。反射是光现象中最为常见的一种,而使用了反射效果的物体看起来就像在表面镀了一层金属膜一样。要模拟反射效果也是比较简单的,理论上只要使用入射光线的方向和表面法线方向计算出反射方向,再用反射方向对立方体纹理采样就行。现在我们来实现一下
2.2 反射的实现
I. 创建一个场景,天空盒使用在 1.5.1 或 1.5.2 中制作的立方体纹理;创建一个 Cube 和一个 Material,一个 shader,命名为 Reflection 。编辑 shader
II. 先定义 Properties 块
其中 _ReflectAmount 控制整体反射程度,_Cubemap 表示要输入的立方体纹理,用来存储反射结果。
III. 包含相关的头文件和声明与 Properties 块 相匹配的属性
其中,要注意的是,立方体纹理的类型为 samplerCUBE
IV. 定义输入输出结构体
在输出结构体中多定义了一个反射方向,所以 SHADOW_COORDS 中的插值寄存器变为 4
V. 定义顶点着色器
顶点着色器里面的操作我们之前已经说过很多次了,这里主要是多了一个计算反射方向的步骤,我们使用 reflect 函数,有关 reflect 函数我在 【Unity Shader】(三) ------ 光照模型原理及漫反射和高光反射的实现 中已经介绍过了,读者可以翻看一下
VI. 定义片元着色器
场景中只有平行光,光照计算比较简单,这里不再赘述。而对立方体纹理采样,我们则是用了 texCUBE 函数,我们可以在MSDN上找到它的定义