PBR Texture Validator

Check a texture set for size mismatches, missing maps, stray alpha, channel and normal problems.

A PBR validator checks a texture set before import: every map has a role, all maps are the same size, the chosen workflow's required and recommended maps are there, sizes are powers of two, grey maps really are grey and a normal map really decodes to unit vectors. Drop one material's maps: roles come from the file names (_basecolor, _normal, _roughness, _ORM …), you choose the workflow, and every issue is listed with its file and the measured number. The JSON report keeps the measurements; no file is renamed or changed.

Drop image files hereProcess many files at once
No upload · processed on this device

What is checked, and against which numbers

Roles from names. The file name is lower-cased, separators become _, and the first matching token wins, most specific first: packed (orm, arm, rma, mra, maskmap, mask), albedo (albedo, basecolor, diffuse, color …), normal (normalgl, normaldx, normal, nrm, n), roughness, smoothness (gloss), metallic, AO (ao, occlusion, ambientocclusion), height (height, displacement, bump), emission, opacity, specular. Tokens of one or two letters (_n, _m, _r) count as low confidence. Every role is a drop-down, so you correct a wrong guess instead of renaming files.

Workflows decide what is missing. Separate maps (glTF / generic): albedo required; normal, roughness, metallic recommended. Unity HDRP: albedo and the mask map required, normal recommended. Unity URP: albedo required; normal and metallic recommended. Godot ORM and Unreal ORM: albedo required; normal and the ORM texture recommended — and when roughness and metallic are present but the ORM is not, you get "pack available" instead of a bare "missing". A roughness map satisfies smoothness and the other way round.

Measurements, not guesses. A single-channel role (roughness, metallic, AO, height, opacity) stored as RGB is "grey stored as RGB" when no texel's channels differ by more than 2, and "channels differ" (probably packed) when they do. A normal map is decoded texel by texel: a sample is off-unit when its length is more than 0.12 from 1; the map passes when at most 1 % of samples are off-unit and no blue is below 128 (a vector pointing into the surface). A map assigned another role that passes the normal-map test (≤ 5 % off-unit, ≤ 0.1 % negative blue) is flagged "looks like a normal map".

Power of two is a warning, not an error. glTF 2.0 says clients SHOULD resize non-power-of-two textures on platforms with limited support when the sampler repeats or uses mipmaps; Unity's importer has a Non Power of 2 option that scales such textures. Whether that matters depends on your target, so the validator reports it and leaves the decision to you.

Workflow
The set of maps an engine's material expects, including how they are packed.
Set name
What is left of the file name after the role token; different set names in one drop trigger "naming inconsistent".
Off-unit sample
A decoded normal whose length differs from 1 by more than 0.12.
Power of two
A size of 2ⁿ pixels: 256, 512, 1024, 2048 …

Example: a rock set checked for Godot 4 ORM

Four PNGs dropped together, workflow Godot 4 ORM. This is what the validator returns:

rock_basecolor.png   2048 × 2048   albedo
rock_normal.png      2048 × 2048   normal
rock_roughness.png   1000 × 1000   roughness
rock_metallic.png    2048 × 2048   metallic

error  dimension-mismatch    2048x2048 vs 1000x1000 (rock_roughness.png)
warn   missing-recommended   orm
info   pack-available        roughness + metallic → Godot 4 ORM preset
warn   not-power-of-two      rock_roughness.png 1000 × 1000

set ok: no (1 error)

One re-export of the roughness at 2048 × 2048 clears the error and the power-of-two warning; packing roughness and metallic (with AO if you have one) in the mask packer clears "missing orm".

Check the result

  • After fixing, drop the new files and keep the same workflow: the summary shows ✓ when there are no errors and no warnings.
  • Download texture-report.json and read issues: each entry has id, level, the files and the numbers (sizes, maxDeviation, ratio, minBlue).
  • For a normal map, normalCheck.meanLength should be close to 1 and blueNonNegative true.

Troubleshooting

SymptomLikely causeHow to checkFix
unclassified for a file you knowThe name has no known token (rock_03.png), or a token outside the English listThe role column shows UnknownPick the role in its drop-down; the report keeps your choice
duplicate-role for the normal mapBoth _NormalGL and _NormalDX from one download were droppedTwo files carry the role normalKeep the one your engine expects (GL for Unity and Godot); convert with the normal map converter if you only have the other
gray-channels-differ on a roughness or metallic fileIt is really a packed texture (or a coloured preview) with a single-map nameThe issue gives the largest channel spread and the share of texels that differSet its role to the packed map, or unpack it with the channel unpacker
looks-like-normal on a height or bump fileA normal map saved as _bump, which the name rules read as heightIt passes the unit-length and blue testChange its role to normal
normal-blue-negative or normal-not-unitNot a tangent-space normal map (a height or object-space map, or a map resized as colour)The issue shows minBlue and the off-unit shareUse the right file, or generate one from height with the normal map generator
unexpected-alpha on a roughness, metallic or AO mapThe exporter added an alpha channel the engine will not readThe issue lists the lowest alpha and the number of alpha-0 texelsExport without alpha; the colour under alpha 0 is kept by the Lab, but most engines ignore it

Other ways to do it

OptionWhen it is the better choice
The full Texture LabYou also need to fix what the check finds: convert normals, unpack or pack channels, bleed edges, resize, and export a batch.
Checking in the engineOne material and one engine: import settings and missing slots show up in the material inspector, but sizes, grey-stored-as-RGB and normal validity are not measured there.

What this page does not cover

  • Colour space is not detected: no ICC profile or gamma is read; the report states which roles an engine expects as sRGB or linear and whether a PNG has an sRGB chunk.
  • The OpenGL/DirectX convention of a normal map is not detected here; the Studio's Texture workspace has a detector.
  • Name rules know English tokens only; files are never renamed.
  • The report is generic JSON; no engine imports it.

Versions and sources

The check report was verified on the Texture Lab (docs/TEXTURE-LAB.md): schemaVersion 1, engineTarget generic, alpha.zeroPixels = 2048 matching the fixture, exactChannels true; a JPEG input gives exactChannels: false. The numbers on this page are the thresholds in src/game/texture-set.js and src/game/texture-normal.js.

Official documentation used

PBR Texture Validator

Check a texture set for size mismatches, missing maps, stray alpha, channel and normal problems.

How it works

  1. Add images
  2. Adjust settings and review the result
  3. Download a new file

Supported formats

PNG / JPG / WebP / AVIF / HEIC → JSON — Input decoding depends on browser support and optional engines.

What this tool does

Check a texture set for size mismatches, missing maps, stray alpha, channel and normal problems.

Implementation and verified quality

advanced · filename classification / pixel measurements / workflow rules. Quality qualification is in progress. Pro/Flagship quality has not been established.

Before you export

Judged from filenames and pixels only: no ICC profile or gamma is read, and colour space is guidance.

Frequently asked questions

What are this tool’s limitations?

Judged from filenames and pixels only: no ICC profile or gamma is read, and colour space is guidance.

Are my files uploaded?

This tool processes the files you open on your device without uploading them. Images you explicitly attach to community posts are uploaded separately. Optional engines and models are downloaded from third parties; those requests expose connection information such as your IP address.

Will my work be saved automatically?

No. Images and editing state stay in this tab; media output can use local temporary storage. Changing language preserves your work; reloading, closing the tab, or following a link to another page can clear it.