需求
当我们在建模软件制作好fbx,导入Unity时,会发现fbx有自带的材质,贴图,蒙皮,网格等多种资源,但是使用起来很不方便,所以想,在向unity导入fbx之后,直接就把里边的材质和贴图提取出来,并且不是默认的 Lit ,而是其它的自己写的shader
成果展示
FBX导入时提取材质
背景知识
当我们在Unity中选中一个fbx资产的时候,可以在右侧的检视面板看到这样的一些按钮
具体的解释可以看官方文档
/cn/current/Manual/FBXImporter-Materials.html#material_description
其中我们比较关心的是:
Import via MaterialDescription (Experimental)导入时,Unity 使用 FBX 文件中嵌入的材质描述来生成材质。与先前的导入方法相比,此方法可提供更准确的结果,并且支持更广泛的材质类型
Use External Materials (Legacy)将导入的材质提取为外部资源。
Naming定义材质的命名策略。
Search定义 Unity 尝试在使用 Naming 选项定义的名称时查找现有材质的位置。
另一部分需要了解的是Unity里的 AssetPostprocessor 类,这个类可以帮助我们实现一些,关于导入导出资产时的相关回调
比如说:
OnPreprocessModel()在导入模型(.fbx、.mb 文件等)之前获取通知。
OnPostprocessModel()在模型完成导入时获取通知
OnPreprocessMaterialDescription这个函数是在把 ModelImporter.materialImportMode 设置为 ImportViaMaterialDescription时,Unity 才会调用此函数
还有其他的一些方法可以在官方文档中查看
/cn/current/ScriptReference/AssetPostprocessor.html
代码实现
List< string> materialName =new List<string>() {};Dictionary<string, string> matTextureMap = new Dictionary<string, string>() {};//当材质为通过description时调用 根据描述获得相关信息void OnPreprocessMaterialDescription(MaterialDescription description, Material material, AnimationClip[] materialAnimation){materialName.Add( description.materialName);List<string> props = new List<string>();description.GetTexturePropertyNames(props);TexturePropertyDescription textureProperty;foreach (string item in props){if (description.TryGetProperty(item, out textureProperty)){if (!matTextureMap.ContainsKey(description.materialName)){matTextureMap.Add(description.materialName, textureProperty.texture.name);}}}}
void OnPreprocessModel(){if (!assetPath.ToLower().EndsWith(".fbx")){return; } ModelImporter mi = assetImporter as ModelImporter;//设置fbx ModelImporter的相关属性mi.materialImportMode = ModelImporterMaterialImportMode.ImportViaMaterialDescription;mi.materialLocation = ModelImporterMaterialLocation.External;mi.materialName = ModelImporterMaterialName.BasedOnMaterialName;mi.materialSearch = ModelImporterMaterialSearch.Everywhere; }
//提取材质 设置shader属性 赋贴图void OnPostprocessModel(GameObject g){foreach (string matName in materialName){string matPath = assetPath.Substring(0, assetPath.LastIndexOf('/') + 1) + "Materials/" + matName + ".mat";Material m = (Material)AssetDatabase.LoadAssetAtPath(matPath, typeof(Material));Shader shader = Shader.Find("X51/透明顶点颜色");if (shader == null){Debug.Log("没找到shader");return;}if (m != null){m.shader = shader;if (matTextureMap.ContainsKey(matName)){string textPath = assetPath.Substring(0, assetPath.LastIndexOf('/') + 1);textPath += g.name + ".fbm/" + matTextureMap[matName] + ".dds";Texture texture = (Texture)AssetDatabase.LoadAssetAtPath(textPath, typeof(Texture));m.SetTexture("_Tex1", texture); }}}
使用方法
把写好的代码放在Unity的Editor文件夹下,就能直接拖入fbx,看到成果啦