godot-3d-materials

Expert patterns for Godot 3D PBR materials using StandardMaterial3D including albedo, metallic/roughness workflows, normal maps, ORM texture packing, transparency modes, and shader conversion. Use when creating realistic 3D surfaces, PBR workflows, or material optimization. Trigger keywords: StandardMaterial3D, BaseMaterial3D, albedo_texture, metallic, metallic_texture, roughness, roughness_texture, normal_texture, normal_enabled, orm_texture, transparency, alpha_scissor, alpha_hash, cull_mode, ShaderMaterial, shader parameters.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "godot-3d-materials" with this command: npx skills add thedivergentai/gd-agentic-skills/thedivergentai-gd-agentic-skills-godot-3d-materials

3D Materials

Expert guidance for PBR materials and StandardMaterial3D in Godot.

NEVER Do

  • NEVER use separate metallic/roughness/AO textures — Use ORM packing (1 RGB texture with Occlusion/Roughness/Metallic channels) to save texture slots and memory.
  • NEVER forget to enable normal_enabled — Normal maps don't work unless you set normal_enabled = true. Silent failure is common.
  • NEVER use TRANSPARENCY_ALPHA for cutout materials — Use TRANSPARENCY_ALPHA_SCISSOR or TRANSPARENCY_ALPHA_HASH instead. Full alpha blending is expensive and causes sorting issues.
  • NEVER set metallic = 0.5 — Materials are either metallic (1.0) or dielectric (0.0). Values between are physically incorrect except for rust/dirt transitions.
  • NEVER use emission without HDR — Emission values > 1.0 only work with HDR rendering enabled in Project Settings.

Available Scripts

MANDATORY: Read the appropriate script before implementing the corresponding pattern.

material_fx.gd

Runtime material property animation for damage effects, dissolve, and texture swapping. Use for dynamic material state changes.

pbr_material_builder.gd

Runtime PBR material creation with ORM textures and triplanar mapping.

organic_material.gd

Subsurface scattering and rim lighting setup for organic surfaces (skin, leaves). Use for realistic character or vegetation materials.

triplanar_world.gdshader

Triplanar projection shader for terrain without UV mapping. Blends textures based on surface normals. Use for cliffs, caves, or procedural terrain.


StandardMaterial3D Basics

PBR Texture Setup

# Create physically-based material
var mat := StandardMaterial3D.new()

# Albedo (base color)
mat.albedo_texture = load("res://textures/wood_albedo.png")
mat.albedo_color = Color.WHITE  # Tint multiplier

# Normal map (surface detail)
mat.normal_enabled = true  # CRITICAL: Must enable first
mat.normal_texture = load("res://textures/wood_normal.png")
mat.normal_scale = 1.0  # Bump strength

# ORM Texture (R=Occlusion, G=Roughness, B=Metallic)
mat.orm_texture = load("res://textures/wood_orm.png")

# Alternative: Separate textures (less efficient)
# mat.roughness_texture = load("res://textures/wood_roughness.png")
# mat.metallic_texture = load("res://textures/wood_metallic.png")
# mat.ao_texture = load("res://textures/wood_ao.png")

# Apply to mesh
$MeshInstance3D.material_override = mat

Metallic vs Roughness

Metal Workflow

# Pure metal (steel, gold, copper)
mat.metallic = 1.0
mat.roughness = 0.2  # Polished metal
mat.albedo_color = Color(0.8, 0.8, 0.8)  # Metal tint

# Rough metal (iron, aluminum)
mat.metallic = 1.0
mat.roughness = 0.7

Dielectric Workflow

# Non-metal (wood, plastic, stone)
mat.metallic = 0.0
mat.roughness = 0.6  # Typical for wood
mat.albedo_color = Color(0.6, 0.4, 0.2)  # Brown wood

# Glossy plastic
mat.metallic = 0.0
mat.roughness = 0.1  # Very smooth

Transition Materials (Rust/Dirt)

# Use texture to blend metal/non-metal
mat.metallic_texture = load("res://rust_mask.png")
# White areas (1.0) = metal
# Black areas (0.0) = rust (dielectric)

Transparency Modes

Decision Matrix

ModeUse CasePerformanceSorting Issues
ALPHA_SCISSORFoliage, chain-link fenceFastNo
ALPHA_HASHDithered fade, LOD transitionsFastNoisy
ALPHAGlass, water, godot-particlesSlowYes (render order)

Alpha Scissor (Cutout)

# For leaves, grass, fences
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA_SCISSOR
mat.alpha_scissor_threshold = 0.5  # Pixels < 0.5 alpha = discarded
mat.albedo_texture = load("res://leaf.png")  # Must  have alpha channel

# Enable backface culling for performance
mat.cull_mode = BaseMaterial3D.CULL_BACK

Alpha Hash (Dithered)

# For smooth fade-outs without sorting issues
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA_HASH
mat.alpha_hash_scale = 1.0  # Dither pattern scale

# Animate fade
var tween := create_tween()
tween.tween_property(mat, "albedo_color:a", 0.0, 1.0)

Alpha Blend (Full Transparency)

# For glass, water (expensive)
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
mat.blend_mode = BaseMaterial3D.BLEND_MODE_MIX

# Disable depth writing for correct blending
mat.depth_draw_mode = BaseMaterial3D.DEPTH_DRAW_DISABLED
mat.cull_mode = BaseMaterial3D.CULL_DISABLED  # Show both sides

Advanced Features

Emission (Glowing Materials)

mat.emission_enabled = true
mat.emission = Color(1.0, 0.5, 0.0)  # Orange glow
mat.emission_energy_multiplier = 2.0  # Brightness (HDR)
mat.emission_texture = load("res://lava_emission.png")

# Animated emission
func _process(delta: float) -> void:
    mat.emission_energy_multiplier = 1.0 + sin(Time.get_ticks_msec() * 0.005) * 0.5

Rim Lighting (Fresnel)

mat.rim_enabled = true
mat.rim = 1.0  # Intensity
mat.rim_tint = 0.5  # How much albedo affects rim color

Clearcoat (Car Paint)

mat.clearcoat_enabled = true
mat.clearcoat = 1.0  # Layer strength
mat.clearcoat_roughness = 0.1  # Glossy top layer

Anisotropy (Brushed Metal)

mat.anisotropy_enabled = true
mat.anisotropy = 1.0  # Directional highlights
mat.anisotropy_flowmap = load("res://brushed_flow.png")

Texture Channel Packing

ORM Texture (Recommended)

# External tool (GIMP, Substance, Python script):
# Combine 3 grayscale textures into 1 RGB:
# R channel = Ambient Occlusion (bright = no occlusion)
# G channel = Roughness (bright = rough)
# B channel = Metallic (bright = metal)
# In Godot:
mat.orm_texture = load("res://textures/material_orm.png")
# This replaces ao_texture, roughness_texture, and metallic_texture!

Custom Packing

# If using custom channel assignments:
mat.roughness_texture_channel = BaseMaterial3D.TEXTURE_CHANNEL_GREEN
mat.metallic_texture_channel = BaseMaterial3D.TEXTURE_CHANNEL_BLUE

Shader Conversion

When to Convert to ShaderMaterial

  • Need custom effects (dissolve, vertex displacement)
  • StandardMaterial3D limitations hit
  • Shader optimizations (remove unused features)

Conversion Workflow

# 1. Create StandardMaterial3D with all settings
var std_mat := StandardMaterial3D.new()
std_mat.albedo_color = Color.RED
std_mat.metallic = 1.0
std_mat.roughness = 0.2

# 2. Convert to ShaderMaterial
var shader_mat := ShaderMaterial.new()
shader_mat.shader = load("res://custom_shader.gdshader")

# 3. Transfer parameters manually
shader_mat.set_shader_parameter("albedo", std_mat.albedo_color)
shader_mat.set_shader_parameter("metallic", std_mat.metallic)
shader_mat.set_shader_parameter("roughness", std_mat.roughness)

Material Variants (Godot 4.0+)

Efficient Material Reuse

# Base material (shared)
var base_red_metal := StandardMaterial3D.new()
base_red_metal.albedo_color = Color.RED
base_red_metal.metallic = 1.0

# Variant 1: Rough
var rough_variant := base_red_metal.duplicate()
rough_variant.roughness = 0.8

# Variant 2: Smooth
var smooth_variant := base_red_metal.duplicate()
smooth_variant.roughness = 0.1

# Note: Use resource_local_to_scene for per-instance tweaks

Performance Optimization

Material Batching

# ✅ GOOD: Reuse materials across meshes
const SHARED_STONE := preload("res://materials/stone.tres")

func _ready() -> void:
    for wall in get_tree().get_nodes_in_group("stone_walls"):
        wall.material_override = SHARED_STONE
    # All walls batched in single draw call

# ❌ BAD: Unique material per mesh
func _ready() -> void:
    for wall in get_tree().get_nodes_in_group("stone_walls"):
        var mat := StandardMaterial3D.new()  # New material!
        mat.albedo_color = Color(0.5, 0.5, 0.5)
        wall.material_override = mat
    # Each wall is separate draw call

Texture Atlasing

# Combine multiple materials into one texture atlas
# Then use UV offsets to select regions

# material_atlas.gd
extends StandardMaterial3D

func set_atlas_region(tile_x: int, tile_y: int, tiles_per_row: int) -> void:
    var tile_size := 1.0 / tiles_per_row
    uv1_offset = Vector3(tile_x * tile_size, tile_y * tile_size, 0)
    uv1_scale = Vector3(tile_size, tile_size, 1)

Edge Cases

Normal Maps Not Working

# Problem: Forgot to enable
mat.normal_enabled = true  # REQUIRED

# Problem: Wrong texture import settings
# In Import tab: Texture → Normal Map = true

Texture Seams on Models

# Problem: Mipmaps causing seams
# Solution: Disable mipmaps for tightly-packed UVs
# Import → Mipmaps → Generate = false

Material Looks Flat

# Problem: Missing normal map or roughness variation
# Solution: Add normal map + roughness texture

mat.normal_enabled = true
mat.normal_texture = load("res://normal.png")
mat.roughness_texture = load("res://roughness.png")

Common Material Presets

# Glass
func create_glass() -> StandardMaterial3D:
    var mat := StandardMaterial3D.new()
    mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
    mat.albedo_color = Color(1, 1, 1, 0.2)
    mat.metallic = 0.0
    mat.roughness = 0.0
    mat.refraction_enabled = true
    mat.refraction_scale = 0.05
    return mat

# Gold
func create_gold() -> StandardMaterial3D:
    var mat := StandardMaterial3D.new()
    mat.albedo_color = Color(1.0, 0.85, 0.3)
    mat.metallic = 1.0
    mat.roughness = 0.3
    return mat

Reference

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

godot-master

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

godot-shaders-basics

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

godot-ui-theming

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

godot-particles

No summary provided by upstream source.

Repository SourceNeeds Review