版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/akof1314/article/details/80291799
原因
在将资源打包成 AssetBundle 进行加载时,发现有一些特效没有达到预期的效果,如下可以看到圆形的硬边:
分析
将这个特效资源导出到另一个工程,单独打包 AssetBundle 进行加载,发现没有问题,如下所示:
对比原 AssetBundle 文件,发现特效里使用的模型因为也被其他特效使用,所以单独打成了依赖的 AssetBundle 包。然后用解包工具解包,用 3D MAX 打开,可以看到:
单独打包的模型 AssetBundle 里面,其模型信息不带有有顶点色。
跟特效一起打包的 AssetBundle 里面,其模型信息带有顶点色。
解决
经了解,是 Unity 的 【 Optimize Mesh Data】功能导致打包 AssetBundle 的时候,自动去除了模型上多余的数据。当模型单独打包的时候,不会检测到特效使用了顶点色数据,所以不保留顶点色数据,详细说明见《 针对移动平台打assetbundle 时,optimize mesh data 选项开启会造成mesh 顶点色不可用的问题》。文章里面也提到可以将模型开启【 Import Materials】,然后将其默认材质换成使用顶点色的着色器,这样即使单独打包,也不会丢失顶点色。
但是,工程里面对特效的模型都做了导入时统一处理,全部关闭了【Import Materials】,如果将这个处理关闭的话,那么就会产生很多无用的材质。所以这里协定,当导入的设置【Material Naming】为【Model Name + Model’s Material】时,则不强制关闭【Import Materials】,如下所示:
另外,模型的默认材质名称不规范,会使得工程乱七八糟,如果再让美术去重新导模型的话,工作量太大,而且也不能保证之后材质名称会规范命名,所以这里使用 OnAssignMaterialModel 接口来拦截模型的附加材质生成。
代码如下:
using System.IO;
using UnityEditor;
using UnityEngine;
public class MyMeshPostprocessor : AssetPostprocessor
{
private bool IsEffectModel()
{
return assetPath.StartsWith("Assets/AB/Effects/Model");
}
private void OnPreprocessModel()
{
if (IsEffectModel())
{
ModelImporter modelImporter = assetImporter as ModelImporter;
if (modelImporter && modelImporter.materialName != ModelImporterMaterialName.BasedOnModelNameAndMaterialName)
{
modelImporter.importMaterials = false;
}
}
}
private Material OnAssignMaterialModel(Material material, Renderer renderer)
{
if (IsEffectModel())
{
ModelImporter modelImporter = assetImporter as ModelImporter;
if (modelImporter && modelImporter.importMaterials)
{
string matPath = Path.GetDirectoryName(assetPath) + "/" + Path.GetFileNameWithoutExtension(assetPath) + ".mat";
Material mat = AssetDatabase.LoadAssetAtPath<Material>(matPath);
if (mat)
{
return mat;
}
AssetDatabase.CreateAsset(material, matPath);
return material;
}
}
return null;
}
}
更近一步,为了不需要记住操作的步骤,增加菜单一键功能,代码如下:
C# Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
using
System.IO; using UnityEditor; using UnityEngine; namespace Tools { public static class FbxPrefabTool { [MenuItem( "Assets/FbxTool/特效模型-保留顶点色" )] private static void HoldOnFbxPrefabsVertexColor() { foreach (var o in Selection.objects) { ModifyFbxPrefabVertexColor(o, true ); } } [MenuItem( "Assets/FbxTool/特效模型-去除顶点色" )] private static void GiveUpFbxPrefabsVertexColor() { foreach (var o in Selection.objects) { ModifyFbxPrefabVertexColor(o, false ); } } [MenuItem( "Assets/FbxTool/特效模型-保留顶点色" , true )] [MenuItem( "Assets/FbxTool/特效模型-去除顶点色" , true )] private static bool ValidateFbxPrefabsVertexColor() { foreach (var obj in Selection.objects) { if (!obj) { return false ; } if (PrefabUtility.GetPrefabType(obj) != PrefabType.ModelPrefab) { return false ; } string fbxPath = AssetDatabase.GetAssetPath(obj); if (!fbxPath.StartsWith( "Assets/AB/Effects/Model" )) { return false ; } } return true ; } private static void ModifyFbxPrefabVertexColor(Object obj, bool holdOn) { if (!obj) { return ; } if (PrefabUtility.GetPrefabType(obj) != PrefabType.ModelPrefab) { return ; } string fbxPath = AssetDatabase.GetAssetPath(obj); if (!fbxPath.StartsWith( "Assets/AB/Effects/Model" )) { return ; } AssetImporter ai = AssetImporter.GetAtPath(fbxPath); if (!ai) { return ; } ModelImporter modelImporter = ai as ModelImporter; if (!modelImporter) { return ; } string matPath = Path.GetDirectoryName(fbxPath) + "/" + Path.GetFileNameWithoutExtension(fbxPath) + ".mat" ; if (holdOn) { if (modelImporter.materialName != ModelImporterMaterialName.BasedOnModelNameAndMaterialName || !modelImporter.importMaterials) { modelImporter.materialName = ModelImporterMaterialName.BasedOnModelNameAndMaterialName; modelImporter.importMaterials = true ; AssetDatabase.ImportAsset(modelImporter.assetPath, ImportAssetOptions.ForceUpdate); Material mat = AssetDatabase.LoadAssetAtPath<Material>(matPath); if (mat) { mat.shader = Shader.Find( "Mobile/Particles/Alpha Blended" ); } } } else { if (modelImporter.materialName == ModelImporterMaterialName.BasedOnModelNameAndMaterialName) { modelImporter.materialName = ModelImporterMaterialName.BasedOnTextureName; modelImporter.SaveAndReimport(); AssetDatabase.DeleteAsset(matPath); } } } } } |
最后自动生成效果如下所示: