给物体边缘加高光轮廓的办法,付Demo(增加一组算法)

2015年03月15日 18:07 0 点赞 0 评论 更新于 2025-11-21 17:14

最近我迷上了Unity,经过一番研究,对一些技术点有了些许心得,在此分享给大家。

1. 边缘光方法(Rim Light)

Unity官方教程中有相关例子,其核心代码为:

half rim = 1.0 - saturate(dot (normalize(IN.viewDir), IN.worldNormal));
o.Emission = _RimColor.rgb * pow (rim, _RimPower);

其中,IN.viewDir 是当前视角向量,IN.worldNormal 是物体的法线。dot 函数用于计算视角向量和法线向量的点积,该点积的值等于视角向量和法线向量夹角的余弦值(Cos值),具体情况如下图所示:

Cos值的范围是从1到0,通过 1 - Cos 计算后,其范围变为从0到1,并且在夹角为90度时达到最大值。这一特性恰好可以用来模拟侧光的强度,因为与视角成90度的部分光线最强,也就是我们所需要的边缘光。

为了强化边缘发亮的效果,我们使用 pow 函数(即 rim_RimPower 次方)对这个值的变化率进行放大。下面进行对比说明:

  • 没有经过 pow 函数放大变化率的边缘光,由于 cos 函数的变化比较平缓,会导致大片区域被染色。
  • 经过 pow 函数放大变化率后,就能够呈现出边缘发亮的效果。下图大致体现了放大前后变化率的曲线。

这种边缘光方法在处理复杂几何形体时效果较好。然而,在处理平直的物体时,边缘光会变得不明显;对于方形物体,边缘光几乎难以看见。这是因为正方形每个面的法线方向都是一致的,无法体现出变化和轮廓。

另外,这种方法在描绘凹的几何体时,凹的部分(包括法线贴图造成的凹凸)的边缘也都会被绘制出来,但这并非真正意义上的边缘轮廓,仅仅是一种侧光效果。

该方法的优点在于实现简单,只需对官方的Shader进行改写,添加计算边缘光的代码,即可实现边缘光效果。在需要显示边缘光时,动态切换Shader即可,基本不需要代码干预,效率较高。

2. 单个物体轮廓渲染方法

这种方法的实现较为复杂,下面仅介绍大致思路:

  1. 将需要渲染轮廓的物体放置在一个单独的层中。
  2. 在该层中设置一个禁用(disable)的摄像机,将其 culling mask 设置为渲染物体所在的层。
  3. 主摄像机的 culling mask 保持为 everything
  4. 生成一个 RenderTexture
  5. 使用 RenderWithShader 方法,让禁用的辅助摄像机指定一个单色渲染的Shader(只需要轮廓,不需要进行光照计算),将物体的轮廓渲染到一个 RenderTexture 中。
  6. 继续使用单色Shader,采用类似Unity自带Blur的方法,将物体轮廓图上下左右移动几个像素,然后叠加在一起,得到一个比原来轮廓更大、边缘模糊的轮廓图,并将其存储到一个临时的 RenderTexture 中。
  7. 将大的轮廓图和原始轮廓图进行叠加,消除中间清晰轮廓的部分,从而得到一个完整带透明度的轮廓图。
  8. 在主摄像机的 OnRenderImage 函数中,将这个透明轮廓图和主摄像机渲染的图像进行Alpha混合,即可产生一个完整且不被遮挡的轮廓效果。

效果如下图所示,明显比侧光效果要好很多。不过,这种方法的开销较大,并且需要较多的代码支持。

小Demo说明

附上一个小Demo,其中包含了上述两种方法。在Demo中,鼠标可以控制镜头进行平移、旋转和缩放操作。鼠标划过物体时显示侧光效果,点击物体时显示清晰轮廓效果,再次点击则消除效果。同时,还可以设置边缘颜色、宽度和模糊度。目标物体按照材质进行分组,方便处理,并且可以将轮廓变换成细线,颜色设置为绿色。

优化内容

对代码进行了优化,减少了一组 RenderTexture 的使用,因为该资源比较耗费性能,同时也减少了计算的次数。另外,增加了一组可以同时完成模糊和裁剪操作的Shader,这种Shader在资源使用上更加节省,但边缘会相对模糊。

两种算法效果比较

  • 多次模糊再裁剪的算法:边缘光滑,模型的锯齿在边缘线处被平滑处理,但开销略大。
  • 一次同时模糊、裁剪算法:边缘较模糊,锯齿也被等比放大,但开销较省。

可以根据实际需求选择合适的算法。总体而言,由于这是全屏效果,与被渲染物体的数量无关,所以基本上显示轮廓物体的多少不会影响效率。

附件里包含了两种方法的代码和Shader。其中,RimLight方法一个Shader就能对应一种材质效果,不需要代码支持;后一种方法则需要代码和Shader配合,类似官方的Image Effect效果。

作者信息

boke

boke

共发布了 3994 篇文章