Unity高性能glTF模型加载指南:glTFast核心原理与工程实践

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和材质球等。这个过程我们称之为“编辑时导入”。

它的主要问题在于:

  1. 阻塞式操作 :导入大型或复杂模型时,Unity编辑器会卡住,无法进行其他工作。
  2. 资源膨胀 :FBX等格式为了兼容性,包含大量冗余数据。Unity导入后,还会生成对应的 .meta 文件和库文件,导致项目资产文件夹体积庞大。
  3. 灵活性差 :模型一旦导入,其缩放、材质球生成规则就被固定。如果想在运行时根据设备性能动态切换不同LOD(细节层次)的模型文件,或者动态下载更新模型,传统方式非常笨重。
  4. 平台依赖 :某些FBX的特性可能在不同版本的Unity或不同建模软件之间表现不一致,导致材质丢失、动画错乱等“玄学”问题。

2.2 基于glTFast的现代工作流

glTFast引入了一种“运行时加载”的范式。你的glTF模型文件( .gltf / .glb )不再必须放在 Assets 文件夹下。它们可以放在 StreamingAssets (随包发布)、 PersistentDataPath (设备可写目录),甚至是从远程服务器直接下载的字节流。

新工作流的优势:

  1. 非阻塞,异步加载 :加载过程在后台线程进行,不会冻结主线程,游戏或应用可以保持流畅响应,并显示加载进度。
  2. 资源精简 :glTF文件本身更小。由于是运行时解析,不会在 Library 文件夹生成庞大的中间数据,项目结构更清爽。
  3. 动态化与热更新 :模型可以作为数据资源进行管理,轻松实现动态下载、替换和更新,无需重新打包App。
  4. 标准统一 :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进行安装,这是最安全、最便于管理版本的方式。

  1. 在Unity编辑器中,打开 Window > Package Manager
  2. 点击左上角的 + 号,选择 Add package from git URL...
  3. 输入glTFast的Git仓库地址: https://github.com/atteneder/glTFast.git 。你也可以使用更稳定的版本标签,例如 https://github.com/atteneder/glTFast.git#v5.0.0 (请查阅GitHub发布页获取最新版本号)。
  4. 点击 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 基础场景搭建

为了测试,我们创建一个最简单的加载场景:

  1. 新建一个空场景。
  2. 在Hierarchy中创建一个空 GameObject ,命名为“GltfLoader”。
  3. 为其添加一个脚本组件,我们暂时命名为 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 加载性能深度调优

  1. 使用GLB格式而非GLTF+分离资源 .glb 是二进制格式,将所有数据(JSON、纹理、缓冲)打包进一个文件。单文件加载比 .gltf (JSON文件)外加多个 .bin 和图像文件的网络请求快得多,也更容易管理。
  2. 纹理优化
    • 压缩格式 :确保glTF中的纹理使用了合适的压缩格式(如KTX2/Basis Universal)。glTFast支持这些格式,它们能显著减少纹理内存和加载时间。你可以使用工具如 glTF-Transform 对glTF文件进行优化和纹理转码。
    • Mipmaps :在 ImportSettings 中开启 GenerateMipMaps ,这对渲染性能,特别是远处物体的渲染,有巨大好处。
    • 分辨率 :对于非重要模型,可以考虑在导出或后期处理时降低纹理分辨率。
  3. 网格优化
    • Draco压缩 :glTF支持Draco几何体压缩。如果模型使用了Draco压缩,glTFast可以解码它,这能极大减少网络传输的网格数据量。确保你的模型导出时启用了Draco压缩(Blender等工具支持),并且glTFast的Draco依赖已正确安装( DracoUnity 包)。
  4. 利用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默认的错误材质色)。

排查步骤:

  1. 检查控制台错误 :首先查看Unity Console,看是否有明确的Shader编译错误或纹理加载错误。
  2. 检查纹理路径 :如果你加载的是 .gltf +分离资源,确保 .bin 缓冲数据文件和纹理图片(如 .png , .jpg )与 .gltf 文件在 相对路径 上是正确的。glTF文件内记录的是相对路径。最简单的方法是将所有相关文件放在同一目录下。
  3. 检查Shader兼容性 :glTFast默认使用Unity的Standard Shader或URP/HDRP的Lit Shader来创建PBR材质。确保你的项目渲染管线(Built-in, URP, HDRP)支持这些Shader。在URP项目中,需要安装 glTFast URP HDRP 扩展包,以提供正确的Shader。
  4. 检查纹理格式 :某些特殊的纹理格式(如 WEBP )可能需要Unity额外的支持。尝试将纹理转换为PNG或JPEG格式。

6.2 加载缓慢,甚至卡死

现象 :调用加载函数后,游戏帧率骤降或完全无响应。

排查步骤:

  1. 确认是同步还是异步 :首先检查代码,你是否错误地使用了 .Result .Wait() 进行了同步调用?务必使用 async/await
  2. 检查模型大小和复杂度 :一个包含数百万多边形和4K纹理的模型,在任何平台上加载都会慢。使用建模软件或glTF优化工具(如 glTF-Transform )对模型进行减面、压缩纹理、合并网格等优化。
  3. 检查是否启用了Draco解码 :如果模型用Draco压缩,但项目中没有正确导入 DracoUnity 包,glTFast会回退到软件解码,可能非常慢。确保 DracoUnity 包已安装。
  4. 使用性能分析器 :打开Unity Profiler ( Window > Analysis > Profiler ),在加载时查看主线程和Job线程的占用。如果主线程阻塞,说明有代码在同步等待。如果Job线程繁忙,说明解码任务繁重,考虑优化模型。

6.3 在WebGL或移动端上崩溃

现象 :在编辑器里运行正常,发布到WebGL或Android/iOS后崩溃或模型不显示。

排查步骤:

  1. 文件路径问题 :在WebGL或移动平台,文件系统路径与编辑器不同。 绝对不要使用 Application.dataPath 。对于随包发布的文件,使用 Application.streamingAssetsPath ;对于可读写目录,使用 Application.persistentDataPath 。对于网络加载,确保URL正确且服务器CORS设置允许跨域请求(WebGL)。
  2. 内存不足 :移动端和WebGL内存限制严格。使用Profiler的内存模块检查加载前后的内存占用。确保纹理格式是压缩的(如ASTC, ETC2),并开启了Mipmaps。考虑实现模型的按需加载和卸载。
  3. Shader变体缺失 :在构建项目时,Unity可能会剥离未使用的Shader变体。确保你项目中的所有PBR材质所使用的Shader变体都被正确包含在构建中。可以在 Project Settings > Graphics 的Shader Stripping设置中调整,或者确保场景中有一个使用该材质的对象。
  4. 多线程限制 :WebGL不支持真正的多线程,因此 Unity Job System Burst 在WebGL上的加速效果有限。这是平台限制,只能通过进一步优化模型数据来缓解。

6.4 从其他格式(如FBX, OBJ)转换为glTF

你可能有大量现存FBX资产。要利用glTFast,需要转换它们。

推荐工具链:

  1. Blender :最强大的免费选择。安装官方glTF导出插件(2.80+版本已内置)。在Blender中导入FBX,然后选择 File > Export > glTF 2.0 。在导出设置中,务必勾选关键选项:
    • Export Format : 选择 .glb (单一文件)以获得最佳加载性能。
    • Compression : 勾选 Draco 进行网格压缩。
    • Images : 选择 Automatic 或转换为 Basis Universal 格式(需额外设置)。
  2. 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
    
  3. 在线转换器 :如 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。

  1. 在Project视图中,右键选择 Import New Asset ,但这里我们直接拖拽 .glb .gltf 文件到 Assets 文件夹。
  2. Unity会将其识别为一种自定义资源。 但实际上,glTFast并没有创建一个真正的“Asset” 。更常见的做法是:
  3. 在场景中创建一个空GameObject。
  4. 为其添加 GltfAsset 组件。
  5. GltfAsset 组件的 Url 字段中,指定你的glTF文件(可以是 Assets/ 下的相对路径)。
  6. 勾选 Load On Start (如果希望在运行时自动加载)。
  7. 关键步骤 :在编辑模式下,点击 GltfAsset 组件上的 Instantiate 按钮。glTFast会立即加载该文件,并在该GameObject下创建出所有模型节点。
  8. 现在,你可以像编辑任何其他Unity对象一样,调整这个模型的材质、挂载脚本等。
  9. 最后,将这个包含 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的“高性能运行时”优势结合了起来,为不同类型的资产选择了最合适的工作流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值