Spring Sale: 30% off bundles with SPRINGBUNDLE or 15% off individual products with SPRING15 — ends Apr 15

StraySparkStraySpark
ProductsFree AssetsDocsBlogGamesAbout
StraySparkStraySpark

Game Studio & UE5 Tool Developers. Building professional-grade tools for the Unreal Engine community.

Products

  • Complete Toolkit (Bundle)
  • Procedural Placement Tool
  • Cinematic Spline Tool
  • Blueprint Template Library
  • DetailForge
  • UltraWire
  • Unreal MCP Server
  • Blender MCP Server
  • Godot MCP Server
  • AI Material Generator
  • Procedural Damage & Wear
  • One-Click PBR Bake

Resources

  • Free Assets
  • Documentation
  • Blog
  • Changelog
  • Roadmap
  • FAQ
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 StraySpark. All rights reserved.

Back to Blog
tutorial
StraySparkApril 12, 20265 min read
ORM Texture Packing: How to Optimize PBR Textures for Game Performance 
Game DevelopmentPerformanceTexturesPbrOptimizationUnreal Engine

Every material in a modern PBR pipeline requires multiple textures: Base Color, Normal, Roughness, Metallic, Ambient Occlusion, and often more. A single material can easily use 5-6 texture samples per pixel. In a scene with dozens of materials, that's hundreds of texture fetches per frame — and each one costs bandwidth, VRAM, and GPU cycles.

ORM texture packing is one of the simplest optimizations you can make, and it's standard practice at every professional studio. If you're not doing it, you're leaving significant performance on the table.

What Is ORM Packing?

ORM stands for Occlusion, Roughness, Metallic. It's a technique where you pack three grayscale textures into the R, G, and B channels of a single RGB texture:

ChannelData
RedAmbient Occlusion
GreenRoughness
BlueMetallic

Since AO, Roughness, and Metallic are all grayscale (single-channel) data, they each only need one color channel. Storing them in separate files wastes two-thirds of each file's capacity. Packing them into one RGB texture uses the same total data but requires one texture sample instead of three.

Why It Matters for Performance

The performance impact is straightforward:

Fewer texture samples. A standard PBR material without packing needs: Base Color (1 sample), Normal (1 sample), AO (1 sample), Roughness (1 sample), Metallic (1 sample) — that's 5 samples. With ORM packing: Base Color (1 sample), Normal (1 sample), ORM (1 sample) — that's 3 samples. You've reduced texture fetches by 40%.

Less VRAM. Three separate 2K textures at 8 bits per channel: 3 files x 2048x2048 x 3 channels = approximately 36 MB uncompressed. One packed 2K ORM texture: 1 file x 2048x2048 x 3 channels = approximately 12 MB uncompressed. With GPU texture compression (BC7/ASTC), the savings carry through proportionally.

Better cache performance. GPUs read textures in blocks. When you sample one channel from an RGB texture, the adjacent channels are already in the cache. Sampling three separate textures means three separate cache fetches from different memory locations.

Fewer draw calls. Some rendering pipelines batch objects by material, and materials with fewer texture bindings are faster to set up.

In real-world scenarios, studios report 15-25% reduction in material rendering cost from channel packing alone — no visual quality loss, no shader changes, just reorganized data.

How to Create ORM Textures

Method 1: Manual Packing in Photoshop/GIMP

The conceptual process:

  1. Open your AO, Roughness, and Metallic textures
  2. Create a new RGB image at the same resolution
  3. Copy the AO grayscale data into the Red channel
  4. Copy the Roughness grayscale data into the Green channel
  5. Copy the Metallic grayscale data into the Blue channel
  6. Save as a non-sRGB format (PNG, TGA, or EXR)

In Photoshop:

1. Open all three source textures
2. Create new document (same dimensions)
3. Window > Channels
4. Select Red channel → Paste AO texture
5. Select Green channel → Paste Roughness texture
6. Select Blue channel → Paste Metallic texture
7. Save As → TGA/PNG (no color profile embedded)

In GIMP:

1. Open all three source textures as layers
2. Colors > Components > Compose
3. Select "RGB" compose type
4. Assign: Red = AO layer, Green = Roughness layer, Blue = Metallic layer
5. Export as TGA/PNG

Method 2: Command-Line with ImageMagick

For batch processing, ImageMagick handles this in a single command:

magick convert ao.png roughness.png metallic.png -combine orm.png

For an entire folder:

for dir in */; do
  magick convert "${dir}ao.png" "${dir}roughness.png" "${dir}metallic.png" \
    -combine "${dir}orm.png"
done

Method 3: Blender Compositor

If your textures are baked in Blender, you can pack them directly in the Compositor:

AO Image → Separate RGB → R ─┐
                               ├→ Combine RGB → Output
Roughness Image → Separate RGB → R ─┤
                               │
Metallic Image → Separate RGB → R ─┘

Connect each grayscale source to the appropriate channel of a Combine RGB node, then render/save the result. This avoids the round-trip to an external image editor.

Method 4: Automated with One-Click PBR Bake

If you're working in Blender and want to skip the manual baking and packing steps entirely, One-Click PBR Bake handles the full pipeline — baking individual PBR maps from your shader setup and packing them into ORM textures ready for import into your target engine. It eliminates the multi-step process of baking each map separately, opening an image editor, and manually assembling channels.

Engine-Specific Requirements

Unreal Engine 5

UE5 natively expects ORM packing in its default material setup. When you import an ORM texture:

  1. Set the texture's Compression Settings to Masks (no sRGB) — this is critical. ORM is linear data, not color data.
  2. In your material, break the ORM texture into channels using a BreakOutFloat3Components node or channel masks.
  3. Connect: R to Ambient Occlusion, G to Roughness, B to Metallic.

UE5's default material template already has inputs designed for this. If you use Quixel assets, they ship with ORM textures by default.

The material setup in UE5:

ORM Texture Sample
  ├─ R → Ambient Occlusion pin
  ├─ G → Roughness pin
  └─ B → Metallic pin

Important: Never set an ORM texture to sRGB in Unreal. sRGB applies a gamma curve that corrupts the linear data. Your roughness will look wrong, metallic transitions will be inaccurate, and AO will be too dark. Set it to Linear/Masks.

Unity (URP/HDRP)

Unity's approach differs by render pipeline:

HDRP uses a Mask Map with a different channel layout:

ChannelData
RedMetallic
GreenAmbient Occlusion
BlueDetail Mask
AlphaSmoothness (inverted Roughness)

Note that HDRP uses Smoothness (1 minus Roughness), not Roughness directly. You'll need to invert the Roughness channel before packing.

URP doesn't have a single packed input by default. You'll need to either use a custom shader or pack into the Metallic Alpha channel (Smoothness) plus separate AO.

# Invert roughness to smoothness for Unity HDRP (ImageMagick)
magick convert roughness.png -negate smoothness.png

# Pack HDRP Mask Map: R=Metallic, G=AO, B=DetailMask(white), A=Smoothness
magick convert metallic.png ao.png \
  -size 2048x2048 xc:white smoothness.png \
  -combine hdrp_mask.png

Godot 4

Godot's ORM material uses a different arrangement:

ChannelData
RedAmbient Occlusion
GreenRoughness
BlueMetallic

This matches the standard ORM layout. In Godot's material editor, enable the ORM texture slot and assign your packed texture. The engine handles the channel splitting automatically.

Common Mistakes

Applying sRGB to packed textures. This is the number one error. Packed data textures must be imported as Linear/Non-Color in every engine and every DCC tool. sRGB gamma correction will corrupt your material values.

Mismatched resolutions. All three source textures must be the same resolution before packing. If your AO is 2K and your Roughness is 1K, resize the Roughness to 2K first (or preferably, bake all maps at the same resolution from the start).

Packing color data. Only pack grayscale data into channels. Base Color and Emissive are color data and must remain as separate RGB textures. Attempting to "pack" a color texture into a single channel destroys two-thirds of its information.

Forgetting to update materials after packing. If you pack textures but your material still samples the three separate files, you've gained nothing and added a texture. Remove the individual texture samples and replace them with channel-split references to the packed texture.

Over-compressing packed textures. When you apply texture compression (BC7, ASTC), the compressor treats the texture as a single image. Since ORM channels contain very different data, the compressor may introduce artifacts where one channel's sharp edges conflict with another channel's smooth gradients. Test your compressed ORM textures in-engine to verify quality.

Beyond ORM: Other Packing Strategies

ORM is the most common packing scheme, but the concept extends to any combination of grayscale data:

  • RMA (Roughness, Metallic, AO) — Same data, different channel order. Some studios prefer this layout.
  • MRAO (Metallic, Roughness, AO, Opacity) — Adds opacity in the alpha channel for masked materials.
  • Normal + AO — Some pipelines pack AO into the Blue channel of a two-channel normal map (since tangent-space normals only use RG in BC5 compression).

The principle is always the same: if you have grayscale data consuming a full RGB texture, it can be packed into a channel. Just document your packing convention clearly so everyone on the team knows which channel holds which data.

Practical Checklist

Before shipping your packed textures, verify:

  • All source textures are the same resolution
  • Packed texture is saved as Linear (no sRGB/gamma)
  • Channel assignment matches your engine's expected layout
  • Material in-engine samples the packed texture with correct channel splits
  • Compressed texture quality is acceptable (check in-engine, not just in the editor)
  • Old individual texture files are removed from the project (don't ship unused assets)

ORM packing is one of those optimizations that costs nothing in visual quality while delivering measurable performance gains. Once you integrate it into your asset pipeline — or automate it with tools like One-Click PBR Bake — it becomes invisible. You just produce better-performing assets by default.

Tags

Game DevelopmentPerformanceTexturesPbrOptimizationUnreal Engine

Continue Reading

tutorial

AI Material Generation in Blender: The Complete Guide for 2026

Read more
tutorial

How AI Is Cutting Asset Creation Time by 60% for Indie Studios in 2026

Read more
tutorial

Blender 5.0 for Game Developers: The Features That Actually Matter

Read more
All posts