现实生活中有许多反射的例子,镜子、平静的水面、光滑的金属表面都有或多或少的反射效果,一种简单的模拟这种现象的做法是利用天空盒和Input结构中的worldRefl变量。
为了使用天空盒资源,我们可以导入官方的Skyboxes资源包,然后自己创建一个天空盒资源。一个天空盒资源需要六张贴图,分别表示盒子的六个面。
worldRefl表示世界空间中的反射向量,关于这个东西,猫猫目前把它理解成反射过程中的入射光方向,具体的细节还不清楚,有时间会详细研究一下。总之,有了这个向量,我们就可以用texCUBE函数去索引到天空盒上的一个颜色。具体的代码如下:
Shader "Custom/CubeRefl" {
Properties {
_MainTint ("Main Color", Color) = (1, 1, 1, 1)
_MainTex ("Base (RGB)", 2D) = "white" {}
_CubeMap ("Cube Map", CUBE) = ""{}
_ReflPower("Refl Power", Range(0, 1)) = 0.5
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
samplerCUBE _CubeMap;
fixed4 _MainTint;
fixed _ReflPower;
struct Input {
float2 uv_MainTex;
float3 worldRefl;
};
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = _MainTint.rgb * c.rgb;
o.Emission = texCUBE(_CubeMap, IN.worldRefl).rgb * _ReflPower;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
实现的效果是这样的:
咦?这里有奇怪的名字出现哦~
话说这位菲先生其实是法国的一位物理学家。关于这位老先生的生平事迹这里就不说啦,总之这位菲先生发现了一个有趣的光学现象,所以这个现象就直接叫做菲先生现象啦。这个现象具体指的是:当我们观察物体表面的角度(相对于法线)越大时,看到的反射效果也越明显。
基于菲先生的结论,我们可以实现一个这样的Shader,效果也很不错。为了得到观察的方向,我们需要用到Input结构中的另一个变量:viewDir。对上面的代码稍作修改就可以做出菲涅尔效果:
Shader "Custom/CubeRefl" {
Properties {
_MainTint ("Main Color", Color) = (1, 1, 1, 1)
_MainTex ("Base (RGB)", 2D) = "white" {}
_CubeMap ("Cube Map", CUBE) = ""{}
_ReflPower("Refl Power", Range(0, 1)) = 0.5
_FresnelPower("Frensnel Power", Range(0.1, 5)) = 2
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
samplerCUBE _CubeMap;
fixed4 _MainTint;
fixed _ReflPower;
fixed _FresnelPower;
struct Input {
float2 uv_MainTex;
float3 worldRefl;
float3 viewDir;
};
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
fixed diff = 1.0 - saturate(dot(o.Normal, normalize(IN.viewDir)));
diff = pow(diff, _FresnelPower);
o.Albedo = _MainTint.rgb * c.rgb;
o.Emission = texCUBE(_CubeMap, IN.worldRefl).rgb * diff * _ReflPower;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
得到的效果是这样的:
话说这位菲先生确实给我们提供了一些思路。用viewDir这个变量,我们可以轻松表示出观察物体表面角度的变化。利用这种变化我们可以实现出很多效果,比如边缘发光,随视角变化的颜色衰减等,如果有足够的想象力,这种方式可以做出很多效果。
反射效果可以极大的增强渲染的真实效果,使用天空盒这种方式牺牲的效率也是比较小的,结合上一回说过的利用贴图实现表面不同部分的不同处理,反射也可以做出不同的形式。而viewDir这个东西也给了我们充分的发挥想象力的空间,这里真的要感谢菲先生啦~