Spine的纹理压缩和半透显示的实现方法
这篇文章主要介绍“Spine的纹理压缩和半透显示的实现方法”,在日常操作中,相信很多人在Spine的纹理压缩和半透显示的实现方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Spine的纹理压缩和半透显示的实现方法”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
站在用户的角度思考问题,与客户深入沟通,找到十堰网站设计与十堰网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:成都网站制作、做网站、企业官网、英文网站、手机端网站、网站推广、域名注册、虚拟空间、企业邮箱。业务覆盖十堰地区。
纹理压缩
如果使用Spine的默认输出格式,是这样的
但是输出纹理的格式必须是未压缩的RGBA,如果你将图片格式改为ETC2或者ASTC,就会变成这样:
而这是绝对不能容忍的画面瑕疵。
ETC2的压缩质量绝不至于这样差,之所以会变成这样,在于Spine的默认输出格式是勾选了“预乘(premultiplied alpha)”参数的,这种做法会将图片原始的RGB通道预先乘以透明度保存成文件,显示时再用特殊的Shader乘回去。而ETC2的压缩算法并没有考虑过这种情况,由此导致了压缩质量降低。
而之所以Spine要使用预乘(premultiplied alpha),目的是为了解决透明图片的采样问题。
如图,左边的像素点是纯透明,右边的像素点是白色点,如果在红点处采样,获得的颜色值就是(0.5,0.5,0.5,0.5)
而正确的颜色值应该是(1,1,1,0.5),因为变化的只应该是透明度,不能因为达到边缘,连图像本身的亮度都降低。
预乘是能完美的解决这个问题的,它生成的像素点是(0x0,0x0,0x0,0),(1x1,1x1,1x1,1),采样后的颜色是0.5,0.5,0.5,0.5,但还原的时候还要再除以透明度,所以结果是(0.5/0.5,0.5/0.5,0.5/0.5,0.5)=(1,1,1,0.5),能够得到正确的值。
而除了预乘以外,还有另一个方法,就是让透明度为0的区域也填充有颜色。虽然有颜色,但因为透明度是0,看上去依然是透明,如图:
这种操作叫做出血(bleeding)。排除掉透明通道,可以看到出血后图片会复制边缘的像素到临近的透明区域。
虽然在某些特殊的采样角度下会有错误,但大部分情况没问题,而这种方法可以正常支持压缩纹理。
Bleeding可以在Spine的输出窗体设置,也可以勾选Unity图片的Alpha Is Transparency激活。
所以,我们应该取消Spine的premultiplied alpha选项,并勾选Bleeding选项来生成普通的图片(SpineEditorUtilities.cs有自动导入脚本,需要修改,否则图片参数会被它重新设置回去)。
Shader内,直接用最普通的方式绘制就好了。
瑕疵依然存在,但是回到了普通不透明图片的压缩质量水准。(具体质量要看使用的压缩格式,比如ASTC肯定要比ETC2更好)
——但是,Spine并不能直接用普通的Alpha Blend方式绘制贴图。
Spine的整个Shader都是基于Blend One OneMinusSrcAlpha,也就是预乘混合模式。它要求frag输出的颜色通道必须是预乘过Alpha通道的,所以,如果输入的图片是未预乘的,就要在采样后乘上透明度,再输出。
col = tex2D(_MainTex,xxxxx);
col.rgb *= col.a;
倒也简单,但为什么不直接将混合模式直接改成普通的Blend SrcAlpha OneMinusSrcAlpha呢?这就是下个话题的内容——
如何用一个PASS同时绘制Alpha Blend和Additive物体?
Alpha Blend 对应的是 Blend SrcAlpha OneMinusSrcAlpha,
相当于lerp(x.rgb,y.rgb,x.a),也就是result = (x.r, x.g, x.b) * x.a + (y.r, y.g, y.b) * (1 - x.a)
Additive则是result = (x.r, x.g, x.b) *x.a + (y.r, y.g, y.b)
而预乘混合Blend One OneMinusSrcAlpha是result = (x.r, x.g, x.b) + (y.r, y.g, y.b) * (1 - x.a),由于我们的纹理并不是预乘过的,而是在shader内相乘,所以是za = x.a,result = (x.r, x.g, x.b) * za + (y.r, y.g, y.b) * (1 - x.a),结果上和Alpha Blend相同。
但这里,za和x.a其实是不同的参数,我们可以让它是不同的值。如果za和x.a始终相等,就是AlphaBlend,如果让za=x.a,同时把x.a赋值为0,那么结果就是result = (x.r, x.g, x.b) *x.a + (y.r, y.g, y.b) * (1 - 0)。
和Additive是相同的。
Spine就是用这种方式同时显示AlphaBlend和Additive的图片的,它的顶点色是预乘过的,比如白色50%透明度就是(0.5,0.5,0.5,0.5),而如果是Additive的部分,白色50%透明度就是(0.5,0.5,0.5,0),因为透明度为0,所以输出的x.a永远都是0,效果就和Additive相同。
这样直接乘在颜色值上,然后用Blend One OneMinusSrcAlpha输出就可以了。
如果并不是将透明度重置为0,而是取一个中间值,还可以得到Alpha Blend和Additive中间的一个结果,在Alpha Blend太暗,Additive太亮的时候可以考虑(一般特效美术会选择用两个不同材质的纹理叠加,其实没必要)
如何做Spine的半透显示?
GrabPass是不可取的,因为存在透明物体的半透叠加。所以唯一的方法就是绘制到RT上再显示。
这时候就会遇到同时绘制Alpha Blend和Additive的问题。需要将摄像机的ClearColor设置成0,0,0,0(而不是0,0,0,1),Alpha的物体不能有ColorMask,Additive的物体需要ColorMask RGB(或者Alpha值为0)。
而显示RT时,必须用Blend One OneMinusSrcAlpha才能正确,否则Addtive的部分会没效果。
在这种情况下,设置为半透不能只修改alpha值,而且是要同时修改全部通道。
Blend One OneMinusSrcAlpha的物体只修改Color的Alpha值,相当于在AlphaBlend和Additive的显示效果之间调整,其实还挺便利的。这个中间的部分其实很适合用来模拟科幻场景的空气投影屏幕,因为AlphaBlend太实,Additive又太像光。
而真正的空气投影屏幕谁也没见过,毕竟都没诞生。
动态立绘应当启用Mipmap
很多人对Mipmap有误解,认为这是一个优化手段,而且是在处理远近物体的时候用的。
Mipmap最初的目的其实是为了处理纹理走样问题,优化只是一个副产品。
比较著名的示例是这个,又称为摩尔纹。
在立绘的情况下是这个,也算是纹理锯齿的一种。
至于出现的原因?纹理过滤时,图像的放大其实和PS里是类似的,也就是普通的2次线性插值,但是缩小时则完全不同。PS将图像缩小一倍,目标像素是对应的4个像素的平均值,但是在纹理过滤的时候,只会取的最近的1个像素的值。
很显然,这是为了效率考虑。
mipMap则将这4个像素的平均值预先储存了一份,这种情况下就可以直接取值了。其实效率是差不多的,但只有mipMap的才是正确的。
但在两个mipMap层级中间的时候,即使使用三向过滤或者多重采样过滤,会从两个mipMap层级之间插值,依然还是不正确的。因为采样了低分辨率的图像,还会导致图像产生模糊。
也就是在信号学所说的“在不提高分辨率的情况下,我们只能把信号中无法还原的高频部分抛弃掉,避免出现剧烈的变化,来实现所谓的反走样”,即是,想要反走样,就必须承担一定程度的模糊。想要反走样又不想模糊,只有一个办法,提升分辨率。
出现走样并不需要3D,只要你的图片存在两个像素被并进一个像素显示的情况(这通过缩放也可以达成),如果你的图片分辨率高于屏幕分辩率就更是如此。
不过,大部分走样效果并不明显,因为人眼会自己修正。但是,如果你的物体是运动的,走样就会产生另一种效果“闪烁”,这就非常明显了。上面的锯齿其实也算是一种线段的时隐时现。
如果你的图片是静态的,用一点点走样换取图片的“清晰”其实更合算。但是动态立绘,请不要。
当然,如果你的分辨率极高,高到人眼无法分辨,走样确实也无所谓了。
但这样的话,模糊也同样无所谓。
而且别忘了,Mipmap确实在很多情况下可以提高性能。
到此,关于“Spine的纹理压缩和半透显示的实现方法”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注创新互联网站,小编会继续努力为大家带来更多实用的文章!
网页名称:Spine的纹理压缩和半透显示的实现方法
新闻来源:http://cdiso.cn/article/gcspdc.html