一般不用改mesh的话读写改了减少一半内存
这个调整模型粗糙程度,还有下面法线可以根据情况关闭导入
找到模型贴图,不需要细节得话MipMap勾掉
然后设置一下压缩格式
还有贴图大小,有些模型是1024x1024的真的占用内存
然后可以打图集,手动拖到material上,不过可以写代码一键替换反正名字都一样
不过这个都可以一件设置
优化动画
主要参考
https://blog.csdn.net/big_di/article/details/79529845
如果是有动画的
动画优化一般分为3种
1.删减无用帧
2.降低动画参数float精度
3.减少骨骼名字
然后打开一个Animation文件,自己随便拿来个,最好别Cube自己K一个动画,因为里面是什么也没有
比如这个文件一个动画浮点数比较精确完全可以保留两位小数
还有一般我们都不动scale 但是动画是动的Position,Rotation还经常用就不剔除了
骨骼名字就不说了一般是自动生成很长,让美术建模创建时候名字改改
Editor脚本
/**
*Copyright(C) 2019 by #COMPANY#
*All rights reserved.
*FileName: #SCRIPTFULLNAME#
*Author: #AUTHOR#
*Version: #VERSION#
*UnityVersion:#UNITYVERSION#
*Date: #DATE#
*Description:
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System;
public class AniOpt
{
// f几就是保留几位
public const string FloatPrecision = "f2";
public const string RemoveCurveName = "scale";
/// <summary>
/// 把当前选取文件夹下Ani文件改变
/// </summary>
[MenuItem("Tools/OptAniFloat", false, 0)]
public static void OptAniF()
{
string[] str = Selection.assetGUIDs;
string path = AssetDatabase.GUIDToAssetPath(str[0]);
DirectoryInfo root = new DirectoryInfo(path);
FileInfo[] files = root.GetFiles("*.anim");
string name;
AnimationClip ac;
for (int i = 0; i < files.Length; i++)
{
name = path + "/" + GetAfterKeyData(files[i].FullName,"\\");
ac = AssetDatabase.LoadAssetAtPath<AnimationClip>(name);
OptAniFloat(ac);
EditorUtility.DisplayProgressBar("进度", i + "/" + files.Length + "完成修改值", (float)i / files.Length);
}
Resources.UnloadUnusedAssets();
//修改立即保存到磁盘
AssetDatabase.SaveAssets();
EditorUtility.ClearProgressBar();
AssetDatabase.Refresh();
GC.Collect();
}
[MenuItem("Tools/RemoveAniCurve", false, 1)]
public static void RemoveAniCurve()
{
string[] str = Selection.assetGUIDs;
string path = AssetDatabase.GUIDToAssetPath(str[0]);
DirectoryInfo root = new DirectoryInfo(path);
FileInfo[] files = root.GetFiles("*.anim");
string name;
AnimationClip ac;
for (int i = 0; i < files.Length; i++)
{
name = path + "/" + GetAfterKeyData(files[i].FullName, "\\");
ac = AssetDatabase.LoadAssetAtPath<AnimationClip>(name);
RemoveAniCurve(ac);
EditorUtility.DisplayProgressBar("进度", i + "/" + files.Length + "完成修改值", (float)i / files.Length);
}
Resources.UnloadUnusedAssets();
//修改立即保存到磁盘
AssetDatabase.SaveAssets();
EditorUtility.ClearProgressBar();
AssetDatabase.Refresh();
GC.Collect();
}
/// <summary>
/// 获取某个限定之后的字符串 如果限定存在多个则取最后一个的位置
/// </summary>
static string GetAfterKeyData(string str, string key)
{
int index = str.LastIndexOf(key) + 1;
int length = str.Length - index;
return str.Substring(index, length);
}
/// <summary>
/// 精简Ani的float精度
/// </summary>
/// <param name="clip"></param>
/// <returns></returns>
static AnimationClip OptAniFloat(AnimationClip clip)
{
//获取所有浮点曲线
EditorCurveBinding[] curves;
curves = AnimationUtility.GetCurveBindings(clip);
Keyframe key;
Keyframe[] keyframes;
for (int i = 0; i < curves.Length; i++)
{
AnimationCurve curve = AnimationUtility.GetEditorCurve(clip, curves[i]);
if (curve == null || curve.keys == null)
continue;
//交换法 把float转换为string
keyframes = curve.keys;
for (int j = 0; j < keyframes.Length; j++)
{
key = keyframes[j];
key.value = float.Parse(key.value.ToString(FloatPrecision));
//传入传出切线
key.inTangent = float.Parse(key.value.ToString(FloatPrecision));
key.outTangent = float.Parse(key.value.ToString(FloatPrecision));
//传入传出权重优化
key.inWeight = float.Parse(key.value.ToString(FloatPrecision));
key.outWeight = float.Parse(key.value.ToString(FloatPrecision));
keyframes[j] = key;
}
curve.keys = keyframes;
//在设置回clip
clip.SetCurve(curves[i].path, curves[i].type, curves[i].propertyName, curve);
}
return clip;
}
/// <summary>
/// 移除Ani 某个曲线
/// </summary>
/// <returns></returns>
static AnimationClip RemoveAniCurve(AnimationClip clip)
{
//获取所有曲线
string name;
foreach (var item in AnimationUtility.GetCurveBindings(clip))
{
//返回小写名字
name = item.propertyName.ToLower();
//就是搜索这个数如果大于0就代表存在 Contaions优化
if (name.IndexOf(RemoveCurveName) >= 0)
{
//null就是删除
AnimationUtility.SetEditorCurve(clip, item, null);
}
}
return clip;
}
}
选择需要更改的文件夹
第一个降float精度,第二个默认去除scale
有个问题精度太低,有些高模会抖动,比如我的就是要自己慢慢调整去改,我是f3抖动的不行,f4有点幻影的感觉,f5更抖动了,直到我直接按原来的精度四舍五入一下就会抖动
因为这里都用了value没有对应参数才会导致
然后修改最终版本
/**
*Copyright(C) 2019 by #COMPANY#
*All rights reserved.
*FileName: #SCRIPTFULLNAME#
*Author: #AUTHOR#
*Version: #VERSION#
*UnityVersion:#UNITYVERSION#
*Date: #DATE#
*Description:
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System;
/// <summary>
/// 先删除无用帧再进行优化float 不然会导致float反弹
/// </summary>
public class AniOpt
{
// f几就是保留几位
public const string FloatPrecision = "f3";
public const string RemoveCurveName = "scale";
public const string OptAniFNamePath = "Tools/OptAniFloat";
public const string RemoveAniCurveNamePath = "Tools/RemoveAniCurve";
[MenuItem(RemoveAniCurveNamePath, true, 0)]
public static bool RemoveAniCurveJudgement()
{
string[] GUIDs = Selection.assetGUIDs;
if (GUIDs.Length == 0)
return false;
else
{
for (int i = 0; i < GUIDs.Length; i++)
{
if (!Directory.Exists(AssetDatabase.GUIDToAssetPath(GUIDs[0])))
return false;
}
}
return true;
}
[MenuItem(RemoveAniCurveNamePath, false, 0)]
public static void RemoveAniCurve()
{
string[] str = Selection.assetGUIDs;
string path = AssetDatabase.GUIDToAssetPath(str[0]);
DirectoryInfo root = new DirectoryInfo(path);
FileInfo[] files = root.GetFiles("*.anim");
string name;
AnimationClip ac;
for (int i = 0; i < files.Length; i++)
{
name = path + "/" + GetAfterKeyData(files[i].FullName, "\\");
ac = AssetDatabase.LoadAssetAtPath<AnimationClip>(name);
RemoveAniCurve(ac);
EditorUtility.DisplayProgressBar("进度", i + "/" + files.Length + "完成修改值", (float)i / files.Length);
}
Resources.UnloadUnusedAssets();
//修改立即保存到磁盘
AssetDatabase.SaveAssets();
EditorUtility.ClearProgressBar();
AssetDatabase.Refresh();
GC.Collect();
}
[MenuItem(OptAniFNamePath, true, 1)]
public static bool OptAniFJudgement()
{
string[] GUIDs = Selection.assetGUIDs;
if (GUIDs.Length == 0)
return false;
else
{
for (int i = 0; i < GUIDs.Length; i++)
{
if (!Directory.Exists(AssetDatabase.GUIDToAssetPath(GUIDs[0])))
return false;
}
}
return true;
}
/// <summary>
/// 把当前选取文件夹下Ani文件改变
/// </summary>
[MenuItem(OptAniFNamePath, false, 1)]
public static void OptAniF()
{
string[] str = Selection.assetGUIDs;
string path = AssetDatabase.GUIDToAssetPath(str[0]);
DirectoryInfo root = new DirectoryInfo(path);
FileInfo[] files = root.GetFiles("*.anim");
string name;
AnimationClip ac;
for (int i = 0; i < files.Length; i++)
{
name = path + "/" + GetAfterKeyData(files[i].FullName, "\\");
ac = AssetDatabase.LoadAssetAtPath<AnimationClip>(name);
OptAniFloat(ac);
EditorUtility.DisplayProgressBar("进度", i + "/" + files.Length + "完成修改值", (float)i / files.Length);
}
Resources.UnloadUnusedAssets();
//修改立即保存到磁盘
AssetDatabase.SaveAssets();
EditorUtility.ClearProgressBar();
AssetDatabase.Refresh();
GC.Collect();
}
/// <summary>
/// 获取某个限定之后的字符串 如果限定存在多个则取最后一个的位置
/// </summary>
static string GetAfterKeyData(string str, string key)
{
int index = str.LastIndexOf(key) + 1;
int length = str.Length - index;
return str.Substring(index, length);
}
/// <summary>
/// 精简Ani的float精度
/// </summary>
/// <param name="clip"></param>
/// <returns></returns>
static AnimationClip OptAniFloat(AnimationClip clip)
{
EditorCurveBinding[] curves;
curves = AnimationUtility.GetCurveBindings(clip);
Keyframe key;
Keyframe[] keyFrames;
AnimationCurve curve = null;
for (int i = 0; i < curves.Length; i++)
{
curve = AnimationUtility.GetEditorCurve(clip, curves[i]); ;
if (curve == null || curve.keys == null)
continue;
//交换法 把float转换为string
keyFrames = curve.keys;
for (int j = 0; j < keyFrames.Length; j++)
{
key = keyFrames[j];
key.value = float.Parse(key.value.ToString(FloatPrecision));
//传入传出切线
key.inTangent = float.Parse(key.inTangent.ToString(FloatPrecision));
key.outTangent = float.Parse(key.outTangent.ToString(FloatPrecision));
//传入传出权重优化
key.inWeight = float.Parse(key.inWeight.ToString(FloatPrecision));
key.outWeight = float.Parse(key.outWeight.ToString(FloatPrecision));
keyFrames[j] = key;
}
curve.keys = keyFrames;
//在设置回clip
clip.SetCurve(curves[i].path, curves[i].type, curves[i].propertyName, curve);
}
return clip;
}
/// <summary>
/// 移除Ani 某个曲线
/// </summary>
/// <returns></returns>
static AnimationClip RemoveAniCurve(AnimationClip clip)
{
//获取所有曲线
string name;
foreach (var item in AnimationUtility.GetCurveBindings(clip))
{
//返回小写名字
name = item.propertyName.ToLower();
//就是搜索这个数如果大于0就代表存在 Contaions优化
if (name.IndexOf(RemoveCurveName) >= 0)
{
//null就是删除
AnimationUtility.SetEditorCurve(clip, item, null);
}
}
return clip;
}
}
这个是最终处理后用的是f3 如果越粗就可能抖动,要自己慢慢调整,但是需要先移除无用帧再优化float,不然会导致float反弹相当于没优化!
fbx文件没有变化 下面分别是优化前优化后
然后fbx模型ani是readonly,可能会改变了之后又重置回来,打包的时候打包的是fbx,我们改的只是本地Library里的数据,所以引用大佬的一个方法
Animator优化
对于Animator组件,应该尽量避免使用SetActive频繁开启禁用动画,改成SetLayer Behaviour.Enable=false的效率能好很多
然后是设置放张图 这样就很棒了