在如今的手游开发中,Unity为我们提供了自定义资源导入和设置流程的功能(AssetPostProcessor),可以在导入时自动设置资源文件的格式。 我们完全可以通过程序的自动处理来处理纹理图片、模型文件、音效资源等文件的导入格式设置。 使用程序自动处理比我们手工处理更可靠,因为人有情绪、情绪、粗心。 如果不小心将一张2048的真彩色图片放入工程中使用,会直接占用16M的内存空间。 因此,作为一个Unity项目,我们应该在研发之初就规划好资源文件的分类以及分类的格式化属性。 通过继承AssetPostProcessor类,可以为Texture、FBX、动画、音效文件编写自动导入设置处理函数unity 图片压缩格式,让程序代替手工工作,确保一切万无一失。
AssetPostProcessor 类描述
//示例代码:
public class MyAssetPostprocessor : AssetPostprocessor
{
public void OnPreprocessModel()
{
ModelImporter modelImporter = (ModelImporter)assetImporter;
if(modelImporter.isReadable)
{
modelImporter.isReadable = false;
modelImporter.SaveAndReimport();
}
}
}
上图列出了AssetPostProcessor派生类可以自行定义和处理的资源类型。 如果需要自定义纹理贴图格式,则需要添加voidOnPostprocessTexture(Texture2Dtexture)函数。 注意,这里的处理函数使用了反射机制,而不是重载虚函数,类似于MonoBehaviour的voidStart()和voidUpdate()。 下面我们详细介绍几种典型的资源文件格式规范。 一些格式说明请参考Unity官方手册。
质地
纹理贴图可以说是游戏中最耗内存的资源,无论是功能UI界面还是场景资源都会用到。 一张1024*1024大小、32位真彩色格式的图片,虽然其PNG文件的原始大小可能只有几百K甚至更小,但在运行时会占用4M的内存空间(因为Texture是通过Opengl创建的)程序中图形接口创建纹理时,会先将压缩文件解压,读出原始像素信息数据,创建GPU所需的Texture对象)。 因此,设置合理的纹理贴图资源格式对于内存优化非常重要。 下面是Texture的一些设置属性的说明:
读/写
启用读/写将导致纹理占用两份内存,一份位于 GPU 端,一份位于系统内存中。 因为启用读/写意味着CPU端逻辑程序可以在运行时读取或修改纹理像素信息(GetPixel32、SetPixel32),因此必须在系统内存中保留像素信息的副本。 在项目中,大部分图像仅用于GPU渲染,因此如果没有特殊需要,请禁用Read/Write。
Mip贴图
Mipmap主要用于3D场景中的模型映射。 渲染底层会根据屏幕上呈现的物体的实际渲染尺寸选择合适的第一级mipmap。 如果相机的距离对渲染到屏幕上的某些对象(例如正交相机)的大小没有影响硬件设备,则应该对这些对象的纹理禁用 mipmap。 最典型的就是UI界面的质感。 这可以将纹理内存使用量减少近一半。
自动压缩
压缩图像格式对于移动设备非常有用,因为与真彩色格式相比,它们将大大减少内存使用量。 注意游戏图片,这里的压缩不仅仅指纹理文件的压缩,而是纹理贴图像素数据在内存中是压缩格式的。 渲染采样时,GPU负责实时解压。 因此,压缩格式与GPU厂商有关,安卓和苹果设备支持的压缩格式不同。 这种压缩是有损的,是以牺牲纹理的像素精度为基础的,所以我们开发者需要根据实际的艺术效果来控制。 作为程序,建议纹理贴图采用自动压缩格式,以便Unity能够根据目标平台生成其对应的压缩格式纹理。 根据以往的项目经验,3D模型纹理、特效纹理以及一些UI纹理都非常适合压缩格式。 一些对图像质量要求较高的图片可以使用真彩色。 这个需要根据项目的实际情况灵活使用。 下图是各个平台的纹理压缩格式的介绍。
1024*2014(ARGB)
1024*2014(RGB)
ETC1(安卓)
不支持
0.5M
ETC2(安卓)
1M
0.5M
PVRTC(IOS)
0.5M
0.5M
DX1(Windows)
不支持
0.5M
DX5(Windows)
1M
不支持
本色
4M
3M
纹理尺寸限制
纹理贴图的大小规格对内存使用有非常重要的影响。 在项目开始时,应该为艺术生准备一份纹理规范文档,明确UI、特效、人物图、场景图等资源图的建议尺寸和最大尺寸限制。
模型
读/写
这个和前面纹理的读/写类似,Unity默认是开启的。 如果不需要在运行时通过程序动态修改模型的顶点数据,那么就没有必要打开这个选项,一般应该禁用它。 另外,如果模型的GameObject上需要MeshCollider组件,则必须打开此选项。
Rigson非角色模型
导入 FBX 文件时,Unity 将默认导出非角色动画模型的通用装备。 这会在 FBX 预制件中产生一个额外的 Animator 组件,这对于不需要动画的模型来说是多余的,因为所有活动的 Animator 组件每帧都会滴答一次。
优化游戏对象选项
“OptimizeGameObjects”选项对动画模型的运行性能影响很大。 如果禁用该选项,Unity在实例化模型时会根据模型中的骨骼结构构建一个巨大的变换树结构,每个骨骼对应一个变换。 如此庞大的转换架构更新起来相当耗时。 它还限制了Unity对于顶点蒙皮和骨骼动画的多线程计算能力。 如果程序中要使用某些骨骼附着点来附着其他模型(例如角色手上的武器附着点等),则可以在 extratransform 列表中单独注明这些骨骼附着点的名称unity 图片压缩格式,以避免错误优化期间。 处理不当。
网格压缩
启用网格压缩将减少用于表示浮点类型数据的位数。 这是基于降低少量浮点数的精度。 因此,相关艺术生应该审视一下最终的渲染效果,看看是否在可以忍受的范围内。 里面。 这种压缩是分层的。 例如,我们可以选择只压缩法线向量和切线向量,而不压缩UV坐标和顶点位置。
网格渲染器设置
将网格渲染器添加到预制件或游戏对象时,Unity 将默认启用“ShadowCast”和“ReceiveShadow”。 如果我们不需要这些,那么这些选项就应该关闭,否则会造成多余的渲染成本,增加渲染。 消耗。 因为渲染实时阴影需要添加额外的渲染通道。
最后是一个在导入资源文件时自动处理格式化的程序示例:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
//资源文件导入自动设置程序
class MyAssetPostProcessor : AssetPostprocessor
{
//贴图导出时处理
void OnPreprocessTexture()
{
TextureImporter textureImporter = (TextureImporter)assetImporter;
if (assetPath.StartsWith("Assets/Art/UI"))
{
//如果是UI贴图,禁用mipmap
textureImporter.mipmapEnabled = false;
textureImporter.textureType = TextureImporterType.Sprite;
if (assetPath.StartsWith("Assets/Art/UI/Common"))
{
//通用UI控件(Button, Input)等复用率高,尺寸小的UI图片,直接用truecolor
//这样能以最小的内存代价提升美术效果
textureImporter.textureFormat = TextureImporterFormat.AutomaticTruecolor;
}
else
{
textureImporter.textureFormat = TextureImporterFormat.AutomaticCompressed;
}
//纹理贴图的最大尺寸限制为<=1024
textureImporter.maxTextureSize = 1024;
textureImporter.isReadable = false;
}
else if(assetPath.StartsWith("Assets/Art/3D/Texture/"))
{
//如果是3D模型的贴图,启用mipmap
textureImporter.mipmapEnabled = true;
textureImporter.textureFormat = TextureImporterFormat.AutomaticCompressed;
//如果是法线贴图
if (assetPath.Contains("_N"))
textureImporter.textureType = TextureImporterType.Bump;
//纹理贴图的最大尺寸限制为<=1024
textureImporter.maxTextureSize = 1024;
textureImporter.isReadable = false;
}
//对于不是2n次方的图片,自动适配到2n次方的大小
textureImporter.npotScale = TextureImporterNPOTScale.ToNearest;
}
//模型导出时处理
void OnPreprocessModel()
{
ModelImporter modelImporter = this.assetImporter as ModelImporter;
modelImporter.isReadable = false;
modelImporter.meshCompression = ModelImporterMeshCompression.Medium;
if (assetPath.Contains("/AnimModel/"))
{
//如果是带动画的模型
modelImporter.importAnimation = true;
modelImporter.importBlendShapes = true;
modelImporter.animationCompression = ModelImporterAnimationCompression.Optimal;
}
else if (assetPath.Contains("/CommonModel/"))
{
//如果是不带动画的模型
modelImporter.importAnimation = false;
modelImporter.importBlendShapes = false;
}
}
//音效导入时处理
public void OnPreprocessAudio()
{
AudioImporter audioImporter = this.assetImporter as AudioImporter;
AudioImporterSampleSettings settings = audioImporter.defaultSampleSettings;
if (assetPath.Contains("/Sound/"))
{
//如果UI事件音效(文件小,播放时间短)
settings.loadType = AudioClipLoadType.DecompressOnLoad;
}
else if (assetPath.Contains("/Music/"))
{
//如果是背景音效(文件大,播放时间长)
settings.loadType = AudioClipLoadType.Streaming;
}
audioImporter.defaultSampleSettings = settings;
}
}
文章来源:https://blog.csdn.net/qq_14939027/article/details/79182105