A model arrives in Unreal and the brass fittings render as grey plastic. The geometry is fine. The base color map looks correct in Photoshop. The client is annoyed. Nine times out of ten the cause is one of four things: metallic values sitting at 0.4 instead of 1.0, a roughness map interpreted as sRGB, a normal map with the wrong green-channel convention, or ambient occlusion baked into base color where it does not belong.
All four are cheap to fix once you know what each map is supposed to contain. This is the physical meaning of the metallic-roughness workflow, plus the practical numbers for shipping it.
Base color is not “the texture”
Base color answers one question: of the light that hits this surface, what fraction of each wavelength bounces back diffusely? Nothing else. No shadows, no highlights, no ambient occlusion, no reflections.
Real-world albedo occupies a surprisingly narrow band. Fresh asphalt sits around 0.05 linear, roughly sRGB 60. Fresh snow tops out near 0.9, about sRGB 243. Nothing natural is pure black or pure white. If your darkest region reads below sRGB 30 or your brightest above sRGB 245, energy conservation breaks and the material will look dead under some lighting and blown out under others. Charcoal at sRGB 20 will absorb every bounce in a global-illumination renderer and turn into a hole.
Metals behave differently. For a metal, base color is not diffuse albedo — it is F0, the specular reflectance at normal incidence, and it is what gives gold its warmth. These are measured values, not taste:
| Metal | Linear RGB (F0) | Approx. sRGB hex |
|---|---|---|
| Gold | 1.000, 0.766, 0.336 | #FFE29C |
| Copper | 0.955, 0.638, 0.538 | #FBD1C4 |
| Aluminium | 0.913, 0.921, 0.925 | #F5F6F7 |
| Iron | 0.560, 0.570, 0.580 | #C4C8CB |
| Silver | 0.972, 0.960, 0.915 | #FDFCF6 |
Note how bright they all are. A dark metal is almost always a mistake — you are probably thinking of a dirty or oxidised metal, which is a dielectric coating over the metal and should be authored with metallic near 0 in those areas.
Metallic is a classification, not a dial
Metallic tells the shader which BRDF branch to take. At 0 the surface is a dielectric: it reflects about 4 percent of incoming light as a white specular highlight and the rest scatters as diffuse base color. At 1 the surface is a conductor: no diffuse term at all, and the specular reflection is tinted by base color.
There is no physical material at 0.5. Intermediate values exist only for two legitimate reasons: antialiasing the boundary between metal and non-metal across a few pixels, and mip-mapping, which averages those boundaries automatically. If you open a metallic map and see broad regions of mid-grey, someone guessed — or a generative model hedged. Threshold it. Levels with the midpoint pushed hard, or a simple step(0.5, x), will get you closer to correct than the original.
This is the strongest argument for the metallic-roughness workflow over the older specular-glossiness one. Specular-glossiness lets you author physically impossible materials without any warning. Metallic-roughness makes most of those states unreachable.
Roughness is microsurface, and it does the most work
Roughness describes variation too small to model — the microfacet distribution. Low roughness concentrates reflections into a tight, bright highlight. High roughness spreads the same energy over a wide, dim one. The total is conserved, which is why a rough metal looks darker even though it reflects just as much light.
| Surface | Roughness | Metallic |
|---|---|---|
| Polished chrome | 0.03–0.08 | 1.0 |
| Car paint clear coat | 0.10–0.18 | 0.0 |
| Brushed aluminium | 0.30–0.42 | 1.0 |
| Glazed ceramic | 0.15–0.25 | 0.0 |
| Worn leather | 0.55–0.70 | 0.0 |
| Dry concrete | 0.85–0.95 | 0.0 |
Uniform roughness is the fastest tell that a material was generated rather than authored. Real surfaces vary: fingerprints, wear on edges, dust settling in recesses. Multiplying a subtle grunge mask over roughness at 10 to 15 percent strength does more for realism than doubling your texture resolution.
One trap: aggressively mip-mapping a detailed normal map without compensating roughness produces specular aliasing — shimmering highlights when the camera moves. The fix is normal-variance-to-roughness conversion (Toksvig or LEAN mapping) at mip generation time. Most engines do this; some exporters do not.
Normal maps fake the light, not the silhouette
A tangent-space normal map stores a per-texel surface direction in a local frame. Red is the tangent axis, green the bitangent, blue the normal itself — which is why they are mostly #8080FF. Lighting responds to the perturbed direction; the geometry does not move. Look at a normal-mapped brick wall edge-on and it is flat.
The green channel is where imports break. OpenGL convention has +Y pointing up in texture space; DirectX has it pointing down. glTF, Blender, Godot and Unity’s standard pipeline use OpenGL (+Y). Unreal and 3ds Max use DirectX (-Y). Get it wrong and the lighting inverts on one axis: bumps read as dents when the light comes from above, and correct when it comes from below. That “correct from one direction only” symptom is diagnostic. Flip the green channel and move on.
Color space: the mistake that costs you an afternoon
Base color and emissive are perceptual data and are stored sRGB-encoded. Metallic, roughness, occlusion and normal are raw numbers and must be sampled linearly. Tag a roughness map as sRGB and every value gets gamma-decoded: 0.5 becomes about 0.21, and your matte concrete turns semi-glossy.
In Blender, that means Image Texture nodes set to Non-Color for everything except base color. In Unity, uncheck sRGB on the import settings. In Unreal, the compression setting handles it if you use Masks for packed maps and Normalmap for normals. In glTF this is enforced by the spec, which is one reason GLB tends to survive round-trips better than FBX.
Packing, and what textures actually cost
glTF packs occlusion, roughness and metallic into one RGB texture — red, green, blue respectively — usually called ORM. Three grayscale maps in one sample instead of three. Unreal’s convention is the same channel order. Models exported from MeshyFlix’s studio ship base color, metallic, roughness and normal as separate 2048×2048 maps, so packing them is a five-node operation if your engine wants ORM.
| Resolution | RGBA8 in VRAM | + mips | BC7 + mips | KTX2 (UASTC) on disk |
|---|---|---|---|---|
| 512×512 | 1.05 MB | 1.40 MB | 0.35 MB | ~180 KB |
| 1024×1024 | 4.19 MB | 5.59 MB | 1.40 MB | ~700 KB |
| 2048×2048 | 16.8 MB | 22.4 MB | 5.59 MB | ~2.8 MB |
| 4096×4096 | 67.1 MB | 89.5 MB | 22.4 MB | ~11 MB |
A single 4K PBR set — base color, ORM, normal — is around 67 MB of VRAM compressed, or 268 MB raw. Ship three of those on a mobile title and you are out of budget before the first character loads. For a web viewer, a sensible ceiling for a hero model is 8 MB total download: that is roughly a 100k-triangle Draco-compressed mesh at 1.5 MB plus 2048² base color and normal in ETC1S at about 3 MB combined, with room to spare.
Do and don’t
- Do keep base color between sRGB 30 and 243 and check it with an eyedropper, not by eye.
- Do threshold generated metallic maps toward 0 or 1 before shipping.
- Do break up roughness with a light grunge mask; it is the highest-value ten minutes in material work.
- Do drop textures to 1024² for anything that never covers more than a quarter of the screen. Nobody will notice, and you save 16.8 MB per map.
- Don’t bake ambient occlusion into base color. AO belongs in its own channel, applied to indirect light only. Baked into albedo it double-darkens under direct light.
- Don’t paint highlights or shadows into base color, however good the reference photo looks.
- Don’t use a 4K normal map with a 1K base color. Match resolutions unless you have a specific reason.
- Don’t trust a material judged under a single HDRI. Studio lighting hides errors that daylight exposes immediately.
A five-minute material check
Before delivering anything, run this. Isolate base color and confirm there are no shadows or highlights in it. Isolate metallic and confirm it is near-binary. Isolate roughness and confirm there is variation, not a flat fill. View the normal map in a flat-lit preview and confirm it is predominantly #8080FF with no colored bleed at UV island edges — bleed there means insufficient padding, and it will show up as bright seams at distance. Then rotate a directional light 360 degrees around the model and watch for the bumps-become-dents inversion.
Where to go from here
Take the last model you exported and open its four maps side by side at 100 percent zoom. You will almost certainly find one of the four problems named at the top of this article — most likely mid-grey metallic or AO in the albedo. Fix that one, re-export, and compare against the original in the same lighting setup.
Then set up a validation scene you reuse: a grey-card floor, one directional light, one neutral HDRI at 1.0 intensity, and a chrome ball plus a 50 percent grey sphere for reference. Judging materials against known values instead of against memory is what separates work that survives a client’s engine from work that only looks right in yours.