← Back to Blog 3d-modeling

ORM Textures in Godot 4: A Complete PBR Workflow with StandardMaterial3D

By BitSoul Team5/17/2026Updated 8/1/20266 min read73 views
ORM Textures in Godot 4: A Complete PBR Workflow with StandardMaterial3D

Godot 4's physically based rendering pipeline is genuinely excellent — but most tutorials stop at dragging an albedo texture into `StandardMaterial3D` and calling it done. That leaves serious performance and quality on the table. The real unlock is understanding ORM textures: a single packed image that encodes Occlusion, Roughness, and Metallic data into three separate channels. One texture slot. Three properties. Zero wasted samples.

This guide walks through the complete ORM workflow: what each channel does, how to author ORM maps in Blender and Substance Painter, how to wire them correctly inside Godot 4, and which common mistakes will silently destroy your material quality.

What Are ORM Textures and Why They Matter

ORM stands for Occlusion (R channel), Roughness (G channel), Metallic (B channel). Instead of sampling three separate grayscale textures at runtime, you pack all three values into the RGB channels of a single texture. The GPU fetches one texture instead of three — reducing memory bandwidth and texture cache misses simultaneously.

Godot 4's `StandardMaterial3D` has native support for this format through the ORM texture input under the *Occlusion*, *Roughness*, and *Metallic* combined workflow. When you assign a texture to the `orm_texture` property and enable `texture_channel` flags correctly, Godot reads R for occlusion, G for roughness, and B for metallic automatically.

What Are ORM Textures and Why They Matter — illustrated

Here is what each channel controls:

| Channel | Property | 0 Value | 1 Value |
|---------|----------|---------|--------|
| R (Red) | Ambient Occlusion | No occlusion (full light) | Full occlusion (shadowed) |
| G (Green) | Roughness | Mirror-smooth | Fully diffuse |
| B (Blue) | Metallic | Dielectric (plastic/stone) | Conductor (metal) |

The green channel is most visually impactful — roughness controls how tightly the specular highlight focuses. A roughness of 0.0 gives you a perfect mirror. At 1.0 you get completely diffuse scattering with no visible specular. Most real-world surfaces live between 0.3 and 0.8.

Why not separate textures? Three 1024x1024 grayscale textures at 8-bit consume 3 MB uncompressed and three texture unit binds per draw call. One 1024x1024 RGB texture consumes 3 MB — but only one bind. On mobile GPUs with limited texture units, this distinction can mean the difference between a shader that compiles and one that doesn't.

Understanding StandardMaterial3D Properties

Godot 4's `StandardMaterial3D` exposes PBR parameters across four property groups: Albedo, Metallic, Roughness, and Emission. For ORM workflows you are working primarily in the Metallic and Roughness groups.

Key properties to configure:

When setting up your ORM texture:
1. Under Metallic, set `Texture Channel` to Blue.
2. Under Roughness, set `Texture Channel` to Green.
3. Under Ambient Occlusion, enable it and set `Texture Channel` to Red.
4. Assign your ORM image to all three texture slots — Godot deduplicates the GPU resource automatically.

```gdscript
# Assign ORM map in GDScript
var mat = StandardMaterial3D.new()
var orm_tex = load("res://textures/my_asset_orm.png")

mat.ao_enabled = true
mat.ao_texture = orm_tex
mat.ao_texture_channel = BaseMaterial3D.TEXTURE_CHANNEL_RED

mat.roughness_texture = orm_tex
mat.roughness_texture_channel = BaseMaterial3D.TEXTURE_CHANNEL_GREEN

mat.metallic_texture = orm_tex
mat.metallic_texture_channel = BaseMaterial3D.TEXTURE_CHANNEL_BLUE

# Scalar multipliers should be 1.0 to let texture drive values
mat.metallic = 1.0
mat.roughness = 1.0
```

Creating ORM Maps in Blender and Substance Painter

The authoring step is where most developers make mistakes. Both tools output the right data, but neither outputs a pre-packed ORM file by default — you have to configure the export correctly.

Creating ORM Maps in Blender and Substance Painter — illustrated

Blender (via Cycles baking)

Blender bakes occlusion, roughness, and metallic as separate images. To pack them:

  1. Bake Ambient Occlusion to save as `ao.png` (grayscale).
  2. Bake Roughness from your material's roughness output to save as `rough.png`.
  3. Plug your metallic node into the Emission bake output to save as `metal.png`.

Then pack in Blender's Compositor using the Combine RGBA node:
- R = ao.png
- G = rough.png
- B = metal.png
- A = 1.0 or opacity mask

Save the result as `asset_orm.png`. Use 8-bit PNG unless you need 16-bit precision on roughness (rare).

Substance Painter

Substance Painter exports ORM natively via the Godot export preset. Go to File > Export Textures, select the Godot preset, and you will see an `ORM` channel in the output list. The preset packs R=AO, G=Roughness, B=Metallic — exactly what Godot 4 expects. No manual compositing needed.

```
# Substance Painter Godot export checklist
[x] Preset: Godot Engine (or manual)
[x] ORM output: R=AO, G=Roughness, B=Metallic
[x] Albedo output: sRGB color space
[x] Normal output: OpenGL convention (NOT DirectX)
[x] Resolution: power-of-two (512, 1024, 2048)
[x] Format: PNG (lossless for import into Godot)
```

Important: Substance Painter uses DirectX normal maps by default. Godot 4 expects OpenGL convention (Y-axis flipped). Either flip Y in the export preset or enable Flip Normal Map Y on your Godot material — never both.

Importing and Configuring ORM Materials in Godot 4

Once your ORM PNG is in your project, Godot's importer needs the correct settings:

  1. Select the ORM texture in the FileSystem panel.
  2. In Import settings, set Compress Mode to VRAM Compressed — Godot will compress to BC5/BC7 on desktop and ETC2 on mobile.
  3. Do not enable sRGB for ORM textures — occlusion, roughness, and metallic data is linear. Importing as sRGB applies a gamma curve that destroys material accuracy.
  4. Keep mipmaps enabled for all 3D surface materials.

After import, create a new `StandardMaterial3D`, assign the ORM texture to all three PBR channels as shown in the GDScript above, and connect your albedo and normal maps in their respective slots. The complete material stack for a game-ready asset:

Four texture files. All PBR properties covered. This is the asset format expected by the BitSoul marketplace for compatible GLB game-ready packs.

Performance Tips and Common Pitfalls

Mip-map bleeding on ORM boundaries. When roughness transitions sharply across a UV seam, lower mip levels blend those values and create a visible band at distance. Pad your UV islands by at least 4 texels at 1024 resolution (8 texels at 2048) to eliminate this.

Metallic fringing on edges. If your metallic mask has anti-aliased edges, partially metallic pixels produce physically impossible results. Keep metallic maps binary — fully 0 or fully 1 — except for intentional worn-metal transitions.

AO too strong on direct light. Setting `ao_light_affect` above 0.0 makes crevices look unnaturally dark in direct sunlight. Keep it at 0.0 and let the shadow system handle direct occlusion.

Wrong specular on non-metals. The default `metallic_specular` of 0.5 (4% F0 reflectance) is correct for most plastics, stone, and wood. If your dielectric material looks too dull or too shiny, tweak this value rather than faking it with metallic values above 0.0.

```gdscript
# Quick validation: confirm channel assignments
func validate_orm_material(mat: StandardMaterial3D) -> void:
assert(mat.ao_texture == mat.roughness_texture, "ORM: AO and Roughness must share texture")
assert(mat.roughness_texture == mat.metallic_texture, "ORM: All three must share texture")
assert(mat.ao_texture_channel == BaseMaterial3D.TEXTURE_CHANNEL_RED, "ORM: AO must read Red")
assert(mat.roughness_texture_channel == BaseMaterial3D.TEXTURE_CHANNEL_GREEN, "ORM: Roughness must read Green")
assert(mat.metallic_texture_channel == BaseMaterial3D.TEXTURE_CHANNEL_BLUE, "ORM: Metallic must read Blue")
print("Material validated: ORM channels correctly configured.")
```

ORM textures pay dividends at every scale — whether you are shipping a mobile game with aggressive memory budgets or a desktop title targeting 4K. One bind, three properties, physically accurate results. Once it clicks, you will never go back to separate channel textures.

Ready to test your ORM-ready assets in a real game engine? Browse game-ready 3D models with pre-packed ORM maps at the BitSoul marketplace — every asset is vetted for correct channel packing and Godot 4 compatibility out of the box.

Tags: Godot 4 PBR ORM textures StandardMaterial3D 3D materials game development texture workflow

Skip the modelling — download it instead

A free BitSoul account gets you 2 game-ready models every month plus 25 AI Engine credits to generate one of your own, no card required. Clean topology, PBR textures, and GLB downloads that drop straight into Unreal, Unity, Godot or Blender — plus OBJ and 3D-printable STL export.

Create a free account → Browse 846 models