ai钢笔工具怎么描线_用SDF处理卡通内描线的锯齿问题

本文介绍了如何通过SDF(Signed Distance Field)处理卡通内描线的锯齿问题,探讨了本村线、Mesh描线和后处理描线等方法的优缺点,并详细阐述了SDF的生成过程和Shader实现,以达到与外描线一致的视觉效果。
摘要由CSDN通过智能技术生成
db9b9b3260f74bf83209e7a70c6e44ff.png

只要是实际做过卡渲的人,就会遇到斜线锯齿的问题。这是因为内描线在纹理里只占用了1到2个像素的大小,斜过来肯定会变成这样。

7d31725db0e40ecfe41fd8e8b6186e6a.png

增加纹理的尺寸自然可以解决问题,但让大片低细节的纹理占用如此大的面积实在太浪费了。而内描线占用的区域又大,分UV2也解决不了问题。

目前常用的内描线精度解决方法有以下几种。

1.本村线

可以看到,纹理里的横线和竖线都不会出现上述的问题,因为它们本身就是平直的。所以可以通过调整UV让所有的线正好处于横线或者竖线的位置。

这种做法只需要调整UV,是GGXX所推行的方案,所以也被很多人认为的这个问题的正规解法。

但实际操作过就明白,这个方法本身是非常麻烦的,如果对已经做好的图修改则更加困难,而且遇到三角形,曲线的时候也不好处理,也不方便做UV的合理布局。

如果描线少还好,在内描线较多的家具、建筑等物体内,它实际上是一个无法完成的任务。你要和美术有仇就可以让他拉这个。

2.Mesh描线

我们可以在有描线的地方单独拉UV,然后指向贴图的一个纯色区域。

这也是一种比较常用的做法(因为也没啥别的办法了),但依然比较麻烦,而且对曲线不友好。同时它会产生比较多的多余顶点。

锯齿问题用几何反锯齿一并处理就好。

3.后处理描线

通过在顶点信息里记录区域信息,绘制到屏幕缓存上,就能利用后处理在区域边缘生成描线。可以和普通的后处理外描线一起处理。

后处理本来就容易生成一些backface无法生成成描线(鼻头等等),而且更符合画师的“思路”,也容易实现软边缘、粗描线、等宽描线,但问题就在于性能和可控性上。

通常不予考虑。


这次我们用的是SDF的做法,将内描边单独分层并生成SDF,然后用SDF的渲染方法显示。

为了避免瑕疵,原始的内描边图片精度要高。我用了PS的钢笔工具勾线,然后绘制到一张8192的贴图上。

a49c8c28900383c91ea73aec48fd47d5.png
b7a6d001b8488a64e29f10e95bcab338.png

然后用这个工具来生成SDF。

http://www.lonesock.net/files/SDFont.zip

(没有用户界面,把PNG拖到SDFont.exe里就行)

注意输出的SDF时要指定大小(我指定是的512,也就是原纹理大小),而且不要再进行缩放了,否则依然会有失真。

SDF图的局部:

e0f7150dc3b73f75355222ddc8a0fb8a.png

然后用Shader把它显示出来就行了,主要代码如下

fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
fixed r = 0.5 - tex2D(_LineTex, i.uv).a;
col.rgb = lerp(col.rgb, _LineColor, step(r,_LineWidth));
return col;
}

初步效果:

87b502d6e867bdf226722602b3b66c93.png

由于使用的是step,所以会有锯齿。虽然也可以用smoothstep来反锯齿,但这里用的是Cell光照里用的一种反锯齿方法,可以确保边缘不模糊,这样观感就能和外描线一致。

//用这个代替原本的step
half stepAntiAliasing(half y, half x)
{
half v = x - y;
return saturate(v / fwidth(v));
}
ae0aee1c9af4442e56d863e245eb6f66.png

之前的方案,由于外描线通常会做成粗细不随距离变化而改变,导致内描线和外描线的表现在缩放后会完全不同。这个瑕疵其实很明显。

而使用SDF描线,利用SDF的性质就能实现内描线粗细的动态设置。和外描线一样处理,就能和外描线的粗细保持一致了。

fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
fixed r = 0.5 - tex2D(_LineTex, i.uv).a;
half w = _LineWidth * i.vertex.w;//乘下Clip空间的w,缩放线宽
col.rgb = lerp(col.rgb, _LineColor, stepAntiAliasing(r,w));
return col;
}

但是由于SDF的精度有限,过细的线会导致锯齿再度出现。

9aad8c28cc93e8c9fd0cfdbc97ea7a22.png

而且线框不能超出允许范围,需要用参数约束实际粗细的范围。

fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
fixed r = 0.5 - tex2D(_LineTex, i.uv).a;
half w = clamp(_LineWidth * i.vertex.w, _LineMinWidth, _LineMaxWidth);
col.rgb = lerp(col.rgb, _LineColor, stepAntiAliasing(r,w));
return col;
}
1e5a68d9a8fe596c88d1af7e345478ed.png

声明:发布此文是出于传递更多知识以供交流学习之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与我们联系,我们将及时更正、删除,谢谢。

作者:flashyiyi

来源:https://zhuanlan.zhihu.com/p/113190695

More:【微信公众号】 u3dnotes

97135728002b4ec8346ebbe672d085fb.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值