对于金属状、玻璃状物体,它们的表面能映射出周围环境。如果碰上这类的物体,用上我们本篇的 shader,就能让这种物体显得更加的逼真。
- 制作Cubemap
写Shader之前呢,要用到一个Cubemap,可以用Unity的编辑器生成.代码如下:
using UnityEngine; using UnityEditor; using System.Collections; public class GenerateCubeMap : ScriptableWizard { public Transform renderformPosition; public Cubemap cubeMap; void OnWizardUpdate(){ helpString="Select transform to render from and cubemap to render int o"; isValid = (renderformPosition != null) && (cubeMap != null); } void OnWizardCreate(){ GameObject go = new GameObject ("CubeMap Camera", typeof(Camera)); go.transform.position = renderformPosition.position; go.transform.rotation = renderformPosition.rotation; go.camera.RenderToCubemap (cubeMap); DestroyImmediate (go); } [MenuItem("Tool/Render to CubeMap")] static void RenderCubeMap(){ ScriptableWizard.DisplayWizard("render cubemap",typeof(GenerateCubeMap),("Render")); } }
这个脚本为菜单栏创建了一个Wizard,用来创建需要的Cubemap.在创建脚本的位置,可以右键创建一个Cubemap,然后通过对打开的Wizard窗口赋值,即可得到目标位置的Cubemap.
- 创建环境映射Shader
环境映射的Shader需要在Properties中增加一个CUBE属性,然后在Input中增加类型为float3 的worldRefl.
Shader "Cutom/11.27/2"{ Properties{ _MainTex("Base(RGB)",2D)="white"{} _Cubemap("Cube Map",CUBE)=""{} } SubShader{ Tags{"RenderType"="Opaque"} LOD 200 CGPROGRAM #pragma surface surf Lambert sampler2D _MainTex; samplerCUBE _Cubemap; struct Input{ float2 uv_MainTex; float3 worldRefl; }; void surf(Input In,inout SurfaceOutput o){ fixed4 c=tex2D(_MainTex,In.uv_MainTex); o.Albedo=c.rgb; fixed4 refcol=texCUBE(_Cubemap,In.worldRefl); refcol*=c.a; o.Emission=refcol.rgb; o.Alpha=refcol.a; } ENDCG } }
将Cubemap上的点设定alpha值,然后将输出的Emission设定为Cubemap相应的值即可.这个 shader 代码,主要是用到了 texCUBE 这个 Unity 内置的方法,这个方法第1个参数是我们的 cubemap 文件,第2个参数是 unity 内置的基于世界坐标系的反射方向,在 Unity 渲染物体的时候,如果我们有 Input 结构需要这个东西,只要在 Input 结构中写上 worldRefl就可以, unity 会帮助把物体某个点的反射方向作为参数送如 shader,我们只要使用就可以。texCUBE 取出的值,我们把它放置到 SurfaceOutput 的 Emission 变量里面,出了 surf()这个方法后,光照方程会被运行, Emission 的值会在此过程保持,最后出了光照方程后( Unity在光照方程中主要计算某个点的光照颜色), Unity 会把 Emission 的颜色做加法加到顶点的颜色上,合成最后的输出到显卡缓存的色彩,也就是我们最后看到的颜色.
- 效果图
虽然看起来很想透明的玻璃球,但这是一个镜子球的效果,我们看到的是反射的样子.