前言
不管是UI、角色、场景、特效,也不管是2D还是3D都离不开纹理,所以这篇我们来详细说一下关于纹理要注意的一些标准与规范。
这里的美术规则上的标准并不是指风格之类的,而是指为了统一达到某种效果而制定的标准,下面会进行详细说明。
通常情况下,纹理是包体中占比最多的那一部分,运行时的内存消耗如果处理不当也会是瓶颈点,所以一定要做好优化处理。
美术规则
假如我们游戏内的主角采用的是PBR材质,那么一个材质对应的贴图有几张?每张贴图代表什么?每个通道又代表什么?
如果没有事先规划并约定好组合方式,那么就会带来很多不必要的麻烦。这里要制定的规则就是刚才所说的美术规则。
还是以上面的PBR例子为前提,PBR工作流分为两种,金属流与高光流,不同的制作方式生成的纹理效果也不一样,所需要的Shader也不一样,所以在前期需要统一制作方式。
贴图数量从优化角度上来讲,肯定是越少越好,所以就看怎么在效果上去找这个平衡点。
比如上面的金属工作流中的纹理数量一共是6个,那么在游戏内我们真的打算6个全部都用上吗,这显然是不明智的,所以折中一些我们可以考虑只用到以下几个纹理来实现我们想要的效果:
-
Albedo(基础色贴图)
-
Normal(法线贴图)
-
Metallic(金属度贴图)
-
Smoothness(光滑度贴图)
以上4张贴图是达到PBR的最低贴图,但是真的必须要用4张吗,有没有办法再节省一些呢?
有的,Metallic和Smoothness其实用到的都是单通道,其余通道完全没有必要使用,所以呢,我们可以把这两者合并成一张贴图,用Metallic做R通道,Smoothness做B通道,或者反过来,只要保证统一和Shader中识别就好了。这样最后我们就只用到了三张纹理来实现PBR的效果。
优化规则
美术方面的规则相对比较容易,性能优化方面才是重点,下面来逐个分析:
纹理开启Read/Write后,可以在运行时进行贴图合并操作,但是也将占用双倍的内存消耗。所以要根据情况进行选择(通常情况下是需要关闭的)。
首先解释下这个是什么意思,假设我们有一个3D场景,现在有一个建筑模型,上面有一张建筑的贴图,那么当这个建筑离我们很近时,我们希望贴图最大化以保证效果最清晰,所以我们将贴图出成1024x1024尺寸的大小,那么当这个建筑离我们很远的时候怎么办呢,难道还是要用这个1024x1024尺寸的贴图吗?
为了解决上面的问题,就需要引用LOD的概念,试想一下刚才的例子,如果是模型的话我们会怎么处理,肯定是模型LOD了,近的时候用面数高的模型,远的时候就用面数低的模型,那贴图自然我们也可以这样处理,MipMaps就是专门解决此问题而生的。
当我们开启了MipMaps后,贴图就会自动生成多级LOD图片,在运行时根据距离自动切换以解决上面的问题。但同时贴图也会增加大约30%的空间占用。
-
UI不开启(因为UI永远都在最上层,也不会有距离上的变化,所以没有必要增加那30%的空间占用)。
-
2D游戏所有图片都不开启。(2D游戏与UI的情况一样)
-
3D场景内的贴图开启。
-
角色和特效根据情况而定,如果视角中看到的远近差距比较大就开启,否则就不开启。
2,4,8,16,32,64,128,256,512,1024,2048,4096....
最优方案:长与宽尺寸一致,并且是2的幂次方,同时尺寸越小性能就越好!
如果纹理不是2的幂次方的话,则会在纹理导入设置面板中进行警告提示:
Only textures with width/height being multiple of 4 can be compressed to ETC1 format.( 只有宽/高的尺寸是4的倍数才能被压缩成ETC1格式。)
Only POT textures can be compressed to ETC1 format. ( 只有POT(Power of two,2的幂次方)的贴图才能被压缩成ETC1格式。)
ETC1格式是OpenGL ES图形标准的一部分,并且能被所有的Android设备所支持,性能较高。但是不支持透明通道,所以仅能用于不透明纹理。
如果纹理的原始尺寸不是2的幂次方的话,则可在Unity中可以通过导入设置来进行更正。
-
None不做处理
-
ToNearest(选择最接近的幂次方)
-
ToLarger(选择最大尺寸的幂次方)
-
ToSmaller(选择最小尺寸的幂次方)
-
None:513x1023
-
ToNearest:512x1024
-
ToLarger:1024x1024
-
ToSmaller:512x512
一张图片原始尺寸为2048x2048,在Unity中我们将最大尺寸设置为512x512,那么打包后这张图片到底是多大呢?是2048x2048,还是512x512呢?
经过测试,打包后的纹理尺寸是512x512,包体内已经不存在2048x2048的这张图片了,不相信的同学可以自行打包并且破解出来查看一下。
所以呢,美术同学完全可以出大图,然后在Unity中进行合适的尺寸设置就可以了,但有一点需要注意的是,在UI上还是尽量要出标准大小的图,不要过大也不要过小,因为UGUI中的Set Native Size是根据原始尺寸来设置的,合适大小的纹理方便我们制作UGUI界面。
这两者息息相关,透明度是指纹理是否含有Alpha通道,这分为原始资源和Unity内两种情况,也就是说同一个图片可以是原始带Alpha通道,但在Unity中不带Alpha通道,只需在导入设置中进行关闭Alpha即可。反之亦可,只是生成的Alpha有限制而已。
而图片格式,不管是jpg还是png,又或者是其他图片格式,在Unity中都一样,唯一的区别就是是否有正确的Alpha通道信息。
也就是说,如果我们希望图片有Alpha通道信息,那么就用png或者tga格式。如果我们希望图片不带Alpha通道信息,也还是可以用png或者tga。因为我们可以在Unity中将Alpha通道关闭。
建议游戏内的图片格式不要太杂,统一用png和tga就可以。有一点需要注意,IOS平台不支持DDS格式。
发现很多美术同学在ps中保存图片的时候喜欢用网页格式的方式来保存,说是可以减小图片容量大小。是,确实可以减小磁盘占用大小,但是呢,先不说压缩后的质量效果,这个磁盘占用大小对于Unity来说是毫无意义的,就像上面有说过的,不管是什么格式的图片,也不管图片是多大的磁盘占用,导入Unity后会被重新进行处理,所以美术输出的图片不要在乎什么磁盘大小,尽量保证图片的清晰度就可以了。
在Unity中我们通常需要对图片进行合适的压缩,否则的话会导致包体与内存占用很大。
首先我们应该尽可能的使用硬件支持的格式,比如Android平台的ECT1和IOS平台的PVRTC格式,这两种格式在相应的硬件上会发挥出最高效的性能。
那么我们来看下如何在Unity中进行设置ETC1格式:
-
在纹理的导入设置界面中,将Alpha Source设置为None.
-
Compression设置为非None.
-
然后当我们切换到Android平台时就可以在纹理导入界面最下方看到ETC的字样。
假如我们把Alpha Source设置为非None呢?
会发现纹理格式变成了ETC2,这是由于ETC1不支持透明通道的原因,所以才会被压缩成支持透明通道的ETC2,但是ETC2只在OpenGL ES3.0及以上的Android设备才支持(在此设备上也是硬件直接支持的,性能也很高效,只不过ES2.0用不了,ETC1要想实现透明通道的话只能采用通道分离了)。
只需把Compression设置为None即可,带透明通道的纹理会自动压缩成RGBA32位的格式,不带透明通道的纹理会被压缩成RGB24位的格式。
但是RGBA32位的性能相比较差,在不得已需要高保真的纹理才会采用此格式。通常情况下我们可以折中选择RGBA16位的格式,在Unity中需要在相应平台下勾选Override for Android才能进行设置(手动选择RGBA16)。
RGBA32>RGBA16>ETC1/ETC2/PVRTC
ETC1/ETC2/PVRTC>RGBA16>RGBA32
两者的排序完全是反过来的,所以最终还是要根据具体情况来设定,不能整个工程统一设置就不管了,还是需要按模块按需求来一一设置。
最后
欢迎大家关注更多干货的公众号:Unity技术美术 ( ID:gh_8b69cca044dc )