1. 项目概述:为什么glTFast是Unity开发者的新宠?
如果你正在Unity里折腾3D模型,尤其是从各种建模软件(比如Blender、Maya)或者网上下载的模型资源,那你一定对模型导入这个环节又爱又恨。爱的是,精美的模型能让你的游戏或应用瞬间提升几个档次;恨的是,这个过程常常伴随着漫长的等待、诡异的材质丢失、巨大的内存占用,甚至直接卡死编辑器。我经历过太多次,导入一个几百兆的FBX文件,Unity转圈圈转了五分钟,然后告诉我“导入失败”。直到我遇到了glTFast,这个痛点才被真正解决。
glTF,全称GL Transmission Format,你可以把它理解为“3D界的JPEG”。它是由Khronos Group(就是制定OpenGL、Vulkan标准的那个组织)推动的开放标准,目标就是成为网络上传输和加载3D模型的通用格式。相比于传统的FBX、OBJ,glTF是“为运行时而生”的。它天生就为Web和实时渲染优化,文件结构更紧凑,加载速度更快,并且原生支持PBR(基于物理的渲染)材质、动画、骨骼等现代图形特性。而glTFast,就是Unity官方钦点的高性能glTF加载库。它不是Unity内置的,但却是Unity官方在GitHub上维护和推荐的项目,地位特殊。它的核心就一个字: 快 。通过高度优化的C#/Unity Job System/Burst编译器技术,它能实现远超传统导入方式的加载速度,并且支持运行时动态加载,这对需要动态下载模型的应用(如数字孪生、AR展示、大型开放世界游戏)来说是革命性的。
所以,这个“完全指南”要解决的,就是如何把glTFast这个利器,无缝集成到你的Unity工作流中,从环境配置、基础导入导出,到高级功能优化和疑难杂症排查,让你彻底告别模型导入的等待与焦虑。无论你是独立开发者、TA(技术美术),还是项目负责人,掌握glTFast都意味着更高效的生产力和更流畅的用户体验。
2. 核心思路与工作流设计
在深入代码之前,我们必须先理清思路:传统工作流和基于glTFast的工作流到底有什么不同?这决定了我们该如何重新设计资产管道。
2.1 传统Unity模型工作流的瓶颈
传统的流程通常是这样的:美术人员在Blender/Max/Maya中完成模型制作,导出为FBX或OBJ文件,然后由程序或TA手动拖入Unity项目的
Assets
文件夹。Unity的
Asset Pipeline
会启动,在后台进行一系列处理:计算光照贴图UV(如果没提前做好)、生成网格碰撞体、压缩纹理、为模型创建Prefab和材质球等。这个过程我们称之为“编辑时导入”。
它的主要问题在于:
- 阻塞式操作 :导入大型或复杂模型时,Unity编辑器会卡住,无法进行其他工作。
-
资源膨胀
:FBX等格式为了兼容性,包含大量冗余数据。Unity导入后,还会生成对应的
.meta文件和库文件,导致项目资产文件夹体积庞大。 - 灵活性差 :模型一旦导入,其缩放、材质球生成规则就被固定。如果想在运行时根据设备性能动态切换不同LOD(细节层次)的模型文件,或者动态下载更新模型,传统方式非常笨重。
- 平台依赖 :某些FBX的特性可能在不同版本的Unity或不同建模软件之间表现不一致,导致材质丢失、动画错乱等“玄学”问题。
2.2 基于glTFast的现代工作流
glTFast引入了一种“运行时加载”的范式。你的glTF模型文件(
.gltf
/
.glb
)不再必须放在
Assets
文件夹下。它们可以放在
StreamingAssets
(随包发布)、
PersistentDataPath
(设备可写目录),甚至是从远程服务器直接下载的字节流。
新工作流的优势:
- 非阻塞,异步加载 :加载过程在后台线程进行,不会冻结主线程,游戏或应用可以保持流畅响应,并显示加载进度。
-
资源精简
:glTF文件本身更小。由于是运行时解析,不会在
Library文件夹生成庞大的中间数据,项目结构更清爽。 - 动态化与热更新 :模型可以作为数据资源进行管理,轻松实现动态下载、替换和更新,无需重新打包App。
- 标准统一 :glTF是开放标准,避免了专有格式的兼容性问题。从Blender导出的glTF和在线的模型库(如Sketchfab)下载的glTF,行为基本一致。
设计决策点: 在你的项目中,你需要决定哪些模型使用传统编辑时导入(FBX),哪些使用运行时加载(glTF)。一个实用的混合策略是:
-
核心、静态场景资产
:如主角模型、主要建筑。这些模型使用频率高,对加载速度要求极致,且不太变化。可以
在编辑时通过glTFast的“预转换”功能
,将其转换为Unity原生的
GameObject预制体,享受运行时零加载开销的好处。 - 动态、可下载内容 :如用户自定义的Avatar、商城道具、大型场景中的次要物件。这些完美契合glTFast的运行时加载模式。
- 需要复杂Unity特定功能 :如与NavMesh系统深度集成、使用复杂的Shader Graph材质且需要大量编辑时调整的模型。可能暂时仍需FBX,但未来glTFast的支持也在不断完善。
注意 :glTFast并非要完全取代FBX。FBX在动画重定向、特定DCC工具链集成上仍有优势。glTFast是为你提供了另一个更高效、更现代的选项,尤其是在网络传输和运行时动态化场景下。
3. 环境配置与项目初始化
理论讲完,我们开始动手。第一步是把glTFast集成到你的Unity项目中。
3.1 安装glTFast
官方推荐并通过Unity的Package Manager进行安装,这是最安全、最便于管理版本的方式。
-
在Unity编辑器中,打开
Window > Package Manager。 -
点击左上角的
+号,选择Add package from git URL...。 -
输入glTFast的Git仓库地址:
https://github.com/atteneder/glTFast.git。你也可以使用更稳定的版本标签,例如https://github.com/atteneder/glTFast.git#v5.0.0(请查阅GitHub发布页获取最新版本号)。 -
点击
Add。Unity会开始下载和解析包。
为什么不用Asset Store版本或直接拖DLL? 通过Package Manager安装,可以轻松更新、查看文档,并且依赖关系(如Newtonsoft Json)会被自动管理。直接复制代码或DLL容易导致版本冲突和后续更新困难。
3.2 关键依赖项检查
glTFast依赖于一些其他包来实现特定功能。安装后,请确保以下包也已就位(通常Package Manager会自动处理):
-
Newtonsoft Json:用于解析JSON格式的.gltf文件。Unity 2020及以上版本通常已内置。 -
Unity Mathematics和Burst:用于高性能数学计算和并行作业。这是glTFast“快”的核心保障。确保Burst包已安装且处于启用状态(Jobs > Burst > Enable Compilation)。 -
Unity Mesh API(可选):用于更高效的网格数据操作。
安装完成后,你会在项目的
Packages
目录下看到
com.atteneder.gltfast
。此时,你的代码中已经可以使用
GLTFast
命名空间下的所有类了。
3.3 基础场景搭建
为了测试,我们创建一个最简单的加载场景:
- 新建一个空场景。
-
在Hierarchy中创建一个空
GameObject,命名为“GltfLoader”。 -
为其添加一个脚本组件,我们暂时命名为
SimpleGltfLoader.cs。
至此,glTFast的环境就配置好了。接下来,我们将进入最核心的加载环节。
4. 核心加载功能全解析
这是glTFast的精华所在。我们将从最简单的同步加载开始,逐步深入到生产环境必备的异步加载、实例化管理和自定义材质。
4.1 同步加载:最简单直接的入门
同步加载会阻塞主线程直到模型加载完成,仅适用于极小的模型或快速原型测试,不推荐用于正式项目。
using UnityEngine;
using GLTFast;
public class SimpleGltfLoader : MonoBehaviour
{
public string gltfFilePath; // 例如: "Assets/StreamingAssets/model.glb"
void Start()
{
LoadModelSync();
}
void LoadModelSync()
{
var gltf = new GltfImport();
// 同步加载并实例化
bool success = gltf.Load(gltfFilePath).Result;
if(success)
{
success = gltf.InstantiateMainScene(transform);
}
if(!success)
{
Debug.LogError("Failed to load or instantiate GLTF model.");
}
}
}
关键点解析:
-
GltfImport是核心类,负责加载和解析glTF数据。 -
Load方法接受文件路径(或byte[]数组、Uri),返回一个Task<bool>。这里用.Result强制同步等待,是造成阻塞的原因。 -
InstantiateMainScene将加载的模型实例化为场景中的GameObject,并作为当前脚本所在GameObject的子物体。
4.2 异步加载:生产环境的标配
99%的情况,你都应该使用异步加载。它不会卡住游戏,并且可以方便地实现加载进度提示。
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using GLTFast;
public class AsyncGltfLoader : MonoBehaviour
{
public string gltfUrl; // 可以是本地路径或网络URL
public Slider progressSlider; // 可选的UI进度条
public Text progressText;
async void Start()
{
await LoadModelAsync();
}
async Task LoadModelAsync()
{
var gltf = new GltfImport();
// 1. 创建加载设置(可选,但推荐)
var settings = new ImportSettings {
GenerateMipMaps = true, // 为纹理生成Mipmap
AnisotropicFilterLevel = 3, // 各向异性过滤等级
NodeNameMethod = NameImportMethod.OriginalUnique // 节点命名方式
};
// 2. 异步加载,并提供进度回调
var loadTask = gltf.Load(gltfUrl, settings);
while (!loadTask.IsCompleted)
{
// 更新UI进度
if (progressSlider != null)
{
progressSlider.value = gltf.LoadingProgress;
}
if (progressText != null)
{
progressText.text = $"Loading... {gltf.LoadingProgress:P0}";
}
await Task.Yield(); // 等待一帧,避免死循环
}
// 3. 检查加载结果
bool success = await loadTask;
if (!success)
{
Debug.LogError("Loading glTF failed!");
// 可以尝试获取具体错误信息
// var logs = gltf.LogMessages;
return;
}
// 4. 异步实例化
var instantiateTask = gltf.InstantiateMainScene(transform);
success = await instantiateTask;
if (!success)
{
Debug.LogError("Instantiating glTF failed!");
}
else
{
Debug.Log("GLTF model loaded and instantiated successfully!");
}
}
}
为什么这么设计?
-
async/await是C#处理异步的现代语法,清晰易读。 -
LoadingProgress属性提供了0-1的加载进度,便于制作加载界面。 -
ImportSettings让你能精细控制导入行为,比如是否生成Mipmaps(对性能影响很大),这在移动端尤其重要。 -
分离
Load和Instantiate两步,让你可以在加载完成后,选择在合适的时机(如进入特定区域时)再实例化模型,实现更精细的内存管理。
4.3 实例化管理与材质定制
直接实例化出来的模型,其材质是glTFast根据glTF文件内的PBR信息自动生成的Standard Shader材质。但你可能需要自定义Shader,或者批量修改材质属性。
async Task LoadAndCustomizeModelAsync()
{
var gltf = new GltfImport();
bool loaded = await gltf.Load(gltfFilePath);
if (!loaded) return;
// 方案1:在实例化后遍历修改
var instantiateTask = gltf.InstantiateMainScene(transform);
bool instantiated = await instantiateTask;
if (instantiated)
{
Renderer[] renderers = GetComponentsInChildren<Renderer>();
foreach (var renderer in renderers)
{
// 替换为你的自定义材质
// renderer.material = myCustomMaterial;
// 或者修改原有材质的某些属性
foreach (var mat in renderer.materials)
{
mat.SetFloat("_Metallic", 0.5f);
mat.SetColor("_EmissionColor", Color.blue);
}
}
}
// 方案2:使用自定义实例化器(更高级)
var customInstantiator = new MyCustomInstantiator(transform);
await gltf.InstantiateMainScene(customInstantiator);
}
// 自定义实例化器,继承自glTFast提供的基类
public class MyCustomInstantiator : GameObjectInstantiator
{
public MyCustomInstantiator(Transform parent) : base(parent) { }
// 重写材质创建方法
public override Material CreateMaterial(UnityEngine.Material source, GLTFast.Schema.Material gltfMaterial)
{
// 根据glTF材质信息,返回你自己的材质
if (gltfMaterial.pbrMetallicRoughness?.baseColorTexture != null)
{
return new Material(Shader.Find("MyCustom/PBRShader"));
}
else
{
return base.CreateMaterial(source, gltfMaterial); // 使用默认
}
}
}
实操心得:
- 方案1(事后修改)简单直接,适合小范围调整。
-
方案2(自定义实例化器)功能强大,可以在模型创建的“源头”就控制材质、GameObject的生成逻辑,适合需要深度定制的大型项目。例如,你可以根据glTF材质中的
extras自定义字段,来决定使用哪套Shader。
5. 高级功能与性能优化
当基础加载满足需求后,为了应对更复杂的项目(尤其是移动端或WebGL),我们必须关注性能和高级特性。
5.1 资源卸载与内存管理
glTFast加载的模型,其纹理、网格数据会占用内存。动态加载的模型必须能被正确卸载,否则会导致内存泄漏。
public class ManagedGltfLoader : MonoBehaviour
{
private GltfImport _gltfInstance;
private GameObject _instantiatedModel;
async Task LoadModel()
{
if (_gltfInstance != null) return; // 防止重复加载
_gltfInstance = new GltfImport();
await _gltfInstance.Load(modelUrl);
var instantiator = new GameObjectInstantiator(transform);
await _gltfInstance.InstantiateMainScene(instantiator);
_instantiatedModel = transform.GetChild(transform.childCount - 1)?.gameObject;
}
void UnloadModel()
{
// 1. 销毁实例化的GameObject
if (_instantiatedModel != null)
{
Destroy(_instantiatedModel);
_instantiatedModel = null;
}
// 2. 释放GltfImport持有的资源(纹理、网格等)
if (_gltfInstance != null)
{
_gltfInstance.Dispose();
_gltfInstance = null;
}
// 3. 可选:手动触发垃圾回收(谨慎使用)
// Resources.UnloadUnusedAssets();
// System.GC.Collect();
}
void OnDestroy()
{
UnloadModel();
}
}
关键点:
Dispose()
方法至关重要。它释放了
GltfImport
对象内部持有的所有Unity引擎对象(Texture2D, Mesh等)。仅仅销毁GameObject是不够的,那些Asset还留在内存中。
5.2 加载性能深度调优
-
使用GLB格式而非GLTF+分离资源
:
.glb是二进制格式,将所有数据(JSON、纹理、缓冲)打包进一个文件。单文件加载比.gltf(JSON文件)外加多个.bin和图像文件的网络请求快得多,也更容易管理。 -
纹理优化
:
-
压缩格式
:确保glTF中的纹理使用了合适的压缩格式(如KTX2/Basis Universal)。glTFast支持这些格式,它们能显著减少纹理内存和加载时间。你可以使用工具如
glTF-Transform对glTF文件进行优化和纹理转码。 -
Mipmaps
:在
ImportSettings中开启GenerateMipMaps,这对渲染性能,特别是远处物体的渲染,有巨大好处。 - 分辨率 :对于非重要模型,可以考虑在导出或后期处理时降低纹理分辨率。
-
压缩格式
:确保glTF中的纹理使用了合适的压缩格式(如KTX2/Basis Universal)。glTFast支持这些格式,它们能显著减少纹理内存和加载时间。你可以使用工具如
-
网格优化
:
-
Draco压缩
:glTF支持Draco几何体压缩。如果模型使用了Draco压缩,glTFast可以解码它,这能极大减少网络传输的网格数据量。确保你的模型导出时启用了Draco压缩(Blender等工具支持),并且glTFast的Draco依赖已正确安装(
DracoUnity包)。
-
Draco压缩
:glTF支持Draco几何体压缩。如果模型使用了Draco压缩,glTFast可以解码它,这能极大减少网络传输的网格数据量。确保你的模型导出时启用了Draco压缩(Blender等工具支持),并且glTFast的Draco依赖已正确安装(
-
利用Addressables或AssetBundles
:对于需要打包发布的模型,可以将glb文件打包进Addressables或AssetBundle。glTFast可以直接加载来自
AsyncOperationHandle的字节流,从而与Unity成熟的资产管理系统无缝集成。
5.3 动画与相机场景加载
glTF文件可以包含动画和预定义的相机。glTFast也能很好地支持。
async Task LoadModelWithAnimation()
{
var gltf = new GltfImport();
await gltf.Load(glbPath);
// 实例化
var instantiator = new GameObjectInstantiator(transform);
await gltf.InstantiateMainScene(instantiator);
// 获取动画片段
var animationClips = gltf.GetAnimationClips();
if (animationClips != null && animationClips.Length > 0)
{
var animator = GetComponentInChildren<Animator>();
if (animator != null)
{
var runtimeController = animator.runtimeAnimatorController as UnityEditor.Animations.AnimatorController;
// 将AnimationClip添加到Animator Controller中...
// 注意:运行时动态管理AnimationClip需要更复杂的逻辑,通常建议在编辑时处理。
}
else
{
// 简单播放:使用Animation组件(如果模型带Skinning)
var animation = GetComponentInChildren<Animation>();
if (animation != null)
{
animation.clip = animationClips[0];
animation.Play();
}
}
}
// 获取相机信息(glTF中的相机是定义,需要手动创建Unity Camera)
var cameras = gltf.GetCameras();
// ... 根据camera数据创建Unity Camera GameObject
}
注意事项
:glTF的动画系统与Unity的Mecanim(Animator)系统并非直接对应。glTFast提取出的是
AnimationClip
,你需要自己将其配置到角色的
Animator Controller
中。对于复杂的角色动画,目前更成熟的流程可能还是FBX。但对于简单的机械动画、变形动画,glTFast完全够用。
6. 常见问题排查与实战技巧
即使按照教程操作,在实际项目中你还是会遇到各种坑。这里记录了我踩过的一些,以及解决方法。
6.1 模型加载失败,一片粉红(Missing Material)
现象 :模型加载出来了,但全部或部分显示为亮粉色(Unity默认的错误材质色)。
排查步骤:
- 检查控制台错误 :首先查看Unity Console,看是否有明确的Shader编译错误或纹理加载错误。
-
检查纹理路径
:如果你加载的是
.gltf+分离资源,确保.bin缓冲数据文件和纹理图片(如.png,.jpg)与.gltf文件在 相对路径 上是正确的。glTF文件内记录的是相对路径。最简单的方法是将所有相关文件放在同一目录下。 -
检查Shader兼容性
:glTFast默认使用Unity的Standard Shader或URP/HDRP的Lit Shader来创建PBR材质。确保你的项目渲染管线(Built-in, URP, HDRP)支持这些Shader。在URP项目中,需要安装
glTFast URP或HDRP扩展包,以提供正确的Shader。 -
检查纹理格式
:某些特殊的纹理格式(如
WEBP)可能需要Unity额外的支持。尝试将纹理转换为PNG或JPEG格式。
6.2 加载缓慢,甚至卡死
现象 :调用加载函数后,游戏帧率骤降或完全无响应。
排查步骤:
-
确认是同步还是异步
:首先检查代码,你是否错误地使用了
.Result或.Wait()进行了同步调用?务必使用async/await。 -
检查模型大小和复杂度
:一个包含数百万多边形和4K纹理的模型,在任何平台上加载都会慢。使用建模软件或glTF优化工具(如
glTF-Transform)对模型进行减面、压缩纹理、合并网格等优化。 -
检查是否启用了Draco解码
:如果模型用Draco压缩,但项目中没有正确导入
DracoUnity包,glTFast会回退到软件解码,可能非常慢。确保DracoUnity包已安装。 -
使用性能分析器
:打开Unity Profiler (
Window > Analysis > Profiler),在加载时查看主线程和Job线程的占用。如果主线程阻塞,说明有代码在同步等待。如果Job线程繁忙,说明解码任务繁重,考虑优化模型。
6.3 在WebGL或移动端上崩溃
现象 :在编辑器里运行正常,发布到WebGL或Android/iOS后崩溃或模型不显示。
排查步骤:
-
文件路径问题
:在WebGL或移动平台,文件系统路径与编辑器不同。
绝对不要使用
Application.dataPath。对于随包发布的文件,使用Application.streamingAssetsPath;对于可读写目录,使用Application.persistentDataPath。对于网络加载,确保URL正确且服务器CORS设置允许跨域请求(WebGL)。 - 内存不足 :移动端和WebGL内存限制严格。使用Profiler的内存模块检查加载前后的内存占用。确保纹理格式是压缩的(如ASTC, ETC2),并开启了Mipmaps。考虑实现模型的按需加载和卸载。
-
Shader变体缺失
:在构建项目时,Unity可能会剥离未使用的Shader变体。确保你项目中的所有PBR材质所使用的Shader变体都被正确包含在构建中。可以在
Project Settings > Graphics的Shader Stripping设置中调整,或者确保场景中有一个使用该材质的对象。 -
多线程限制
:WebGL不支持真正的多线程,因此
Unity Job System和Burst在WebGL上的加速效果有限。这是平台限制,只能通过进一步优化模型数据来缓解。
6.4 从其他格式(如FBX, OBJ)转换为glTF
你可能有大量现存FBX资产。要利用glTFast,需要转换它们。
推荐工具链:
-
Blender
:最强大的免费选择。安装官方glTF导出插件(2.80+版本已内置)。在Blender中导入FBX,然后选择
File > Export > glTF 2.0。在导出设置中,务必勾选关键选项:-
Export Format: 选择.glb(单一文件)以获得最佳加载性能。 -
Compression: 勾选Draco进行网格压缩。 -
Images: 选择Automatic或转换为Basis Universal格式(需额外设置)。
-
-
glTF-Transform (命令行)
:这是一个Node.js工具,非常适合批量处理和自动化。
# 安装 npm install -g @gltf-transform/cli # 基本转换 (FBX需先通过其他工具如FBX2glTF转换) gltf-transform cp input.fbx output.glb # 强大的优化命令(压缩纹理、网格、合并材质等) gltf-transform optimize input.glb output.glb --texture-compress webp -
在线转换器
:如
https://products.aspose.com/3d/zh/conversion/fbx-to-gltf/或AnyConv.com,适合偶尔转换单个文件。
转换后检查
:转换后,务必在简单的glTF查看器(如
https://gltf-viewer.donmccurdy.com/
)或Unity中用glTFast测试一下,确保材质、动画和网格结构正确无误。
7. 编辑时预转换:兼顾性能与工作流
对于确定会频繁使用、且不需要动态更新的核心模型,我们可以利用glTFast的“编辑时导入”功能,将其转换为原生的Unity Prefab,从而获得最佳的运行时性能(零加载开销)和便利的编辑时调整能力。
7.1 使用Gltf Asset Importer
glTFast提供了一个
GltfAsset
组件,它可以在编辑模式下就执行加载和实例化,并将结果保存为Prefab。
-
在Project视图中,右键选择
Import New Asset,但这里我们直接拖拽.glb或.gltf文件到Assets文件夹。 - Unity会将其识别为一种自定义资源。 但实际上,glTFast并没有创建一个真正的“Asset” 。更常见的做法是:
- 在场景中创建一个空GameObject。
-
为其添加
GltfAsset组件。 -
在
GltfAsset组件的Url字段中,指定你的glTF文件(可以是Assets/下的相对路径)。 -
勾选
Load On Start(如果希望在运行时自动加载)。 -
关键步骤
:在编辑模式下,点击
GltfAsset组件上的Instantiate按钮。glTFast会立即加载该文件,并在该GameObject下创建出所有模型节点。 - 现在,你可以像编辑任何其他Unity对象一样,调整这个模型的材质、挂载脚本等。
-
最后,将这个包含
GltfAsset组件和已实例化模型的GameObject,拖回Project视图, 创建一个Prefab 。
这样,你就得到了一个完全由Unity原生GameObject和Component构成的Prefab。在运行时,这个Prefab的实例化速度就和普通Prefab一样快,因为不需要再解析glTF文件了。
GltfAsset
组件在运行时要么不加载(如果你取消了
Load On Start
),要么加载速度极快(因为数据已预转换)。
7.2 编写自定义编辑器脚本进行批量预转换
对于大量模型,手动操作不现实。我们可以编写一个简单的Editor脚本来自动化这个过程。
using UnityEditor;
using UnityEngine;
using System.IO;
using GLTFast.Editor; // 注意:这是Editor命名空间
public class GltfBatchPrefabCreator : EditorWindow
{
[MenuItem("Tools/glTFast/批量创建Prefab")]
static void Init()
{
GetWindow<GltfBatchPrefabCreator>("glTF to Prefab");
}
public string sourceDirectory = "Assets/Models/GLTF";
public string targetPrefabDirectory = "Assets/Prefabs/Converted";
void OnGUI()
{
GUILayout.Label("批量转换设置", EditorStyles.boldLabel);
sourceDirectory = EditorGUILayout.TextField("GLTF源目录", sourceDirectory);
targetPrefabDirectory = EditorGUILayout.TextField("Prefab目标目录", targetPrefabDirectory);
if (GUILayout.Button("开始转换"))
{
ConvertAllGltfInDirectory();
}
}
void ConvertAllGltfInDirectory()
{
if (!Directory.Exists(sourceDirectory))
{
Debug.LogError($"源目录不存在: {sourceDirectory}");
return;
}
if (!Directory.Exists(targetPrefabDirectory))
{
Directory.CreateDirectory(targetPrefabDirectory);
}
string[] gltfFiles = Directory.GetFiles(sourceDirectory, "*.gltf", SearchOption.AllDirectories);
string[] glbFiles = Directory.GetFiles(sourceDirectory, "*.glb", SearchOption.AllDirectories);
string[] allFiles = new string[gltfFiles.Length + glbFiles.Length];
gltfFiles.CopyTo(allFiles, 0);
glbFiles.CopyTo(allFiles, gltfFiles.Length);
foreach (var filePath in allFiles)
{
CreatePrefabFromGltf(filePath);
}
AssetDatabase.Refresh();
Debug.Log($"转换完成,共处理 {allFiles.Length} 个文件。");
}
void CreatePrefabFromGltf(string gltfPath)
{
// 1. 创建父级GameObject并添加GltfAsset
GameObject rootGo = new GameObject(Path.GetFileNameWithoutExtension(gltfPath));
var gltfAsset = rootGo.AddComponent<GltfAsset>();
gltfAsset.url = "file://" + Path.GetFullPath(gltfPath); // 使用绝对路径
// 2. 在编辑模式下同步加载并实例化(这里简化,实际需处理异步)
// 注意:GltfAsset.Instantiate() 可能在编辑模式下有同步调用的方式,或需使用`EditorUtility.DisplayProgressBar`和轮询。
// 此处仅为思路,生产代码需更健壮,可能需调用内部方法或使用反射。
Debug.LogWarning("此示例仅展示流程,编辑模式下同步Instantiate需要更复杂的实现。");
// 更实用的做法可能是:调用一个模拟加载的进程,或者使用glTFast的`GltfImporter`在编辑器中直接导入。
// 3. 假设实例化完成,保存为Prefab
string relativePath = gltfPath.Substring(gltfPath.IndexOf("Assets"));
string prefabPath = Path.Combine(targetPrefabDirectory, Path.GetFileNameWithoutExtension(relativePath) + ".prefab");
PrefabUtility.SaveAsPrefabAsset(rootGo, prefabPath);
// 4. 清理临时GameObject
DestroyImmediate(rootGo);
}
}
重要提示
:上面的批量转换脚本是一个
概念演示
。在编辑器中同步执行
GltfAsset
的加载和实例化需要更精细的处理,因为其底层是异步的。一个更可靠的方法是深入研究glTFast的编辑器代码(
GltfImporter
),或者考虑在运行时进行首次加载并保存为Prefab(适用于开发期资源构建管线)。这个脚本旨在为你提供一个自动化思路的起点。
通过编辑时预转换,你巧妙地将glTF的“高效传输”优势与Unity原生Prefab的“高性能运行时”优势结合了起来,为不同类型的资产选择了最合适的工作流。

488

被折叠的 条评论
为什么被折叠?



