MaterialPropertyBlocks
Override material properties per object without manually cloning materials
MaterialPropertyBlocks let you customize material properties on individual objects while sharing the same base material. This provides a clean API for per-object variations without manually cloning materials.
::: tip Available since 4.14.0 MaterialPropertyBlocks were introduced in Needle Engine 4.14.0. :::
What are MaterialPropertyBlocks?
In traditional Three.js, if you want multiple objects to have different colors but use the same material, you'd need to clone the material for each object. This is tedious, can lead to memory bloat with many material instances, and makes it harder to manage variants that share some settings - for example, objects that need individual lightmaps or custom reflection probes while sharing the same base material.
MaterialPropertyBlocks solve this by allowing per-object property overrides that are applied dynamically during rendering, without manually creating new material instances.
How they work:
Override properties are temporarily applied in
onBeforeRenderOriginal values are restored in
onAfterRenderShader defines are managed automatically for correct shader compilation
Per-object texture transforms are supported
Benefits:
✅ Clean API for per-object material variations
✅ No manual material cloning required
✅ Automatic memory management via WeakMaps
✅ Works transparently with Groups and child meshes
✅ Supports any Three.js material property
::: info Note on Batching MaterialPropertyBlocks don't change Three.js's default rendering behavior - each mesh is still rendered as a separate draw call, just as it would be without property blocks. For GPU-level batching, you'd need to use InstancedMesh or BatchedMesh regardless of whether you use MaterialPropertyBlocks. :::
Built-in Features Using MaterialPropertyBlocks
Needle Engine uses MaterialPropertyBlocks under the hood for several features - so you get the benefits automatically without writing any code:
Lightmaps - Apply unique lightmap textures to objects (Sample)
Reflection Probes - Per-object environment maps (Sample)
See-Through Component - Dynamic transparency effects (Sample)
Quick Start
Basic Usage
Important: Always use MaterialPropertyBlock.get(object) to obtain a property block. The constructor is protected and should not be called directly.
Core API
Getting a MaterialPropertyBlock
Setting Property Overrides
Supported property types:
number- Roughness, metalness, opacity, etc.number[]- Array uniformsColor- Base color, emissive color, etc.Texture- Albedo maps, normal maps, lightmaps, etc.Vector2,Vector3,Vector4- UV offsets, custom shader parametersEuler- Rotation values (e.g.,envMapRotation)boolean- Flags liketransparentnull- To clear a property
Essentially, any property that exists on a Three.js material can be overridden.
Getting Override Values
Removing Overrides
Advanced Features
Shader Defines
Set shader defines that affect shader compilation per object:
Use cases:
Enable/disable shader features per object
Quality level variations
Custom shader behavior per instance
Type-Safe Overrides
When using TypeScript with specific material types, you get full type safety:
Working with Groups
MaterialPropertyBlocks automatically handle Three.js Group objects:
Common Use Cases
1. Lightmapping
Apply unique lightmap textures to objects sharing the same material:
2. Reflection Probes
Apply different environment maps per object:
3. See-Through Effect
Create X-ray or see-through effects by dynamically changing transparency:
4. Color Variations
Create color variations across instanced objects:
5. Dynamic Material Properties
Animate or change material properties at runtime:
6. Texture Tiling and Offset
Apply different UV transforms per object:
Transparent and Opaque Rendering
One unique feature of MaterialPropertyBlocks is the ability to render the same material as both transparent and opaque on different objects.
This is handled automatically by the engine's render list management system.
Performance Considerations
How it Works Under the Hood
MaterialPropertyBlocks modify material properties temporarily during rendering:
Properties are applied in
onBeforeRenderOriginal values are restored in
onAfterRenderUniforms are re-uploaded per object when values differ
This has the same rendering cost as cloning materials would. The key advantage is that MaterialPropertyBlocks provide a much cleaner API and make it easier to reason about your code.
Benefits
Developer Experience:
✅ No manual material cloning or management
✅ Clean API for per-object variations
✅ Easy to add/remove overrides dynamically
✅ Works transparently with the component system
Memory:
✅ No cloned Material objects in JavaScript heap
✅ Automatic cleanup via WeakMaps
✅ Single shader program shared across objects (when defines match)
Best Practices
✅ Do:
Use for per-object variations (colors, textures, parameters)
Use for dynamic property changes at runtime
Use for lightmaps and environment maps
❌ Don't:
Use if all objects should have the same value (just modify the shared material directly)
Troubleshooting
Properties not updating
Problem: Override values not visible in rendered output.
Solutions:
Ensure you're calling
MaterialPropertyBlock.get()(not creating instances manually)Verify the property name matches the material's property exactly (e.g.,
colornotColor)Check that the object has a material assigned
Confirm the object is actually rendering
Shader defines not working
Problem: Custom defines not affecting shader behavior.
Solutions:
Ensure defines are set before the first render
Check that define values are the correct type (usually numbers)
Verify the shader actually uses the define you're setting
TypeScript API Reference
For complete API documentation including all methods, properties, and type definitions, see:
MaterialPropertyBlock API Documentation
Examples
Complete Example: Object Highlighter
Related Documentation
Lightmapping in Blender - Baking lightmaps
Unity Lightmapping - Unity lightmap workflow
See-Through Component - X-ray effect component
Custom Shaders - Creating custom materials
Scripting Guide - Creating components
Need Help?
Discord Community - Ask questions about MaterialPropertyBlocks
Forum - Share your use cases and examples
GitHub Issues - Report bugs or request features
Last updated