SpriteRenderer之前用的比较基础,没遇到过什么问题,这几天使用SpriteRenderer的平铺时发现平铺变形了,研究了一下,原来有这么多在逻辑在里面。
当我们导入图片选择Texture Type为Sprite时表示我们的图片用途是UI或者SpriteRenderer,可以看到有个导入属性为Pixels Per Unit(下文简称为PPU),该属性默认值为 100,按照字面意思理解,PPU意为一个 “单位” 内含的像素数,这里的 “单位” 指的是Unity空间内的单位,可以理解为场景的一个格子长宽各为一个单位,下面开始对同一张图片设置不同的PPU进行显示测试。
首先强调下 “单位” 这个概念,我们在场景中创建一个cube,Scale值默认为1,那么这个Cube就可以理解为长宽高各为1个单位,场景中显示的所有包括2D,3D的内容都可以以此Cube为基准进行衡量。导入一个空白的白色图片,图片大小为100*100,PPU修改为100,如图:
然后分别创建缩放为1的Cube,缩放为2的Cube,缩放为1的SpriteRenderer,贴图内容为上面导入的图片,方便对比大小,切换到2D视角对比,结果如图 ,各个对象用不同颜色标注,左上角SR *1表示SpriteRenderer,Scale值为1,其他同理:
可以明显看到SpriteRenderer的大小与Cubex1的大小相同,表示此时,该SpriteRenderer的长宽各位1个 “单位”,Cubex2的长宽各为2个 “单位”,结合各个对象的Scale值,那是不是可以理解为对象的Scale值就表示为的单位数量呢?比如Scale = (3,5,0.5f),是否就表示该对象长宽高分别为3个 “单位”, 5 个 “单位”, 0.5个 “单位”?
答案当然是否定的,但是上面的结果又如何解释呢?当我们随意修改SpriteRenderer的Scale值,会发现无论如何都会与相应缩放的Cube所对齐,不就说明Scale 与 “单位”是完全对应的吗?而为什么会出现这样的结果,答案其实很简单 ——“巧合”,没错,就是巧合,只是凑巧而已,而导致这个 “巧合” 结果的,正是PPU的值。
下面我们将上面导入的图片复制两份,分别修改PPU为20,200,再进行对比,设置如下:
创建同样Scale为1的两个SpriteRenderer,贴图分别设置为上面两个,对象设置如图:
结果如图:
可以看到,相同的图片尺寸,相同的缩放值,不同PPU值,在表现上的尺寸差距是巨大的,而为什么会造成这样的结果呢?就是因为每个SpriteRenderer所占的 “单位”不同,各自占的“单位”值又是多少呢?
我们记“单位”为Unit,先计算PPU = 100的图片,图片分辨率为100*100,即水平和垂直方向像素数量均为Pixel = 100, PPU = 100表示显示该图片是每个单位占据100个像素,那么完全显示该图片需要 一共 需要 Unit = Pixel / PPU = 100/ 100 = 1 ,即1个 “单位”;同理计算PPU = 20的图片,Unit = Pixel / PPU = 100 / 20 = 5 ,即5个 “单位‘ ;PPU = 200 的图片, Unit = Pixel / PPU = 100/ 200 = 0.5,即0.5个 ”单位“。
总结:PPU = 100,Unit = Pixel / PPU = 100 / 100 = 1
PPU = 20, Unit = Pixel / PPU = 100 / 20 = 5
PPU = 200,Unit = Pixel / PPU = 100 / 200 = 0.5
即不同的PPU值,在Scale值相同时所占的 “单位”是不同的,所以表现上面尺寸差距巨大,而如果我们像让这些图片尺寸看上去都一样的话,就需要根据所占的 “单位”数量反向缩放,缩放值即为目标“单位”值/当前所占“单位”值, 对上面的对象进行相应的缩放,可以得到如下结果:
可以看到,进行相应的缩放之后,三个对象在表现上大小一致了,所以在我们想修改图片在spriterenderer上表现的大小时,不但可以通过修改Scale值,也可以修改PPU达到相同的效果,为了验证上面的结果不是因为图片分辨率是 100* 100 导致的 “巧合”,可以导入其他任意分辨率的图片进行测试验证,这里只做少量的验证,导入一张新的分辨率为65*65的图片,PPU为默认值100,设置如图:
创建一个SpriteRenderer,将上面图片赋值,与分辨率为100*100,PPU = 100的图片做对比,结果如图:
根据上面的结果计算,左边 Unit = Pixel / PPU = 100 / 100 = 1,而右边 Unit = Pixel / PPU = 65 / 100 = 0.65,所以右边显示会比左边小,而想要让右边显示与左边一致,即占据1个 “单位”,两种方式,1:修改Scale,放大 100/65倍;2:修改PPU , PPU = Pixel / Unit = 65 / 1 = 65。其他验证这里省略。
“单位” 与 PPU 的概念至关重要,错误的值会导致SpriteRenderer平铺变形。
方便看出来变形效果,导入一张包含纹理的图片,分辨率为92*92,PPU设置为100,设置如图:
先创建一个SpriteRenderer赋值,Scale = 1,填充方式Draw Mode为完全填充 Simple,根据上面逻辑可以得出该SpriteRenderer的Unit = 92 / 100 = 0.92,然后复制该SpriteRenderer,修改Draw Mode为Tiled,设置Size 值width = heigth = 1,设置完成之后,会发现该SpriteRenderer的显示大小并没有发生变化,但是Scale值却变成了(0.92,0.92,1),图片填充显示也有问题(下文再解释),如图,其中左边方块为Simple方式,右边方块为Tiled方式,为什么有这样的结果?
Simple填充的表现是复合预期的,想要解释Tiled为什么会有这样的表现,首先要理解Tiled模式下的Size属性, 千万不要理解为Size值表示水平和垂直方向平铺的图片数量,这是完全错误的!其中的width的解释为 The width dimension value for the sprite(精灵的宽度尺寸值),实在是被这个解释坑了好久,不知道官方的 dimension 具体指的是什么尺寸,经过一系列测试,发现这个值,与上面我们定义的 “单位” 是完全对应的,即width的含义,可以理解为 平铺之后水平方向的 “单位”值。width = 1,表示平铺后,水平方向 “单位” 大小为1,而因为填充模式为Simple时,“单位”大小为 0.92,所以这里会自动缩放Scale = 0.92,保持与修改前的表现大小一致。然后我们将 Scale再修改为1,那么该SpriteRenderer 显示大小会重新与 “单位”为1的SpriteRenderer保持一致,如图:
验证下Tiled模式下width 与 “单位”的关系,新建Tiled,填充上面的图片,width值设置为10,然后再新建一个Cube,Scale值设置为(10,1,1),即此时该Cube长度 “单位” 为10,对比长度,结果如图:
长度是吻合的,表示width 与 “单位”是相等关系,是标准的,通关修改导入贴图的PPU信息,不影响尺寸表现效果。
理解了上面的width之后,就可以理解为什么平铺的图片会有问题了。
先看第一个问题,上面 图1 右边的图片,填充的时候,会比左边的图片多显示了一部分,这是因为我们平铺模式选择的是 Continuous,均匀的平铺,不进行缩放,因为我们这里设置的width = 1,即占的 “单位” Unit = 1,而贴图分辨率Pixel = 92x92,PPU = 100,所以在 1个“单位”里面会显示 100(PPU)个像素,而我们的图片分辨率只有 92,所以还剩下 100 - 92 = 8个像素用于平铺,就造成了 图1 的情况。要修改这种结果,只需要修改 平铺模式 为 Adaptive即可,该模式会对图片进行拉伸,效果如图,其中右下角平铺方式为Adaptive:
但是这样就解决问题了吗?
新建一个SpriteRenderer,依然导入上面的图片,填充模式设置为Tiled,width设置为20,height设置为0.92以保证垂直方向不进行缩放(因为上面我们计算的结果是该图片水平垂直方向 的“单位”值均为0.92),平铺模式修改为Adaptive,如图,其中最左边的方块和最上面的方块都为Simple模式填充,Scale为1,为了方便观察,只截取了一部分原大小:
可以明显看到平铺的 的长宽已经不是比例,发生了变形,垂直方向保证了原大小,但是水平方向有些微的差异,如果width值更大,那么变形会更明显,通过调节Adaptive 方式下的Stretch Value会有一定的效果,但是我发现不同的size值需要对应不同的Stretch Value,通过修改这个Stretch Value,不同的值也没有修复掉变形的问题,而且我确实没有搞明白Stretch Value的逻辑具体是什么,就放弃了这个方式。而出现这样的情况,是因为导入图片的分辨率Pixel与PPU设置值不匹配而导致的,根据上面的逻辑,我们可以知道,width设置为20,表示水平占据 20个 “单位”,根据上面我们算的结果,这个图片水平方向的 “单位”值是0.92,不能整除 “20”单位,所以显示的结果一定是经过缩放的,但是垂直方向没有进行缩放,所以看起来才会变形,如果我们把height也修改为20,那么水平垂直同比缩放,就不会有变形的问题了,但是那样的结果只能是正方形,不符合我们的预期。此时我们就可以通过修改PPU来解决现在的问题,因为平铺基本都是整数的,上面我们height设置0.92是为了观察变形效果,所以我们只需要保证我们的一张图片的“单位”能被整数整除就行,比如上面的图片分辨率为92*92,那么我们修改PPU = 92,保证每张图片都是一个单位,那么在平铺时只要水平垂直方向都是整数,这样就不会变形。
那么我们必须保证平铺和图片所占 “单位”都是整数,甚至图片只能是正方形才能保证平铺不会变形吗?当然不是的,变形只是因为长宽缩放不一致导致的,而如果我们能保证缩放一致,无论怎样都不会变形,或者说我们只要保证水平和垂直方向都是均匀拉伸就不会变形,而要达到这个要求,只需要保证平铺是的width 和 height能分别整除 图片水平和垂直方向所占的 “单位”大小,即 width % (pixel.x / PPU) = 0,height % (pixel.y / PPU) = 0。可以自行测试验证。
告一段落,基本上就是这个样子了,之后会看时间配上视频具体讲下,有错误的地方还望指出。
关于“单位”的应用与正交相机的Size计算也有关系,正在研究,后面研究完再记录。