定义
当光线照射到物体表面时,一部分发生反射,一部分进入物体内部,发生折射或散射。
效果
思路
近似公式如下:
实现
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Custom/Fresnel" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_FresnelScale("_FresnelScale", Range(0,1)) = 0.5
_Cubemap ("CubeMap", Cube) = "_Skybox" {}
}
SubShader {
Tags { "RenderType"="Opaque" "Queue"="Geometry"} // 渲染类型::不透明物体 渲染队列:不透明几何体
Pass {
Tags { "LightMode"="ForwardBase" } //前向渲染
CGPROGRAM
编译PassType.ForwardBase所需的所有变体
#pragma multi_compile_fwdbase
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "AutoLight.cginc"
fixed4 _Color;
samplerCUBE _Cubemap; //定义立方体纹理的数据类型
float _FresnelScale;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : SV_POSITION;
float3 worldPos : TEXCOORD0;
fixed3 worldNormal : TEXCOORD1;
fixed3 worldViewDir : TEXCOORD2;
fixed3 worldRefl : TEXCOORD3;
SHADOW_COORDS(4)//声明了一个名为_ShadowCoord的阴影纹理坐标变量。
};
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.worldRefl = reflect( o.worldViewDir, o.worldNormal);
//refract函数计算折射的出射光线的方向,
//第一个参数是入射方向,必须归一化
//第二个参数是表面法线,需归一化
//第三个参数是入射光线所在介质的折射率和折射光线所在介质的折射率的比值
//返回的是折射光线的方向
TRANSFER_SHADOW(o);
//SHADOW_COORDS这个宏后面的参数是指第几个通道,不要和其他的出现冲突,也就是要改变投影的颜色话必须要占用一个通道。
//在顶点处理器里调用TRANSFER_SHADOW。
//然后像素着色器调用UNITY_LIGHT_ATTENUATION,返回的就是这个像素是否存在阴影中。
//此时得到的atten就是综合了衰减和阴影的结果,可以用其来作为【衰减】和【阴影】的因子与最终的光照颜色相乘。
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLight = normalize( UnityWorldSpaceLightDir(i.worldPos));
fixed3 worldViewDir = normalize(i.worldViewDir);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 diffuse = _LightColor0.rgb * _Color.rgb * saturate( dot( worldNormal,worldLight ));
fixed3 reflection = texCUBE( _Cubemap, i.worldRefl ).rgb ; //对立方体纹理采样(提供折射的方向),
//使用菲尼尔公式计算如下:
fixed fresnel = _FresnelScale + (1 - _FresnelScale) * pow ( 1 - dot( worldViewDir, worldNormal ),5 );
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
//根据菲尼尔值, 在漫反射与反射之间取值, 应用于物体边界处,产生更加真实的效果。
fixed3 color = (ambient + lerp( diffuse,reflection, saturate(fresnel)) * atten); //lerp(a,b,w) 根据w返回a到b之间的插值 根据折射程度变量,返回插值。
return fixed4(color,1.0);
}
ENDCG
}
}
FallBack "Reflective/VertexLit"
}