参考文献:《unity shader入门精要》
立方体纹理
立方体纹理时环境映射的一种实现方式。环境映射可以模拟物体周围的效果。而使用了环境映射的物体可以看起来像镀了层金属一样反射周围的环境。立方体纹理一共包含6张图像,这些图像对应了一个立方体的六个面,立方体纹理的名称也是由此得来。
对立方体纹理采样我们需要提供一个三维的纹理坐标。这个三维纹理坐标表示我们在世界坐标空间下的一个3D方向。这个矢量方向从立方体的中心出发,当它向外部延伸时就会和立方体的6个纹理之一发生相交,而采样的结果就是该交点计算得来。
eg:天空盒子,环境映射
创建用于环境映射的立方体纹理
在Unity5中,创建用于环境映射的立方体纹理的方法有三种:
1. 第一种方法是直接由一些特殊布局的纹理创建
2. 手动创建一个Cubemap资源,再把六张图赋给它
3. 由脚本生成,通过调用Unity提供的Camera.RenderToCubeMap函数来实现。Camera.RenderToCubeMap函数可以把从任意位置观察到的场景图像存储到6张图像中,从而创建出该位置上对应的立方体纹理。
反射
shader代码如下:
Shader "Unlit/Chapter10-Reflection"
{
Properties
{
_Color("Color Tint",Color)=(1,1,1,1)
_ReflectColor("Reflection Color",Color)=(1,1,1,1) //用于控制反射的颜色
_ReflectAmount("Reflect Amount",Range(0,1))=1 //用于控制这个材质的反射程度
_Cubemap("Reflection Cubemap",Cube)="_Skybox"{} //用于模拟反射的环境映射纹理
}
SubShader
{
Tags { "RenderType"="Opaque" "Queue"="Geometry"}
//LOD 100
Pass
{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma multi_compile_fwdbase
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "AutoLight.cginc"
fixed4 _Color;
fixed4 _ReflectColor;
fixed _ReflectAmount;
samplerCUBE _Cubemap;
struct a2v{
float4 vertex :POSITION;
float3 normal:NORMAL;
};
struct v2f{
float4 pos:SV_POSITION;
float3 worldPos:TEXCOORD0;
fixed3 worldNormal:TEXCOORD1;
fixed3 worldViewDir:TEXCOORD2;
fixed3 worldRef1:TEXCOORD3;
SHADOW_COORDS(4)
};
v2f vert(a2v v){
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.worldNormal=UnityObjectToWorldNormal(v.normal);
o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
o.worldViewDir=UnityWorldSpaceViewDir(o.worldPos);
//计算顶点处的反射方向,利用法线和视角方向来计算
o.worldRef1=reflect(-o.worldViewDir,o.worldNormal);
TRANSFER_SHADOW(o);
return o;
}
fixed4 frag(v2f i):SV_Target{
fixed3 worldNormal=normalize(i.worldNormal);
fixed3 worldLightDir=normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 worldViewDir=normalize(i.worldViewDir);
fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 diffuse=_LightColor0.rgb*_Color.rgb*max(0,dot(worldNormal,worldLightDir));
//利用反射方向来对立方体纹理进行采样
fixed3 reflection=texCUBE(_Cubemap,i.worldRef1).rgb*_ReflectColor.rgb;
UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos);
//将采样结果算进光照模型
fixed3 color=ambient+lerp(diffuse,reflection,_ReflectAmount)*atten;
return fixed4(color,1.0);
}
ENDCG
}
}
FallBack "Reflective/VertexLit"
}
折射
shader代码如下:
Shader "Unlit/Chapter10-Refraction"
{
Properties
{
_Color("Color Tint",Color)=(1,1,1,1)
_RefractColor("Refraction Color",Color)=(1,1,1,1) //用于控制折射颜色
_RefractAmount("Refraction Amount",Range(0,1))=1 //用于控制这个材质的折射程度
_RefractRatio("Refraction Ratio",Range(0.1,1))=0.5 //得到不同介质的透射比,即折射率
_Cubemap ("Refraction Cubemap",Cube)="_Skybox"{} //用于模拟折射的环境映射纹理
}
SubShader
{
Tags { "RenderType"="Opaque" "Queue"="Geometry"}
LOD 100
Pass
{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma multi_compile_fwdbase
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "AutoLight.cginc"
fixed4 _Color;
fixed4 _RefractColor;
float _RefractAmount;
fixed _RefractRatio;
samplerCUBE _Cubemap;
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f{
float4 pos:SV_POSITION;
float3 worldPos:TEXCOORD0;
fixed3 worldNormal:TEXCOORD1;
fixed3 worldViewDir:TEXCOORD2;
fixed3 worldRefr:TEXCOORD3;
SHADOW_COORDS(4)
};
v2f vert(a2v v){
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.worldNormal=UnityObjectToWorldNormal(v.normal);
o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
o.worldViewDir=UnityWorldSpaceViewDir(o.worldPos);
//同反射,利用折射率和视角方向,法线方向计算折射方向
o.worldRefr=refract(-normalize(o.worldViewDir),normalize(o.worldNormal),_RefractRatio);
TRANSFER_SHADOW(o);
return o;
}
fixed4 frag(v2f i):SV_target{
fixed3 worldNormal=normalize(i.worldNormal);
fixed3 worldLightDir=normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 worldViewDir=normalize(i.worldViewDir);
fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 diffuse=_LightColor0.rgb*_Color.rgb*max(0,dot(worldNormal,worldLightDir));
//利用折射方向进行立方体纹理采样,得到采样结果
fixed3 refraction=texCUBE(_Cubemap,i.worldRefr).rgb*_RefractColor.rgb;
UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos);
//将采样结果算进光照模型
fixed3 color=ambient+lerp(diffuse,refraction,_RefractAmount)*atten;
return fixed4(color,1.0);
}
ENDCG
}
}
FallBack "Reflective/VertexLit"
}
菲涅耳反射
菲涅耳反射:菲涅尔反射描述了一种光学现象,即当光线照射到物体表面上时,一部分发生反射,一部分进入物体内部发生折射或者是散射。被反射的光和入射光之间存在一定的比率关系,这个比率关系可以通过菲涅尔等式进行计算。
Schlick菲涅耳近似等式:
其中F0是一个反射系数,用于控制菲涅耳反射的强度,v是视角方向,n是表面法线。
另一个用的比较宽泛的等式是Empricial菲涅耳近似等式:
其中,bias,scale和power是控制项
在许多车漆和水面等材质的渲染中,我们经常使用菲涅耳反射来模拟更加真实的反射效果。