Skip to content

Textures created and kept in memory even when no material generator use them #49

@anonymous2585

Description

@anonymous2585

Is your feature request related to a problem?

Yes
I have multiple glb files that use the same material with textures.
When I instantiate the models at runtime, I want them to share the same Unity material reference. To do so, I made a custom Material generator that cache the created materials and retrun the cache version when material already exists.

The problem is: GlftImport loads the textures (this is a useless heavy operation) and keep them in memory even when not used because the material generator returned the shared material for the second object.

Describe the solution you'd like
A way to generate Unity Textures only when really needed by the material generator.

Additional context

Using glTFast 6.18.0

2 sample glb sharing the same material: Models.zip

The material generator I use:

using GLTFast;
using GLTFast.Materials;
using System.Collections.Generic;
using UnityEngine;


/// <summary>
/// Generates the same materials as <see cref="BuiltInMaterialGenerator"/> but caches them and reuse them by name.
/// </summary>
public class BuiltInMaterialGeneratorWithCache : BuiltInMaterialGenerator
{
    private Dictionary<string, Material> materialsCache = new Dictionary<string, Material>();

    /// <inheritdoc />
    public override Material GenerateMaterial(
        GLTFast.Schema.MaterialBase gltfMaterial,
        IGltfReadable gltf,
        bool pointsSupport = false
    )
    {
        lock (materialsCache)
        {
            if (!materialsCache.TryGetValue(gltfMaterial.name, out var material))
            {
                material = base.GenerateMaterial(gltfMaterial, gltf, pointsSupport);
                materialsCache.Add(gltfMaterial.name, material);
            }
            return material;
        }
    }
}

The script calling GltfAsset using a single instance of this generator:

using GLTFast;
using UnityEngine;

public class InstantiateModels : MonoBehaviour
{
    /// <summary>
    /// Populate the urls in inspector with the path of the glb on your computer.
    /// </summary>
    [SerializeField] private string[] urls;

    private async void Start()
    {
        BuiltInMaterialGeneratorWithCache builtInMaterialGeneratorWithCache = new BuiltInMaterialGeneratorWithCache();
        foreach (string url in urls)
        {
            GameObject gltfGameObject = new GameObject();
            gltfGameObject.transform.SetParent(transform);
            GltfAsset gltfAsset = gltfGameObject.AddComponent<GltfAsset>();
            await gltfAsset.Load(url, materialGenerator: builtInMaterialGeneratorWithCache);
        }
    }
}

The memory result when loading the two models, the texture is present twice instead of once:
Image
The second texture (the selected one with red cross) is only referenced by the GltfImport in the GltfAsset component, it is unused in scene nor in any material. Also, it is not possible to Dispose() the GltfImport to free it, because it will also remove the mesh of the second object.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions