You drag a GLB model into a Unity project, hit Play, and it looks right — base color, normal maps, roughness all correct. You cut a build for Windows or Android, launch the player, and the same model is a flat, featureless pink blob. Nothing in your import settings changed, and the import itself is fine. What broke is Unity's build pipeline: it strips shader variants it can't prove are in use, and glTFast's generated materials point at a shader the stripper doesn't recognize as "used." The fix takes about two minutes once you know where to look — Project Settings > Graphics > Always Included Shaders — but the two minutes only happen after you stop blaming the import.
Why glTFast's shader disappears only in builds
![]()
glTFast doesn't reuse Unity's Standard or URP Lit shaders. It ships its own material generators — a base `ShaderGraphMaterialGenerator`, plus a `UniversalRPMaterialGenerator` and a `HighDefinitionRPMaterialGenerator` — and each one assigns a shader named `glTF-pbrMetallicRoughness` (with a `-Clearcoat` variant for URP clearcoat surfaces) or `glTF-unlit` for anything flagged with `KHR_materials_unlit`. None of those shaders show up anywhere in your scene files the way a hand-assigned material would, because glTFast wires them up in code at import or load time. That's exactly the pattern Unity's build-time shader stripper is bad at: it scans scenes and materials for static references, and a shader assigned dynamically doesn't leave one.
It's a well-documented failure mode, not a one-off bug. glTFast's own tracker has multiple open reports of the same shape: issue #368, "Shader is missing in build," issue #407, URP shader compile errors specifically on WebGL, and issue #408, a "can't load shader" error on import in older Unity versions. Issues #713 and #714 cover Draco-compressed GLBs loaded from remote storage at runtime, coming back pink specifically on mobile. Issue #725 states the pattern most cleanly: correct in the Windows Player, solid pink on Android and Quest — because IL2CPP builds strip more aggressively than the Mono editor does.
Which shader you need
| Source material | glTFast shader | Add it when |
|---|---|---|
| Standard glTF metallic-roughness | `glTF-pbrMetallicRoughness` | Every GLB import — this is the default |
| `KHR_materials_unlit` | `glTF-unlit` | Any material flagged unlit in the source file |
| URP clearcoat surfaces | `glTF-pbrMetallicRoughness-Clearcoat` | URP projects with clearcoat-tagged materials |
| Legacy spec-gloss exports | `glTF-pbrSpecularGlossiness` | Older glTF 1.x-style tooling, still shows up in some exporters |
Fix it with Always Included Shaders
![]()
First, confirm it's actually a stripping problem and not a broken import: play the scene in the Editor's Game view. If the model is correct there and only turns pink in a Development Build or a device build, you're chasing stripping — re-importing the asset changes nothing, because the import was never the problem.
- Open Edit > Project Settings > Graphics.
- Scroll to the Always Included Shaders list and increase its Size by one for each shader you need from the table above.
- In the Project window, search `glTF-pbrMetallicRoughness` with the search bar's Type filter set to Shader, and drag the result into the new slot. Repeat for `glTF-unlit` if any source GLB uses `KHR_materials_unlit`, and for the Clearcoat variant if you're on URP with clearcoat materials.
- Rebuild and test on the actual target platform, not just the editor's Development Build for desktop — Quest and Android strip harder than Windows does.
Always Included Shaders guarantees the shader ships, but not every keyword combination glTFast might request at runtime — normal mapping on, normal mapping off, emissive on, and so on are separate variants. For GLBs loaded at runtime rather than imported as editor assets — a remote catalog fetch, for instance — warm a Shader Variant Collection on startup so those specific combinations are compiled before a model ever loads:
```csharp
[SerializeField] ShaderVariantCollection gltfShaderVariants;
void Awake()
{
// Compiles every variant baked into the collection
// before the first glTFast model loads at runtime.
gltfShaderVariants.WarmUp();
}
```
Build that collection by playing through a scene that touches every material type you ship — metallic-roughness, unlit, clearcoat — with Graphics > Shader Loading Log recording enabled, then save the tracked variants to an asset. A collection built from a scene that only exercises one material type will warm that one type and leave the rest to strip.
If you're loading GLBs at runtime instead of importing them as editor assets, the same shaders need the same treatment, just triggered from your own load code instead of the AssetDatabase:
```csharp
var gltf = new GLTFast.GltfImport();
bool ok = await gltf.Load(uri);
if (ok) await gltf.InstantiateMainSceneAsync(transform);
// If ok is true but materials render pink, it's the build
// stripping the shader above, not this load path failing.
```
The gotchas
Still on the Built-in Render Pipeline? Confirm glTFast is actually generating Built-in-compatible materials before you chase a stripping ghost — Built-in shader graph support is optional in glTFast and behaves differently from the URP and HDRP material generators, so the fix here may not even apply to you.
Always Included Shaders adds a small amount to build size per entry. Four or five glTFast shaders won't move the needle; padding the list with shaders "just in case" will.
A Shader Variant Collection only captures the keyword combinations your test scene actually exercised. A material combination you didn't test — a new `KHR_materials_emissive_strength` value, say — can still come back pink until you add a case for it.
Test Draco-compressed runtime loads separately from editor-imported assets. Issues #713 and #714 both showed the same project passing for imported assets and failing for a remote Draco fetch, because the two code paths request materials at different times.
Every model in BitSoul3D's catalog ships as GLB, so this hits any of them the same way it hits your own assets. Glass Market Pavilion is a decent stress test since it mixes glass, metal, and standard metallic-roughness surfaces in one mesh — pull it into a test scene and confirm it survives an actual device build, not just Play mode, before you trust the fix on your own models.
If you've already dealt with Unity 6's GPU Resident Drawer ignoring imported GLB models or Unity's glTF shader breaking under HDRP ray tracing, this is the same underlying pattern: Unity's build and rendering tooling doesn't expect materials that get assigned in code instead of by hand. And if your build is crashing outright rather than just rendering pink, check that against Unity 6.3 LTS's own asset-import crash bug first — the two problems look similar from a bug report but have nothing to do with each other.
---
*This post is part of the Ultimate Guide to Free 3D Game Assets — BitSoul's complete reference for formats, texturing, rigging, optimization, and engine integration.*