【舊博客轉移 - 2016年1月3日 16:40 】
最近學習了一些Shader效果,打算把學到的知識總結一下,這篇講一下這種輪廓發光的效果(如下圖所示),也有一些地方管這個叫X光


1.原理
可以看到圖上的藍色人物,邊緣顏色比較深,而中間的比較淺,這是利用法線跟視線向量的點乘值計算出顏色濃度來實現的
2.代碼
Shader "lijia/Xray" { Properties { _RimColor("RimColor", Color) = (0, 0, 1, 1) _RimIntensity("Intensity", Range(0, 2)) = 1 } SubShader { Tags {"Queue"="Transparent" "RenderType"="Opaque" } LOD 200 Pass { Blend SrcAlpha One//打開混合模式 ZWrite off Lighting off CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal:Normal; }; struct v2f { float4 pos : SV_POSITION; fixed4 color:COLOR; }; fixed4 _RimColor; float _RimIntensity; v2f vert (appdata v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); float3 viewDir = normalize(ObjSpaceViewDir(v.vertex));//計算出頂點到相機的向量 float val = 1 - saturate(dot(v.normal, viewDir));//計算點乘值 o.color = _RimColor * val * (1 + _RimIntensity);//計算強度 return o; } fixed4 frag (v2f i) : COLOR { return i.color; } ENDCG } } }
float3 viewDir = normalize(ObjSpaceViewDir(v.vertex));//計算出頂點到相機的向量
這一句是調用了UnityCG.cginc庫中的ObjSpaceViewDir方法,獲得viewDir
inline float3 ObjSpaceViewDir( in float4 v ) { float3 objSpaceCameraPos = mul(_World2Object, float4(_WorldSpaceCameraPos.xyz, 1)).xyz; return objSpaceCameraPos - v.xyz; }
翻看UnityCG中ObjSpaceViewDir方法的源碼,發現它是拿到_WorldSpaceCameraPos(世界坐標相機的位置),左乘World2Object矩陣,轉成模型坐標系
最后objSpaceCameraPos - v.xyz (向量相減),得到viewDir向量
viewDir跟normal的點乘值,就表示兩個向量的夾角大小
- 夾角 < 90°時,點乘>0
- 夾角 = 90°時,點乘=0
- 夾角 > 90°時,點乘<0
邊緣的頂點,點乘值接近90度,也就是值接近0,所以這里用1減去點乘值( saturate函數:返回0-1之間的數 )
float val = 1 - saturate(dot(v.normal, viewDir)); 計算出顏色強度后,把顏色傳給fragment着色器去輸出渲染,就可以看到效果了