atteneder / glTFast

Efficient glTF 3D import / export package for Unity
Other
1.24k stars 251 forks source link

Freeze frame during runtime loading in Android #686

Open ChocolateRacoon opened 7 months ago

ChocolateRacoon commented 7 months ago

Hello,

Could you please tell me if there is any way to get rid of freeze frames?

As far as I understand, the use of IDeferAgent is intended specifically for loading multiple models and increases the frame rate by queuing. Freeze frames occur even when loading one model.

Files

Model (glb): https://sketchfab.com/3d-models/warcraft-3-alliance-footmanfanmade-201452e568064aedadccfafb668ef6a5

Script

using System.IO;
using System.Threading.Tasks;
using GLTFast;
using UnityEngine;

namespace GLTFLoading
{
    public class GltfLoader : MonoBehaviour
    {
        [SerializeField] private string fileName = "Footman_RIG.glb";
        [SerializeField] [Range(.01f, 5f)] private float frameBudget = 0.1f;
        private GltfImport _gltf;

        async void Start()
        {
            fileName = Path.Combine(Application.persistentDataPath, fileName);
            Debug.Log($"Path for file = {fileName}");
            await LoadGltfBinaryFromMemory(transform);
        }

        private async Task<bool> LoadGltfBinaryFromMemory(Transform parent)
        {
            TimeBudgetPerFrameDeferAgent deferAgent = parent.gameObject.AddComponent<TimeBudgetPerFrameDeferAgent>();
            deferAgent.SetFrameBudget(frameBudget);
            GltfImport.SetDefaultDeferAgent(deferAgent);
            ImportSettings importSettings = new()
            {
                AnimationMethod = AnimationMethod.Mecanim,
                AnisotropicFilterLevel = 3,
                GenerateMipMaps = true
            };
            var success = await _gltf.Load(fileName, importSettings); // Frame freeze is here
            if (success)
                return await _gltf.InstantiateMainSceneAsync(parent);

            return success;
        }

    }
}

To Reproduce

Steps to reproduce the behavior:

  1. Create URP unity project
  2. Create scene
  3. Add the script (you can see it above) to scene
  4. Build the application
  5. Install the app on the device, download the model and place the model in the Persistence Data Path
  6. Open the app
  7. See frame freeze

Expected behavior

We get a frame freeze

Video

https://github.com/atteneder/glTFast/assets/108283613/d4f69fd1-83c9-4d52-a441-f48767b895af

Additional data

Device

Optional

As I understand, parameter GenerateMipMaps = true

is very hard for the app.

Setting this parameter to False reduced the peaks (according to the profiler data), but it still doesn't look good. Below I present the profiler data when loading GLTF via gltf fast

GenerateMipMaps = true

image

GenerateMipMaps = false

image

atteneder commented 1 month ago

Hi,

You've been using TimeBudgetPerFrameDeferAgent correctly, but there might be a misunderstanding what it actually does.

Whenever the glTF loading procedure reaches certain milestones the defer agent can decide if the process continues within this frame or "call it a frame" and defer further processing to the next frame. Unfortunately the procedure cannot be stopped at any arbitrary time, so even if you set a low enough time budget a bigger chunk of the process might stall your rendering, especially on weaker hardware.

After I had a glimpse on your model I noticed you use many, quite large PNG textures. Those are likely the problem, as the decoding happens on the main thread (Unity API limitation).

I recommend encoding all textures as KTX Basis Universal files and use KTX for Unity to load them (supported by glTFast). Those are transcoded in a thread and usually load with less friction.

hth