当我们在玩部分游戏的时候会发现,有些游戏的模型的边缘会有泛光效果,这种效果顿时给人一种高大上的感觉,今天就用shader来实现一个边缘泛光的效果。
原理
当我们的摄像机面正向面对物体的时候,模型的法线越平行于于摄像机的视线方向的时候那么夹角就越小,越是边缘的地方夹角越接近90度,所以我们可以用视线的方向和模型法线的方向进行点乘,越是边缘点乘结果越接近0。
Shader "MyShader/RimShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Diffuse("Diffuse", Color) = (1,1,1,1)
_RimColor("Rim Color", Color) = (1,1,1,1)
_RimPower("Rim Power", Range(0.0, 10)) = 0.3
_RimIntensity("Rim Intensity", Range(0.0, 50)) = 3
}
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal:NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 worldNormal : NORMAL;
float4 worldPos : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Diffuse;
float4 _RimColor;
float _RimPower;
float _RimIntensity;
v2f vert (appdata v)
{
v2f o;
float4 worldPos;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
//转化为世界空间下的顶点坐标
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
//转化为世界空间下的法线向量
o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
//----------------半兰伯特模型---------------------------------------
fixed4 color = tex2D(_MainTex, i.uv);
//归一化世界法线
fixed3 worldNormal = normalize(i.worldNormal);
//光照方向归一化
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
//环境光计算
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Diffuse.xyz;
//半兰伯特模型计算公式
fixed halfLambert = dot(worldNormal, worldLightDir)*0.5 + 0.5;
//最终漫反射结果
fixed3 diffuse = _LightColor0.xyz*_Diffuse.xyz*halfLambert + ambient;
//----------------边缘光计算----------------------------------------
//获取摄像机世界空间下的视角的方向,并归一化
float3 worldViewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
//通过点乘来判断该点位置是否在边缘,越是边缘夹角越接近90度
float rim = 1 - max(0, dot(worldViewDir, worldNormal));
//计算边缘光
fixed3 rimColor = _RimColor * pow(rim, 1 / _RimPower)*_RimIntensity;
//最终光照结果
fixed3 finalColor = color.rgb* diffuse + rimColor;
return fixed4(finalColor,1);
}
ENDCG
}
}
FallBack "Diffuse"
}