网易首页 > 网易号 > 正文 申请入驻

Unity社区精华帖 | SBP - Scriptable Build Pipeline

0
分享至

Scriptable Build Pipeline 是什么?能来带什么好处?

自定义 Unity 如何构建应用内容

将原先处于C++的引擎代码移到了C#

加速了AssetBundle的构建时间

改善增量构建处理

对开发者来说具备更多的灵活性

Unity 版本要求:Unity 2018.3 +

术语

Asset

磁盘上的源文件,通常位于项目的 “Assets” 文件夹中。此文件在内部导入到您的资产的可用于游戏的表示形式,其中可以包含多个 Object(SubAsset)。

Object (SubAsset)

单个 Unity 可序列化单元。也称为 SubAsset。导入的 Asset 由一个或多个对象组成。

Includes

从中构造 Asset 的唯一一组 Object。

References

一组需要被 Asset 使用,但不在该 Asset 中的 Object。

快速入门 & BuildIn切换

BuildAssetBundles

BuildIn Pipeline


using System.IO;using UnityEditor;
public static class BuildAssetBundlesExamplepublic static bool BuildAssetBundles(string outputPath, bool forceRebuild, bool useChunkBasedCompression, BuildTarget buildTarget)var options = BuildAssetBundleOptions.None;if (useChunkBasedCompression)options |= BuildAssetBundleOptions.ChunkBasedCompression;
if (forceRebuild)options |= BuildAssetBundleOptions.ForceRebuildAssetBundle;
Directory.CreateDirectory(outputPath);var manifest = BuildPipeline.BuildAssetBundles(outputPath, options, buildTarget);return manifest != null;

SBP

CompatibilityBuildPipeline 是 SBP 目前官方使用 SBP 流程适配 BuildIn 流程的适配实现。

SBP 不支持以前支持的所有功能。


using System.IO;using UnityEditor;// Added new usingusing UnityEditor.Build.Pipeline;
public static class BuildAssetBundlesExamplepublic static bool BuildAssetBundles(string outputPath, bool forceRebuild, bool useChunkBasedCompression, BuildTarget buildTarget)var options = BuildAssetBundleOptions.None;if (useChunkBasedCompression)options |= BuildAssetBundleOptions.ChunkBasedCompression;
if (forceRebuild)options |= BuildAssetBundleOptions.ForceRebuildAssetBundle;
Directory.CreateDirectory(outputPath);// Replaced BuildPipeline.BuildAssetBundles with CompatibilityBuildPipeline.BuildAssetBundles herevar manifest = CompatibilityBuildPipeline.BuildAssetBundles(outputPath, options, buildTarget);return manifest != null;

注意事项

CompatibilityBuildPipeline.BuildAssetBundles vs BuildPipeline.BuildAssetBundle 的特性与行为的对比。

AssetBundleBuild.addressableNames:

https://docs.unity3d.com/ScriptReference/AssetBundleBuild-addressableNames.html

BuildAssetBundleOptions

AssetBundle SBP 构建流程

01 Setup - 平台环境初始化

SwitchToBuildPlatform

RebuildSpriteAtlasCache

02 Player Scripts - 工程源代码编译

BuildPlayerScripts、PostScriptsCallback

03 Dependency

CalculateSceneDependencyData

CalculateCustomDependencyData (UNITY_2019_3_OR_NEWER)

CalculateAssetDependencyData

StripUnusedSpriteSources

PostDependencyCallback

04 Packing

GenerateBundlePacking

GenerateBundleCommands

GenerateSubAssetPathMaps

GenerateBundleMaps

PostPackingCallback

05Writing

WriteSerializedFiles

ArchiveAndCompressBundles

AppendBundleHash

GenerateLinkXml

PostWritingCallback

06 Generate manifest files

官方 TODO 项

01 Setup

SwitchToBuildPlatform

切换当前平台为构建 AssetBundle 的目标平台对应的 BuildTargetGroup 、 BuildTarget。

执行回调 IPreprocessShaders 、IProcessScene、IProcessSceneWithReport

关键逻辑:


EditorUserBuildSettings.SwitchActiveBuildTarget(m_Parameters.Group, m_Parameters.Target);

RebuildSpriteAtlasCache

针对目标平台重新构建 工程内所有的 SpriteAtlas。

关键逻辑:


SpriteAtlasUtility.PackAllAtlases(m_Parameters.Target);

02 Player Scripts

BuildPlayerScripts

编译目标平台源代码生成 ScriptInfo(TypeDB - 记录了脚本类型 、 属性数据)

TypeDB 为后续的序列化提供正确的字段名称。

关键逻辑:


PlayerBuildInterface.CompilePlayerScripts(m_Parameters.GetScriptCompilationSettings(), m_Parameters.ScriptOutputFolder);

PostScriptsCallback

回调脚本订阅了脚本编译完成节点的所有函数。

上层开发者,注册监听 BuildCallbacks.PostScriptsCallbacks。

关键逻辑:


IScriptsCallback.PostScripts(IBuildParameters parameters, IBuildResults results);

03 Dependency

CalculateSceneDependencyData - 计算所有场景的依赖信息

判断是否使用 Cache 机制;计算场景相关依赖项

关键逻辑:


#if UNITY_2019_3_OR_NEWERContentBuildInterface.CalculatePlayerDependenciesForScene(scenePath, settings, usageTags, m_DependencyData.DependencyUsageCache);#elseContentBuildInterface.PrepareScene(scenePath, settings, usageTags, m_DependencyData.DependencyUsageCache, outputFolder);#endif

Cache 仅记录预制相关的依赖。

CalculateCustomDependencyData (UNITY_2019_3_OR_NEWER)

计算未被 AssetDatabase 追踪的自定义 Assets 依赖的 Object 关系;

由 IBundleBuildContent.CustomAssets 自定义 AssetBundle 包含的内容。

关键逻辑:


foreach (CustomContent info in IBundleBuildContent.CustomAssets)info.Processor(info.Asset, this);

CalculateAssetDependencyData - 计算所有 Asset的依赖数据

基础入参

源代码的 TypeDB

GraphicsSettings

场景的 LightSetting

获取 Asset 的所包含的 Objects

即为该 Asset 引用的 Object;为 该 Asset YAML 序列化中 !u![ClassID] 段所表示的 Object。

通过 TypeDB 获取 Objects 所引用的 Objects

如果是 Sprite 类型资源,则进行 Sprite Atlas 的打包设置

计算 SubAssets

关键逻辑:


var includedObjects = ContentBuildInterface.GetPlayerObjectIdentifiersInAsset(asset, input.Target);var referencedObjects = ContentBuildInterface.GetPlayerDependenciesForObjects(includedObjects, input.Target, input.TypeDB);ObjectIdentifier[] representations = ContentBuildInterface.GetPlayerAssetRepresentations(asset, target);// Main Asset always returns at index 0, we only want representations, so check for greater than 1 lengthif (representations.IsNullOrEmpty() || representations.Length < 2)return;extendedData = new ExtendedAssetData();extendedData.Representations.AddRange(representations.Skip(1));

StripUnusedSpriteSources - 删除 Assets引用中被Packer的Sprite

筛选出已经被 SpritePacker 打包的Sprite,所归属的 SourceTexture;

删除 Assets 中引用的 Sprite信息;

关键逻辑:


var unusedSources = new HashSet();var textures = m_SpriteData.ImporterData.Values.Where(x => x.PackedSprite).Select(x => x.SourceTexture);unusedSources.UnionWith(textures);
// Count refs from assetsvar assetRefs = m_DependencyData.AssetInfo.SelectMany(x => x.Value.referencedObjects);foreach (ObjectIdentifier reference in assetRefs)unusedSources.Remove(reference);
// Count refs from scenesvar sceneRefs = m_DependencyData.SceneInfo.SelectMany(x => x.Value.referencedObjects);foreach (ObjectIdentifier reference in sceneRefs)unusedSources.Remove(reference);
// SetOutputInformationforeach (var source in unusedSources)var assetInfo = m_DependencyData.AssetInfo[source.guid];assetInfo.includedObjects.RemoveAt(0);
ExtendedAssetData extendedData;if (m_ExtendedAssetData != null && m_ExtendedAssetData.ExtendedData.TryGetValue(source.guid, out extendedData))extendedData.Representations.Remove(source);if (extendedData.Representations.Count == 1)m_ExtendedAssetData.ExtendedData.Remove(source.guid);

PostDependencyCallback

在依赖计算完成后的事件通知

上层开发者,注册监听 BuildCallbacks.PostDependencyCallback

关键逻辑:


IDependencyCallback.PostDependency(IBuildParameters parameters, IDependencyData dependencyData);

04Packing - 资源构建

GenerateBundlePacking - 组装AssetBundle以及计算依赖加载列表

Normal AssetBundle

Streamed Scene AssetBundle

ArchiveFileSystem

校验 Object 是否是 Assets 类型 或 自定义Assets类型 | Scene 类型,创建对应类型的 “容器结构”

可通过 ValidationMethods.ValidAssetFake 接管校验逻辑

计算 Asset 所依赖的加载列表

剔除 Unity默认的内置资源引用 - 处理依赖关系中的重复递归依赖 & 打破环形依赖;(若是 Scene Bundle,则剔除 sharedAssets 的重复引用)

关键逻辑:


foreach (var bundle in m_BuildContent.BundleLayout)if (ValidAssetBundle(bundle.Value, customAssets))PackAssetBundle(bundle.Key, bundle.Value, assetToReferences);else if (ValidationMethods.ValidSceneBundle(bundle.Value))PackSceneBundle(bundle.Key, bundle.Value, assetToReferences);
// Remove Default Resources and Includes for Assets assigned to Bundlesforeach (ObjectIdentifier reference in references)if (reference.filePath.Equals(CommonStrings.UnityDefaultResourcePath, StringComparison.OrdinalIgnoreCase))continue;if (dependencyData.AssetInfo.TryGetValue(reference.guid, out AssetLoadInfo referenceInfo))referencedAssets.Add(referenceInfo);continue;referencesPruned.Add(reference);

GenerateBundleCommands - 为需要序列化的AssetBundle创建WriteOperation行为

初始化 AssetBundle MainAsset

创建对应的 BundleCommand (CreateAssetBundleCommand、CreateSceneBundleCommand + CreateSceneDataCommand)

AssetBundleCommand :

1.建立加载 Asset的入参与 Object 的映射关系

2.记录 AssetsBundle 中包含的Assets相关信息(依赖的Object hash、序列化组织形式等)并排序,以此确保每次序列化数据的稳定性

SceneBundleCommand :

1.建立加载 Scene 所包含需要序列化的Object与加载的入参的映射关系

2.记录 SceneBundle 依赖的Object 至 preloadObjects

SceneDataCommand :

1.建立加载Scene 所需要附加的Assets 的映射关系

2.记录 SceneBundle 依赖的Object 至 preloadObjects

关键逻辑:


Dictionarystring> assetToMainFile = new Dictionarystring>();foreach (var pair in m_WriteData.AssetToFiles)assetToMainFile.Add(pair.Key, pair.Value[0]);
foreach (var bundlePair in m_BuildContent.BundleLayout)if (ValidAssetBundle(bundlePair.Value, customAssets))// Use generated internalName here as we could have an empty asset bundle used for raw object storage (See CreateStandardShadersBundle)var internalName = string.Format(CommonStrings.AssetBundleNameFormat, m_PackingMethod.GenerateInternalFileName(bundlePair.Key));CreateAssetBundleCommand(bundlePair.Key, internalName, bundlePair.Value);else if (ValidationMethods.ValidSceneBundle(bundlePair.Value))var firstScene = bundlePair.Value[0];CreateSceneBundleCommand(bundlePair.Key, assetToMainFile[firstScene], firstScene, bundlePair.Value, assetToMainFile);for (int i = 1; i < bundlePair.Value.Count; ++i)var additionalScene = bundlePair.Value[i];CreateSceneDataCommand(assetToMainFile[additionalScene], additionalScene);

Unity 官方微信

第一时间了解Unity引擎动向,学习最新开发技巧

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
住房被写成“大宗耐用消费品”:一次迟到的定性追认

住房被写成“大宗耐用消费品”:一次迟到的定性追认

虎嗅APP
2026-07-17 19:58:21
一位婆婆写给儿媳妇的信,看哭了无数的婆婆,太让人寒心了

一位婆婆写给儿媳妇的信,看哭了无数的婆婆,太让人寒心了

千秋文化
2026-07-18 19:02:42
马宁回应世界杯只执法一场比赛:这是我们决定不了的事情,不要自我制造焦虑,那场比赛完成得非常好,展示了我们中国足球裁判应有的风采

马宁回应世界杯只执法一场比赛:这是我们决定不了的事情,不要自我制造焦虑,那场比赛完成得非常好,展示了我们中国足球裁判应有的风采

鲁中晨报
2026-07-18 11:48:37
查出冠心病,离心衰有多远?医生:还能撑多久,就看这5点!

查出冠心病,离心衰有多远?医生:还能撑多久,就看这5点!

观星赏月
2026-07-18 13:49:29
25国派兵,俄军强敌一次到齐,普京被逼到墙角,中方亮出中俄条约

25国派兵,俄军强敌一次到齐,普京被逼到墙角,中方亮出中俄条约

面包夹知识
2026-07-17 19:13:58
杭州宝爸做了个“卷了么”小程序!每次送儿子上兴趣班都问东问西,老婆发火:“亏你还是程序员……” 没想到,真做成了

杭州宝爸做了个“卷了么”小程序!每次送儿子上兴趣班都问东问西,老婆发火:“亏你还是程序员……” 没想到,真做成了

都市快报橙柿互动
2026-07-18 20:35:47
姆巴佩主动让出金靴?39岁梅西的世界杯,可能只剩这一次了

姆巴佩主动让出金靴?39岁梅西的世界杯,可能只剩这一次了

带你逛体坛
2026-07-18 12:59:22
男子装“富二代”谈恋爱,骗父母称申请研究生要用钱,向亲友借款上千万元,转头为女友花了900多万元,最终因涉嫌诈骗被判11年

男子装“富二代”谈恋爱,骗父母称申请研究生要用钱,向亲友借款上千万元,转头为女友花了900多万元,最终因涉嫌诈骗被判11年

扬子晚报
2026-07-17 21:59:42
大马丁:手每天都疼在小组赛时无法训练,卫冕就退役?首先得赢球

大马丁:手每天都疼在小组赛时无法训练,卫冕就退役?首先得赢球

兰亭墨未干
2026-07-18 08:26:07
有人预言:从下半年开始,社区食堂、预制菜,很可能迎来行业新一轮洗牌

有人预言:从下半年开始,社区食堂、预制菜,很可能迎来行业新一轮洗牌

小谈食刻美食
2026-07-16 08:19:00
图赫尔再谈对阿根廷:如果你需要找人怪罪,我承担这个责任

图赫尔再谈对阿根廷:如果你需要找人怪罪,我承担这个责任

画夕
2026-07-18 13:34:27
笑不活了!网友集体冲进冉莹颖账号评论区,各种神评涌现太离谱

笑不活了!网友集体冲进冉莹颖账号评论区,各种神评涌现太离谱

娱乐圈笔娱君
2026-07-17 16:13:59
许雅钧终于开口了!一句“资产分配”戳中大S家最痛的伤疤!

许雅钧终于开口了!一句“资产分配”戳中大S家最痛的伤疤!

TVB的四小花
2026-07-19 05:13:47
米体:前国米主席莫拉蒂2006年曾2.5亿欧报价梅西,但遭拒绝

米体:前国米主席莫拉蒂2006年曾2.5亿欧报价梅西,但遭拒绝

懂球帝
2026-07-18 20:22:17
十五五重磅信号!工资、养老金双双上涨,这三类人最受益

十五五重磅信号!工资、养老金双双上涨,这三类人最受益

80后已是老登
2026-07-18 13:08:57
Stephen A. Smith怒批詹姆斯:你早就知道去哪,别演了

Stephen A. Smith怒批詹姆斯:你早就知道去哪,别演了

热血体育社
2026-07-17 01:27:26
世界杯金靴奖金为零?FIFA官宣:金球、金手套全都没钱

世界杯金靴奖金为零?FIFA官宣:金球、金手套全都没钱

元气满分吖
2026-07-19 01:30:29
拳王都看不下去了!梅威瑟公开喊话C罗“我兄弟”打脸多少黑粉?

拳王都看不下去了!梅威瑟公开喊话C罗“我兄弟”打脸多少黑粉?

童叔不飙车
2026-07-11 22:42:02
落地!丰台这3个村划入征地范围!未来片区交通拥堵将大幅改善!

落地!丰台这3个村划入征地范围!未来片区交通拥堵将大幅改善!

北京安置房大全
2026-07-17 18:53:49
最牛美女处长,1000天和男上司开房410次,临时工晋升财务副处长

最牛美女处长,1000天和男上司开房410次,临时工晋升财务副处长

三石记
2026-06-26 07:16:19
2026-07-19 06:03:00
Unity incentive-icons
Unity
Unity中国官方帐户
2488文章数 6733关注度
往期回顾 全部

科技要闻

WAIC2026看什么?这份"不迷路"攻略请收好

头条要闻

“黄总请你去包厢” “黄总”身份公布

头条要闻

“黄总请你去包厢” “黄总”身份公布

体育要闻

德尚是非典型法国人 14年执教留下丰厚遗产

娱乐要闻

大S给具俊晔留遗产是昏头?实际上她清醒得很

财经要闻

股民当街砍博主!韩国股市 终极大屠杀

汽车要闻

把中国超跑卖到英国,比亚迪正在被世界看见

态度原创

本地
亲子
房产
艺术
公开课

本地新闻

十年了,为什么鬼怪CP还能让人美美嗑上?

亲子要闻

健康提醒:暑期重视儿童防晒 科学应对日晒伤害

房产要闻

突然出手!千亩城更+一线江景,世嘉亮出超级四代宅!

艺术要闻

蒋校长和郭沫若同题“黄帝陵”,水平谁高谁低?

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版