Unity自动化PBR材质配置:基于命名规范的FBX贴图智能匹配方案 1. 项目概述与核心痛点做Unity项目尤其是涉及大量外部美术资源的项目最头疼的环节之一就是资源导入后的“二次加工”。你从美术同学那里拿到一个FBX模型兴冲冲地拖进项目结果发现模型是灰的——材质球要么丢失要么是默认的Standard Shader完全不是美术在DCC工具如Blender、Maya、3ds Max里调好的那个PBR效果。于是你不得不手动为每一个模型、每一个材质槽去创建材质球拖拽贴图设置Shader参数。一个模型还好要是一次性导入几十上百个建筑、植被、道具模型这种重复劳动足以让人崩溃。这个场景相信每个Unity开发者都经历过。其核心痛点在于Unity在导入FBX文件时虽然能识别模型网格和动画但对于材质信息的处理却相对“保守”。它通常不会自动创建基于物理的渲染PBR工作流所需的材质球尤其是当贴图文件如Albedo、Normal、Metallic、Roughness等与FBX文件分离存放时。手动配置不仅效率低下而且极易出错比如贴图类型设置错误把法线贴图当成Albedo使用或者Shader参数如光滑度、金属度没有正确映射。因此一个能够自动化完成“FBX模型导入 - 扫描关联贴图 - 智能创建并配置PBR材质球”流程的工具或方法就成了提升团队协作效率和项目规范性的刚需。本文将深入拆解这一需求背后的技术原理并分享一套我经过多个项目实战验证的自动化解决方案包含完整的思路、代码实现以及一个即拿即用的编辑器工具。2. 技术原理与方案选型要实现自动化配置我们首先要理解Unity的材质Material和着色器Shader是如何与外部模型FBX及贴图Texture关联起来的。2.1 Unity材质系统与FBX导入流程一个标准的PBR材质球在Unity中通常使用Standard或Universal Render Pipeline (URP)/High Definition Render Pipeline (HDRP)中的PBR Shader如Lit。它的核心配置包括Shader类型决定了材质的渲染方程和可用属性。纹理属性主要是各种贴图如_MainTex(Albedo),_BumpMap(Normal),_MetallicGlossMap(Metallic/Smoothness)等。标量/向量属性如_Color(色调),_Metallic(金属度),_Glossiness(光滑度)等。当FBX文件被导入Unity时导入器FBX Importer会解析文件内的数据。对于材质它主要做两件事材质名称提取从FBX中读取材质名称并在Unity项目内生成对应的材质资产Asset。但早期或简单导出时这个生成的材质可能只是一个空壳或者使用了非常基础的Shader。纹理引用尝试如果FBX文件内嵌了纹理路径Unity会尝试根据这个相对路径在项目内查找贴图文件。但更多的情况是贴图文件是单独提供的路径信息可能丢失或不对应。问题的关键在于Unity的默认导入行为缺乏“智能推断”。它不知道如何根据贴图文件的命名约定Convention来自动匹配到材质球的正确属性上。2.2 自动化方案的核心思路我们的自动化工具核心思路就是弥补这个“智能推断”的缺口。方案基于以下前提这也是现代美术生产流程中的常见规范贴图命名规范美术输出贴图时会遵循一套命名规则。例如模型名_Albedo.png模型名_Normal.png模型名_Metallic.png模型名_Roughness.png(或与Metallic合并为MetallicRoughness)模型名_AO.png(环境光遮蔽)模型名_Emission.png(自发光)贴图与模型位置关联贴图文件通常与FBX文件放在同一个文件夹或者在一个约定的子目录如/Textures/下。基于此自动化流程可以设计为触发器监听Unity的AssetPostprocessor事件在FBX模型导入完成后自动执行。扫描与匹配在模型文件所在目录及其子目录下扫描所有贴图文件。规则解析根据文件名中的关键词如“Albedo”, “Diffuse”, “BaseColor”, “Normal”, “Nrm”, “Metallic”, “Roughness”, “Height”, “AO”, “Emission”等来识别贴图类型。材质创建与配置为FBX模型中的每个材质槽Material Slot创建或获取对应的Unity材质球。根据项目使用的渲染管线Built-in, URP, HDRP选择正确的PBR Shader。将扫描匹配到的贴图赋值到材质球对应的纹理属性上。根据贴图类型如法线贴图自动设置正确的纹理导入类型Texture Type。资产保存将配置好的材质球保存为.mat文件通常放在与模型相邻的Materials文件夹中以保持项目整洁。2.3 方案选型内置管线 vs SRP (URP/HDRP)选择哪种PBR Shader是方案的第一步它决定了工具的通用性。内置渲染管线Built-in使用StandardShader。优点是通用性最强任何Unity项目都支持。缺点是StandardShader比较庞大且未来可能不再是开发重点。可编程渲染管线SRP包括URP和HDRP。需要根据项目实际使用的渲染管线包来创建对应的材质如Universal Render Pipeline/Lit。工具需要具备检测和适配不同渲染管线的能力。一个健壮的工具应该能自动检测当前项目使用的渲染管线并创建对应的材质。我们可以通过检查GraphicsSettings.renderPipelineAsset是否为空来判断项目是否使用了SRP并进一步判断是URP还是HDRP通过资产类型或包引用。注意对于需要同时支持多个管线的工具或者提供给不确定管线环境的外部团队使用时可以考虑提供配置选项让用户手动指定目标Shader或者为不同管线分别生成材质。3. 工具设计与实现细节下面我将分步骤拆解一个完整的编辑器工具的实现。这个工具将以一个AssetPostprocessor脚本为核心并可以扩展一个编辑器窗口用于手动批量处理。3.1 核心类继承自AssetPostprocessorAssetPostprocessor是Unity提供的编辑器API允许我们在资源导入前后执行自定义操作。我们将主要使用OnPostprocessModel方法它在模型包括FBX导入完成后被调用。using UnityEngine; using UnityEditor; using System.IO; using System.Linq; using System.Collections.Generic; public class AutoPBRMaterialPostprocessor : AssetPostprocessor { // 定义贴图类型关键词映射到材质属性名的规则 private static readonly Dictionarystring, string _textureKeywordToProperty new Dictionarystring, string(System.StringComparer.OrdinalIgnoreCase) { {albedo, _MainTex}, {diffuse, _MainTex}, {basecolor, _MainTex}, {color, _MainTex}, {normal, _BumpMap}, {nrm, _BumpMap}, {metallic, _MetallicGlossMap}, {metalness, _MetallicGlossMap}, // 注意Standard Shader中光滑度(Roughness的反面)信息通常存储在_MetallicGlossMap的Alpha通道或由单独的_MetallicGlossMap的Alpha通道或由单独的_Smoothness贴图提供。这里假设我们使用Metallic(RGB) Smoothness(A)的合并贴图。 // 如果粗糙度是单独的贴图需要反转并存入光滑度。 {roughness, _MetallicGlossMap}, // 需要特殊处理反转并存入Alpha通道 {gloss, _MetallicGlossMap}, {smoothness, _MetallicGlossMap}, {height, _ParallaxMap}, {displacement, _ParallaxMap}, {ao, _OcclusionMap}, {occlusion, _OcclusionMap}, {emission, _EmissionMap}, {emissive, _EmissionMap}, }; // 定义哪些关键词表示该贴图需要被设置为法线贴图类型 private static readonly HashSetstring _normalMapKeywords new HashSetstring(System.StringComparer.OrdinalIgnoreCase) { normal, nrm, bump }; void OnPostprocessModel(GameObject g) { // 1. 检查是否是FBX文件或其他3D模型格式 string modelPath assetPath; if (!modelPath.ToLower().EndsWith(.fbx)) // 可以扩展支持.obj, .blend等 { return; } // 2. 可选通过配置决定是否启用自动处理。这里假设总是启用。 // 在实际工具中最好通过一个ScriptableObject或EditorPrefs来配置开关。 // 3. 获取模型所在目录 string modelDirectory Path.GetDirectoryName(modelPath); string modelNameWithoutExt Path.GetFileNameWithoutExtension(modelPath); // 4. 扫描目录下的所有贴图文件 string[] supportedImageExtensions new string[] { .png, .jpg, .jpeg, .tga, .bmp, .tif, .tiff }; Liststring allTexturePaths new Liststring(); foreach (var ext in supportedImageExtensions) { allTexturePaths.AddRange(Directory.GetFiles(modelDirectory, * ext, SearchOption.AllDirectories)); } // 5. 为模型的每个渲染器下的每个材质槽进行处理 Renderer[] renderers g.GetComponentsInChildrenRenderer(); foreach (Renderer renderer in renderers) { Material[] sharedMats renderer.sharedMaterials; for (int matIndex 0; matIndex sharedMats.Length; matIndex) { // 获取或创建材质球 Material targetMaterial sharedMats[matIndex]; string materialSlotName targetMaterial ! null ? targetMaterial.name : $Material_{matIndex}; // 我们倾向于创建新的材质而不是修改可能来自FBX的默认材质 string newMaterialName ${modelNameWithoutExt}_{materialSlotName}; targetMaterial GetOrCreateMaterial(modelDirectory, newMaterialName); // 6. 智能匹配贴图 MatchAndAssignTextures(targetMaterial, allTexturePaths, modelNameWithoutExt, materialSlotName); // 7. 保存材质资产 SaveMaterialAsset(targetMaterial, modelDirectory, newMaterialName); // 更新渲染器上的材质引用 sharedMats[matIndex] targetMaterial; } renderer.sharedMaterials sharedMats; } // 8. 重要刷新AssetDatabase让新创建的材质在Project窗口中显示 AssetDatabase.Refresh(); } // 其他辅助方法GetOrCreateMaterial, MatchAndAssignTextures, SaveMaterialAsset 等将在下文实现 }3.2 关键方法实现贴图匹配与赋值逻辑MatchAndAssignTextures方法是工具的大脑负责将扫描到的贴图文件与材质属性关联起来。private void MatchAndAssignTextures(Material material, Liststring texturePaths, string modelName, string materialSlotName) { // 首先确定使用哪个Shader Shader targetShader GetTargetPBRShader(); if (targetShader null) { Debug.LogWarning($无法为模型 {modelName} 的材质 {materialSlotName} 找到合适的PBR Shader。); return; } material.shader targetShader; // 遍历所有贴图路径尝试匹配 foreach (string texPath in texturePaths) { string fileName Path.GetFileNameWithoutExtension(texPath).ToLower(); string fullPath texPath.Replace(\\, /); // 基础筛选文件名是否包含模型名和/或材质槽名(这是一个可选的强化匹配逻辑) // 例如模型叫“Barrel”材质槽叫“Metal”那么贴图“Barrel_Metal_Albedo.png”的匹配度更高。 // 这里我们先实现一个宽松的匹配只要文件名包含关键词。 // 更复杂的实现可以优先匹配同时包含模型名和材质槽名的贴图。 string matchedProperty null; foreach (var kvp in _textureKeywordToProperty) { if (fileName.Contains(kvp.Key)) { matchedProperty kvp.Value; break; // 找到第一个匹配的关键词就退出 } } if (string.IsNullOrEmpty(matchedProperty)) { continue; // 没有匹配到已知类型 } // 加载贴图 Texture2D loadedTex AssetDatabase.LoadAssetAtPathTexture2D(fullPath); if (loadedTex null) { Debug.LogWarning($无法在路径 {fullPath} 加载贴图。); continue; } // 特殊处理法线贴图 bool isNormalMap _normalMapKeywords.Any(keyword fileName.Contains(keyword)); if (isNormalMap) { // 确保贴图导入设置中的Texture Type为Normal map TextureImporter texImporter AssetImporter.GetAtPath(fullPath) as TextureImporter; if (texImporter ! null texImporter.textureType ! TextureImporterType.NormalMap) { texImporter.textureType TextureImporterType.NormalMap; texImporter.SaveAndReimport(); // 需要重新导入以应用设置 loadedTex AssetDatabase.LoadAssetAtPathTexture2D(fullPath); // 重新加载 } } // 特殊处理粗糙度贴图 (Roughness) // 假设我们得到的是一张灰度粗糙度图需要反转并存入Metallic贴图的Alpha通道。 // 这是一个简化处理。更完善的方案是检查是否已存在_MetallicGlossMap然后合并RGB和A通道。 if (fileName.Contains(roughness) matchedProperty _MetallicGlossMap) { // 这是一个进阶话题可能需要使用Texture2D.SetPixels进行CPU处理或者依赖美术输出合并贴图。 // 此处仅作提示简化处理直接赋值并假设它是包含金属度的合并贴图。 Debug.Log($检测到粗糙度贴图 {fileName}请确保您的PBR流程使用合并的MetallicRoughness贴图或需要额外处理。); } // 将贴图赋值给材质属性 if (material.HasProperty(matchedProperty)) { material.SetTexture(matchedProperty, loadedTex); Debug.Log($已为材质 {material.name} 分配贴图 {fileName} 到属性 {matchedProperty}); } else { Debug.LogWarning($材质 {material.name} 的Shader {material.shader.name} 没有属性 {matchedProperty}无法分配贴图 {fileName}。); } // 根据贴图类型设置一些默认标量值 // 例如如果设置了自发光贴图通常需要开启自发光并设置一个颜色/强度 if (matchedProperty _EmissionMap material.HasProperty(_EmissionColor)) { material.SetColor(_EmissionColor, Color.white); // 默认白色强度为1 material.EnableKeyword(_EMISSION); } // 如果使用了金属光滑度贴图通常需要将_Metallic和_Glossiness值设为1.0因为信息全在贴图里 if (matchedProperty _MetallicGlossMap) { if (material.HasProperty(_Metallic)) material.SetFloat(_Metallic, 1.0f); if (material.HasProperty(_Glossiness)) material.SetFloat(_Glossiness, 1.0f); // 对于Standard Shader还需要设置使用贴图而非标量值 material.SetFloat(_SmoothnessTextureChannel, 0); // 0 Albedo Alpha, 1 Metallic Alpha. 取决于工作流。 // 更准确的做法是根据贴图命名判断工作流。 } } } private Shader GetTargetPBRShader() { // 检测当前渲染管线 var rpAsset GraphicsSettings.renderPipelineAsset; if (rpAsset null) { // 内置管线 return Shader.Find(Standard); } else { // SRP管线通过资产类型或名称判断URP/HDRP string rpAssetTypeName rpAsset.GetType().ToString(); if (rpAssetTypeName.Contains(UniversalRenderPipelineAsset) || rpAsset.name.Contains(Universal)) { return Shader.Find(Universal Render Pipeline/Lit); } else if (rpAssetTypeName.Contains(HDRenderPipelineAsset) || rpAsset.name.Contains(HD)) { // HDRP的Lit Shader路径可能不同 return Shader.Find(HDRP/Lit); } } Debug.LogError(无法确定当前渲染管线使用Standard Shader作为后备。); return Shader.Find(Standard); }3.3 资产管理与保存我们需要创建新的材质球资产并保存到磁盘而不是仅仅在内存中修改。private Material GetOrCreateMaterial(string modelDirectory, string materialName) { // 理想情况下材质球应该保存在一个子文件夹里比如“Materials” string materialsSubFolder Path.Combine(modelDirectory, Materials); if (!Directory.Exists(materialsSubFolder)) { Directory.CreateDirectory(materialsSubFolder); AssetDatabase.Refresh(); // 创建文件夹后需要刷新 } string materialPath Path.Combine(materialsSubFolder, materialName .mat).Replace(\\, /); Material existingMat AssetDatabase.LoadAssetAtPathMaterial(materialPath); if (existingMat ! null) { return existingMat; } else { // 创建一个新的临时材质使用正确的Shader会在MatchAndAssignTextures中设置 Material newMat new Material(Shader.Find(Standard)); // 先用Standard初始化后面会覆盖 AssetDatabase.CreateAsset(newMat, materialPath); return newMat; } } private void SaveMaterialAsset(Material material, string modelDirectory, string materialName) { // 在GetOrCreateMaterial中已经创建了资产这里主要是确保更改被保存。 // Unity Editor会自动跟踪对Material的更改。 // 我们可以强制保存这个资产。 EditorUtility.SetDirty(material); // AssetDatabase.SaveAssets(); // 谨慎使用会保存所有未保存的资产。通常在工具手动触发时调用。 }3.4 扩展编辑器工具窗口除了自动导入处理提供一个手动批量处理的编辑器窗口也很有用可以处理已经导入的模型或者进行测试。using UnityEditor; using UnityEngine; using System.IO; public class PBRMaterialAutoAssignerWindow : EditorWindow { [MenuItem(Tools/美术工具/PBR材质自动配置器)] public static void ShowWindow() { GetWindowPBRMaterialAutoAssignerWindow(PBR材质配置器); } private string targetFolderPath Assets/; void OnGUI() { GUILayout.Label(批量处理已导入的FBX模型, EditorStyles.boldLabel); EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); targetFolderPath EditorGUILayout.TextField(目标文件夹, targetFolderPath); if (GUILayout.Button(选择..., GUILayout.Width(60))) { string newPath EditorUtility.OpenFolderPanel(选择包含FBX的文件夹, Application.dataPath, ); if (!string.IsNullOrEmpty(newPath)) { // 转换为相对于项目的路径 if (newPath.StartsWith(Application.dataPath)) { targetFolderPath Assets newPath.Substring(Application.dataPath.Length); } else { Debug.LogWarning(请选择项目Assets目录内的文件夹。); } } } EditorGUILayout.EndHorizontal(); EditorGUILayout.HelpBox(此操作将扫描选定文件夹及其子文件夹下的所有FBX文件并尝试为其匹配贴图、创建/配置PBR材质球。, MessageType.Info); if (GUILayout.Button(开始批量处理, GUILayout.Height(30))) { ProcessFolder(targetFolderPath); } } private void ProcessFolder(string folderPath) { string absolutePath Path.GetFullPath(Path.Combine(Application.dataPath, .., folderPath)); if (!Directory.Exists(absolutePath)) { Debug.LogError($文件夹不存在: {absolutePath}); return; } // 查找所有FBX文件 string[] fbxFiles Directory.GetFiles(absolutePath, *.fbx, SearchOption.AllDirectories); Debug.Log($找到 {fbxFiles.Length} 个FBX文件。); int processedCount 0; foreach (string fbxFile in fbxFiles) { string relativePath Assets fbxFile.Substring(Application.dataPath.Length); EditorUtility.DisplayProgressBar(处理中, $正在处理: {Path.GetFileName(fbxFile)}, (float)processedCount / fbxFiles.Length); // 模拟导入后处理重新导入该FBX会触发我们的AssetPostprocessor AssetDatabase.ImportAsset(relativePath, ImportAssetOptions.ForceUpdate); processedCount; } EditorUtility.ClearProgressBar(); AssetDatabase.Refresh(); Debug.Log($批量处理完成共处理 {processedCount} 个文件。); } }4. 实操配置与使用指南将上述代码整合到Unity项目中后你需要进行一些配置和了解使用方式。4.1 工具部署与配置脚本放置将AutoPBRMaterialPostprocessor.cs脚本放在项目的任意Editor文件夹下例如Assets/Editor/或Assets/MyTools/Editor/。Editor文件夹下的脚本只在Unity编辑器中运行不会被打进游戏包。菜单栏PBRMaterialAutoAssignerWindow.cs也需要放在Editor文件夹下。放置后在Unity编辑器顶部菜单栏会出现Tools - 美术工具 - PBR材质自动配置器。关键词配置工具的核心是_textureKeywordToProperty字典。你需要根据你们团队的美术命名规范来修改和扩展这个字典。示例如果你们团队用_d表示漫反射_n表示法线_m表示金属度那么需要添加映射{_d, _MainTex}, {_n, _BumpMap}, {_m, _MetallicGlossMap},注意顺序字典的遍历顺序就是匹配顺序。如果两个关键词都能匹配同一个文件名如“diffuse”和“albedo”先定义的会生效。4.2 标准工作流与使用步骤场景一新模型导入全自动美术提供FBX文件和一套按照命名规范命名的贴图如MyRock_Albedo.png,MyRock_Normal.png,MyRock_Metallic.png。将这些文件全部放入Unity项目的某个文件夹例如Assets/Models/Environment/。将FBX文件拖入该文件夹。Unity开始导入。导入完成后检查该文件夹下是否自动生成了一个Materials子文件夹里面包含了配置好贴图的材质球。在Scene或Prefab中查看模型材质应已正确显示PBR效果。场景二处理已导入的旧模型半自动打开工具窗口 (Tools - 美术工具 - PBR材质自动配置器)。在“目标文件夹”中输入或选择包含旧FBX模型的文件夹路径。点击“开始批量处理”。工具会重新导入强制更新该文件夹下所有FBX文件从而触发自动材质配置逻辑。处理完成后检查各个模型文件夹下的Materials文件夹。4.3 参数详解与高级设置贴图类型自动设置工具会自动将包含“normal”、“nrm”等关键词的贴图在导入设置中标记为Texture Type: Normal Map。这对于法线贴图正确解码至关重要。渲染管线自适应GetTargetPBRShader方法尝试自动判断项目使用的渲染管线。如果判断失败例如使用了自定义SRP你需要修改此方法返回正确的Shader。材质命名规则工具生成的材质球命名格式为{模型文件名}_{材质槽名}.mat。你可以在GetOrCreateMaterial方法中修改这个规则例如加入更多分类信息。重要提示自动处理依赖于命名规范。如果美术资源命名混乱工具可能无法正确匹配。因此推行并遵守一套团队内的美术资源命名规范是此工具能高效工作的前提。工具本身也可以作为推动规范落地的“催化剂”。5. 常见问题排查与优化技巧在实际使用中你可能会遇到一些问题。以下是一些常见情况的排查思路和优化建议。5.1 贴图匹配失败症状模型材质球是空的或只有部分贴图。排查检查命名确认贴图文件名是否包含工具字典里定义的关键词不区分大小写。可以在MatchAndAssignTextures方法中打印fileName进行调试。检查路径贴图文件是否在FBX文件所在目录或其子目录下工具默认会搜索子目录。检查扩展名工具支持常见的图片格式。如果使用.exr、.psd等需要在supportedImageExtensions数组中添加。优化增强匹配逻辑。例如优先匹配同时包含模型名和材质槽名的贴图。这需要对MatchAndAssignTextures方法进行改进为每个材质槽计算一个“匹配分数”。5.2 材质Shader显示粉色Missing Shader症状生成的材质球显示为粉色。排查渲染管线最常见原因。项目使用了URP/HDRP但工具创建的材质球使用了Built-in的StandardShader或者反之。检查GetTargetPBRShader方法的逻辑是否正确识别了你的项目设置。Shader丢失在极少数情况下Shader可能未被正确编译或包含。确保项目渲染管线配置正确。解决手动在材质球上选择正确的Shader。如果是批量问题检查并修正工具的Shader检测逻辑。5.3 法线贴图显示不正确紫色或颜色怪异症状法线贴图看起来是彩色的或者没有凹凸效果。排查贴图类型确保贴图在Unity中的Texture Type被设置为Normal Map。工具已尝试自动设置但如果贴图在工具运行前已导入其设置可能未被更改。可以手动在Project窗口选中贴图在Inspector中将Texture Type改为Normal Map并点击Apply。颜色空间确保法线贴图是切线空间Tangent Space法线贴图这是游戏行业标准。有些DCC工具可能输出对象空间Object Space法线。解决对于已存在的贴图可以写一个小脚本批量修改其TextureImporter设置。5.4 性能与处理速度症状导入大量模型时编辑器卡顿。优化延迟操作在AssetPostprocessor中如果处理非常耗时可以考虑将操作延迟到一帧之后执行使用EditorApplication.delayCall。选择性处理不是所有FBX都需要处理。可以在OnPostprocessModel开头添加过滤条件例如只处理特定文件夹下的模型或者检查模型是否包含某个特定标签。缓存机制对于已经处理过并生成材质球的模型可以跳过处理。可以通过检查是否已存在对应的材质文件来判断。5.5 处理特殊PBR工作流金属度/粗糙度分离贴图有些工作流使用单独的Metallic灰度和Roughness灰度贴图。我们的工具目前假设它们是合并的RGB存储金属度A存储光滑度/粗糙度。要支持分离贴图需要在匹配规则中区分_Metallic和_Roughness。在运行时或导入时将两张灰度图合并成一张RGBA贴图然后赋值给_MetallicGlossMap。这涉及Texture2D的像素操作复杂度较高。更推荐的做法是要求美术在导出前使用工具如Substance工具链或在线转换器合并贴图或者使用支持分离贴图的Shader如一些自定义Shader。环境光遮蔽AO贴图StandardShader有_OcclusionMap属性。如果匹配到AO贴图直接赋值即可。在某些工作流中AO会合并到其他贴图的通道中如金属粗糙度的绿色通道这需要更复杂的处理逻辑通常也建议在DCC环节完成合并。这套自动化工具的核心价值在于将开发者从重复劳动中解放出来并强制推行了资源规范。它的效果高度依赖于命名约定的遵守程度。在项目初期花时间与美术团队共同制定并确认这套规范并在工具中完美体现将为整个项目周期的资源管理带来巨大的效率提升和一致性保障。工具本身也可以不断迭代适应更复杂的工作流和特殊的项目需求。