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

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

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

相关文章

【go项目01_学习记录12】

代码组织 1 代码结构2 重构与测试2.1 安装测试功能2.2 testify 的常用断言函数 3 表组测试 1 代码结构 所有的代码写在一个main.go文件里面,GO编译器也是可以正常执行的。但是当代码量很庞大时,很难进行维护。 Go Web 程序的代码组织 单文件——反模式…

C语言笔记15

指针2 1.数组名的理解 int arr[ 10 ] { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }; int *p &arr[ 0 ];17391692786 arr是数组名&#xff0c;数组名是首元素地址&#xff0c;&arr[0]就是取出首元素的地址放在指针变量p中。 #include <stdio.h> int main()…

基于GWO灰狼优化的CNN-GRU-Attention的时间序列回归预测matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1卷积神经网络&#xff08;CNN&#xff09;在时间序列中的应用 4.2 GRU网络 4.3 注意力机制&#xff08;Attention&#xff09; 4.4 GWO优化 5.算法完整程序工程 1.算法运行效果图预览…

ChatGlm的部署和训练

一、chatGlm的环境部署 1.安装anocoda 下载安装anaconda。具体教程详见官网教程。 2.安装CUDA 1&#xff09;首先在终端查看你的Nividian版本&#xff0c;命令如下&#xff1a; 2)如果你没有下载你要去下载cuda下载网站&#xff0c;这里是12.3是因为我cuda version版本12…

【保姆级】生成式网络模型基础知识(图像合成/语音合成/GPT)

生成式模型基础知识 初步接触生成任务 生成任务&#xff0c;顾名思义就是要去生成一个东西&#xff0c;比如生成图片/音频/文字等等。 大家接触最多比如chatGPT、stable diffusion、还有一些语音合成相关的东西。 那么问题来了&#xff0c;具体生成步骤是什么样的&#xff…

【计算机毕业设计】基于SSM++jsp的高校专业信息管理系统【源码+lw+部署文档+讲解】

目录 第1章 绪论 1.1 课题背景 1.2 课题意义 1.3 研究内容 第2章 开发环境与技术 2.1 MYSQL数据库 2.2 JSP技术 2.3 SSM框架 第3章 系统分析 3.1 可行性分析 3.1.1 技术可行性 3.1.2 经济可行性 3.1.3 操作可行性 3.2 系统流程 3.2.1 操作流程 3.2.2 登录流程 3.2.3 删除信息流…

ChatGPT-4o发布了,所有人都可以免费用

前言 美国时间 5 月 13 日&#xff0c;在 Sam Altman 缺席的情况下&#xff08;为什么缺席&#xff0c;猜测是可能后面还有更重磅的消息&#xff0c;这次的产品只是一个中间过渡产品&#xff09;&#xff0c;OpenAI CTO Mira Murati 介绍了新的 ChatGPT 产品 ChatGPT-4o。这个…

node安装以及node的包管理工具

node安装以及node的包管理工具 node安装nvm管理工具 node安装 1、下载node链接: 点击这里 2、选择需要下载的版本以及对应的系统版本 nvm管理工具 1、下载nvm链接: 点击这里 2、双击运行.exe文件 全部默认安装即可 3、nvm常用命令 nvm list avaliable 显示所有可以下载的n…

企业管理咨询公司不会选?一文带你避开“坑人”陷阱

近年来&#xff0c;企业管理咨询公司如雨后春笋般涌现&#xff0c;数量之多令人眼花缭乱。所以&#xff0c;面对这么多的企业管理咨询公司&#xff0c;企业该选谁&#xff1f;又该如何选择&#xff1f;本文将从以下几个方面为大家解析。 首先&#xff0c;我们要明确自己的需求和…

R语言:ROC分析

> install.packages("pROC") > library(pROC) > inputFile"结果.txt" > rtread.table(inputFile, headerT, sep"\t", check.namesF, row.names1) > head(rt) con treat TCGA-E2-A1L7-11A-con…

【论文速读】|大语言模型是零样本模糊测试器:通过大语言模型对深度学习库进行模糊测试

本次分享论文&#xff1a;Large Language Models are Zero-Shot Fuzzers: Fuzzing Deep-Learning Libraries via Large Language Models 基本信息 原文作者&#xff1a;Yinlin Deng, Chunqiu Steven Xia, Haoran Peng, Chenyuan Yang, Lingming Zhang 作者单位&#xff1a;U…

vue+vant项目0-1快速发布到--钉钉应用

uniapp开发笔记----vue开发项目配置钉钉应用 一、 vuevant开发项目1. 自定义vuevant项目或者已经有的旧项目1. 自定义vuevant项目1. 创建vue项目2. 安装依赖3. 引入所有组件4. 使用一个组件/效果和代码如下&#xff1a; 2. git官网仓库&#xff0c;直接拉默认dome代码3. 打包项…

CTF如何学习?

CTF如何学习&#xff1f;打CTF有什么用 CTF本身有几个常见的领域 MISC WEB [逆向 密码学](https://www.zhihu.com/search?q逆向 密码学&search_sourceEntity&hybrid_search_sourceEntity&hybrid_search_extra{“sourceType”%3A"answer"%2C"sourc…

Hadoop 3.4.0+HBase2.5.8+ZooKeeper3.8.4+Hive+Sqoop 分布式高可用集群部署安装 大数据系列二

创建服务器,参考 虚拟机创建服务器 节点名字节点IP系统版本master11192.168.50.11centos 8.5slave12192.168.50.12centos 8.5slave13192.168.50.13centos 8.5 1 下载组件 Hadoop:官网地址 Hbase:官网地址 ZooKeeper:官网下载 Hive:官网下载 Sqoop:官网下载 为方便同学…

TypeScript学习日志-第二十六天(weakMap,weakSet,set,map)

weakMap,weakSet,set,map 一、set set 的基本用法如下&#xff1a; 二、map map 与 set 的 区别 就是 map 的 key 可以是引用类型 object array , map 的添加时使用 set 三、weakmap weakset weakmap和weakset 都是弱项 弱引用 其键必须是引用类型&#xff0c;不能是其它类…

弹幕游戏-压力测试 Python-Locust模拟送礼物

Hey&#xff0c;读者们&#xff01;今天给大家带来一个Python性能测试的新玩法——使用Locust模拟发送礼物。是不是听起来就很酷&#xff1f;&#x1f60e; &#x1f3af;目标 想象一下&#xff0c;在直播平台上&#xff0c;你希望测试某个直播间的礼物发送功能。那么&#x…

有一个21年的前端vue项目,死活安不上依赖

在公司开发的时候遇到的一个很玄幻的问题,这个项目是21年开发的,现在我是24年中途二开增加新功能 这个项目经过多人之手,现在已经出现了问题------项目依赖安不上,我能启动完全是因为在23年的时候写这个项目的时候将依赖费九牛二虎之力下载好后打成了压缩包发给另外一个安不上依…

Qt学习笔记1.3.3QtCore-隐式共享

文章目录 概述隐式共享细节类列表 Qt中的许多c类使用隐式数据共享来最大化资源使用并最小化复制。隐式共享类作为参数传递时既安全又高效&#xff0c;因为只传递指向数据的指针&#xff0c;并且只有当函数写入数据时才会复制数据&#xff0c;即写时复制(copy-on-write)。 概述 …

【Node.js】事件循环

Node.js 中的事件循环是基于单线程的异步非阻塞模型。它是 Node.js 的核心机制&#xff0c;用于处理非阻塞的 I/O 操作和异步事件。 1. Node.js 事件循环介绍 Node.js 的事件循环是一个 Event Loop&#xff0c;通过异步回调函数的方式实现非阻塞的处理。事件循环会在主线程上…

信创替代后的设备处置

信创替代后的设备处置 在信创项目中替换下来的设备&#xff0c;如果从技术层面讲还具有较高的应用价值&#xff0c;如何处置呢&#xff1f; 一、数据处置 信创适配完成后&#xff0c;这些被替换下来的服务器上有大量的数据&#xff08;包括结构化和非结构化&#xff09;&…