【猫猫的Unity Shader之旅】之反光材质

利用天空盒实现简单的反光效果

  现实生活中有许多反射的例子,镜子、平静的水面、光滑的金属表面都有或多或少的反射效果,一种简单的模拟这种现象的做法是利用天空盒和Input结构中的worldRefl变量。

  为了使用天空盒资源,我们可以导入官方的Skyboxes资源包,然后自己创建一个天空盒资源。一个天空盒资源需要六张贴图,分别表示盒子的六个面。

  【猫猫的Unity Shader之旅】之反光材质_第1张图片

  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"
}

  实现的效果是这样的:

  【猫猫的Unity Shader之旅】之反光材质_第2张图片
  

菲涅尔效果

  咦?这里有奇怪的名字出现哦~

  话说这位菲先生其实是法国的一位物理学家。关于这位老先生的生平事迹这里就不说啦,总之这位菲先生发现了一个有趣的光学现象,所以这个现象就直接叫做菲先生现象啦。这个现象具体指的是:当我们观察物体表面的角度(相对于法线)越大时,看到的反射效果也越明显。

  基于菲先生的结论,我们可以实现一个这样的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"
}

  得到的效果是这样的:

  【猫猫的Unity Shader之旅】之反光材质_第3张图片
  

  话说这位菲先生确实给我们提供了一些思路。用viewDir这个变量,我们可以轻松表示出观察物体表面角度的变化。利用这种变化我们可以实现出很多效果,比如边缘发光,随视角变化的颜色衰减等,如果有足够的想象力,这种方式可以做出很多效果。

结束语

  反射效果可以极大的增强渲染的真实效果,使用天空盒这种方式牺牲的效率也是比较小的,结合上一回说过的利用贴图实现表面不同部分的不同处理,反射也可以做出不同的形式。而viewDir这个东西也给了我们充分的发挥想象力的空间,这里真的要感谢菲先生啦~

你可能感兴趣的:(【猫猫的Unity,Shader之旅】,猫猫的Unity,Shader之旅)