Unity Pixels Per Unit 与 Sprite Renderer Scale的逻辑关系,为什么平铺的Sprite Renderer会变形?

        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方式,为什么有这样的结果?

        

图1

         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计算已经更新,地址Unity2D正交相机Camera.size的含义和计算方式,及自适应分辨率的实现

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MegaFiers是完整的网格变形,动画和变形系统,包括超过50个修改器,例如弯曲,扭曲,FFD,位移,锥度等等。它们可以以任何组合堆叠,并且可以将任意数量的修改器应用于网格以实现复杂的结果。无论您的想象力如何,物体都可以拉伸,挤压或弯曲变形。或者,当对象在空间中移动时,使用空间扭曲使其自动变形。该套件的其他新增功能包括Point Cache动画支持,动态水波纹和浮动对象系统。 所有变形都可以在编辑器模式和播放模式下工作,因此在构建场景时,可以使用变形器为模型添加多样性。 MegaFiers还是变形TextMeshPro对象(Mesh和现在的UI版本)的理想选择,因此您可以用有趣的方式对文本进行动画处理。并且还可以与ProBuilder一起使用,使您可以直接在Unity中创建更多有趣的关卡。一个新功能是可以使用修改器使Sprite变形。 另一个强大的功能是我们的“网格包裹”系统,该系统允许一个网格被另一个变形和设置动画,使其非常适合服装等。该包裹系统还可以与Unity Blendshapes和蒙皮网格一起使用。 MegaWrap也已被重写为使用Jobs and Burst的速度提高了5倍以上。 MegaFiers用C#编写,并且包含所有源代码,并支持所有同时支持Burst和Jobs的Unity平台。从2019年起兼容所有版本的Unity,并且可以在IOS和Android以及VR和AR平台上使用。 MegaFiers还与所有Unity Rendering管道完全兼容。我们还将为Unity的所有新发行版不断更新资产。如果您有关于修改器的想法,请让我们知道或编写。 还包括先进的花键系统,该系统还允许路径跟随或将花键转换为网格,动态软管系统和用于履带车辆的系统。 更多详情:https://assetstore.unity.com/packages/tools/modeling/megafiers-2-188378#description
Unity 中,`SpriteRenderer` 是用于渲染 2D 精灵(Sprite)的组件。它可以将指定的 Sprite 显示在场景中,并支持一些常见的渲染设置,比如颜色、透明度、层级等。 `SpriteRenderer` 组件可以在 Unity 的编辑器中通过 `Add Component` 菜单添加到游戏对象上。要使用 `SpriteRenderer` 渲染精灵,需要将 Sprite 赋值给其 `sprite` 属性。 以下是 `SpriteRenderer` 常见的属性: - `sprite`:要渲染的精灵。 - `color`:精灵的颜色。 - `flipX` 和 `flipY`:精灵是否水平/垂直翻转。 - `sortingLayerName` 和 `sortingOrder`:精灵的层级和排序。 - `material`:精灵使用的材质。 `SpriteRenderer` 组件还可以通过设置 `Sorting Layer` 和 `Order in Layer` 属性来控制精灵的层级和排序。可以在 `Edit` -> `Project Settings` -> `Tags and Layers` 中添加自定义的 Sorting Layer。 例如,以下代码可以在场景中创建一个渲染指定 Sprite 的精灵: ```csharp using UnityEngine; public class SpriteRendererDemo : MonoBehaviour { public Sprite spriteToRender; void Start() { // 创建一个新的游戏对象 GameObject spriteObject = new GameObject("Sprite"); // 添加 SpriteRenderer 组件 SpriteRenderer renderer = spriteObject.AddComponent<SpriteRenderer>(); // 设置要渲染的精灵 renderer.sprite = spriteToRender; // 设置精灵的颜色 renderer.color = Color.white; // 设置精灵的层级和排序 renderer.sortingLayerName = "Foreground"; renderer.sortingOrder = 0; } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值