Unity_Shader实战:从顶点法线到屏幕空间的轮廓光进阶
1. 轮廓光效果的基础原理
轮廓光效果在游戏开发中非常常见,比如角色被选中、处于危险状态或者释放技能时的视觉反馈。这种效果的核心思路是通过改变物体边缘的着色方式,让边缘呈现出与主体不同的颜色和亮度。在Unity中,我们通常使用Shader来实现这种效果。
理解轮廓光效果的关键在于掌握三个核心概念:法线方向、视角方向和它们的点积运算。法线是垂直于模型表面的向量,视角方向是从摄像机指向物体表面的向量。当这两个向量的夹角接近90度时,说明我们正在观察物体的边缘部分。
在实际Shader编写中,我们会先对模型顶点进行法线方向的外扩,然后在片元着色器中计算法线与视角方向的点积。这个点积值越小,说明该位置越接近物体边缘,我们就给它赋予更强的轮廓光颜色。
2. 顶点着色器的法线外扩技术
2.1 顶点外扩的基本实现
顶点外扩是轮廓光效果的第一步。我们需要在顶点着色器中将模型的顶点沿着法线方向向外移动一定距离。这个操作相当于给模型"套"上一层稍大的外壳。
v2f vert (appdata v) { v2f o; float4 new_vert = v.vertex + float4(v.normal,1) * float4(0.1,0.1,0.1,1); o.vertex = UnityObjectToClipPos(new_vert); o.uv = TRANSFORM_TEX(v.uv, _MainTex); o.w_normal = UnityObjectToWorldNormal(v.normal); o.w_vertex = mul(unity_ObjectToWorld,v.vertex); UNITY_TRANSFER_FOG(o,o.vertex); return o; }这段代码中,v.vertex + float4(v.normal,1) * float4(0.1,0.1,0.1,1)就是外扩的核心操作。0.1是外扩的距离系数,可以根据需要调整。值越大,轮廓光看起来就越"厚"。
2.2 坐标空间的转换
在顶点着色器中,我们需要处理多个坐标空间的转换:
- 模型空间:顶点的原始坐标
- 世界空间:将顶点转换到游戏世界的全局坐标系
- 裁剪空间:最终用于渲染的坐标空间
UnityObjectToClipPos和mul(unity_ObjectToWorld,v.vertex)分别完成了从模型空间到裁剪空间和模型空间到世界空间的转换。这些转换非常重要,因为后续的视角方向计算需要在世界空间中进行。
3. 片元着色器中的轮廓光计算
3.1 视角方向与法线的点积
在片元着色器中,我们需要计算当前像素的轮廓光强度。这个强度取决于视角方向与表面法线的夹角:
float3 view_dir = i.w_vertex - _WorldSpaceCameraPos; float3 w_normal = i.w_normal; view_dir = normalize(view_dir); w_normal = normalize(w_normal); float value = dot(view_dir,w_normal); value = (value < 0) ? 0 : value; value = pow(value,2); fixed4 col = fixed4(0,1,0,value);这里有几个关键点:
view_dir是从摄像机位置指向当前像素位置的向量dot(view_dir,w_normal)计算两个单位向量的点积,结果在-1到1之间pow(value,2)用于增强对比度,使轮廓光过渡更锐利
3.2 混合模式的选择
轮廓光效果通常需要与原始模型进行混合,这时就需要设置合适的混合模式:
Blend SrcAlpha One这种混合模式可以实现类似发光的效果,其中:
SrcAlpha表示使用源颜色的alpha通道One表示使用目标颜色的全强度
不同的混合模式会产生不同的视觉效果,开发者可以根据需要调整。比如Blend One One会产生更强烈的发光效果,而Blend SrcAlpha OneMinusSrcAlpha则更适合半透明效果。
4. 进阶技巧与优化方案
4.1 多Pass渲染策略
高质量的轮廓光效果通常需要多个Pass配合:
- 第一个Pass绘制外扩的黑色轮廓作为底色
- 第二个Pass绘制发光效果
- 第三个Pass绘制原始模型
这种多Pass方案虽然性能开销稍大,但能产生更丰富的视觉效果。在实际项目中,我们可以通过Shader LOD技术在不同性能的设备上使用不同复杂度的版本。
4.2 基于屏幕空间的优化
传统的顶点法线方法在某些复杂模型上可能会出现不一致的轮廓效果。更先进的方案是使用屏幕空间技术:
- 先渲染模型的深度和法线信息到纹理
- 在屏幕空间进行边缘检测
- 应用轮廓光效果
这种方法虽然实现复杂,但效果更加稳定,特别适合需要高质量轮廓的项目。
4.3 性能优化建议
轮廓光效果虽然美观,但需要注意性能影响:
- 尽量控制外扩距离,避免过度放大模型
- 对于移动平台,考虑使用更简单的混合模式
- 使用Shader变体为不同设备提供适当的效果级别
- 对于静态物体,可以考虑预计算部分光照信息
在实际项目中,我通常会创建一个可配置的Shader,通过参数控制轮廓光的颜色、强度、宽度等属性,方便美术人员调整效果。
