【Unity Shader】(八) ------ 高级纹理之立方体纹理及光线反射、折射的实现 (2)

第三种方法比较特殊,前面两张方法都是使用定义好的贴图,制作出来的立方体纹理也是全局共享的。而第三种方法不使用准备好的图像,而是依赖于脚本,由物体在不同的位置生成。核心方法为 Camera.RenderToCubeMap ,这个方法可以从任意位置观察到的图像存储到 6 张图像中,从而创建当前位置的立方体纹理。我们可以在 Unity 官方脚本手册中找到其解释及用法。

 

当然需要注意的是:

Camera.RenderToCubeMap (Cubemap cubemap, int faceMask“静态” 的方法。当场景变化时,立方体纹理不会变化,从效果上看,类似 “烘焙”。

RenderToCubemap (RenderTexture cubemap, int faceMask) 是 “动态” 的方法,能够实时渲染,但同时也需要注意资源的消耗。

对于这种方法实现的立方体纹理,我不打算在这里赘述了,因为本文重点在后文,感兴趣的读者可以自行实现一下。

 

 

二. 光线反射

【Unity Shader】(八) ------ 高级纹理之立方体纹理及光线反射、折射的实现

 

2.1 何为光线反射

反射是光现象中最为常见的一种,且遵循光的反射定律,即光射到一个界面时,其入射光线与反射光线成相同角度。光入射到不同介质的界面上会发生折射,如图

 

 

【Unity Shader】(八) ------ 高级纹理之立方体纹理及光线反射、折射的实现

反射时会出现以下情况:

反射线跟入射线和法线在同一平面

反射线和入射线分居法线两侧,并且与界面法线的夹角(分别叫做入射角和反射角)相等

反射角等于入射角

 

前文介绍了如何制作立方体纹理,现在我们需要用上它来实现一些效果。反射是光现象中最为常见的一种,而使用了反射效果的物体看起来就像在表面镀了一层金属膜一样。要模拟反射效果也是比较简单的,理论上只要使用入射光线的方向和表面法线方向计算出反射方向,再用反射方向对立方体纹理采样就行。现在我们来实现一下

 

2.2 反射的实现

I. 创建一个场景,天空盒使用在 1.5.1 或 1.5.2 中制作的立方体纹理;创建一个 Cube 和一个 Material,一个 shader,命名为 Reflection 。编辑 shader

 

II. 先定义 Properties 块

【Unity Shader】(八) ------ 高级纹理之立方体纹理及光线反射、折射的实现

 

其中 _ReflectAmount 控制整体反射程度,_Cubemap 表示要输入的立方体纹理,用来存储反射结果。

 

III. 包含相关的头文件和声明与 Properties 块 相匹配的属性

【Unity Shader】(八) ------ 高级纹理之立方体纹理及光线反射、折射的实现

其中,要注意的是,立方体纹理的类型为 samplerCUBE

 

IV. 定义输入输出结构体

【Unity Shader】(八) ------ 高级纹理之立方体纹理及光线反射、折射的实现

在输出结构体中多定义了一个反射方向,所以 SHADOW_COORDS 中的插值寄存器变为 4

 

V. 定义顶点着色器

【Unity Shader】(八) ------ 高级纹理之立方体纹理及光线反射、折射的实现

顶点着色器里面的操作我们之前已经说过很多次了,这里主要是多了一个计算反射方向的步骤,我们使用 reflect 函数,有关 reflect 函数我在  【Unity Shader】(三) ------ 光照模型原理及漫反射和高光反射的实现 中已经介绍过了,读者可以翻看一下

 

VI. 定义片元着色器

【Unity Shader】(八) ------ 高级纹理之立方体纹理及光线反射、折射的实现

 场景中只有平行光,光照计算比较简单,这里不再赘述。而对立方体纹理采样,我们则是用了  texCUBE 函数,我们可以在MSDN上找到它的定义

【Unity Shader】(八) ------ 高级纹理之立方体纹理及光线反射、折射的实现

 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygsdp.html