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
Procedural Weathering in Blender with Geometry Nodes: Edge Wear, Rust, and Dirt 
BlenderGeometry NodesProcedural GenerationGame DevelopmentMaterials

Procedural weathering is one of those techniques that separates polished game art from placeholder assets. A pristine sword looks like a 3D model. A sword with worn edges, subtle rust spots near the guard, and accumulated grime in the fuller looks like something that exists in a world. The difference is weathering — and doing it procedurally in Blender means you can apply it to any mesh, adjust the intensity with a slider, and never touch a paintbrush.

This tutorial covers three core weathering effects using Blender's Geometry Nodes: curvature-based edge wear, gravity-driven dirt accumulation, and Voronoi-pattern rust. These techniques work on any mesh topology and produce vertex color attributes that export to game engines.

Why Geometry Nodes Instead of Shader Nodes?

The critical difference between shader-based and geometry-based weathering is mesh awareness. Shader nodes operate in UV space or object space — they do not know where edges are, which surfaces face up, or where cavities exist on the actual mesh. Geometry Nodes can analyze the mesh itself:

  • Curvature detection identifies convex edges (corners, ridges) and concave regions (crevices, joints)
  • Normal direction tells you which surfaces face up (dust accumulates there) and which face down (protected from rain)
  • Proximity fields can detect how close one surface is to another (dirt gathers where objects meet)

This mesh awareness produces weathering that follows the actual geometry — paint chips on exposed edges, rust forms in recessed areas, dirt accumulates on upward-facing horizontal surfaces. Shader-only approaches can approximate this with procedural noise, but the results always look random rather than physically motivated.

Technique 1: Curvature-Based Edge Wear

Edge wear is the most visually impactful weathering effect. In reality, protruding edges receive more physical contact — hands grip them, objects bump against them, paint wears off first at corners. Reproducing this in Blender requires detecting high-curvature convex regions.

The Approach

Blender does not have a native "curvature" node in Geometry Nodes, but you can approximate it by comparing each vertex's normal to its neighbors' normals. Where normals diverge sharply (high curvature), you have an edge or corner.

Here is the node setup:

  1. Mesh to Points — Convert the mesh to a point cloud for per-vertex analysis
  2. Sample Nearest Surface — For each point, sample nearby points on the mesh
  3. Normal comparison — Compare each vertex normal to the sampled normals. Large differences indicate high curvature
  4. Map Range — Normalize the curvature values to 0-1
  5. Float Curve — Shape the falloff (sharp cutoff for crisp edge lines, gradual falloff for broader wear)
  6. Store Named Attribute — Write the result as a vertex color attribute called edge_wear

A simplified version uses the Edge Angle node on the mesh edges:

Edge Angle → Greater Than (threshold ~0.3 radians)
→ Blur Attribute (spread the mask to nearby vertices)
→ Map Range (normalize)
→ Store Named Attribute ("edge_wear")

Controlling the Effect

Key parameters to expose as Group Inputs:

  • Threshold angle — How sharp an edge must be to show wear (lower = more wear, higher = only sharp corners)
  • Blur radius — How far the wear spreads from edges (small = crisp paint chips, large = broad polish/rub marks)
  • Intensity — Overall strength multiplier
  • Noise break-up — Multiply with a noise pattern to prevent uniform wear (real wear is irregular)

The noise break-up is important. Without it, every edge wears identically, which looks artificial. Adding a Noise Texture multiplied against the curvature mask creates patches where wear is heavier or lighter, mimicking real physical variation.

Using It in Materials

In your shader nodes, read the edge_wear attribute with an Attribute node and use it to mix between your base material and a worn material:

Attribute("edge_wear") → Mix Shader Factor
  Shader A: Base paint/coating material
  Shader B: Exposed underlayer (bare metal, wood grain, primer)

Technique 2: Gravity-Based Dirt Accumulation

Dirt, dust, and moss accumulate on surfaces based on gravity. Horizontal upward-facing surfaces collect the most. Vertical surfaces collect less. Overhangs and undersides stay clean.

The Approach

This is simpler than edge detection because Blender's Geometry Nodes give you direct access to face normals:

  1. Normal node — Get the surface normal in world space
  2. Separate XYZ — Extract the Z component
  3. Map Range — Map Z normal from your desired range (e.g., 0.3 to 1.0) to 0-1. This means surfaces between horizontal (Z=1) and slightly tilted (Z=0.3) receive dirt
  4. Clamp — Ensure values stay in 0-1
  5. Noise multiplication — Multiply with a Noise Texture for organic variation
  6. Store Named Attribute — Save as dirt_accumulation
Normal → Separate XYZ → Z component
→ Map Range (0.3-1.0 → 0.0-1.0)
→ Multiply (Noise Texture for break-up)
→ Store Named Attribute ("dirt_accumulation")

Advanced: Cavity Dirt

Dirt does not just sit on top — it accumulates in crevices, seams, and joints. Combine the gravity mask with a concave curvature mask (the inverse of the edge wear detection) to create cavity dirt:

  • Concave curvature — Where normals converge (the inside of corners)
  • Combine with gravity mask using Maximum or Add (clamped)

This produces dirt on horizontal surfaces AND in crevices, which matches real-world accumulation patterns.

Parameters to Expose

  • Angle threshold — How tilted a surface can be and still collect dirt (90 degrees = only perfectly horizontal, lower = more surfaces affected)
  • Noise scale — Size of the dirt pattern variation
  • Cavity strength — How much extra dirt appears in crevices
  • Overall intensity — Global multiplier

Technique 3: Voronoi Rust Patterns

Rust does not form in smooth gradients or regular noise patterns. It forms in cell-like patches that expand outward from initiation points — places where the protective coating failed first. The Voronoi texture in Blender is perfect for this because it naturally produces cell-like patterns.

The Approach

  1. Voronoi Texture — Set to F1 distance mode, which produces organic cell boundaries
  2. Scale control — Adjust scale to control the size of rust patches
  3. Color Ramp — Shape the Voronoi output to create distinct rust patches with soft edges
  4. Noise modulation — Add a Noise Texture to break up the regularity
  5. Combine with cavity/moisture mask — Rust forms preferentially in areas where water collects
  6. Store Named Attribute — Save as rust
Voronoi Texture (F1, scale ~4.0)
→ Color Ramp (sharpen to create distinct patches)
→ Multiply (Noise Texture for irregularity)
→ Multiply (moisture/cavity mask for physical plausibility)
→ Store Named Attribute ("rust")

Making Rust Physically Plausible

Real rust behavior to simulate:

  • Rust starts in damaged areas — Multiply the rust mask with the edge wear mask. Where paint has worn off, rust can begin
  • Rust spreads downward from initiation points — Use the gravity mask (inverted from dirt — rain runs down) to bias rust spread
  • Rust is rougher than the base material — When mixing materials, increase roughness in rusted areas (rust roughness ~0.8-0.95)
  • Heavy rust raises the surface — Add slight displacement in heavily rusted areas to simulate the volume of rust buildup

The combination of Voronoi patches, edge-wear initiation, and gravity-influenced spread produces rust patterns that look motivated rather than random.

Exporting to Game Engines

All three techniques store their results as vertex color attributes. This is intentional — vertex colors are the most universal data transfer format between 3D applications and game engines.

Export Workflow

  1. Apply the Geometry Nodes modifier (or keep it live if your engine supports it)
  2. Verify attributes — In Blender's Spreadsheet editor, confirm that edge_wear, dirt_accumulation, and rust attributes exist as vertex colors
  3. Export as FBX — Enable "Vertex Colors" in the FBX export settings. Blender exports named vertex color layers which most engines can read
  4. In Unreal Engine — Access vertex colors in the material using the Vertex Color node. Each channel (R, G, B, A) can carry a different mask

Channel Packing for Export

Since vertex colors have four channels (RGBA), you can pack multiple masks:

ChannelMask
REdge wear
GDirt accumulation
BRust
AReserved / custom

This is more efficient than multiple vertex color sets and works with every game engine.

In your Unreal material:

Vertex Color → Break into R, G, B
  R (edge_wear) → Mix between base material and worn underlayer
  G (dirt_accumulation) → Mix in dirt/dust overlay
  B (rust) → Mix in rust material with increased roughness

Building a Complete Weathering Stack

The three techniques combine naturally into a full weathering system:

  1. Start with edge wear — This establishes where protective coatings have failed
  2. Layer rust on exposed areas — Multiply rust with edge wear for physical plausibility
  3. Add dirt accumulation — Dirt settles on top of everything, including rusted areas
  4. Fine-tune with global controls — Age slider that scales all effects simultaneously

The layering order matters. A freshly damaged object has edge wear but no rust or dirt. An old object has all three. By exposing an "age" parameter that progressively enables each layer, you get a single slider that takes an object from new to ancient.

The Faster Path: Pre-Built Systems

Building this entire system from scratch in Geometry Nodes is educational and gives you complete control, but it is also 15-20 hours of work to get production-ready with proper controls, edge cases handled, and good performance. The node trees get complex — a full weathering system can easily be 200+ nodes across multiple node groups.

The Procedural Damage & Wear System provides all of these techniques (and several more — scratches, paint chipping, water stains, moss growth) as a ready-to-use Geometry Nodes setup with exposed slider controls. It handles the edge cases that take the most time to solve manually: performance optimization for high-poly meshes, proper attribute interpolation across subdivision levels, and correct behavior on non-manifold geometry.

Whether you build your own system or use a pre-built one, the underlying principles are the same: detect mesh features with Geometry Nodes, generate masks, store as vertex colors, and use those masks in your material to blend between clean and weathered states.

Performance Considerations

Geometry Nodes weathering adds computation cost. For real-time preview performance:

  • Reduce evaluation frequency — Use Geometry Nodes only for baking, not real-time viewport display on high-poly meshes
  • Blur operations are expensive — The Blur Attribute node on dense meshes can be slow. Pre-compute and cache results when possible
  • Bake to textures for final export — For game engine use, vertex colors work well for simple cases. For dense weathering detail, bake the Geometry Nodes output to texture maps, which have zero runtime cost in the engine

A good workflow is to use Geometry Nodes for authoring and preview, then bake the results to textures before exporting to your game engine. This gives you the mesh-aware generation of Geometry Nodes with the zero-cost runtime of pre-baked textures.

Conclusion

Procedural weathering through Geometry Nodes gives you something that no other approach can: mesh-aware aging effects that adapt to any geometry automatically. Once you build or acquire a weathering system, you can apply it to every asset in your game with consistent quality. A chair, a weapon, a building facade — the same weathering nodes produce appropriate results on each because they read the actual mesh geometry.

The techniques covered here — curvature-based edge wear, gravity-driven dirt, and Voronoi rust patterns — form the foundation of believable environmental storytelling. A world where every object shows its history feels alive. Procedural weathering is how you get there without painting every asset by hand.

Tags

BlenderGeometry NodesProcedural GenerationGame DevelopmentMaterials

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