【旧博客转移 - 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着色器去输出渲染,就可以看到效果了