Blast
TL;DR
坑点:
- 本身也是个预切割的方案,并没有根本上解决碎片太多导致的加载问题
- c++库引入会有一定风险,且没有官方支持
- 工具流缺失,没有完备的Unity集成,配套产出可破坏物描述文件工具需要自己维护
但是也并非没有可以借鉴的地方:
- 实现了一套层次化破坏方案
- 性能较好(不光是c++库的原因,内部光判定联通就有不少算法层面优化手段,非常值得学习)
- 可定制的伤害策略
- Stress Solver,更加精确的垮塌计算
- 代码格式规整,设计感强,注释很多
Blast概要
底层:NvBlast : 核心算法库,聚焦于层次化结构维护以及破坏时的联通变化计算
上层:NvBlastTk : event system/object manage/process damage/joint
扩展: NvBlastExt : Streee Solver/……
外围工具:
- AuthoringTool,一个命令行工具,用来输入模型,切分,产出blast文件
- BlastTool,可视化工具(但是最新的master分支里被干掉了,原因不明)
- SampleAssetViewer,预览做好的blast资源
该项目本身只负责计算纯几何学上的结构维护,联通判定,破坏计算。
至于游戏对象管理,物理模拟,渲染,统统交给用户。
关于官方的Unity样例
首先会根据blast格式,描述一个chunk集合,然后丢给blast初始化
接着就用blast提供的chunk数据初始化真实的游戏内对象,即GameObject,或者说碎片对象。
事实上,对于所有的碎片实际上也是预先Instantiate出来的:
1 | // Actual Cubes |
构建完毕即可利用damage系统对其施加伤害,伤害计算结束后,重新拿到blast的计算结果,调整游戏内对象状态,该Active的Active,该干掉的干掉
1 | actor.GenerateFracture( _fractureBuffers, damP, programParams ); |
使用上的大致流程以及一些关键API:
根据chunk描述构建asset
1 | var asset = NvBlastCreateAsset( mem, desc, NvBlastWrapper.GetScratch( (int)scratchSize ), NvBlastWrapper.Log ); |
根据assest构建family(主要在分配内存)
1 | var family = NvBlastAssetCreateFamily( mem, asset.ptr, NvBlastWrapper.Log ); |
创建actor(初始化,创建联通。。。)
1 | var actor = NvBlastFamilyCreateFirstActor( family.ptr, desc, NvBlastWrapper.GetScratch((int)scratchSize), NvBlastWrapper.Log ); |
伤害
1 | NvBlastActorGenerateFracture( buffers, ptr, program, programParams, NvBlastWrapper.Log, null ); |
一些议题
1. 如何描述层级结构
离线数据
虽然看不到blast二进制文件,不过于可视化编辑器中可以直接看到。
对于一个可破坏物,其表示为一个树状结构:
举例而言,对于一个原始物件,称作depth 0

切分一次后,称作depth 1

针对某个碎片再次切分,称作 depth 2

这里碎片之间联通是离线弄好的,理论上也可以增删改
内部结构

Assest中:
chunk:
- 位置
- 父节点
- 是否为support
bond: - 两端点
- 方向
- 面积
chunk之间通过bond连接,chunk之下有子层级,整个形成一个树型结构。
联通关系在代码内部被Support Graph所描述为一个图,官网上的图基本解释的比较清楚了。
破坏如何处理
第一步
构造NvBlastDamageProgram:
- NvBlastGraphShaderFunction
- NvBlastSubgraphShaderFunction
这里理论上可以通过描述破坏来定制不同种类的伤害算法(比如仅沿边缘切割等
也可更复杂,这里简化之,简单的构造一个圆形伤害
- 坐标
- 半径
- 伤害值
Q: 如何找到需要破坏的chunk?
此处不和任何物理库相关,所以这里一定是纯几何学作出的判定
第二步
NvBlastActorApplyFracture
这里又分两部分
chunk fracture
此处会掉chunk血,一旦掉完了就尝试破坏子层级。
这里伤害数值首先减去父层级当前收到的伤害,然后溢出的伤害会平摊到子层级的每个chunk中。
然后递归之,继续处理子层级。
不过这里仅仅做了HP计算,并没有做其他的了,结构化的伤害计算在后面。bond fracture
掉血,通知 familyGraph edgeRemoved
设置node脏位
构造Fracture Event
第三步
Split
这一步干了最多的活,即根据当前结构中HP情况计算新结构。
上一步会找到graph中脏node,针对每个脏node findIsIands,即判断是否已经不连通了。
每个island有个root,此处会尝试针对每个脏节点findRoute到rootNode。
此处做了很多优化(TODO):
- TryFastPath
- Hop Counts
一旦没找到path,就把当前脏节点作为新Island的根节点,建立新的Island。
外部(Unity)获取到当前结构中哪些被断开了,找到对应的GameObject,该干掉干掉,该激活激活。
Stress Solver
Rayfire对此的应对:
- 简单的stress判定
- 整体破碎完整度,据此判定垮塌
Rayfire的方案会出现,某些伸出来的”厂”形结构,末端看起来很不物理
https://docs.nvidia.com/gameworks/content/gameworkslibrary/blast/1.1/api_docs/files/pageextstress.html
模拟碎片收到的重力和离心力
Blast官网上的例子:子弹打到桌子腿上,桌子腿关节处会断裂
bond stress计算公式:
1 | stress = (bond.linearStress * stressLinearFactor + bond.angularStress * stressAngularFactor) / hardness; |
另外为了加速stress计算,此处设置了一个setting值:graphReductionLevel,计算的时候会归并一些Node,合并为一个大node。
最终解算完毕获取stress的时候,内部stress直接平摊一下,以在效率和效果上进行平衡。
graphReductionLevel is the number of node merge passes. The resulting graph will be roughly 2^graphReductionLevel times smaller than the original.
解算大致流程:
每个Family会有一个solver,solve会接受碎裂信息,同时这个solver会不断更新:
1 | void ExtPxStressSolverImpl::update(bool doDamage) |
迭代计算:
这里大概的意思是,求出bond对应连接的两个Node(碎片)的冲量
然后用其差值作为bond 的 linearStress/angularStress
(用人话说就是如果两个碎片向不同的方向运动,就会将这个关节撕裂)
1 | void solve(uint32_t iterationCount, bool warmStart = true) |
其他资料
- 官网:https://developer.nvidia.com/blast
- github:https://github.com/NVIDIAGameWorks/Blast
- blast UE4集成:https://docs.nvidia.com/gameworks/content/gameworkslibrary/blast/1.1/authoring_docs/BlastUe4_QuickStart.html
- 雷火可破坏物专题,提到了Blast:https://zhuanlan.zhihu.com/p/346846195
- 配套的美术制作工具文档:https://gameworksdocs.nvidia.com/Blast/1.1/authoring_docs/BlastTool_QuickStart.html
- Form上的讨论:
- https://forum.unity.com/threads/nvidia-blast.472623/
- 网友写的build c++文档:https://docs.google.com/document/d/174HfCHWoRMcrLgKsVY5ozIIVLgzm-koww8V3UuZ6OFM/edit
- 网友自己做的整合:https://github.com/razzraziel/nvblast_razz
- 另一个整合:https://gitlab.com/dima13230/unity-libre-fracture
- 鸽了的插件:https://forum.unity.com/threads/magic-destruction-toolkit-nvidia-blast-integration.1005617/
- Android相关讨论,目前比较大的坑点:
- https://forums.developer.nvidia.com/t/using-nvidia-blast-in-android-build-with-unity3d/110565