Pixiv - KiraraShss
Unity场景资产提取器 - 完整教程与代码分析
2347 字
12 分钟
Unity场景资产提取器 - 完整教程与代码分析
前言
最近在迁移老项目的资产但是不想一个个去手动寻找转移,同时想到工作中交接可能也会遇到资产交接,遂开发了这个工具,码了2k多行屎山,目前可能还有一些bug但基本满足我个人的使用了,打算开源分享
项目地址
Waiting for api.github.com...
工具概述
Unity 场景资产提取器用于从当前场景中自动识别、分类和导出所有相关资产。这个工具能够解决开发者在项目整理、资产迁移和场景分析中遇到的常见问题。
主要功能亮点
- 自动资产识别:智能分析场景中使用的所有资产
- 多格式导出:支持文件夹复制和 UnityPackage 导出
- 智能分类:按类型或自定义规则组织资产
- HLSL 依赖追踪:自动提取 Shader 引用的 HLSL 文件
- 地形资产支持:专门处理 Terrain 和 TerrainData 资产
- 脚本识别:准确识别 MonoScript 和自定义脚本
安装与使用
安装步骤
- 将
SceneAssetExtractor.unitypackage拖到unity项目中导入 - 在 Unity 编辑器中打开菜单:
Tools/场景资产提取器 - 工具窗口将显示,可以开始使用
基本使用流程
1. 打开需要提取资产的场景2. 点击 "Tools/场景资产提取器" 打开工具窗口3. 点击 "刷新资产列表" 扫描场景资产4. 根据需要配置过滤器和导出选项5. 选择导出方式并执行导出Note
打包成Package文件是完全没有问题的他是保持原始文件夹结构打包的一次不会破坏文件之间的相对路径因此预制体与模型和材质之间的依赖关系不会被破坏,同理材质也是。
但是导出到文件夹并且选择按特定类型分类这回破坏原有的路径关系因此会出现材质与shader之间关联以及预制体与其他资产之间的关系破坏
界面UI


核心功能详解
1. 资产识别系统
资产收集机制
private void ExtractSceneAssets(){ // 收集场景根对象的所有资产 GameObject[] rootObjects = currentScene.GetRootGameObjects(); HashSet<UnityEngine.Object> collectedObjects = new HashSet<UnityEngine.Object>();
foreach (GameObject root in rootObjects) { CollectAssetsFromGameObject(root, collectedObjects); }}特殊资产处理
- 预制体识别:通过
PrefabUtility识别预制体引用 - 脚本收集:通过
MonoScript.FromMonoBehaviour获取脚本资产 - 地形资产:专门处理 Terrain 组件及相关数据
- HLSL 文件:解析 Shader 代码中的
#include指令
2. HLSL 依赖追踪系统
核心算法
private void ExtractHLSLReferencesFromCode(string shaderCode, string sourceFilePath, HashSet<UnityEngine.Object> collectedObjects){ // 使用正则表达式匹配 #include 指令 Regex includeRegex = new Regex(@"#include\s*(?:<\s*([^>]+)\s*>|[""']\s*([^""']+)\s*[""'])", RegexOptions.Multiline | RegexOptions.IgnoreCase); MatchCollection matches = includeRegex.Matches(shaderCode);
foreach (Match match in matches) { string includePath = match.Groups[1].Success ? match.Groups[1].Value : match.Groups[2].Value; ResolveAndAddHLSLFile(includePath, sourceDirectory, sourceFilePath, collectedObjects); }}路径解析策略
- 直接路径:检查绝对路径是否存在
- 相对路径:基于 Shader 文件位置解析
- 项目搜索:在整个项目中搜索匹配文件
- 递归解析:继续解析 HLSL 文件中的嵌套引用
3. 智能导出系统
导出路径计算
private string GetDestinationPath(string baseFolder, AssetInfo asset, string sourcePath){ string fileName = Path.GetFileName(sourcePath);
if (preserveFolderStructure) { // 保持原始文件夹结构 string relativePath = GetRelativeAssetPath(sourcePath); return Path.Combine(baseFolder, relativePath); } else if (exportBySpecificType) { // 按特定类型分类 string typeFolder = GetSpecificTypeFolder(asset, sourcePath); return Path.Combine(baseFolder, typeFolder, fileName); } // ... 其他分类方式}多位置 HLSL 导出
// 为 HLSL 文件创建多个副本,满足不同 Shader 的路径要求if (specificTypeSettings.createHLSLSymlinks && hlslUsageMap.ContainsKey(asset.Path)){ foreach (string shaderPath in hlslUsageMap[asset.Path]) { string altDestPath = GetHLSLDestinationPathForShader(exportFolder, asset, asset.Path, shaderPath); // 为每个使用该 HLSL 的 Shader 创建对应路径的副本 }}代码架构分析
1. 核心数据结构
AssetInfo 类
[System.Serializable]public class AssetInfo{ public UnityEngine.Object Object; // Unity 对象引用 public string Path; // 资产路径 public System.Type Type; // 资产类型 public long FileSize; // 文件大小}HLSL 引用映射
public class HLSLReference{ public string hlslPath; // HLSL 文件实际路径 public string includePath; // #include 指令中的路径 public string shaderPath; // 引用该文件的 Shader 路径}2. 主要组件模块
用户界面系统
- 主窗口:继承自
EditorWindow,提供完整的 GUI - 折叠面板:使用
EditorGUILayout.Foldout组织界面 - 实时过滤:基于搜索条件和类型过滤器的动态列表
资产收集系统
- 递归遍历:深度遍历场景层次结构
- 序列化分析:通过
SerializedObject分析组件属性 - 依赖追踪:使用
AssetDatabase.GetDependencies获取完整依赖链
导出引擎
- 文件操作:安全的文件复制和目录创建
- 元数据保护:同时复制
.meta文件 - 进度反馈:使用
EditorUtility.DisplayProgressBar显示进度
3. 关键算法实现
资产类型识别
private string GetDisplayType(AssetInfo asset){ // 基于文件扩展名和实际类型进行智能识别 if (asset.Path.ToLower().EndsWith(".prefab")) return "Prefab"; if (IsHLSLFile(asset.Path)) return "HLSL"; if (asset.Type.Name == "Terrain") return "Terrain"; // ... 其他类型判断}URP 资产过滤
private bool IsURPAsset(string assetPath){ string[] urpKeywords = { "Packages/com.unity.render-pipelines.universal", "UniversalRenderPipelineAsset", // ... 其他 URP 标识 };
// 检查路径是否包含 URP 关键字 return urpKeywords.Any(keyword => assetPath.ToLower().Contains(keyword.ToLower()));}高级功能配置
1. HLSL 提取配置
// 在 SpecificTypeSettings 中配置 HLSL 行为public bool extractShaderIncludes = true; // 是否提取 Shader 引用public bool preserveHLSLFolderStructure = true; // 保持 #include 路径结构public bool createHLSLSymlinks = false; // 为多引用创建副本public bool excludeURPAssets = true; // 排除 URP 内置资产2. 地形资产处理
private void CollectTerrainAssets(HashSet<UnityEngine.Object> collectedObjects){ Terrain[] terrains = UnityEngine.Object.FindObjectsOfType<Terrain>(); foreach (Terrain terrain in terrains) { collectedObjects.Add(terrain); if (terrain.terrainData != null) { collectedObjects.Add(terrain.terrainData); // 收集地形相关的材质、纹理、细节资源等 } }}3. 脚本资产识别
private void CollectScriptAssets(HashSet<UnityEngine.Object> collectedObjects){ // 通过 MonoBehaviour 组件收集脚本 MonoBehaviour[] monoBehaviours = UnityEngine.Object.FindObjectsOfType<MonoBehaviour>(); foreach (MonoBehaviour mb in monoBehaviours) { MonoScript monoScript = MonoScript.FromMonoBehaviour(mb); if (monoScript != null) { collectedObjects.Add(monoScript); } }}使用场景与最佳实践
1. 项目迁移
当需要将场景及其依赖资产迁移到新项目时:
- 使用 “导出Unity包” 功能创建完整的资产包
- 启用 “排除URP资产” 避免包含渲染管线特定资源
- 使用报告功能检查导出的资产列表
2. 资产清理
识别场景中未使用的资产:
- 导出场景使用的所有资产
- 与项目资产库对比找出未使用的资源
- 使用类型过滤专注于特定类型的资产
3. 渲染管线迁移
从 Built-in 迁移到 URP:
- 导出所有材质和 Shader
- 使用 HLSL 提取功能获取自定义 Shader 代码
- 排除 URP 内置资产避免冲突
4. 团队协作
分享特定场景的资产:
- 创建包含所有依赖的 UnityPackage
- 生成详细的资产报告供团队成员参考
- 使用自定义文件夹结构保持组织性
故障排除
常见问题
1. HLSL 文件路径问题
症状:导出的 HLSL 文件路径不正确 解决方案:
- 启用 “多位置副本” 选项
- 使用 “分析路径问题” 功能诊断
- 检查 Shader 中的
#include路径
2. 脚本识别失败
症状:MonoScript 资产未被正确识别 解决方案:
- 使用 “调试脚本” 功能检查识别过程
- 确保脚本文件存在于项目中
- 检查资产类型过滤器设置
3. 预制体引用缺失
症状:预制体实例未被识别为预制体资产 解决方案:
- 使用 “调试预制体” 功能
- 检查
PrefabUtility相关代码 - 确保预制体已保存到项目中
调试工具
工具内置了多个调试功能:
- 调试预制体:显示预制体识别详情
- 调试脚本:分析脚本收集过程
- 测试HLSL提取:单独测试 Shader 解析
- 查看HLSL映射:显示 Shader 与 HLSL 的引用关系
性能优化建议
1. 大型场景处理
- 分批处理资产,避免一次性处理过多资源
- 使用进度条显示长时间操作的状态
- 考虑禁用子资产收集以减少处理时间
2. 内存管理
- 使用
HashSet<UnityEngine.Object>避免重复收集 - 及时清理临时集合和缓存
- 使用
EditorUtility.UnloadUnusedAssets释放内存
3. 文件操作优化
- 批量文件操作减少 IO 开销
- 使用缓存机制避免重复路径计算
- 异步操作处理大量文件导出
扩展与自定义
添加新的资产类型
// 1. 在 GetDisplayType 中添加类型识别case "YourCustomType": return specificTypeSettings.yourCustomType ? specificTypeSettings.yourCustomFolder : null;
// 2. 在 SpecificTypeSettings 中添加配置项public bool yourCustomType = true;public string yourCustomFolder = "YourCustom";
// 3. 添加专用的收集方法private void CollectYourCustomAssets(HashSet<UnityEngine.Object> collectedObjects){ // 实现自定义资产的收集逻辑}自定义导出逻辑
重写 GetDestinationPath 方法实现自定义的文件组织结构:
protected virtual string GetDestinationPath(string baseFolder, AssetInfo asset, string sourcePath){ // 实现自定义的路径计算逻辑 return customPath;}总结
感谢你看到这里该工具主要是由于我个人需求所产生并扩展的,它能够基本满足我的日常项目资产的转移,同时还能清理无效资产、材质、脚本和shader等,并且也能够打包成package文件方便与项目成员对接。这个工具可以一定程度上解决实际的开发需求无论是用于项目迁移、资产清理还是团队协作,都是非常不错的。
后续更新(有需求的话会更新同时也会修复一些bug)
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!
Unity场景资产提取器 - 完整教程与代码分析
https://stellaastra.dpdns.org/posts/script/sceneassetextractor/ 相关文章 智能推荐
1
Generic 动画骨骼重映射插件实现与使用
小工具 解包动画后动画资产因为路径问题导致不可使用解决方案
2
RenderDoc MCP Server 详细分析报告
小工具 AI自动化分析逆向工具
3
RenderDoc 扩展工具集 — 技术原理解析
小工具 截帧过程中遇到的需求开发的一些方便的工具,会持续更新如果有遇到新需求的话
4
mhy游戏资源查询更新小工具-fuck_mhy.py
小工具 拆分json文件并对比上版本json文件浏览增加内容
5
终末地渲染Shader流程
游戏角色Shader还原 终末地角色渲染方案-unity
随机文章 随机推荐