All Guides

What is a Roughness Map? A 3D Artist's Plain-English Guide

By Voise · 3D artist since 200910 min read
Two identical spheres rendered side by side — left is a polished chrome ball with a sharp reflection, right is a matte rubber ball with diffuse shading — labelled 'roughness 0' and 'roughness 1'
Same sphere, same light, same albedo. Only the roughness map changed. Left: 0. Right: 1.

A roughness map is a grayscale texture that tells a PBR shader how matte or shiny every pixel of a surface is. Black means the surface is smooth and reflective, like a polished sink. White means it's rough and diffuse, like dry clay. The shader doesn't touch the colour, the shape, or the metalness — only the way light scatters when it lands. (Yes, the gloss-versus-roughness swap is exactly as confusing as it sounds.)

TL;DR

  • A roughness map is a grayscale 0–1 mask of how rough every pixel is.
  • Black is smooth and shiny. White is rough and matte. Glossiness maps flip that.
  • It lives in the green channel of a packed ORM file. Get the channel wrong and metal turns to plastic.
  • Always linear, never sRGB. Roughness is data, not colour.
  • Match the resolution of your albedo. Going higher is just a bigger file.

Right. The roughness map is the friend who walks into the room and tells you, quietly, exactly how shiny everything is. Albedo handles the colour. Normal handles the bumps. AO handles the dirt. But roughness is the map that decides whether your weathered copper teapot looks like an actual weathered copper teapot or a wet, sad balloon. I've been shipping material packs into Unity, Unreal, Blender, Godot, and Three.js since 2009. The single most common reason a metal ships looking like plastic is the roughness map being wrong — wrong values, wrong colour space, or wrong channel.

Why we use roughness maps

Real surfaces are uneven on a tiny scale. A car panel is glossy where the clear coat is intact and matte where it's scuffed. A wooden floorboard is satin where it's been polished, dry where the varnish has worn through, oily where someone's been eating chips on it. Without a roughness map, every pixel of that floorboard reflects light the same way, and the floor looks like a sheet of vinyl.

A roughness map fixes that. It paints the unevenness in. Where the map is dark, the shader keeps the reflections tight. Where the map is light, the shader smears them out. One grayscale image and a flat surface starts behaving like the real thing.

Without one, you're shading with a roughness slider — a single value across the whole material. That works for billiard balls. It does not work for a kitchen knife that's been through a dishwasher cycle since 2018.

How a roughness map actually works

The shader reads one number per pixel from the map. That number runs from 0 to 1. It feeds straight into the lighting equation — specifically into the term that controls how wide the reflection lobe is. The wider the lobe, the more the highlight spreads out and the duller the surface looks.

At roughness 0, the lobe is razor-thin. Light bounces off in a single sharp direction and you get a mirror. At roughness 1, the lobe is a hemisphere. Light scatters in every direction equally and you get a diffuse surface with no visible reflection at all. Every value in between gives a softer-edged highlight, like a window seen through more and more frosted glass.

The clever bit is that this is the same maths that drives both dielectrics (wood, stone, plastic) and metals. The shader doesn't need different equations for chrome and clay — it just reads the same grayscale value and modulates the reflection accordingly. PBR's quiet genius, basically: one number, every material.

Five identical spheres rendered in a row with roughness values 0.0, 0.25, 0.5, 0.75, and 1.0 — same albedo and lighting, showing the gradient from mirror reflection to fully matte
One material, five roughness values. Same shader, same light. The reflection just keeps spreading out.

Reading the map: chrome to rubber

The trick to a believable roughness map is knowing what a real surface looks like in numbers. Most beginners paint the whole thing somewhere around 0.5 and wonder why everything looks like a cheap dashboard. Real materials sit in narrower bands than you expect.

Rule-of-thumb values, from my own jobs:

  • Polished chrome — 0.00 to 0.10. Anywhere above that and the reflection starts to dull.
  • Brushed steel or aluminium — 0.20 to 0.40. The brushing direction can be painted in as a slight variation.
  • Painted plastic — 0.30 to 0.50. Toothbrush handle, kettle, dashboard.
  • Sealed wood, satin finish — 0.40 to 0.60. Most furniture lives here.
  • Weathered wood — 0.60 to 0.80. Fence panels, old skirting board.
  • Fresh concrete — 0.70 to 0.90. Dry, dusty, almost no reflection.
  • Raw clay or chalk — 0.90 to 1.00. The closest real surfaces get to a perfect diffuser.

Honest numbers: I have never, in 16 years, used a value of exactly 0 or exactly 1 in production. Nature has a slightly softer touch than that. Sit half a notch off the extremes and the material reads as a real thing instead of a maths exercise.

Roughness vs glossiness: same data, opposite labels

Here's where the wheels come off for a lot of people. Glossiness and roughness store the same information — just backwards. A glossiness map of 1.0 means a perfect mirror. A roughness map of 1.0 means a perfect diffuser. Same grayscale image, flipped. OpenGL and DirectX going through a rough patch about which way up looks, except this time it's about which way is shiny.

Two grayscale texture maps shown side by side — the left labelled 'roughness' with black smooth areas and white rough areas, the right labelled 'glossiness' with the values inverted
Same surface, two encodings. The numbers under the pixels are identical — only the labels disagree about which end is shiny.

To convert between the two, you invert the image. In Photoshop that's Ctrl-I. In Substance, it's a one-node invert. In Blender, a Math node set to "subtract from 1". Three seconds either way. If your render suddenly has every shiny thing looking matte and every matte thing looking shiny, this is almost certainly what happened.

The reason both exist: roughness lives in the metalness workflow (Unreal, Unity HDRP and URP, glTF, Godot 4). Glossiness lives in the older specular workflow (legacy Unity standard shader, older Maya pipelines, some Substance Painter exports). When you import assets from a specular-workflow source into a metalness-workflow engine, somebody has to invert. Often that somebody is you, at 11pm, the night before a deadline.

Metalness workflow vs specular workflow

Quick detour, because this is where the roughness map sits inside the bigger picture. There are two ways modern PBR shaders describe a surface:

  • Metalness workflow — uses an albedo, a normal, a roughness, a metalness, and usually an AO map. The shader looks at the metalness value to decide whether the albedo means "diffuse colour" (for dielectrics) or "specular tint" (for metals). Roughness handles the reflection sharpness for both. This is the modern default. glTF uses it. Unreal uses it. Unity URP/HDRP uses it.
  • Specular workflow — uses an albedo (or diffuse), a normal, a glossiness, and a separate specular colour map. More expressive, more authoring effort, more file size, more chances to get wrong. Lingers in older pipelines.

The roughness map shows up in both. It just has a different name in the second one. Same job either way: tell the shader how scattered the reflection should be at each pixel.

Channel packing: where roughness actually lives

A grayscale roughness map technically only needs one channel of an image to store the values — every pixel is one number. So if you ship it as a full RGB PNG, you're wasting two-thirds of the file. Modern pipelines pack three different grayscale maps into one RGB image to save VRAM. This is channel packing. The most common layout is ORM:

  • R = Ambient Occlusion
  • G = Roughness
  • B = Metalness

Three maps, one file, one texture sample at runtime instead of three. About a third of your VRAM back. Like three roommates in a one-bedroom file — works fine as long as everyone agrees who lives where.

Diagram showing a channel-packed ORM texture split into its three components — red channel labelled 'Ambient Occlusion', green channel labelled 'Roughness', blue channel labelled 'Metalness'
One file, three maps. Red = AO. Green = Roughness. Blue = Metalness. The engine reads each channel separately.

The glTF 2.0 spec calls the packed file a Metallic-Roughness texture. It only uses two channels (G = roughness, B = metalness) and ignores the rest. Unreal Engine documentation recommends the same ORM order, and so does most of Unity's modern pipeline. Some older tools pack as RMA, or AOR-Metalness, or whatever the studio decided one afternoon — verify the order before you bake, not after.

Channel-packing rule of thumb: the channels are in alphabetical order more often than you'd guess (Ambient Occlusion, Metalness, Roughness — AMR, ARM, ORM, RMO depending on the source). When in doubt, open the packed file, split the channels, and look at each one. If the green channel looks like a roughness map (varied grayscale), you're probably fine.

When metal looks like plastic

The famous failure mode. You've made a copper teapot. The albedo is the right colour. The metalness map is correctly 1.0 everywhere it should be. You hit render and the teapot looks like a wet, sad balloon. Plastic. (My junior Jake calls this "the balloon effect" — he didn't coin it but he loves saying it.)

Same copper teapot rendered twice — left with a correct roughness map looking like real copper, right with the channel order wrong and the surface looking like glossy plastic
Left: roughness in the correct channel, copper looks like copper. Right: roughness in the wrong channel, copper looks like a pool floatie.

Three usual suspects, in order of how often I've hit them on a paid job:

  1. The values are too high. Real metals sit between 0.2 and 0.5 unless they're heavily oxidised. If your map averages 0.7, the shader thinks the metal is covered in a fine dust and dulls the reflection accordingly. Pull the levels down.
  2. The channel is wrong. Your packer dropped roughness into the red channel instead of green. The shader is now reading the AO map as roughness, which tends to be brighter overall, so the metal looks rougher than it is. Re-pack with R=AO, G=Roughness, B=Metalness.
  3. The colour space is wrong. You imported the roughness map as sRGB. The engine ran an sRGB-to-linear curve over the values, pushing them slightly higher. Roughness is data, not colour — it has to be loaded linear. In Blender, that's "Non-Color" on the image texture node. In Unity, untick sRGB. In Unreal, set the texture compression to "Masks" or "Default (non-color)".

Check those three before you blame the engine. Nine plastic metals out of ten are one of those three. The tenth is your monitor needing a calibration, which is a different post.

How to make a roughness map (three methods)

There are three real ways to make a roughness map in 2026. They serve different jobs.

1. Paint it in Substance Painter (or Mari, or Blender)

The classic. Paint roughness values directly onto your model's UVs as a grayscale channel. Mask in scratches, wear, oil patches, fingerprints, polished edges. Reference photos help — a real worn surface has roughness variation, not a single value. A scuffed boot is shinier on the toe than on the heel; paint that in.

Pros: total control. You can author wear that tells a story. Cons: time. A hero prop is half a day of texturing minimum once you start fussing over the corners.

2. Derive from an albedo or photo

Quick approximation. Take your albedo, desaturate it, level-correct it, and use the result as a starting-point roughness. Darker areas of the photo tend to be wetter, dirtier, or more recessed (and therefore rougher); brighter areas tend to be smoother. It gets you 60% of the way there for free. The other 40% is paint-over by hand.

You can also invert a height map and use that as a base — pits read as rough, raised areas read as smoother (because they're where polishing actually happens).

3. Generate from a text prompt with AI

New flavour. Describe the surface in plain words and an AI model produces a full PBR set — albedo, normal, roughness, AO, metalness — designed together. The roughness map comes out coherent with the rest of the maps, which is the bit photo-to-roughness conversions usually get wrong. The scratches in the normal match the smoother values in the roughness, because they were generated as a single material, not stitched after the fact.

Pros: seconds, not hours. The colour space is set correctly on export, and a good tool packs the ORM file for you. Cons: AI-generated maps still need a human to fix the corners. The model does the heavy lifting; I do the cleanup.

A full PBR texture set generated from a single text prompt for weathered copper — albedo, normal, roughness, ambient occlusion, and metalness shown as five tiles
One text prompt, five PBR maps. The roughness in the middle agrees with the bumps in the normal map. That coherence is the point.

If you want to try the prompt-to-PBR route, CraftPBR generates the full PBR set from a text description, no sign-up needed. Free up to ten generations a day. That's genuinely enough to finish a small game.

Generate a roughness map in 30 seconds

Describe any surface. CraftPBR returns the full PBR set — albedo, normal, roughness, AO, metalness — ready for Unity, Unreal, Blender, Godot, or Three.js. Linear colour space, channels packed correctly, no fiddling.

Try It Free

When to stop tweaking

Roughness is the easiest map to over-author. Every dust speck, every fingerprint, every edge gets its own value adjustment and you end up with a map that looks busy at 4K and mush at 1K. Some rules I've had to teach myself:

  • If the variation isn't visible at the asset's real view distance, don't paint it. A floor seen from third-person eye-height doesn't need pore-level roughness.
  • Real materials are simpler than you think. A clean tile floor is two roughness values — the tile and the grout. That's it. The fifteenth pass at polishing the grout doesn't help anyone.
  • If the silhouette is right and the highlights land where you expect, stop. Render. Move on. The next material won't paint itself.

Straight answers

The questions I get asked at the pub, one beer in.

What does a roughness map do?

It controls how sharply light reflects off every pixel. Black is a mirror, white is a diffuser, everything in between is the gradient. Nothing else about the material changes.

What is the difference between a roughness map and a glossiness map?

They're the same data, inverted. Roughness: 1 is matte. Glossiness: 1 is shiny. The metalness workflow uses roughness; the older specular workflow uses glossiness. Feed one in where the other is expected and your material flips polarity.

Should a roughness map be sRGB or linear?

Linear. Always. Roughness values are data, not colour. Loading them as sRGB pushes the numbers slightly brighter, which in roughness terms means slightly more matte, and the whole material drifts toward chalky. Non-Color in Blender, sRGB unchecked in Unity, "Masks" in Unreal.

Why does my metal look like plastic?

Roughness values are too high, the channel is wrong in a packed ORM file, or the map was loaded as sRGB instead of linear. Check those three in order. They cover nine plastic metals out of ten.

Where does roughness live in a packed ORM texture?

The green channel. Convention: R = Ambient Occlusion, G = Roughness, B = Metalness. That's what glTF, Unreal, and most of modern Unity expect. If your packer wrote it somewhere else, the engine reads AO or metalness as roughness and everything looks off.

What roughness values do real materials have?

Polished chrome 0.0 to 0.1. Brushed metal 0.2 to 0.4. Painted plastic 0.3 to 0.5. Weathered wood 0.6 to 0.8. Fresh concrete 0.7 to 0.9. Raw clay 0.9 to 1.0. Almost nothing real sits at pure 0 or pure 1 — leave a little room.

Do AI-generated roughness maps work in Unity and Unreal?

Yes. A roughness map is a standard grayscale texture; once the colour space is linear and the channel order is right, the engine doesn't care who made it. A good AI tool exports it already paired with a coherent albedo, normal, AO, and metalness, which is usually where the trouble starts otherwise.

If you want the full picture of how the roughness map fits into a PBR material, read my guide to PBR materials — it covers all the maps that travel together and how they interact. The roughness map shares a channel with two of them, and the relationships matter. If you'd like to see how the bump side of the same conversation works, the normal map guide walks through that map's own quirks. And if you just want to grab some free PBR sets to drop into a scene right now, the community library has CC0 sets ready to download — roughness packed correctly, in case you were worried.

Further reading

A weathered copper teapot rendered in a softly lit studio scene with a correct PBR roughness map driving the reflection variation across the surface
One roughness map doing its job. The polished bits read polished, the worn bits read worn. Nothing else changed.

That's roughness. One grayscale image, one number per pixel, the whole story of how a surface meets the light. Get the values right and your material reads as a real thing. Get them wrong and your copper teapot files a complaint with the union. Either way: go make something. And if your metal looks like plastic, check the channel order before you blame the engine.

↑ Back to top