玻璃效果主要是折射效果的计算和反射效果的计算。
折射:
1.利用Grass Pass对当前屏幕的渲染图像进行采样
2.得到法线贴图对折射的影响
3.对采集的屏幕图像进行关于法线方向上的扭曲和偏移,以模拟折射效果
反射:
主要利用环境贴图产生反射的残影,并和主贴图采样结果混合
得到反射和折射的结果后,以一个变量控制最终效果(类似于玻璃的透光率);
效果如下:
代码如下:
Shader "MyShader/011"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
_Diffuse("Color",Color) = (1,1,1,1)
_BumpMap("Normal Map",2D) = "white"{}
_BumpScale("Bump Scale", float) = 1
_Cubemap("CubeMap",Cube) = "_Skybox"{}
_Distortion("Distortion",Range(0,100)) = 10//模糊程度
_RefractAmount("RefractAmount",Range(0,1)) = 1//一个折射系数,用于控制折射和反射的占比
}
SubShader
{
Tags { "RenderType" = "Opaque" "Queue" = "Transparent+100"}//在所有物体渲染之后再抓屏
LOD 100
GrabPass{"GrabPass"}//抓取当前屏幕的渲染图像并存入指定纹理
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct v2f
{
float4 vertex : SV_POSITION;
float4 uv :TEXCOORD0;
float4 TtoW0 : TEXCOORD1;
float4 TtoW1 :TEXCOORD2;
float4 TtoW2 :TEXCOORD3;
float4 scrPos: TEXCOORD4;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Diffuse;
sampler2D _BumpMap;
float4 _BumpMap_ST;
float _BumpScale;
sampler2D GrabPass;//要和GrabPass中的名字一样
float4 GrabPass_TexelSize;//抓取的纹理图的大小
float _Distortion;
samplerCUBE _Cubemap;
float _RefractAmount;
v2f vert(appdata_tan v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.scrPos = ComputeGrabScreenPos(o.vertex);//得到屏幕采样坐标
o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
o.uv.zw = TRANSFORM_TEX(v.texcoord, _BumpMap);
fixed3 worldPos = mul(unity_ObjectToWorld, v.vertex);
fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;
o.TtoW0 = float4(worldTangent.x,worldBinormal.x,worldNormal.x, worldPos.x);
o.TtoW1 = float4(worldTangent.y,worldBinormal.y,worldNormal.y, worldPos.y);
o.TtoW2 = float4(worldTangent.z,worldBinormal.z,worldNormal.z, worldPos.z);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT;
fixed4 albedo = tex2D(_MainTex, i.uv.xy);
float3 worldPos = float3(i.TtoW0.w,i.TtoW1.w,i.TtoW2.w);
fixed3 lightDir = UnityWorldSpaceLightDir(worldPos);
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
//求法线
fixed4 packedNormal = tex2D(_BumpMap,i.uv.zw);
fixed3 tangentNormal = UnpackNormal(packedNormal);
tangentNormal.xy *= _BumpScale;
fixed3 worldNormal = normalize(float3(dot(i.TtoW0.xyz, tangentNormal), dot(i.TtoW1.xyz, tangentNormal),dot(i.TtoW2.xyz,tangentNormal)));
//采样抓屏贴图
//对采集的屏幕图像进行关于法线方向上的扭曲和偏移,也就是模拟折射的效果
float2 offset = tangentNormal.xy * _Distortion * GrabPass_TexelSize.xy;
i.scrPos.xy = offset * i.scrPos.z + i.scrPos.xy;
fixed3 refrCol = tex2D(GrabPass, i.scrPos.xy / i.scrPos.w).rgb;//齐次除法还原
//模拟反射的效果,反射越强,也就是透光度越低,越能看到主贴图纹理以及周围环境反射的残影
fixed3 reflCol = texCUBE(_Cubemap, reflect(-viewDir, worldNormal)).rgb * albedo;
//将折射和反射进行一个综合叠加,_RefractAmount可以认为是透光率,当它为1时,就是全透过而没有反射,为0时就是全反射跟镜子一样
fixed3 color = reflCol * (1 - _RefractAmount) + refrCol * _RefractAmount;
return fixed4(color,1);
}
ENDCG
}
}
}