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

news2025/1/19 11:32:16

        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计算也有关系,正在研究,后面研究完再记录。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1674302.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【刷题(2)】矩阵

一、矩阵问题基础 遍历: for i in range(len(matrix[0])): for j in range(len(matrix): while 倒序遍历: for i in range(right,left,-1) 临时存储:temp w,h:len(matrix[0])-1 len(matrix)-1 left,right,top,bottom:0 len(matrix[0])-1 0 l…

NMACDR:基于邻居交互增强和多头注意力机制的跨域推荐模型

基于邻居交互增强和多头注意力机制的跨域推荐模型 湖北民族大学学报-孙克雷、汪盈盈-2023 思路 针对基于映射的跨域推荐模型没有充分关注源域中数据稀疏的用户,导致用户偏好的迁移效率降低的问题,提出本文。 首先,利用邻居用户的交互来增强源域中数据稀疏用户的交互序列,…

热搜榜小工具,摸鱼必备NO.99

本文一共:188 个字,需要阅读:1 分钟,更新时间:2024年5 月14日,部分内容具有时效性,如有失效请留言,阅读量:0 这个小工具集成了微博热搜、百度热搜、今日头条热搜、抖音热搜,随意切换 右上角有个设置,可以设置自动刷新时间、监控关键词、透明度、靠边隐藏…

鸿蒙内核源码分析 (编码方式篇) | 机器指令是如何编码的?

本篇说清楚 ARM指令是如何被编码的,机器指令由哪些部分构成,指令有哪些类型,每种类型的语法又是怎样的 ? 代码案例 | C -> 汇编 -> 机器指令 看一段C语言编译(clang)成的最后的机器指令(armv7) int main(){int a 0;if( a ! 1) a …

dataframe数据常用python操作

dataframe数据常用python操作 dataframe数据常用知识点1.创建dataframe1.1使用字典创建DataFrame:1.2使用列表创建DataFrame:1.3使用numpy数组创建DataFrame:1.4从TXT文件中创建DataFrame:1.5从CSV文件中创建DataFrame&#xff1a…

卡巴斯基:2024年Q1漏洞和利用报告

近日,卡巴斯基发布了《2024年Q1漏洞和利用报告》,提供了一系列有洞察力的统计和分析快照,揭示了新漏洞和利用的发展趋势,以及攻击者最常利用的漏洞概述。为组织获悉和应对相关威胁提供了有价值的见解。 已注册漏洞统计数据 为了…

大企业总部与分部组网方案

在全球化的经济环境中,大企业往往设有总部和多个地理分散的分部。为了确保信息的快 速流通、资源的优化配置以及管理的高效运作,构建一个稳定、安全且高效的组网方案显 得尤为重要。本文将探讨大企业如何通过技术手段和管理策略,实现总部与分…

常见加解密算法03 - RC4逆向认识

各位聪明绝顶,才高八斗的读者们你们好!今天我们主要讨论编译之后的RC4算法识别。 题外话,之前看到一个蛋疼的小知识,说“势”这个字最好不好查词典释义。我是很好奇的,果然后来无法直视势不可挡这个成语。 言归正传&am…

Python tensor向量维度转换,不同维度的向量转化为相同的维度,经过全连接层MLP的维度转换,代码实战

问题:在机器学习特征工程中,假如每类特征需要转化为相同的维度进行拼接,那该怎么办呢?接一个全连接层MLP就可以了。 例子:将(128,64) 维度的向量转化为(128,32)维。 impo…

安装ps提示找不到msvcp140.dll,无法继续执行此代码如何修复

MSVCP140.dll,作为Windows操作系统中的一个关键组件,扮演着不可或缺的角色,尤其对于基于C开发的应用程序而言。本文旨在深入探讨这一动态链接库文件的功能、重要性、常见问题及解决方案,为您提供全面的MSVCP140.dll指南。 一、MSV…

zookeeper集群部署以及zookeeper原理

文章目录 简介工作原理特性官网地址准备节点准备环境准备JAVA主机映射 部署 简介 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服…

触摸播放视频,并用iframe实现播放外站视频

效果&#xff1a; html: <div:style"{ height: homedivh }"class"rightOne_content_div_div"mouseenter"divSeenter(i)"mouseleave"divLeave(i)"click"ItemClick(i)"><!-- isUser是否是用户上传 --><divv-if…

react18【系列实用教程】组件 (2024最新版 | 含父子组件传值、兄弟组件传值、越层组件传值、“插槽“)

什么是组件&#xff1f; 一个组件就是用户界面的一部分&#xff0c;它可以有自己的逻辑和外观。 组件之间可以互相嵌套&#xff0c;也可以复用多次 为什么要用组件&#xff1f; 组件能让开发者像搭积木一样快速构建一个完整的庞大应用&#xff0c;大大提升了开发效率&#xff…

刚刚OpenAI发布ChatGPT-4o模型,免费使用GPT4o并免费提供更多功能

就在今日凌晨1点&#xff0c;OpenAI举行了春季发布会&#xff0c;发布了GPT-4o 并免费提供更多功能。 亲测GPT-4o已经可以免费试用&#xff0c;每个人都可以使用它并从中受益&#xff0c;GPT4终于不再是少部分人的玩物。 点击加入ChatGPT4交流群&#xff1a;https://www.aijour…

vue3专栏项目 -- 五、权限管理(上)

一、登录部分 1、第一部分&#xff1a;获取token 前面我们主要是在获取数据上下功夫&#xff0c;到目前为止我们已经能获取首页和详情页的数据了&#xff0c;现在我们将数据转移到权限管理上来&#xff0c;也就是说我们要处理用户登录、注册等一系列的行为&#xff0c;在这部…

JavaScript:正则表达式属于字符串吗-不属于/字符串转正则表达式的两种方法

一、需求描述 js 字符串转正则表达式 二、理解正则表达式属于字符串吗? 正则表达式不属于字符串&#xff0c;它是一种用于匹配、查找和操作文本的模式。正则表达式是一种特殊的语法&#xff0c;用于描述字符串的特征。通过使用正则表达式&#xff0c;可以检查一个字符串是否…

找不到vcomp140.dll多种修复方法分享,轻松解决dll报错问题

当你在尝试运行某款软件时&#xff0c;系统突然弹出一个错误提示&#xff0c;明确指出“vcomp140.dll文件丢失”&#xff0c;这个错误通常会导致某些应用程序无法正常运行。为了解决这个问题&#xff0c;我们需要采取一些修复措施。本文将详细介绍vcomp140.dll丢失的5种修复方法…

Java的VO,BO,PO,DO,DTO

写在前面 本文看下VO&#xff0c;BO&#xff0c;PO&#xff0c;DO&#xff0c;DTO&#xff0c;都是啥&#xff01; 1&#xff1a;正文 先看一张图&#xff0c;看了图就能知道个大概了&#xff1a; 1.1&#xff1a;PO 全称是persistent object&#xff0c;对应数据的表&am…

记录一次 vue2 前端项目整合过程

整合成功效果图 具体说明&#xff1a; 项目A是现在的vue2前端项目&#xff0c;项目B是一个开源的工作流前端&#xff0c;项目后端代码已经整合了&#xff0c;就不多提了。这里主要记录下前端整合的过程和思路。 1、开源工作流里面的功能&#xff0c;拷贝到自己对应的vue2项目里…

【Linux】解析键盘组合键产生信号的完整过程:从硬件中断到信号发送

前言 每一个了解Linux的都知道这样一个知识&#xff0c;CtrlC组合键能够终止一个进程。 个人了解进程相关知识之后知道&#xff0c;一个进程被终止只会有有三种情况&#xff1a; 代码运行完毕&#xff0c;结果正确代码运行完毕&#xff0c;结果不正确代码运行异常&#xff…