Unity 导入FBX提取材质贴图
需求
当我们在建模软件制作好fbx,导入Unity时,会发现fbx有自带的材质,贴图,蒙皮,网格等多种资源,但是使用起来很不方便,所以想,在向unity导入fbx之后,直接就把里边的材质和贴图提取出来,并且不是默认的 Lit ,而是其它的自己写的shader
成果展示
FBX导入时提取材质
背景知识
当我们在Unity中选中一个fbx资产的时候,可以在右侧的检视面板看到这样的一些按钮
具体的解释可以看官方文档
https://docs.unity3d.com/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 才会调用此函数
还有其他的一些方法可以在官方文档中查看
https://docs.unity.cn/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,看到成果啦