Import a GLB built on a standard glTF pipeline into Unity HDRP, plug its texture into the Lit shader's Mask Map slot, and the model turns to chrome. Wood reads as brushed steel, cloth goes wet-looking, and the ambient occlusion baked into the texture disappears entirely. The cause is a channel mismatch, not a broken file: glTF's ORM texture and Unity's HDRP Mask Map both pack metallic, occlusion, and roughness into one RGBA image, but in different channels. glTF puts occlusion in red, roughness in green, metallic in blue. HDRP's Mask Map wants metallic in red, occlusion in green, and smoothness — not roughness — in alpha. Feed one straight into the other and every channel drives the wrong property on the material.
Why the channels swap
![]()
glTF 2.0 doesn't actually define a single "ORM texture." The spec defines `occlusionTexture` and `pbrMetallicRoughness.metallicRoughnessTexture` as two separate references, and most exporters — Blender's glTF exporter included — point both at the same image file to save a texture fetch at runtime: the red channel supplies occlusion, green and blue supply roughness and metallic. That convention, used everywhere from Substance Painter to Unreal Engine 5's texture packing, is what everyone calls ORM. Unity's HDRP never adopted it. The Lit shader's Mask Map is Unity's own packing, built around its own artist tooling, and it orders the channels differently on purpose.
glTF ORM vs Unity's HDRP Mask Map
| Channel | glTF ORM | Unity HDRP Mask Map | Unity Built-in / URP Metallic map |
|---|---|---|---|
| R | Occlusion | Metallic | Metallic |
| G | Roughness | Occlusion | (unused) |
| B | Metallic | Detail mask | (unused) |
| A | unused | Smoothness | Smoothness |
Two mismatches compound each other here. Red and blue swap between occlusion and metallic, so whatever an AO bake looks like becomes the metallic mask. And glTF stores roughness while Unity wants its inverse, smoothness (`smoothness = 1 - roughness`), so without that inversion matte surfaces turn glossy and glossy surfaces turn matte.
What actually renders wrong
Take a hard-surface prop with a mix of metal and non-metal parts. A typical AO bake on that kind of prop sits around 80-100% white across the open shell, where nothing blocks ambient light, and drops to 20-40% only in the tight creases around grips, seams, and screws. Read as the Mask Map's metallic channel, that's a prop that's 80-100% metallic across almost the entire surface, including any rubber or plastic parts, everywhere except the creases. The real metallic map, sitting in blue, gets read as the detail mask and does nothing visible. And because most exporters don't write an alpha channel into the ORM image at all, Unity treats a missing alpha as 1.0: full smoothness. The whole prop ends up with a wet, mirror-like specular stacked on top of metallic values that are backwards.
Fix it: repack the texture in under a minute
![]()
No re-export needed — this is a channel repack on the same bitmap, so any tool that reads and writes individual channels works. Python with Pillow is fastest for batching more than one texture:
```python
from PIL import Image
o, r, m = Image.open("orm.png").convert("RGB").split()
smooth = r.point(lambda v: 255 - v) # roughness -> smoothness
mask = Image.merge("RGBA", (m, o, Image.new("L", o.size, 0), smooth))
mask.save("mask_map.png") # R=metal G=AO B=detail A=smooth
```
That swaps occlusion and metallic, inverts roughness into the alpha channel, and zeroes blue since there's no detail mask to pack. Import the result with Texture Type set to Default and sRGB (Color Texture) unchecked in the Inspector. Mask Maps are data, not color — leaving sRGB on darkens the mid-tones the same way it does on a mistagged normal map.
The gotchas
- Built-in and URP use a third layout. Their Metallic map reads metallic from a single channel and smoothness from alpha, with no occlusion channel at all — ambient occlusion goes in its own separate Occlusion Map slot. Don't reuse an HDRP Mask Map there; repack again with a different target.
- glTFast doesn't save you here. Unity's official glTFast importer remaps metallic-roughness correctly for the materials it auto-generates, but the moment a source texture gets hand-assigned to a Lit or HDRP/Lit master node directly, that remapping is bypassed and the raw glTF channels are what the shader reads.
- Check the source before touching Unity. Open the model in 3D Studio first — its materials inspection panel shows exactly which texture is bound to which slot before any time gets spent re-importing, and poly and UV checks run in the same pass, on-GPU, free.
- Don't fix it with the Metallic slider. Nudging the scalar Metallic value in the material inspector masks the symptom on one hero asset and leaves every other prop sharing that texture set still broken.
Worth testing this against a real asset rather than a placeholder cube: the Sci-fi industrial welder pistol ships with a full ORM set and enough mixed metal-and-grip surface to make a bad repack obvious immediately. A free account's two monthly downloads cover evaluation like this; commercial use is included with paid memberships (pricing).
Two related failures are worth ruling out while the Inspector is already open: pink materials on Unity 6 GLB import come from a render-pipeline mismatch, not a channel one, and for anyone wiring the Mask Map by hand in Shader Graph instead of using the Lit shader's built-in slot, the node setup is covered in building custom PBR materials in URP Shader Graph.
---
*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.*