Unity优化杂谈4(UI)
2017-10-12 16:59
447 查看
UI这块我们用的NGUI,这里不得不说NGUI的图集,而图集的使用直接影响一个界面加载的速度。我们的UI加载机制是,有部分常驻UI界面,一些动态加载关闭直接卸载的UI界面,一些动态加载打开另外界面才卸载的,所以如果UI里面引用了太多的图集会使界面卡顿,而图集这里也是分为常驻(头像,图标,以及通用的按钮等)的和无用时卸载的。不管加载方式是同步还是异步,规整好图集会使界面加载速度提升。
一般图集都不会压缩,一张RGBA 1024*1024的图集是4M,但是可以把他分为RGA图一张和A图一张,一共1M,同时图集使用的shader需要做相应的修改,在计算的时候要把两张图叠加返回。当然这个在加载bundle的时候需要加载两张,根据手机性能不同一张大图和两张小图的速度各有不同,但内存减少很多。
public
static
voidSetTextureInfo(string
texPath)
{
TextureImporter textureImporter =
AssetImporter.GetAtPath(texPath)
as
TextureImporter;
if (null
==textureImporter)
return;
4000
textureImporter.textureType = TextureImporterType.Advanced;
textureImporter.mipmapEnabled = false;
textureImporter.wrapMode = TextureWrapMode.Clamp;
textureImporter.filterMode = FilterMode.Trilinear;
textureImporter.anisoLevel = 5;
textureImporter.SetPlatformTextureSettings("Default",
2048, TextureImporterFormat.AutomaticCompressed);
textureImporter.SetPlatformTextureSettings("iPhone",
2048, TextureImporterFormat.PVRTC_RGB4, 98,
false);
textureImporter.SetPlatformTextureSettings("Android",
2048, TextureImporterFormat.ETC2_RGB4, 98,
false);
AssetDatabase.ImportAsset(texPath,
ImportAssetOptions.ForceUpdate |
ImportAssetOptions.ForceSynchronousImport);
}
private
static
voidProcessMaterial(string
mPath)
{
//更换材质
Material mat =
AssetDatabase.LoadAssetAtPath<Material>(mPath);
if (mat ==
null)
return;
Shader oldShader = mat.shader;
Shader newShader =
Shader.Find(atlasExtendShaderName);
if (oldShader ==
null || newShader==
null || oldShader.name !=atlasBaseShaderName)
return;
Texture2D tex2D = mat.GetTexture("_MainTex")
as
Texture2D;
string texPath =
AssetDatabase.GetAssetPath(tex2D);
if (!texPath.EndsWith(".png"))
return;
//设置图片可读
TextureImporter textureImporter =
AssetImporter.GetAtPath(texPath)
as
TextureImporter;
textureImporter.isReadable = true;
AssetDatabase.ImportAsset(texPath,
ImportAssetOptions.ForceUpdate |
ImportAssetOptions.ForceSynchronousImport);
//进行修改
int textWidth = 0;
if (tex2D.width >= tex2D.height)
textWidth = tex2D.width;
else
textWidth = tex2D.height;
Texture2D rgbTex =
new
Texture2D(textWidth,textWidth,
TextureFormat.RGB24,
false);
Texture2D aTex =
new
Texture2D(textWidth,textWidth,
TextureFormat.RGB24,
false);
if (!SplitTexture(tex2D,
ref rgbTex,
ref aTex))
return;
string rgbTexPath = texPath.Replace(".png",
"_rgb.png");
string aTexPath = texPath.Replace(".png",
"_a.png");
if (null
== rgbTex || string.IsNullOrEmpty(rgbTexPath))
return;
File.WriteAllBytes(prjDataPath.Replace("Assets",
"") + rgbTexPath, rgbTex.EncodeToPNG());
if (null
== aTex || string.IsNullOrEmpty(aTexPath))
return;
File.WriteAllBytes(prjDataPath.Replace("Assets",
"") + texPath, aTex.EncodeToPNG());
AssetDatabase.SaveAssets();
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate
| ImportAssetOptions.ForceSynchronousImport);
SetTextureInfo(rgbTexPath);
SetTextureInfo(aTexPath);
Texture2D rgbReplaceTex =
AssetDatabase.LoadAssetAtPath<Texture2D>(rgbTexPath);
Texture2D aReplaceTex =
AssetDatabase.LoadAssetAtPath<Texture2D>(aTexPath);
if (rgbReplaceTex ==
null || aReplaceTex ==
null)
return;
mat.shader = newShader;
mat.SetTexture("_MainTex", rgbReplaceTex);
mat.SetTexture("_Mask", aReplaceTex);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate
| ImportAssetOptions.ForceSynchronousImport);
Object.DestroyImmediate(rgbTex,
true);
Object.DestroyImmediate(aTex,
true);
textureImporter = AssetImporter.GetAtPath(texPath)
as
TextureImporter;
textureImporter.isReadable = false;
AssetDatabase.ImportAsset(texPath,
ImportAssetOptions.ForceUpdate |
ImportAssetOptions.ForceSynchronousImport);
Resources.UnloadUnusedAssets();
}
//拆分贴图
private
static
bool SplitTexture(Texture2D
oldTex, ref
Texture2D rgbTex,
ref
Texture2D aTex)
{
if (oldTex ==
null || rgbTex ==
null || aTex ==
null)
return
false;
if (rgbTex.width != rgbTex.height ||
aTex.width != aTex.width ||
rgbTex.width != aTex.width ||
oldTex.width > rgbTex.width ||
oldTex.height > rgbTex.width)
return
false;
Color32[] oldPixels = oldTex.GetPixels32();
Color32[] rgbPixels =
new
Color32[rgbTex.width *rgbTex.height];
Color32[] aPixels =
new
Color32[aTex.width *aTex.height];
if (oldPixels ==
null || rgbPixels==
null || aPixels ==
null)
return
false;
for(int
i = 0; i <rgbTex.height; ++i)
{
for (int
j = 0; j <rgbTex.width; ++j)
{
int sorIdx = i * oldTex.width
+ j;
int tarIdx = i * rgbTex.width + j;
if (i >= oldTex.height || j >= oldTex.width)
{
rgbPixels[tarIdx] = Color.black;
aPixels[tarIdx] = Color.white;
}
else
{
//copy color
rgbPixels[tarIdx].r =oldPixels[sorIdx].r;
rgbPixels[tarIdx].g =oldPixels[sorIdx].g;
rgbPixels[tarIdx].b =oldPixels[sorIdx].b;
rgbPixels[tarIdx].a = 0;
//copy alpha
aPixels[tarIdx].r =oldPixels[sorIdx].a;
aPixels[tarIdx].g = 0;
aPixels[tarIdx].b = 0;
aPixels[tarIdx].a = 0;
}
}
}
rgbTex.SetPixels32(rgbPixels);
aTex.SetPixels32(aPixels);
rgbTex.Apply();
aTex.Apply();
return
true;
}
NGUI这里的代码也是有些坑的,类似uiTween,uiTable等使用不当的时候都会存在GC,当然这些最好根据自己项目需求写自己的功能(比如按钮的反馈,图片拖拽,循环滑动列表,UITable的response方法)。
还有就是场景上的UI,如血条,名字之类的,要在一个panel下。
文字在一个界面上放到一个层级上。
这些都会有利于降低UI上的DC。
一般图集都不会压缩,一张RGBA 1024*1024的图集是4M,但是可以把他分为RGA图一张和A图一张,一共1M,同时图集使用的shader需要做相应的修改,在计算的时候要把两张图叠加返回。当然这个在加载bundle的时候需要加载两张,根据手机性能不同一张大图和两张小图的速度各有不同,但内存减少很多。
public
static
voidSetTextureInfo(string
texPath)
{
TextureImporter textureImporter =
AssetImporter.GetAtPath(texPath)
as
TextureImporter;
if (null
==textureImporter)
return;
4000
textureImporter.textureType = TextureImporterType.Advanced;
textureImporter.mipmapEnabled = false;
textureImporter.wrapMode = TextureWrapMode.Clamp;
textureImporter.filterMode = FilterMode.Trilinear;
textureImporter.anisoLevel = 5;
textureImporter.SetPlatformTextureSettings("Default",
2048, TextureImporterFormat.AutomaticCompressed);
textureImporter.SetPlatformTextureSettings("iPhone",
2048, TextureImporterFormat.PVRTC_RGB4, 98,
false);
textureImporter.SetPlatformTextureSettings("Android",
2048, TextureImporterFormat.ETC2_RGB4, 98,
false);
AssetDatabase.ImportAsset(texPath,
ImportAssetOptions.ForceUpdate |
ImportAssetOptions.ForceSynchronousImport);
}
private
static
voidProcessMaterial(string
mPath)
{
//更换材质
Material mat =
AssetDatabase.LoadAssetAtPath<Material>(mPath);
if (mat ==
null)
return;
Shader oldShader = mat.shader;
Shader newShader =
Shader.Find(atlasExtendShaderName);
if (oldShader ==
null || newShader==
null || oldShader.name !=atlasBaseShaderName)
return;
Texture2D tex2D = mat.GetTexture("_MainTex")
as
Texture2D;
string texPath =
AssetDatabase.GetAssetPath(tex2D);
if (!texPath.EndsWith(".png"))
return;
//设置图片可读
TextureImporter textureImporter =
AssetImporter.GetAtPath(texPath)
as
TextureImporter;
textureImporter.isReadable = true;
AssetDatabase.ImportAsset(texPath,
ImportAssetOptions.ForceUpdate |
ImportAssetOptions.ForceSynchronousImport);
//进行修改
int textWidth = 0;
if (tex2D.width >= tex2D.height)
textWidth = tex2D.width;
else
textWidth = tex2D.height;
Texture2D rgbTex =
new
Texture2D(textWidth,textWidth,
TextureFormat.RGB24,
false);
Texture2D aTex =
new
Texture2D(textWidth,textWidth,
TextureFormat.RGB24,
false);
if (!SplitTexture(tex2D,
ref rgbTex,
ref aTex))
return;
string rgbTexPath = texPath.Replace(".png",
"_rgb.png");
string aTexPath = texPath.Replace(".png",
"_a.png");
if (null
== rgbTex || string.IsNullOrEmpty(rgbTexPath))
return;
File.WriteAllBytes(prjDataPath.Replace("Assets",
"") + rgbTexPath, rgbTex.EncodeToPNG());
if (null
== aTex || string.IsNullOrEmpty(aTexPath))
return;
File.WriteAllBytes(prjDataPath.Replace("Assets",
"") + texPath, aTex.EncodeToPNG());
AssetDatabase.SaveAssets();
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate
| ImportAssetOptions.ForceSynchronousImport);
SetTextureInfo(rgbTexPath);
SetTextureInfo(aTexPath);
Texture2D rgbReplaceTex =
AssetDatabase.LoadAssetAtPath<Texture2D>(rgbTexPath);
Texture2D aReplaceTex =
AssetDatabase.LoadAssetAtPath<Texture2D>(aTexPath);
if (rgbReplaceTex ==
null || aReplaceTex ==
null)
return;
mat.shader = newShader;
mat.SetTexture("_MainTex", rgbReplaceTex);
mat.SetTexture("_Mask", aReplaceTex);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate
| ImportAssetOptions.ForceSynchronousImport);
Object.DestroyImmediate(rgbTex,
true);
Object.DestroyImmediate(aTex,
true);
textureImporter = AssetImporter.GetAtPath(texPath)
as
TextureImporter;
textureImporter.isReadable = false;
AssetDatabase.ImportAsset(texPath,
ImportAssetOptions.ForceUpdate |
ImportAssetOptions.ForceSynchronousImport);
Resources.UnloadUnusedAssets();
}
//拆分贴图
private
static
bool SplitTexture(Texture2D
oldTex, ref
Texture2D rgbTex,
ref
Texture2D aTex)
{
if (oldTex ==
null || rgbTex ==
null || aTex ==
null)
return
false;
if (rgbTex.width != rgbTex.height ||
aTex.width != aTex.width ||
rgbTex.width != aTex.width ||
oldTex.width > rgbTex.width ||
oldTex.height > rgbTex.width)
return
false;
Color32[] oldPixels = oldTex.GetPixels32();
Color32[] rgbPixels =
new
Color32[rgbTex.width *rgbTex.height];
Color32[] aPixels =
new
Color32[aTex.width *aTex.height];
if (oldPixels ==
null || rgbPixels==
null || aPixels ==
null)
return
false;
for(int
i = 0; i <rgbTex.height; ++i)
{
for (int
j = 0; j <rgbTex.width; ++j)
{
int sorIdx = i * oldTex.width
+ j;
int tarIdx = i * rgbTex.width + j;
if (i >= oldTex.height || j >= oldTex.width)
{
rgbPixels[tarIdx] = Color.black;
aPixels[tarIdx] = Color.white;
}
else
{
//copy color
rgbPixels[tarIdx].r =oldPixels[sorIdx].r;
rgbPixels[tarIdx].g =oldPixels[sorIdx].g;
rgbPixels[tarIdx].b =oldPixels[sorIdx].b;
rgbPixels[tarIdx].a = 0;
//copy alpha
aPixels[tarIdx].r =oldPixels[sorIdx].a;
aPixels[tarIdx].g = 0;
aPixels[tarIdx].b = 0;
aPixels[tarIdx].a = 0;
}
}
}
rgbTex.SetPixels32(rgbPixels);
aTex.SetPixels32(aPixels);
rgbTex.Apply();
aTex.Apply();
return
true;
}
NGUI这里的代码也是有些坑的,类似uiTween,uiTable等使用不当的时候都会存在GC,当然这些最好根据自己项目需求写自己的功能(比如按钮的反馈,图片拖拽,循环滑动列表,UITable的response方法)。
还有就是场景上的UI,如血条,名字之类的,要在一个panel下。
文字在一个界面上放到一个层级上。
这些都会有利于降低UI上的DC。
相关文章推荐
- [UnityUI]NGUI性能优化之ScrollView
- Unity优化杂谈1
- unity优化杂谈1
- Unity优化杂谈5(代码优化)
- unity优化杂谈2
- Unity UI优化技术与技巧
- Unity UI模块优化(3.优化更新开销)
- Unity UI优化技术与技巧
- unity游戏の优化--UI
- Unity优化杂谈2(MONO内存)
- Unity优化杂谈3(资源)
- Untiy3d-unity游戏性能优化-详细介绍
- 【Unity&NPC&UI】如何使得鼠标悬浮NPC对象,进而响应对应的函数
- Unity优化 CPU-GC(内存回收)和Sricpt
- unity优化之项目优化策略
- unity 场景跳转初步优化——异步跳转
- Unity优化大全(七)之 GPU-几何体和显存宽带
- Unity优化大全(十)之 Memory - Mono的托管内存
- iOS性能调优(全)---内存优化和UI优化
- Unity琐碎(3) UGUI 图文混排解决方案和优化