atteneder/glTFast

Shader variants for RPM avatar missing when loaded in addressable scene

Opened this issue · 2 comments

I’ve encountered an issue with shader variants when loading GLTF objects into an addressable scene: some materials look wrong (no transparency, wrong lighting...).
After investigating, I discovered that the necessary shader variant was missing, causing Unity to apply a fallback shader. To troubleshoot, I enabled strictShaderVariantMatching in the Project Settings/Player, which resulted in numerous ‘Shader Shader Graphs/glTF-pbrMetallicRoughness, subshader 0, pass 0, stage pixel: variant SHADOWS_SHADOWMASK _ADDITIONAL_LIGHTS _MAIN_LIGHT_SHADOWS_CASCADE _SHADOWS_SOFT _SURFACE_TYPE_TRANSPARENT not found.’ errors.

I confirmed that glTFastShaderVariantsURP.shadervariants is included in the PreloadedShaders array, so I was puzzled by this issue. Loading an object into a built-in scene worked as expected. However, loading the same object into a scene loaded from Unity Addressables resulted in missing shader variants.

I’ve created a test project to demonstrate this issue: https://github.com/dnnkeeper/UnityRPMLoadingTest

After discussion in forum I managed to pin down that ShaderGraphMaterialGenerator is unable to find suitable shader using Shader.Find method because shader is loaded with the Addressable system.

I replaced Shader.Find method with this code, and my issue was resolved after I added glTF-pbrMetallicRoughness.shadergraph as Shader Graphs/glTF-pbrMetallicRoughness to addressable group

        protected static Shader FindShader(string shaderName, ICodeLogger logger)
        {
            var shaderLoading = Addressables.LoadAssetAsync<Shader>(shaderName);
            Shader shader = shaderLoading.WaitForCompletion();

            if (shader != null)
            {
                return shader;
            }

            shader = Shader.Find(shaderName);
            if (shader == null)
            {
                logger?.Error(LogCode.ShaderMissing, shaderName);
            }
            return shader;
        }

It seems that GLTF package needs to reference the Addressable system and use this loading method when this system is present.

@BorisDex Thanks for reporting and putting in the effort to pin it down!

I think this would be a meaningful addition, given it's wrapped in a version define and documented properly.

After giving it some more thought we concluded that it's probably a better solution to create an injection point for FindShader. Users are then able to implement their own shader lookup solution without introducing fixed heuristics for Addressables.

I cannot offer a timeline yet.