You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity编辑器保存1.5亿顶点Mesh崩溃的解决方案咨询

问题

我通过C#脚本创建Mesh对象,尝试用AssetDatabase.CreateAsset()方法保存为资源,保存代码如下:

AssetDatabase.StartAssetEditing();
AssetDatabase.CreateAsset(tempMesh, $"Assets/Export/{fileName}.asset");
AssetDatabase.StopAssetEditing();

已添加tempMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;设置,当tempMesh顶点数约为80000时可正常保存,但顶点数达约150000000时编辑器崩溃。

我考虑将Mesh按每100000个顶点拆分(生成1500个Mesh),再为每个Mesh生成对象,但尽可能不想拆分。请问如何保存约1.5亿顶点的Mesh?

环境:

  • MacBook Pro 2020,13英寸,8GB RAM
  • Unity 2020.3.47f1

崩溃日志:

Obtained 46 stack frames.
#0  0x0000011048d0d1 in BytesToHexString(void const*, unsigned long, char*)
#1  0x0000011014044d in TextDOMTransferWriteBase<YAMLWrite>::TransferTypelessData(unsigned int, void*, TransferMetaFlags)
#2  0x0000011025898a in void VertexData::Transfer<YAMLWrite>(YAMLWrite&)
#3  0x0000010ff78f64 in void YAMLWrite::Transfer<VertexData>(VertexData&, char const*, TransferMetaFlags)
#4  0x00000111d3ab32 in void Mesh::Transfer<YAMLWrite>(YAMLWrite&)
#5  0x00000111d3a514 in void YAMLWrite::Transfer<Mesh>(Mesh&, char const*, TransferMetaFlags)
#6  0x000001106dabbf in void SerializedFile::WriteTextSerialized<Object>(core::basic_string<char, core::StringStorageDefault<char>>&, Object&, BuildUsageTag const&, TransferInstructionFlags)
#7  0x000001106da73e in SerializedFile::WriteObject(Object&, long long, short, BuildUsageTag const&, GlobalBuildData const&)
#8  0x000001106b9f6d in PersistentManager::WriteFile(core::basic_string_ref<char>, int, WriteData const*, int, GlobalBuildData const&, VerifyWriteObjectResult (*)(Object*, BuildTargetPlatform), BuildTargetSelection, TransferInstructionFlags, WriteInformation&, InstanceIDResolver const*, PersistentManager::LockFlags, int (*)(PersistentManager::ReportWriteObjectStep, int, core::basic_string<char, core::StringStorageDefault<char>> const&, int, void*), void*)
#9  0x000001106b8b23 in PersistentManager::WriteFile(core::basic_string_ref<char>, int, WriteData const*, int, GlobalBuildData const&, VerifyWriteObjectResult (*)(Object*, BuildTargetPlatform), BuildTargetSelection, TransferInstructionFlags, InstanceIDResolver const*, PersistentManager::LockFlags, int (*)(PersistentManager::ReportWriteObjectStep, int, core::basic_string<char, core::StringStorageDefault<char>> const&, int, void*), void*)
#10 0x000001110e11c8 in WriteObjectsToDiskThreadSafe(core::basic_string<char, core::StringStorageDefault<char>> const&, Object**, long long const*, unsigned long, TransferInstructionFlags)
#11 0x000001113e722f in CreateSerializedAssetV2(Object**, int, core::basic_string<char, core::StringStorageDefault<char>> const&, AssetDatabase::CreateAssetMask)
#12 0x00000111382c9c in AssetDatabase::CreateSerializedAsset(Object&, core::basic_string<char, core::StringStorageDefault<char>> const&, AssetDatabase::CreateAssetMask)
#13 0x00000111739d78 in AssetDatabaseBindings::CreateAsset(PPtr<Object>, core::basic_string<char, core::StringStorageDefault<char>> const&, ScriptingExceptionPtr*)
#14 0x000001117d7b04 in AssetDatabase_CUSTOM_CreateAsset(ScriptingBackendNativeObjectPtrOpaque*, ScriptingBackendNativeStringPtrOpaque*)
#15 0x000001b52959e5 in  (wrapper managed-to-native) UnityEditor.AssetDatabase:CreateAsset (UnityEngine.Object,string) {0x7fc4732dab20} + 0x65 (0x1b5295980 0x1b5295a6d) [0x151982960 - Unity Child Domain]
#16 0x000001824d2fab in  Cysharp.Threading.Tasks.CompilerServices.AsyncUniTask`1<MainAsync/<tengunMeshGenerator>d__3>:Run () {0x7fc471c24c10} + 0x2b (0x1824d2f80 0x1824d2fcb) [0x151982960 - Unity Child Domain]
#17 0x000001824dd2cb in  Cysharp.Threading.Tasks.Internal.ContinuationQueue:Update () {0x7fc4729ea3d0} + 0x1b (0x1824dd2b0 0x1824dd2d0) [0x151982960 - Unity Child Domain]
#18 0x0000015683b1f5 in mono_jit_runtime_invoke
#19 0x000001569d9213 in do_runtime_invoke
#20 0x000001569d916d in mono_runtime_invoke
#21 0x0000011064c197 in scripting_method_invoke(ScriptingMethodPtr, ScriptingObjectPtr, ScriptingArguments&, ScriptingExceptionPtr*, bool)
#22 0x00000110647746 in ScriptingInvocation::Invoke(ScriptingExceptionPtr*, bool)
#23 0x00000110323cd9 in ExecutePlayerLoop(NativePlayerLoopSystem*)
#24 0x00000110323b65 in ExecutePlayerLoop(NativePlayerLoopSystem*)
#25 0x00000110323fb5 in PlayerLoop()
#26 0x00000110e930c2 in PlayerLoopController::UpdateScene(bool)
#27 0x00000110e8d207 in PlayerLoopController::UpdateSceneIfNeeded()
#28 0x00000110e8a664 in Application::TickTimer()
#29 0x000001121bca3f in -[EditorApplication TickTimer]
#30 0x007ff805399766 in __NSFireTimer
#31 0x007ff8044e9358 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__
#32 0x007ff8044e8ed3 in __CFRunLoopDoTimer
#33 0x007ff8044e8af9 in __CFRunLoopDoTimers
#34 0x007ff8044cee39 in __CFRunLoopRun
#35 0x007ff8044cdf31 in CFRunLoopRunSpecific
#36 0x007ff80df49dad in RunCurrentEventLoopInMode
#37 0x007ff80df49bbe in ReceiveNextEventCommon
#38 0x007ff80df49918 in _BlockUntilNextEventMatchingListInModeWithFilter
#39 0x007ff8075625d0 in _DPSNextEvent
#40 0x007ff80756147a in -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:]
#41 0x007ff807553ae8 in -[NSApplication run]
#42 0x007ff807527d02 in NSApplicationMain
#43 0x000001121d856d in EditorMain(int, char const**)
#44 0x000001121d8799 in main
#45 0x007ff80409a41f in start
Launching bug reporter

解决方案

1. 先解决内存瓶颈

你的设备仅8GB RAM,1.5亿顶点的Mesh序列化时会占用巨量内存(按单顶点最低32字节计算,仅顶点数据就需要4.8GB,还未包含索引、UV等额外数据),再加上Unity编辑器本身的内存开销,极易触发内存不足导致崩溃。

  • 关闭编辑器内所有不必要的窗口、场景对象,释放尽可能多的内存。
  • 保存Mesh前手动调用内存清理方法,减少内存碎片:
GC.Collect();
Resources.UnloadUnusedAssets();
AssetDatabase.StartAssetEditing();
AssetDatabase.CreateAsset(tempMesh, $"Assets/Export/{fileName}.asset");
AssetDatabase.StopAssetEditing();

2. 改用二进制序列化替代YAML

Unity默认用YAML文本格式序列化Mesh,内存开销极大。可以尝试使用Mesh.SaveMesh()内部方法直接保存二进制格式的.asset文件,跳过Unity的YAML序列化流程:

using UnityEditorInternal;
using System.IO;

var filePath = Path.Combine(Application.dataPath, $"Export/{fileName}.asset");
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
tempMesh.SaveMesh(filePath, false);
AssetDatabase.Refresh();

注意:SaveMesh是Unity内部方法,不同版本可能存在兼容性问题,需测试验证。

3. 调整编辑器内存限制

打开Unity编辑器的Edit > Preferences > Performance,将Memory Limit调至系统允许的最大值,降低内存限制触发崩溃的概率。

4. 拆分Mesh仍是最稳妥方案

如果以上方法均无效,拆分Mesh是最可靠的选择。可以将大Mesh按顶点数切割为多个子Mesh,保存时分开存储,运行时可通过合并渲染保证效果:

List<Mesh> subMeshes = SplitMeshIntoSubMeshes(tempMesh, 100000);
AssetDatabase.StartAssetEditing();
for (int i = 0; i < subMeshes.Count; i++)
{
    AssetDatabase.CreateAsset(subMeshes[i], $"Assets/Export/{fileName}_{i}.asset");
}
AssetDatabase.StopAssetEditing();

拆分逻辑可按顶点索引范围切割,确保每个子Mesh的顶点数在安全阈值内。

内容的提问来源于stack exchange,提问作者sssccc210

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 14:54:56