查看原文
其他

中枪了没有!游戏开发过程中容易忽略的事

2016-07-13 张大伟 Gad-腾讯游戏开发者平台
在你的游戏开发过程中,有很多东西都有可能会出错。比如你的模型可能有太多的三角形而超出了你的目标平台可以处理的能力、你选择的算法可能对于你的CPU来说计算量太大了或者你可能使用了太多材质以至于批次合并渲染没有办法有效地工作。这些都是棘手的问题,而你作为一个游戏开发者应该永远记住,要保持视觉效果和性能之间的良好平衡。然而,有一些事情是如此的简单,我们会经常忘记它们的存在,但是这些简单的事情可以对你的游戏性能产生严重的影响。
纹理的导入设置
当你添加一个纹理到你的项目的时候,Unity在背后做了很多魔术般的工作-它会把纹理基于当前的纹理导入设置转换为一个合适的格式。在大多数情况下默认设置足够好,但Unity没有办法知道这对于用户来说是否已经足够好了,除非你明确告诉Unity这一信息。这正是需要你介入的步骤。 要访问纹理的导入设置的话,只需要选择你希望更改的一个或者多个纹理。你的检视窗口看起来或多或少是这样的
在这个窗口,还有3个主要的事情你应该留意下

纹理的类型

纹理类型是一种告诉Unity这个纹理将被用于什么地方的方式。除了高级以外的所有这些选项都将按照选定的目的调整你的纹理内部设置来尽可能的按照你的要求来调整到最佳设置。需要注意的是,标记为“Texture ”类型的纹理就是三维空间使用的简单漫反射纹理,这在三维游戏中应该是最常见的纹理类型。关于纹理类型的描述可以在官方手册中找到。 提示下风险:如果把纹理类型设置错了可能在起初并不明显,但是你会得到一些性能损失。有些时候,一些着色器代码需要某些类型的纹理才能够正常工作(举个简单的例子来说,在使用凹凸映射纹理的时候就必须有一张纹理的类型被设置为法线贴图)。凹凸纹理映射是一种纹理混合方法,它可以创建三维物体复杂的纹理外观表面。普通的纹理映射只能模拟比较平滑的三维物体表面,难以显示表面高低起伏、凹凸不平的效果。凹凸纹理映射能够通过一张表示物体表面凹凸程度的高度图(称为凹凸纹理),对另一张表示物体表面环境映射的纹理图的纹理坐标进行相应的干扰,经过干扰的纹理坐标将应用于环境映射,从而产生凹凸不平的显示效果。凹凸纹理映射通常由三张纹理映射图组成,第一张纹理图表示物体表面原始纹理颜色,第二张凹凸纹理图表示物体表面凹凸的高度起伏值,用来对下一张环境纹理图坐标进行干扰,第三张纹理图表示周围镜面反射或漫反射光照的环境光照映射图。
尺寸大小


在这里,你可以决定你的纹理的尺寸大小应该为多大,以及这个纹理应该如何存储在设备内存中。要注意的是,这里面的设置有一个最大尺寸,而不是尺寸?这主要是因为你可以在质量设置里面来给你的游戏中的所有纹理降低纹理的分辨率。

在这里将最大尺寸设置为2048并不能保证这个纹理的大小就是这个尺寸,即使在质量设置里面将纹理质量设置为最高也不行。如果你的原始纹理文件不够大的话,这个纹理的分辨率将会比较低。了解到这一点以后,让纹理的尺寸比你需要的尺寸大一些是一个非常好的实践,因为这样做的话,你就可以比较自在的放缩这些纹理了。
提示下风险:某些模型可能在屏幕上表现的非常小而这些模型的纹理可能有一个非常高的分辨率。你可以通过设置你的场景渲染为Mipmap来识别出这些物体

纹理采样的格式
纹理采样也被称为纹理过滤,我们的纹理是要贴到三维图形表面的,而三维图形上的像素中心和纹理上的像素中心并不一致(三维图形上的像素中心不一定对应纹理上的采样中心点),大小也不一定一致。当纹理大于三维图形表面时,会导致一个像素被映射到许多纹理像素上;当纹理的大小小于三维图形表面时,许多个象素都映射到同一纹理。当这些情况发生时,贴图就会变得模糊或发生错位以及马赛克。要解决此类问题,必须通过技术平滑两者之间的对应。这种技术就是纹理采样。不同的过滤模式,计算复杂度不一样,会得到不同的效果。过滤模式由简单到复杂包括:Nearest Point Sampling(最近点采样),Bilinear(双线性过滤)、Trilinear(三线性过滤)、Anisotropic Filtering(各向异性过滤)。
最近点采样是这个最简单的纹理采样方式,每个像素的纹理坐标,并不是刚好对应纹理上的一个采样点纹理,怎么办呢?最近点采样取最接近的纹理像素进行采样。当纹理的大小与贴图的三维图形的大小差不多时,这种方法非常有效和快捷。如果大小不同,纹理就需要进行放大或缩小,这样,结果就会变得矮胖、变形或模糊。
双线性过滤以像素对应的纹理坐标为中心,采该纹理坐标周围4个像素,再取平均,以平均值作为采样值。双线性过滤会使得像素之间的过渡更加平滑,但是它只作用于一个MipMap的等级上,它会选取纹理像素和图像像素之间大小最接近的那一层MipMap进行采样。当和图像像素大小匹配的纹理像素大小在两层Mipmap 的等级之间时,双线性过滤在有些情况效果就不太好。于是就有了三线性过滤。
三线性过滤以双线性过滤为基础。会对图像像素的大小与纹理像素的大小最接近的两层Mipmap等级分别进行双线性过滤,然后再对两层得到的结果进行线性插值。三线性过滤在一般情况下效果非常理想了。但是到目前为止,我们均是假设是纹理投射到屏幕空间是各向同性的。但是当各向异性的情况时,效果仍然不理想,于是产生了各向异性过滤。
各向异性过滤是用来过滤、处理当视角变化导致3D物体表面倾斜时造成的纹理错误。传统的双线性和三线性过滤技术都是指“Isotropy”(各向同性)的,其各方向上矢量值是一致的,就像正方形和正方体。三线性过滤原理同双线性过滤一样,都是将相邻像素及彼此之间的相对关系都记忆下来,然后在视角改变的时候绘制出来。只不过三线性过滤的采集范围更大,计算更精确,画面更细腻,当然占用资源也更多。各向异性过滤技术的过滤单元并不是“四四方方”的,其典型单元是矩形,还可以变形为梯形和平行四边形。画面上的一个象素,在一个方向上可以包含不同纹理单元的信息。这就需要一个“非正多边形”的过滤单元,来保证准确的透视关系和透明度。不然,如果在某个轴上的纹理部分有大量信息,或是某个方向上的图象和纹理有个倾角,那么得到的最终纹理就会变得很滑稽,比例也会失调。当视角为90度,或是处理物体边缘纹理时,情况会更糟。各向异性过滤是最新型的过滤方法(相对各向同性2/3线性过滤),它需要对映射点周围方形8个或更多的像素进行取样,获得平均值后映射到像素点上。对于许多3D加速卡来说,采用8个以上像素取样的各向异性过滤几乎是不可能的,因为它比三线性过滤需要更多的像素填充率。但是对于3D游戏来说,各向异性过滤则是很重要的一个功能,因为它可以使画面更加逼真,自然处理起来也比三线性过滤会更慢。 
Mipmap
Mipmap是目前应用最为广泛的纹理映射技术之一。它是将低一级图像的每边的分辨率取为高一级图像的每边的分辨率的二分之一,而同一级分辨率的纹理组则由红、绿、蓝三个分量的纹理数组组成。由于这一个查找表包含了同一纹理区域在不同分辨率下的纹理颜色值,因此被称为Mipmap。 MIP map技术与材质贴图技术结合,根据距观看者远近距离的不同,以不同的分辨率将单一的材质帖图以多重图像的形式表现出来并代表平面纹理:尺寸最大的图像放在前面显著的位置,而相对较小的图像则后退到背景区域。每一个不同的尺寸等级定义成一个MIP map水平。MIP map技术帮助避免了不想要的锯齿边缘(称为锯齿状图形)在图像中出现,这种锯齿状图形可能是由于在不同分辨率下使用bit map图像产生的。
Mipmap可以用一个四棱锥来描述。,如图所示。该四棱锥的总层数为4 ,S为初始纹理图像每边的分辨率。若最底层图像为给定的原始图像,则第二层图像可以由最底层图像与边长为2个象素的正方形滤波器做卷积运算得到。一般的,第n 层图像可以由第(n-1) 层图像与边长为2 个象素的正方形滤波器做卷积运算得到。例如,某一纹理图像的Mipmap的层数为10层,第10层图像为一个象素,它由原始图像经与边长为512个象素的正方形滤波器做卷积运算压缩得到,其分辨率为1×1。
Mipmap纹理映射在确定屏幕上每一象素内可见的平均纹理颜色时需要计算三个参数,即屏幕象素中心在纹理平面上映射点的坐标和屏幕象素内可见表面在纹理平面上所映射的边长d。其中 取屏幕象素内可见表面在纹理平面上近似正方形映射区域的中心,d取该近似正方形的边长。显然,d决定了应该在哪一级分辨率的纹理图像平面上查找Mipmap表。
虽然我们很容易通过纹理映射变换和取景变换的逆变换求得屏幕象素中心在纹理平面上映射点的参数坐标,但是d的值却不容易确定。一般而言,d的取值应使得在纹理平面上以为中心,d为边长的正方形尽可能地覆盖屏幕象素地实际映射区域,从而可取该正方形内平均纹理颜色值作为屏幕象素实际映射区域的平均纹理颜色的近似值。在实际处理时,可取d为屏幕象素在纹理屏幕上映射区域的最大边长。

批次合并渲染
批次合并渲染器是大部分引擎提高渲染效率的方法,基本原理就是通过将一些渲染状态一致的物体合成一个大物体,一次提交给显卡的gpu进行绘制,如果不合并批次的话,就要提交给很多次,这可以显著的节省渲染调用,实际上这主要节省了cpu的时间,cpu从提交多次到提交一次,对显卡的gpu来说也不用多次切换渲染状态。当然能合并批次的前提一定是渲染状态一致的一组物体。Unity的批渲染分为两种,动态批次合并和静态批次合并。 
静态批次合并
静态批次合并的要求是要合并的物体必须使用同一张材质,然后在编辑器里设置为需要静态批次合并。这样就带来一个静态合并批次的特点,静态批次合并是无法运动的。所以一般制作流程上,对于场景这些静态的物体都采用静态批次合并,美术会根据场景的规模,将相邻的一片物件的贴图合并到一张或几张1024或512的大图上,这样这些物件可以使用同一个材质,就可以静态批次合并在一起,大幅节省渲染调用。静态合并批次的时候Unity会在运行时生成一个合并的大模型,并且为这个模型指定一张共同的贴图,所以能够合并在一起的批次的数量是有限的,如果合并在一起的批次的顶点数过多,它就会自动分成两个合并批次,一个静态合并批次的上限大约在60000多个顶点单元左右。 
动态批次合并
动态批次合并是对那些没有标记成静态批次合并的物体在运行的时候由 unity自动将他们合并在一起,这种做法是可以支持运动物体的,但是限制较为严格,主要是以下限制:1.  一个批次的总顶点单元少于9002.  合并在一起的所有的模型应用同样的缩放值3.  使用相同的材质4.  相同的一张光照贴图5.  不能使用多pass的着色器6.  不能接收阴影所以一般是小的运动的模型才比较容易动态合并批次在一起,当然unity有可能在后续版本放宽这个限制。 
格式
纹理格式是另外一件很容易引起一些混乱的事情。
除了高级这个选项以外,纹理类型一共还有其他四种选择:1.  压缩格式–这种类型是牺牲一点显卡的性能来得到一个尺寸小得多的纹理。压缩选项将会针对你的目标平台来选择最合适的压缩算法


2.  16比特位 –这是一种低质量的真彩显示方式。它会以一种不压缩的方式来保存纹理但是它会使用16比特大小的调色板。对于颜色数量比较少的纹理非常合适。


3.  真彩色- 这是最高质量的保存纹理的方式,它不会对纹理进行压缩,使用的是32位的调色板。这种类型看上去效果非常棒,但是一张大纹理比如2048×2048将需要17M 的内存。


4.   Crunched – 这种类型将会根据显卡的GPU来选择合适的压缩格式进行压缩然后会选用一种CPU上就能处理的压缩格式再压缩一遍。如果在制作供人下载的资源包的时候这种类型非常的合适。这个类型的压缩需要很长时间,但在运行时解压是非常快的。


正如你所看到的那样,你在这里所做的事情(设置纹理的类型)就是牺牲纹理的尺寸大小来换取纹理的质量,或者反过来牺牲纹理的质量来换取纹理的尺寸大小。我的建议是始终把纹理的类型设置成压缩类型,直到你看到你游戏中的一些纹理的表现是有问题的话,再对这些有问题的纹理进行处理(选择合适的纹理类型和采样类型,或者放大纹理的尺寸等等)。 稍等一下,还有一个纹理类型的选项我们还没有说明。如果你把纹理的类型设置成高级,你将获得更多的纹理格式的控制权,包括可以选择更多的纹理压缩方法等等。需要注意的是,你的目标平台可能不会支持这里列出来的所有压缩格式(举个简单的例子来说,不同的安卓设备会支持不同的纹理压缩格式,但都应该支持ETC格式。) ETC 是由 Khronos 支持的开放标准,在移动平台中广泛采用。 它是一种为感知质量设计的有损算法,其依据是人眼对亮度改变的反应要高于色度改变。ETC v1 具有一个小缺陷,以这种格式压缩的纹理会丢失任何 Alpha 通道信息,而且也没有透明区域。由于在纹理中使用 Alpha 通道可以实现许多更聪明、更有趣的做法,许多开发人员因此采用其他纹理压缩算法,其中很多为硬件支持有限的专有格式。
提示下风险某些类型的纹理可能在压缩以后会看起来让人很不舒服,但纹理的类型如果设置为16位或者是真彩色的话就可能占用太多的空间。可以在构建你的游戏之后从editor.log里面查看纹理到底占据了多大的空间。


如果想要了解更多有关纹理压缩格式的知识,请看这里《通过代码来比较安卓的纹理压缩》。

验证
你想要做的最后一件事情是验证你的纹理导入信息。在纹理预览的底部位置你可以了解到下面这些信息:1.  使用的纹理大小2.  使用的压缩格式3.  最终的纹理大小请记住,有时你会需要先建立你的游戏然后才能看到纹理的目标大小。


近期热文:

深入讲解:在Unity中使用多个相机 - 及其重要性

鹅厂解密文档:揭秘天涯明月刀的无栈协程应用

腾讯游戏开发者平台长按,识别二维码,加关注
经验分享丨项目实践项目孵化丨渠道发行做有梦想的游戏人-GAME AND DREAM-


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存