unity 3d物体描边效果_轮廓&描边—基础
轮廓描边是游戏渲染中的常用技术,一种是用于风格化的游戏表现,如塞尔达传说,图片如下(现拍的比较垃圾,有空再补),在这张图片中,很明显得可以看出角色的周围有一层白色的轮廓线,那个可不是锯齿哦。还有一种用法是为了显示被遮挡的物体目标,这种也十分常见,比如刺客信条中可以显示隐藏的物体,守望先锋中能够显示不在视野范围内的队友,像黑寡妇的大招等。描边的方法有很多种,最简单的方式直接是在shader...
轮廓描边是游戏渲染中的常用技术,一种是用于风格化的游戏表现,如塞尔达传说,图片如下(现拍的比较垃圾,有空再补),在这张图片中,很明显得可以看出角色的周围有一层白色的轮廓线,那个可不是锯齿哦。
还有一种用法是为了显示被遮挡的物体目标,这种也十分常见,比如刺客信条中可以显示隐藏的物体,守望先锋中能够显示不在视野范围内的队友,像黑寡妇的大招等。
描边的方法有很多种,最简单的方式直接是在shader里实现的,这里就简单介绍两种。第一种仅基于法线去做偏移。另一种基于法线加视线的夹角描述边缘,这两种方法的原理都很好理解。
偏移的本质是对边缘进行扩张,它需要两个PASS,一个用来剔除物体正面进行边缘绘制,一个用来正常绘制物体正面。先上Unity中的效果图,从第一张到第二张表示GPU的绘制顺序,红色是设置的边缘色,可以看出来,渲染顺序是先从背面对物体进行了扩张,再将物体的正面按正常方法绘制上去,这样就有了边缘的效果。
根据原理,在U3D里实现起来就很简单了,只需要乘上对应的转换矩阵,将物体的顶点和法线转换到投影空间中(可以简单理解为模型空间到摄像机空间再投影到屏幕空间的过程),再根据一个权重值对顶点进行偏移即可。
float3 normal = mul((float3x3) UNITY_MATRIX_IT_MV, v.normal);
normal.xy = mul((float2x2) UNITY_MATRIX_P, normal.xy);
o.pos.xy += _OutlineVal * normal.xy;
这里我只给物体加了经典的Lambert漫反射(物体会有明暗)和高光反射(局部显得比较亮)。如果是风格化的游戏,一般会有其独特的光照方式,比如上图塞尔达传说中,仔细观察的话会发现人物以及场景表现都会有明显的色块,这种实现起来也不难,只需要添加一个多段的参数区间,实现漫反射或高光反射的突变即可。
第二种常用的描边方法是利用视线与法线的夹角,可以想象一下,它们的夹角越大,则说明越接近边缘,反之则是面向视角的一面。因此实现方法也可以简单写成:
float outline = pow(1.0 - saturate(dot(viewDir, normal)), _OulineVal);
color *= outline;
除此之外,边缘检测还有基于图像后处理的方法,即每次绘制对场景中透明或是不透明的对象执行完毕后,对整个屏幕空间进行边缘检测,检测方法是根据传进来的纹理坐标对法线和深度进行采样,如果不一样就表明是边缘。法线和深度信息在Unity中是可以直接获取的,Shader中的内置变量是_CameraDepthNormalsTexture,在fragment中对该图进行采样并进行比较即可。比较方法参考利用Robert算子进行卷积操作。轮廓描边的方式有许多,它们也是各有优缺点,需要灵活应用,我看过一篇关于崩三的文章有提到它们的勾边方法是场景用边缘检测,而人物用backface或是一种连接轮廓线的方法。
这里有利用到深度信息,值得注意的是,在写shader的过程中,不能滥用深度,否则每一个物体对象相机都要输出一张深度图,这样积少成多也会影响到性能,对应也有优化的方法。
如果在绘制边缘的Pass中添加深度检测的判断,就可以判断对象是否在另一个物体的后面,这样就可以实现显示被遮挡的物体对象了,根据需求还可以做成各种不一样的效果,如对边缘进行高亮、模糊或者直接显示一个纯色。U3D里只需要在PASS前面增加一行ZTest Greater,这样GPU在进行绘制的时候就在执行该PASS时候将对应的深度值与帧缓存中深度值进行判断,按照默认的设置,深度值越大越远离摄像机,将深度检测改为Greater比较方式后,就可以控制渲染方式,达到图中的效果。
写在后面,风格化的渲染还是很有趣的,我也是最近才在工作闲暇的时候研究一下,卡通渲染还会不经意间拨动大家的童心。想到之前看的无敌破坏王2,深深被迪士尼的离线渲染所折服,其中的光影细节,简直是超棒了!
More:【微信公众号】 u3dnotes
免责声明:部分资源收集整理自网络,版权归原作者所有,仅作学习交流使用,不用于任何商业途径,如不慎该资源侵犯了您的权利,请通知我及时删除,谢谢。
更多推荐


所有评论(0)