您当前的位置:钢材 > 型钢 > 市场分析

unity ao贴图怎么贴,unity贴图透明通道

来源:头条 作者: chanong
分享到
关注德勤钢铁网在线:
  • 扫描二维码

    关注√

    德勤钢铁网微信

在线咨询:
  • 扫描或点击关注德勤钢铁网在线客服

简介在制作手机游戏时,您可能会遇到以下问题。

UI学生每天都会抱怨iOS上的一些透明纹理在压缩后变得模糊。

在一些较旧的Android 智能手机上,相同的纹理消耗的内存比其他智能手机多几倍,常常导致游戏崩溃。

本文介绍了手游项目中常见的一种解决方案:纹理alpha通道分离,以及其基于Unity引擎的实现过程和细节。思路主要取自https://zhuanlan.zhihu.com/p/32674470。本文是对该方法的实践和补充。

为什么分离1.为什么会出现这个问题?

为了理解这些问题的原因,我们首先需要简单解释一下纹理压缩格式的基本概念。

为了确保你的纹理在手机上运行时占用尽可能少的内存,你需要设置纹理的压缩格式。 Unity目前支持的主要压缩格式有:Android上的ETC/ETC2、iOS上的PVRTC以及将来可能会使用的ASTC。这些压缩格式均具有以下特征:

ETC:不支持透明通道。所有Android 设备均支持

ETC2:支持透明通道。您的Android 设备的GPU 必须支持OpenGL es 3.0 才能使用。对于不支持的设备,它以未压缩的格式存储在内存中,占用更多的内存。

PVRTC:适用于所有Apple 设备。压缩纹理的长度和宽度必须相等且为2的幂(POT,2的幂)。

ASTC:一种高质量、低内存的压缩格式,将来可能会普遍使用,但目前某些型号不支持。

一般来说,Android上的Unity手游目前不透明纹理使用RGB压缩ETC 4-bit,透明纹理使用RGBA压缩ETC2 8-bit,iOS非透明纹理使用RGB压缩PVRTC 4-bit,透明纹理使用RGBA压缩PVRTC 4 位。

这里的比特的概念是指每个像素占用的比特数。例如,对于RGB 压缩PVRTC 4 位格式的1024x1024 纹理,在内存中占用的大小=1024x1024x4(位)=4M(位)=0.5M(字节)。

在iOS 上,您可以看到非透明和透明纹理都是4bpp(每像素4 位)。即使透明通道增加,它们也将保持相同的大小。当然,4bpp 透明纹理的压缩效果较差。当你在实际机器上看到它时,它看起来确实很糟糕。这是你第一个问题的答案。

由于一些早期的Android 机器不支持OpenGL es 3.0,RGBA 压缩的ETC2 8 位纹理通常以RGBA 32 位格式驻留在内存中,导致内存使用量高达原始的四倍。在内存较少的旧机器上,情况并非如此。令人惊奇的是,在这种情况下,系统会如何杀死系统。这是你第二个问题的答案。当然,需要注意的是,不支持OpenGL es 3.0的机器的市场份额已经相当低(不到1%),大多数情况下可以忽略不计。

更多纹理压缩格式请参见:https://zhuanlan.zhihu.com/p/113366420

2. 如何解决问题

要解决上述图像模糊问题,您可以执行以下步骤:

透明纹理未压缩并占用32bpp 内存。

独立的alpha通道,内存使用4bpp+4bpp(或4bpp+8bpp)

不压缩当然是不可能的,毕竟32bpp对于手机,尤其是内存较低的iOS设备来说,内存消耗太大了。所以考虑分离alpha通道,将不透明和透明部分分割成两幅图像(如下图)。

关于内存使用,非透明部分一般分为RGB压缩的PVRTC 4位,透明通道部分为RGB压缩的PVRTC 4位或Alpha8格式(8bpp)。 Alpha8格式的不同版本的Unity似乎对手机上的Mali芯片的支持不同,但我没有做过详细的研究。测试时,我们使用RGB压缩的PVRTC 4位格式来压缩透明通道图,效果完全可以接受。

分离方法1.溶液1

当然,您会希望继承SpriteRenderer/Image 组件并在运行时替换材质以实现您的目标。这种解决方案有一些缺点,对于开发到后期的项目来说,更改所有组件的成本非常高。更不用说,在添加版本控制的项目中,修改预制件的成本也非常高。此外,对于已经开发的项目来说,修改预制件的成本也非常高,对于使用定制材料的组件来说也非常不方便。

2. 选项2

直接修改精灵的RenderData,以便在打包时将关联的纹理、alphaTexture 等信息直接正确填充到包中。

这样做的好处是你不需要改变任何组件,只需要做一次,只要定制整个打包流程即可。这不是问题,因为大多数商业项目本质上都需要定制的包装过程。

首先说明一下实现,这个方案在2017.4就通过了测试,我使用废弃的Sprite Packer方法创建了一个图集,我没有研究过Sprite Atlas的方法,但是我认为应该可以实现,但是,改变可能有必要。有不少流程。

具体实现稍后再讲,但打包前的大致流程如下。

我简单解释一下上面的过程。

UpdateAtlases:强制更新图集缓存(需要alpha 通道分离的图集需要更改其压缩格式以删除A 通道)

FindAllEntries:查找所有精灵,检查其PackingTag,对所有精灵和图集信息进行分类和排序。

GenerateAlphaTextures/SaveTextureAssets:根据图集信息绘制alpha通道纹理并保存文件。

AssetDatabase.Refresh:事实上,如果不更新某些纹理可能会丢失。

ReloadTextures:从文件加载纹理作为写入RenderData 的数据。

WriteSpritesRenderData:最重要的一步是将纹理、alphaTexture 和其他信息写入精灵的RenderData。

最后,打包前,禁用SpritePacker,避免打包时覆盖图集和精灵的RenderData。

透明通道贴图在生成Alpha 通道贴图时不受影响,因为它使用散点贴图位置和图集中的其他信息直接渲染顶点信息,然后压缩到贴图上。需要注意的是,没有通过压缩。

//临时渲染纹理

varrt=RenderTexture.GetTemporary(texWidth, texHeight,0, RenderTextureFormat.ARGB32);

Graphics.SetRenderTarget(rt);

GL.Clear(true,true, Color.clear);GL.PushMatrix;GL.LoadOrtho;foreach(varspriteEntryinatlasEntry.SpriteEntries){varsprite=spriteEntry.Sprite;varuvs=spriteEntry.Uvs;varatlasUvs=spriteEntry.AtlasUvs;//压缩后的前一个精灵的顶点信息被渲染到临时纹理中。 mat.mainTexture=spriteEntry.Texture;mat.SetPass(0);GL.Begin(GL.TRIANGLES);vartriangles=sprite.triangles;foreach(varindexintriangles){GL.TexCoord(uvs [index]);GL.Vertex(atlasUvs) [索引]);}GL.End;

}

GL.Pop 矩阵;

//最终的alpha 贴图

varfinalTex=newTexture2D(texWidth, texHeight, TextureFormat.RGBA32,false);

FinalTex.ReadPixels(newRect(0,0, texWidth, texHeight),0,0);

//换颜色

varcolors=FinalTex.GetPixels32;

varcount=颜色. 长度;

varnewColors=newColor32[计数];

for(vari=0; i 计数; ++i){

vara=color[i].a;newColors[i]=newColor32(a, a, a,255);

}

FinalTex.SetPixels32(newColors);finalTex.Apply;

RenderTexture.ReleaseTemporary(rt);

将透明通道纹理写入文件时要记住的一件事是,您正在打印的图集将生成多个页面,并且这些页面都将具有相同的纹理名称,因此如果直接保存它们,您可能会意外覆盖它们。这是有可能完成的。与Page不同的是,这里我们使用Texture的哈希码。

//支持多页图册

varhashCode=atlasEntry.Texture.GetHashCode;

//导出alpha纹理

如果(atlasEntry.NeedSeparateAlpha){

varfileName=atlasEntry.Name +\'_\'+ hashCode +\'_alpha.png\';varfilePath=Path.Combine(path, fileName);File.WriteAllBytes(filePath, atlasEntry.AlphaTexture.EncodeToPNG);atlasEntry.AlphaTextureAssetPath=Path.Combine(assetPath, 文件名);

}

接下来,我们将解释编写SpriteRenderData的最重要的部分。

varspr=spriteEntry.Sprite;

varso=newSerializedObject(spr);

//获取散点图属性

varrect=so.FindProperty(\'m_Rect\').rectValue;

varpivot=so.FindProperty(\'m_Pivot\').vector2Value;

varpixelsToUnits=so.FindProperty(\'m_PixelsToUnits\').floatValue;

vartightRect=so.FindProperty(\'m_RD.textureRect\').rectValue;

varoriginSettingsRaw=so.FindProperty(\'m_RD.settingsRaw\').intValue;

//散点图像(全矩形)内散点图像(紧)的位置、宽度和高度

vartightOffset=newVector2(tightRect.x,ightRect.y);

vartightWidth=tinyRect.width;

vartightHeight=tinyRect.height;

//计算散点图(完美矩形)在图集中的矩形和偏移量。

varfullRectInAtlas=GetTextureFullRectInAtlas(atlasTexture,

spriteEntry.Uvs, spriteEntry.AtlasUvs);

varfullRectOffsetInAtlas=newVector2(fullRectInAtlas.x, fullRectInAtlas.y);

//计算图集中散点图像(紧密)的矩形。

vartightRectInAtlas=newRect(fullRectInAtlas.x +tinyOffset.x, fullRectInAtlas.y + tinyOffset.y,tinyWidth,tinyHeight);

//计算uvTransform

//x: 像素换算为单位X

//y: 图集X中心点位置

//z: 像素到Y 单位

//w: 图集中心点位置Y

varuvTransform=newVector4(

PixelsToUnits, 矩形宽度* 枢轴.x + fullRectOffsetInAtlas.x, 像素到单位, 矩形. 高度* 枢轴.y + fullRectOffsetInAtlas.y);

//计算设置

//位0:已打包。 1表示已打包,0表示未打包

//1 位:SpritePackingMode。 0 表示紧密,1 表示矩形

//第2-5 位:SpritePackingRotation。 0表示不旋转,1表示水平翻转,2表示垂直翻转,3表示180度旋转,4表示90度旋转。

//6 位:SpriteMeshType。 0 表示完美直角,1 表示紧密

//67=SpriteMeshType(紧) + SpritePackingMode(矩形) + pack

varsettingsRaw=67;

//写入RenderDataso.FindProperty(\'m_RD.texture\').objectReferenceValue=atlasTexture;so.FindProperty(\'m_RD.alphaTexture\').objectReferenceValue=alphaTexture;so.FindProperty(\'m_RD.textureRect\') 马苏。 rectValue=tinyRectInAtlas;so.FindProperty(\'m_RD.textureRectOffset\').vector2Value=tinyOffset;so.FindProperty(\'m_RD.atlasRectOffset\').vector2Value=fullRectOffsetInAtlas;so.FindProperty(\'m_RD.settingsRaw\' ) .intValue=settingsRaw;so.FindProperty(\'m_RD.uvTransform\').vector4Value=uvTransform;so.ApplyModifiedProperties;

//备份原始数据以便恢复

spriteEntry.OriginTextureRect=tinyRect;spriteEntry.OriginSettingsRaw=originSettingsRaw;需要修改的部分的含义已经在注释中写得很清楚了,大家看一下就可以大概明白了。还有一些概念需要解释。

精灵导入设置将要求您设置网格类型。默认值是“紧密”,它根据Alpha 裁剪尽可能多的像素。另一方面,全矩形意味着将使用与图像纹理大小相同的矩形。

使用这两个选项创建图集时,如果散点图像周围有很多alpha,您会注意到使用完整的矩形会使图像非常分散,但使用紧密的矩形会使外观非常紧凑。以及效果如下:

您可以在上面的原始散点图中看到它周围有很多透明区域。

上面是使用紧密网格类型创建的图集,可以看到中间的间隙缩小了。

上面是使用全矩形网格类型创建的图集,但是您可以看到中间有很大的间隙。

通常我们使用的是Tight,所以上面的代码需要计算一些与Tight相关的值,但是具体的计算方法可以直接在代码中看到,所以应该不难理解。

还有一个方法GetTextureFullRectInAtlas 可以获取计算散点图像的图集中的矩形(完整矩形)。这是代码:

privatestaticRect GetTextureFullRectInAtlas(Texture2D atlasTexture, Vector2[] uvs, Vector2[] atlasUvs){vartextureRect=newRect;//查找x/y不相等的点varindex=0;varcount=uvs.Length;for(vari=1; i count ; i++){if(Math.Abs(uvs[i].x - uvs[0].x) 1E-06Math.Abs(uvs[i].y - uvs[0].y) 1E- 06 ) { index=i;break;}}//计算大图像中散乱图像的纹理矩形varatlasWidth=atlasTexture.width;varatlasHeight=atlasTexture.height;textureRect.width=(atlasUvs[0].x - atlasUvs[索引] .x )/(uvs[0].x - uvs[索引].x) * atlasWidth;textureRect.height=(atlasUvs[0].y - atlasUvs[index].y)/(uvs[0 ]. y - uvs[索引].y) * atlasHeight;textureRect.x=atlasUvs[0].x * atlasWidth -textureRect.width * uvs[0].x;textureRect.y=atlasUvs[0].y * atlasHeight - 纹理矩形.height * uvs [0].y;returntextureRect;

}

最后,需要决定是否需要自定义图集规则、分离Alpha通道纹理、更改相应的压缩格式,例如RGBA ETC2改为RGB ETC或RGBA PVRTC改为RGB PVRTC。这样做是为了从图集中生成不透明纹理的原始图像。大概的代码是:

//如果需要分离alpha通道

if(TextureUtility.IsTransparent(settings.format)) {

settings.format=TextureUtility.TransparentToNoTransparentFormat(settings.format);} 关于如何自定义图集规则,请参考官方文档:https://docs.unity3d.com/Manual/SpritePacker.html

一些补充: 1. 手机上UI.Image 中显示的纹理似乎丢失了材质。

原因是Image组件使用该方案时,使用了内置着色器DefaultETC1。这应该包含在始终包含的着色器中。

2、分离出alpha通道纹理精灵资源并打包。

下图显示了未分离Alpha 通道的散点图,如AssetStudio 工具中所示。您可以看到每个精灵都引用一个Texture2D。

下图显示了alpha 通道分离的图集。正如你所看到的,这个AssetBundle包只有几个sprite和两个Texture2D(一个不透明贴图和一个透明通道贴图)。

3. 如何找出精灵的哪些渲染数据需要更改?

在实际试用中,你可以使用UABE工具来比较分离和不分离alpha通道的精灵渲染数据的差异,并确定需要改变哪些数据才能达到你的目标,我确定是有的。

从下图中可以看到(左边是正常的图集数据,右边是我尝试模拟写入RenderData的不正确数据),texture、alphaTexture、textureRect、textureRectOffset、settingsRaw和uvTransform字段都是m_RD一切都必须改变。由于我们无法获取源代码,因此一些价值算法是通过分析和推测来验证的。

4、m_RD.settingsRaw的值是什么意思?

settingsRaw的部分定义可以在AssetStudio源代码中找到。

位0:已打包。 1表示已打包,0表示未打包

位1:SpritePackingMode。 0 表示紧密,1 表示矩形

位置2-5:SpritePackingRotation。 0表示不旋转,1表示水平翻转,2表示垂直翻转,3表示180度旋转,4表示90度旋转。

6 位:SpriteMeshType。 0 表示完美直角,1 表示紧密

正常生成的图集值为67。这是,

SpriteMeshType(紧) + SpritePackingMode(矩形) + pack.

5.使用Unity 2017测试通过。我可以通过其他版本吗?

我不知道。如果你看AssetStudio源码可以看到,根据Unity版本的不同,序列化后会进行不同的处理(见下文),如果不同版本出现问题,可以通过对比精灵的RenderData来解决问题。需要在AssetBundle 包中输入额外的数据,如上所述。

延伸思考:如果我用TexturePacker代替更新图集缓存的第一个操作,我是否可以使用TexturePacker的一些功能来优化和定制图集?这是可能的,但并非微不足道。虽然仍然很乏味,但肯定是个好主意。有需要的同学可以学**一下。

参考Unity Atlas IOS上透明通道分割(不带TP):https://zhuanlan.zhihu.com/p/32674470

[2018.1]Unity纹理压缩格式设置:https://zhuanlan.zhihu.com/p/113366420

(旧版)Sprite Packer:https://docs.unity3d.com/Manual/SpritePacker.html

文章中提到的工具:

AssetStudio,一个可以轻松查看AssetBundles内容的工具:https://github.com/Perfare/AssetStudio

UABE,一个可以解压/打包AssetBundles并显示其中详细数据的工具:https://github.com/DerPopo/UABE

代码库:

上面的代码被组织到一个代码存储库中,演示包含一个完整的测试示例。

https://github.com/RayRiver/UnityAlphaSeparateDemo

责任编辑:德勤钢铁网 标签:

热门搜索

相关文章

广告
德勤钢铁网 |市场分析

unity ao贴图怎么贴,unity贴图透明通道

chanong

|

简介在制作手机游戏时,您可能会遇到以下问题。

UI学生每天都会抱怨iOS上的一些透明纹理在压缩后变得模糊。

在一些较旧的Android 智能手机上,相同的纹理消耗的内存比其他智能手机多几倍,常常导致游戏崩溃。

本文介绍了手游项目中常见的一种解决方案:纹理alpha通道分离,以及其基于Unity引擎的实现过程和细节。思路主要取自https://zhuanlan.zhihu.com/p/32674470。本文是对该方法的实践和补充。

为什么分离1.为什么会出现这个问题?

为了理解这些问题的原因,我们首先需要简单解释一下纹理压缩格式的基本概念。

为了确保你的纹理在手机上运行时占用尽可能少的内存,你需要设置纹理的压缩格式。 Unity目前支持的主要压缩格式有:Android上的ETC/ETC2、iOS上的PVRTC以及将来可能会使用的ASTC。这些压缩格式均具有以下特征:

ETC:不支持透明通道。所有Android 设备均支持

ETC2:支持透明通道。您的Android 设备的GPU 必须支持OpenGL es 3.0 才能使用。对于不支持的设备,它以未压缩的格式存储在内存中,占用更多的内存。

PVRTC:适用于所有Apple 设备。压缩纹理的长度和宽度必须相等且为2的幂(POT,2的幂)。

ASTC:一种高质量、低内存的压缩格式,将来可能会普遍使用,但目前某些型号不支持。

一般来说,Android上的Unity手游目前不透明纹理使用RGB压缩ETC 4-bit,透明纹理使用RGBA压缩ETC2 8-bit,iOS非透明纹理使用RGB压缩PVRTC 4-bit,透明纹理使用RGBA压缩PVRTC 4 位。

这里的比特的概念是指每个像素占用的比特数。例如,对于RGB 压缩PVRTC 4 位格式的1024x1024 纹理,在内存中占用的大小=1024x1024x4(位)=4M(位)=0.5M(字节)。

在iOS 上,您可以看到非透明和透明纹理都是4bpp(每像素4 位)。即使透明通道增加,它们也将保持相同的大小。当然,4bpp 透明纹理的压缩效果较差。当你在实际机器上看到它时,它看起来确实很糟糕。这是你第一个问题的答案。

由于一些早期的Android 机器不支持OpenGL es 3.0,RGBA 压缩的ETC2 8 位纹理通常以RGBA 32 位格式驻留在内存中,导致内存使用量高达原始的四倍。在内存较少的旧机器上,情况并非如此。令人惊奇的是,在这种情况下,系统会如何杀死系统。这是你第二个问题的答案。当然,需要注意的是,不支持OpenGL es 3.0的机器的市场份额已经相当低(不到1%),大多数情况下可以忽略不计。

更多纹理压缩格式请参见:https://zhuanlan.zhihu.com/p/113366420

2. 如何解决问题

要解决上述图像模糊问题,您可以执行以下步骤:

透明纹理未压缩并占用32bpp 内存。

独立的alpha通道,内存使用4bpp+4bpp(或4bpp+8bpp)

不压缩当然是不可能的,毕竟32bpp对于手机,尤其是内存较低的iOS设备来说,内存消耗太大了。所以考虑分离alpha通道,将不透明和透明部分分割成两幅图像(如下图)。

关于内存使用,非透明部分一般分为RGB压缩的PVRTC 4位,透明通道部分为RGB压缩的PVRTC 4位或Alpha8格式(8bpp)。 Alpha8格式的不同版本的Unity似乎对手机上的Mali芯片的支持不同,但我没有做过详细的研究。测试时,我们使用RGB压缩的PVRTC 4位格式来压缩透明通道图,效果完全可以接受。

分离方法1.溶液1

当然,您会希望继承SpriteRenderer/Image 组件并在运行时替换材质以实现您的目标。这种解决方案有一些缺点,对于开发到后期的项目来说,更改所有组件的成本非常高。更不用说,在添加版本控制的项目中,修改预制件的成本也非常高。此外,对于已经开发的项目来说,修改预制件的成本也非常高,对于使用定制材料的组件来说也非常不方便。

2. 选项2

直接修改精灵的RenderData,以便在打包时将关联的纹理、alphaTexture 等信息直接正确填充到包中。

这样做的好处是你不需要改变任何组件,只需要做一次,只要定制整个打包流程即可。这不是问题,因为大多数商业项目本质上都需要定制的包装过程。

首先说明一下实现,这个方案在2017.4就通过了测试,我使用废弃的Sprite Packer方法创建了一个图集,我没有研究过Sprite Atlas的方法,但是我认为应该可以实现,但是,改变可能有必要。有不少流程。

具体实现稍后再讲,但打包前的大致流程如下。

我简单解释一下上面的过程。

UpdateAtlases:强制更新图集缓存(需要alpha 通道分离的图集需要更改其压缩格式以删除A 通道)

FindAllEntries:查找所有精灵,检查其PackingTag,对所有精灵和图集信息进行分类和排序。

GenerateAlphaTextures/SaveTextureAssets:根据图集信息绘制alpha通道纹理并保存文件。

AssetDatabase.Refresh:事实上,如果不更新某些纹理可能会丢失。

ReloadTextures:从文件加载纹理作为写入RenderData 的数据。

WriteSpritesRenderData:最重要的一步是将纹理、alphaTexture 和其他信息写入精灵的RenderData。

最后,打包前,禁用SpritePacker,避免打包时覆盖图集和精灵的RenderData。

透明通道贴图在生成Alpha 通道贴图时不受影响,因为它使用散点贴图位置和图集中的其他信息直接渲染顶点信息,然后压缩到贴图上。需要注意的是,没有通过压缩。

//临时渲染纹理

varrt=RenderTexture.GetTemporary(texWidth, texHeight,0, RenderTextureFormat.ARGB32);

Graphics.SetRenderTarget(rt);

GL.Clear(true,true, Color.clear);GL.PushMatrix;GL.LoadOrtho;foreach(varspriteEntryinatlasEntry.SpriteEntries){varsprite=spriteEntry.Sprite;varuvs=spriteEntry.Uvs;varatlasUvs=spriteEntry.AtlasUvs;//压缩后的前一个精灵的顶点信息被渲染到临时纹理中。 mat.mainTexture=spriteEntry.Texture;mat.SetPass(0);GL.Begin(GL.TRIANGLES);vartriangles=sprite.triangles;foreach(varindexintriangles){GL.TexCoord(uvs [index]);GL.Vertex(atlasUvs) [索引]);}GL.End;

}

GL.Pop 矩阵;

//最终的alpha 贴图

varfinalTex=newTexture2D(texWidth, texHeight, TextureFormat.RGBA32,false);

FinalTex.ReadPixels(newRect(0,0, texWidth, texHeight),0,0);

//换颜色

varcolors=FinalTex.GetPixels32;

varcount=颜色. 长度;

varnewColors=newColor32[计数];

for(vari=0; i 计数; ++i){

vara=color[i].a;newColors[i]=newColor32(a, a, a,255);

}

FinalTex.SetPixels32(newColors);finalTex.Apply;

RenderTexture.ReleaseTemporary(rt);

将透明通道纹理写入文件时要记住的一件事是,您正在打印的图集将生成多个页面,并且这些页面都将具有相同的纹理名称,因此如果直接保存它们,您可能会意外覆盖它们。这是有可能完成的。与Page不同的是,这里我们使用Texture的哈希码。

//支持多页图册

varhashCode=atlasEntry.Texture.GetHashCode;

//导出alpha纹理

如果(atlasEntry.NeedSeparateAlpha){

varfileName=atlasEntry.Name +\'_\'+ hashCode +\'_alpha.png\';varfilePath=Path.Combine(path, fileName);File.WriteAllBytes(filePath, atlasEntry.AlphaTexture.EncodeToPNG);atlasEntry.AlphaTextureAssetPath=Path.Combine(assetPath, 文件名);

}

接下来,我们将解释编写SpriteRenderData的最重要的部分。

varspr=spriteEntry.Sprite;

varso=newSerializedObject(spr);

//获取散点图属性

varrect=so.FindProperty(\'m_Rect\').rectValue;

varpivot=so.FindProperty(\'m_Pivot\').vector2Value;

varpixelsToUnits=so.FindProperty(\'m_PixelsToUnits\').floatValue;

vartightRect=so.FindProperty(\'m_RD.textureRect\').rectValue;

varoriginSettingsRaw=so.FindProperty(\'m_RD.settingsRaw\').intValue;

//散点图像(全矩形)内散点图像(紧)的位置、宽度和高度

vartightOffset=newVector2(tightRect.x,ightRect.y);

vartightWidth=tinyRect.width;

vartightHeight=tinyRect.height;

//计算散点图(完美矩形)在图集中的矩形和偏移量。

varfullRectInAtlas=GetTextureFullRectInAtlas(atlasTexture,

spriteEntry.Uvs, spriteEntry.AtlasUvs);

varfullRectOffsetInAtlas=newVector2(fullRectInAtlas.x, fullRectInAtlas.y);

//计算图集中散点图像(紧密)的矩形。

vartightRectInAtlas=newRect(fullRectInAtlas.x +tinyOffset.x, fullRectInAtlas.y + tinyOffset.y,tinyWidth,tinyHeight);

//计算uvTransform

//x: 像素换算为单位X

//y: 图集X中心点位置

//z: 像素到Y 单位

//w: 图集中心点位置Y

varuvTransform=newVector4(

PixelsToUnits, 矩形宽度* 枢轴.x + fullRectOffsetInAtlas.x, 像素到单位, 矩形. 高度* 枢轴.y + fullRectOffsetInAtlas.y);

//计算设置

//位0:已打包。 1表示已打包,0表示未打包

//1 位:SpritePackingMode。 0 表示紧密,1 表示矩形

//第2-5 位:SpritePackingRotation。 0表示不旋转,1表示水平翻转,2表示垂直翻转,3表示180度旋转,4表示90度旋转。

//6 位:SpriteMeshType。 0 表示完美直角,1 表示紧密

//67=SpriteMeshType(紧) + SpritePackingMode(矩形) + pack

varsettingsRaw=67;

//写入RenderDataso.FindProperty(\'m_RD.texture\').objectReferenceValue=atlasTexture;so.FindProperty(\'m_RD.alphaTexture\').objectReferenceValue=alphaTexture;so.FindProperty(\'m_RD.textureRect\') 马苏。 rectValue=tinyRectInAtlas;so.FindProperty(\'m_RD.textureRectOffset\').vector2Value=tinyOffset;so.FindProperty(\'m_RD.atlasRectOffset\').vector2Value=fullRectOffsetInAtlas;so.FindProperty(\'m_RD.settingsRaw\' ) .intValue=settingsRaw;so.FindProperty(\'m_RD.uvTransform\').vector4Value=uvTransform;so.ApplyModifiedProperties;

//备份原始数据以便恢复

spriteEntry.OriginTextureRect=tinyRect;spriteEntry.OriginSettingsRaw=originSettingsRaw;需要修改的部分的含义已经在注释中写得很清楚了,大家看一下就可以大概明白了。还有一些概念需要解释。

精灵导入设置将要求您设置网格类型。默认值是“紧密”,它根据Alpha 裁剪尽可能多的像素。另一方面,全矩形意味着将使用与图像纹理大小相同的矩形。

使用这两个选项创建图集时,如果散点图像周围有很多alpha,您会注意到使用完整的矩形会使图像非常分散,但使用紧密的矩形会使外观非常紧凑。以及效果如下:

您可以在上面的原始散点图中看到它周围有很多透明区域。

上面是使用紧密网格类型创建的图集,可以看到中间的间隙缩小了。

上面是使用全矩形网格类型创建的图集,但是您可以看到中间有很大的间隙。

通常我们使用的是Tight,所以上面的代码需要计算一些与Tight相关的值,但是具体的计算方法可以直接在代码中看到,所以应该不难理解。

还有一个方法GetTextureFullRectInAtlas 可以获取计算散点图像的图集中的矩形(完整矩形)。这是代码:

privatestaticRect GetTextureFullRectInAtlas(Texture2D atlasTexture, Vector2[] uvs, Vector2[] atlasUvs){vartextureRect=newRect;//查找x/y不相等的点varindex=0;varcount=uvs.Length;for(vari=1; i count ; i++){if(Math.Abs(uvs[i].x - uvs[0].x) 1E-06Math.Abs(uvs[i].y - uvs[0].y) 1E- 06 ) { index=i;break;}}//计算大图像中散乱图像的纹理矩形varatlasWidth=atlasTexture.width;varatlasHeight=atlasTexture.height;textureRect.width=(atlasUvs[0].x - atlasUvs[索引] .x )/(uvs[0].x - uvs[索引].x) * atlasWidth;textureRect.height=(atlasUvs[0].y - atlasUvs[index].y)/(uvs[0 ]. y - uvs[索引].y) * atlasHeight;textureRect.x=atlasUvs[0].x * atlasWidth -textureRect.width * uvs[0].x;textureRect.y=atlasUvs[0].y * atlasHeight - 纹理矩形.height * uvs [0].y;returntextureRect;

}

最后,需要决定是否需要自定义图集规则、分离Alpha通道纹理、更改相应的压缩格式,例如RGBA ETC2改为RGB ETC或RGBA PVRTC改为RGB PVRTC。这样做是为了从图集中生成不透明纹理的原始图像。大概的代码是:

//如果需要分离alpha通道

if(TextureUtility.IsTransparent(settings.format)) {

settings.format=TextureUtility.TransparentToNoTransparentFormat(settings.format);} 关于如何自定义图集规则,请参考官方文档:https://docs.unity3d.com/Manual/SpritePacker.html

一些补充: 1. 手机上UI.Image 中显示的纹理似乎丢失了材质。

原因是Image组件使用该方案时,使用了内置着色器DefaultETC1。这应该包含在始终包含的着色器中。

2、分离出alpha通道纹理精灵资源并打包。

下图显示了未分离Alpha 通道的散点图,如AssetStudio 工具中所示。您可以看到每个精灵都引用一个Texture2D。

下图显示了alpha 通道分离的图集。正如你所看到的,这个AssetBundle包只有几个sprite和两个Texture2D(一个不透明贴图和一个透明通道贴图)。

3. 如何找出精灵的哪些渲染数据需要更改?

在实际试用中,你可以使用UABE工具来比较分离和不分离alpha通道的精灵渲染数据的差异,并确定需要改变哪些数据才能达到你的目标,我确定是有的。

从下图中可以看到(左边是正常的图集数据,右边是我尝试模拟写入RenderData的不正确数据),texture、alphaTexture、textureRect、textureRectOffset、settingsRaw和uvTransform字段都是m_RD一切都必须改变。由于我们无法获取源代码,因此一些价值算法是通过分析和推测来验证的。

4、m_RD.settingsRaw的值是什么意思?

settingsRaw的部分定义可以在AssetStudio源代码中找到。

位0:已打包。 1表示已打包,0表示未打包

位1:SpritePackingMode。 0 表示紧密,1 表示矩形

位置2-5:SpritePackingRotation。 0表示不旋转,1表示水平翻转,2表示垂直翻转,3表示180度旋转,4表示90度旋转。

6 位:SpriteMeshType。 0 表示完美直角,1 表示紧密

正常生成的图集值为67。这是,

SpriteMeshType(紧) + SpritePackingMode(矩形) + pack.

5.使用Unity 2017测试通过。我可以通过其他版本吗?

我不知道。如果你看AssetStudio源码可以看到,根据Unity版本的不同,序列化后会进行不同的处理(见下文),如果不同版本出现问题,可以通过对比精灵的RenderData来解决问题。需要在AssetBundle 包中输入额外的数据,如上所述。

延伸思考:如果我用TexturePacker代替更新图集缓存的第一个操作,我是否可以使用TexturePacker的一些功能来优化和定制图集?这是可能的,但并非微不足道。虽然仍然很乏味,但肯定是个好主意。有需要的同学可以学**一下。

参考Unity Atlas IOS上透明通道分割(不带TP):https://zhuanlan.zhihu.com/p/32674470

[2018.1]Unity纹理压缩格式设置:https://zhuanlan.zhihu.com/p/113366420

(旧版)Sprite Packer:https://docs.unity3d.com/Manual/SpritePacker.html

文章中提到的工具:

AssetStudio,一个可以轻松查看AssetBundles内容的工具:https://github.com/Perfare/AssetStudio

UABE,一个可以解压/打包AssetBundles并显示其中详细数据的工具:https://github.com/DerPopo/UABE

代码库:

上面的代码被组织到一个代码存储库中,演示包含一个完整的测试示例。

https://github.com/RayRiver/UnityAlphaSeparateDemo


市场分析