threejs-syntax-materials
Quick Reference
Material Type Decision Tree
| Use Case |
Material |
Why |
| UI elements, unlit scenes |
MeshBasicMaterial |
Cheapest, no light computation |
| Matte diffuse (low-end devices) |
MeshLambertMaterial |
Fast diffuse, no specular |
| Legacy specular highlights |
MeshPhongMaterial |
Blinn-Phong model, not physically correct |
| General-purpose 3D (recommended) |
MeshStandardMaterial |
PBR metalness/roughness, industry standard |
| Glass, car paint, fabric, soap bubbles |
MeshPhysicalMaterial |
Advanced PBR (clearcoat, transmission, sheen, iridescence) |
| Cartoon/anime style |
MeshToonMaterial |
Discrete cel-shading steps |
| Sculpting previews, no lights |
MeshMatcapMaterial |
Matcap texture, zero light setup |
| Debug normals |
MeshNormalMaterial |
RGB = surface normal direction |
| Invisible shadow receiver |
ShadowMaterial |
Transparent shadow catcher |
| Solid lines |
LineBasicMaterial |
Simple colored lines |
| Dashed lines |
LineDashedMaterial |
Requires line.computeLineDistances() |
| Particles |
PointsMaterial |
Point cloud rendering |
| Billboards |
SpriteMaterial |
Always-facing-camera quads |
Base Material Properties (All Materials)
| Property |
Type |
Default |
Description |
side |
number |
FrontSide |
FrontSide, BackSide, or DoubleSide |
transparent |
boolean |
false |
Enable alpha blending |
opacity |
number |
1 |
Requires transparent: true to take effect below 1 |
depthWrite |
boolean |
true |
Write to depth buffer |
depthTest |
boolean |
true |
Test against depth buffer |
blending |
number |
NormalBlending |
NoBlending, AdditiveBlending, SubtractiveBlending, MultiplyBlending, CustomBlending |
alphaTest |
number |
0 |
Discard fragments with alpha below this value |
visible |
boolean |
true |
Whether to render this material |
wireframe |
boolean |
false |
Wireframe rendering mode |
fog |
boolean |
true |
Affected by scene fog |
clippingPlanes |
Plane[] |
null |
Array of clipping planes |
clipIntersection |
boolean |
false |
Clip where ALL planes intersect (vs union) |
needsUpdate |
boolean |
false |
Set true to trigger shader recompilation |
toneMapped |
boolean |
true |
Apply renderer tone mapping |
Base Material Methods
| Method |
Signature |
Description |
clone |
(): Material |
Clone the material |
copy |
(source: Material): Material |
Copy properties from source |
dispose |
(): void |
Free GPU resources -- ALWAYS call when removing |
onBeforeCompile |
(shader, renderer): void |
Hook to modify shader before compilation |
setValues |
(values: Object): void |
Set multiple properties at once |
Critical Warnings
NEVER set opacity < 1 without transparent: true -- the opacity value is silently ignored. ALWAYS pair them together.
NEVER use MeshPhysicalMaterial when MeshStandardMaterial suffices -- Physical compiles a significantly larger shader. ONLY use it when you need clearcoat, transmission, sheen, iridescence, or anisotropy.
NEVER set SRGBColorSpace on normal maps, roughness maps, metalness maps, or any data texture -- this corrupts the data and causes incorrect lighting. ONLY set SRGBColorSpace on diffuse/color/emissive textures.
NEVER forget to call material.dispose() and texture.dispose() when removing objects -- GPU memory leaks accumulate and crash the application.
NEVER set linewidth > 1 on LineBasicMaterial -- it is silently ignored on most platforms due to WebGL limitations. ALWAYS use Line2 + LineMaterial from three/addons/lines/ for thick lines.
ALWAYS set material.needsUpdate = true after changing properties that affect shader compilation (e.g., toggling flatShading, changing side, adding/removing texture maps at runtime).
ALWAYS set wrapS and wrapT to RepeatWrapping when using texture.repeat values other than (1, 1) -- the default ClampToEdgeWrapping does NOT tile textures.
MeshStandardMaterial (PBR)
The recommended material for most 3D scenes. Uses physically-based metalness/roughness workflow.
import { MeshStandardMaterial, TextureLoader, SRGBColorSpace, RepeatWrapping } from 'three';
const loader = new TextureLoader();
const material = new MeshStandardMaterial({
color: 0xffffff,
roughness: 0.7, // 0 = mirror, 1 = fully rough
metalness: 0.0, // 0 = dielectric, 1 = metal
map: null, // Diffuse/albedo texture
roughnessMap: null, // Per-pixel roughness
metalnessMap: null, // Per-pixel metalness
normalMap: null, // Surface normal perturbation
normalScale: new Vector2(1, 1),
aoMap: null, // Ambient occlusion (requires uv2)
aoMapIntensity: 1.0,
emissive: 0x000000, // Emissive color
emissiveMap: null, // Emissive texture
emissiveIntensity: 1.0,
envMap: null, // Environment reflection map
envMapIntensity: 1.0,
bumpMap: null, // Grayscale height map
bumpScale: 1.0,
displacementMap: null, // Vertex displacement map
displacementScale: 1.0,
displacementBias: 0.0,
alphaMap: null, // Per-pixel transparency
lightMap: null, // Baked lighting (requires uv2)
lightMapIntensity: 1.0,
flatShading: false,
wireframe: false,
fog: true
});
MeshPhysicalMaterial (Advanced PBR)
Extends MeshStandardMaterial with ALL its properties, plus:
| Property |
Type |
Default |
Description |
clearcoat |
float |
0.0 |
Clear coat layer intensity (0-1) |
clearcoatRoughness |
float |
0.0 |
Clear coat roughness |
clearcoatMap |
Texture |
null |
Clear coat intensity map |
clearcoatNormalMap |
Texture |
null |
Clear coat normal map |
transmission |
float |
0.0 |
Physically-based transparency (0-1) |
transmissionMap |
Texture |
null |
Transmission map |
thickness |
float |
0.0 |
Volume thickness for transmission |
thicknessMap |
Texture |
null |
Thickness map |
ior |
float |
1.5 |
Index of refraction (1.0-2.333) |
attenuationDistance |
float |
Infinity |
Light attenuation distance in volume |
attenuationColor |
Color |
white |
Light attenuation tint |
sheen |
float |
0.0 |
Sheen layer intensity (fabric-like) |
sheenColor |
Color |
0x000000 |
Sheen tint color |
sheenRoughness |
float |
1.0 |
Sheen roughness |
iridescence |
float |
0.0 |
Thin-film interference (0-1) |
iridescenceIOR |
float |
1.3 |
Iridescence index of refraction |
iridescenceThicknessRange |
[float, float] |
[100, 400] |
Thin-film thickness range (nm) |
anisotropy |
float |
0.0 |
Anisotropic reflection strength |
anisotropyRotation |
float |
0.0 |
Anisotropy rotation (radians) |
specularIntensity |
float |
1.0 |
Specular layer intensity |
specularColor |
Color |
white |
Specular tint color |
dispersion |
float |
0.0 |
Chromatic dispersion (rainbow effect) |
reflectivity |
float |
0.5 |
Reflectivity at normal incidence |
Texture System
Color Space Rules (Critical)
| Map Type |
Color Space |
Channels Used |
map (diffuse/albedo) |
SRGBColorSpace |
RGB(A) |
emissiveMap |
SRGBColorSpace |
RGB |
lightMap |
SRGBColorSpace |
RGB |
envMap |
SRGBColorSpace |
RGB |
sheenColorMap |
SRGBColorSpace |
RGB |
specularColorMap |
SRGBColorSpace |
RGB |
normalMap |
NoColorSpace |
RGB |
roughnessMap |
NoColorSpace |
G channel |
metalnessMap |
NoColorSpace |
B channel |
aoMap |
NoColorSpace |
R channel |
bumpMap |
NoColorSpace |
R channel |
displacementMap |
NoColorSpace |
R channel |
alphaMap |
NoColorSpace |
R channel |
clearcoatMap |
NoColorSpace |
R channel |
clearcoatRoughnessMap |
NoColorSpace |
R channel |
clearcoatNormalMap |
NoColorSpace |
RGB |
transmissionMap |
NoColorSpace |
R channel |
thicknessMap |
NoColorSpace |
R channel |
iridescenceMap |
NoColorSpace |
R channel |
iridescenceThicknessMap |
NoColorSpace |
R channel |
sheenRoughnessMap |
NoColorSpace |
R channel |
anisotropyMap |
NoColorSpace |
RG channels |
specularIntensityMap |
NoColorSpace |
A channel |
Rule: Diffuse/emissive/color textures = SRGBColorSpace. ALL data textures = NoColorSpace. Getting this wrong causes washed-out or over-saturated rendering.
Texture Loaders
| Loader |
Format |
Import |
TextureLoader |
PNG, JPG, WebP |
three core |
CubeTextureLoader |
6x PNG/JPG cube maps |
three core |
RGBELoader |
.hdr (Radiance HDR) |
three/addons/loaders/RGBELoader.js |
EXRLoader |
.exr (OpenEXR HDR) |
three/addons/loaders/EXRLoader.js |
KTX2Loader |
.ktx2 (GPU compressed) |
three/addons/loaders/KTX2Loader.js |
Wrapping Modes
| Constant |
Description |
ClampToEdgeWrapping |
Edge texels stretched (default) |
RepeatWrapping |
Texture tiles/repeats |
MirroredRepeatWrapping |
Tiles with alternating mirror |
Filter Modes
| Constant |
Type |
Description |
NearestFilter |
Mag/Min |
Pixelated, crisp (retro, toon gradients) |
LinearFilter |
Mag/Min |
Smooth interpolation |
LinearMipmapLinearFilter |
Min |
Trilinear filtering (default, best quality) |
Texture Properties
| Property |
Type |
Default |
Description |
wrapS / wrapT |
number |
ClampToEdgeWrapping |
Wrapping mode |
magFilter |
number |
LinearFilter |
Magnification filter |
minFilter |
number |
LinearMipmapLinearFilter |
Minification filter |
anisotropy |
number |
1 |
Anisotropic filtering (max = renderer.capabilities.getMaxAnisotropy()) |
repeat |
Vector2 |
(1, 1) |
UV repeat count |
offset |
Vector2 |
(0, 0) |
UV offset |
rotation |
number |
0 |
UV rotation in radians |
center |
Vector2 |
(0, 0) |
Center of rotation |
flipY |
boolean |
true |
Flip vertically on upload |
colorSpace |
string |
NoColorSpace |
Color space interpretation |
generateMipmaps |
boolean |
true |
Auto-generate mipmaps |
needsUpdate |
boolean |
false |
Trigger GPU re-upload |
flipY Rules
flipY = true (default): Correct for loaded image textures (PNG, JPG)
flipY = false: ALWAYS use for WebGLRenderTarget textures, DataTexture, and framebuffer textures
Material Disposal
// ALWAYS dispose materials and textures when removing objects
function disposeMesh(mesh) {
if (mesh.material) {
// Dispose all texture maps
for (const key of Object.keys(mesh.material)) {
const value = mesh.material[key];
if (value && value.isTexture) {
value.dispose();
}
}
mesh.material.dispose();
}
if (mesh.geometry) {
mesh.geometry.dispose();
}
}
needsUpdate Flag
ALWAYS set material.needsUpdate = true after changing these at runtime:
- Toggling
flatShading
- Changing
side (FrontSide/BackSide/DoubleSide)
- Adding or removing a texture map (e.g., setting
map from null to a texture)
- Changing
transparent or alphaTest
- Toggling
wireframe
- Any property that changes the compiled shader variant
NEVER set needsUpdate = true every frame -- it forces expensive shader recompilation. ONLY set it once after the property change.
For textures: set texture.needsUpdate = true after modifying texture.image data to trigger GPU re-upload.
Toon Material Special Rule
When using MeshToonMaterial, ALWAYS set gradientMap.minFilter = NearestFilter and gradientMap.magFilter = NearestFilter. Linear filtering blurs the discrete shading steps into smooth gradients, defeating the toon effect.
Reference Links
- references/methods.md -- All material types with constructor signatures and key properties
- references/examples.md -- Complete working examples (PBR, textures, multi-material)
- references/anti-patterns.md -- What NOT to do, with explanations
Official Sources
1---2name: threejs-syntax-materials3description: Use when choosing or configuring materials, loading textures, or setting up PBR workflows in Three.js. Prevents the common mistake of wrong color space on textures, forgetting material.dispose(), or not calling material.needsUpdate after changes. Covers all 15+ material types, PBR metalness/roughness, MeshPhysicalMaterial, texture maps, color space. Keywords: MeshStandardMaterial, MeshPhysicalMaterial, material, texture, PBR, metalness, roughness, normalMap, color space, SRGBColorSpace, blurry texture, pixelated, texture quality, filtering.4license: MIT5---67# threejs-syntax-materials89## Quick Reference1011### Material Type Decision Tree1213| Use Case | Material | Why |14|----------|----------|-----|15| UI elements, unlit scenes | `MeshBasicMaterial` | Cheapest, no light computation |16| Matte diffuse (low-end devices) | `MeshLambertMaterial` | Fast diffuse, no specular |17| Legacy specular highlights | `MeshPhongMaterial` | Blinn-Phong model, not physically correct |18| General-purpose 3D (recommended) | `MeshStandardMaterial` | PBR metalness/roughness, industry standard |19| Glass, car paint, fabric, soap bubbles | `MeshPhysicalMaterial` | Advanced PBR (clearcoat, transmission, sheen, iridescence) |20| Cartoon/anime style | `MeshToonMaterial` | Discrete cel-shading steps |21| Sculpting previews, no lights | `MeshMatcapMaterial` | Matcap texture, zero light setup |22| Debug normals | `MeshNormalMaterial` | RGB = surface normal direction |23| Invisible shadow receiver | `ShadowMaterial` | Transparent shadow catcher |24| Solid lines | `LineBasicMaterial` | Simple colored lines |25| Dashed lines | `LineDashedMaterial` | Requires `line.computeLineDistances()` |26| Particles | `PointsMaterial` | Point cloud rendering |27| Billboards | `SpriteMaterial` | Always-facing-camera quads |2829### Base Material Properties (All Materials)3031| Property | Type | Default | Description |32|----------|------|---------|-------------|33| `side` | `number` | `FrontSide` | `FrontSide`, `BackSide`, or `DoubleSide` |34| `transparent` | `boolean` | `false` | Enable alpha blending |35| `opacity` | `number` | `1` | Requires `transparent: true` to take effect below 1 |36| `depthWrite` | `boolean` | `true` | Write to depth buffer |37| `depthTest` | `boolean` | `true` | Test against depth buffer |38| `blending` | `number` | `NormalBlending` | `NoBlending`, `AdditiveBlending`, `SubtractiveBlending`, `MultiplyBlending`, `CustomBlending` |39| `alphaTest` | `number` | `0` | Discard fragments with alpha below this value |40| `visible` | `boolean` | `true` | Whether to render this material |41| `wireframe` | `boolean` | `false` | Wireframe rendering mode |42| `fog` | `boolean` | `true` | Affected by scene fog |43| `clippingPlanes` | `Plane[]` | `null` | Array of clipping planes |44| `clipIntersection` | `boolean` | `false` | Clip where ALL planes intersect (vs union) |45| `needsUpdate` | `boolean` | `false` | Set `true` to trigger shader recompilation |46| `toneMapped` | `boolean` | `true` | Apply renderer tone mapping |4748### Base Material Methods4950| Method | Signature | Description |51|--------|-----------|-------------|52| `clone` | `(): Material` | Clone the material |53| `copy` | `(source: Material): Material` | Copy properties from source |54| `dispose` | `(): void` | Free GPU resources -- ALWAYS call when removing |55| `onBeforeCompile` | `(shader, renderer): void` | Hook to modify shader before compilation |56| `setValues` | `(values: Object): void` | Set multiple properties at once |5758### Critical Warnings5960**NEVER** set `opacity < 1` without `transparent: true` -- the opacity value is silently ignored. ALWAYS pair them together.6162**NEVER** use `MeshPhysicalMaterial` when `MeshStandardMaterial` suffices -- Physical compiles a significantly larger shader. ONLY use it when you need clearcoat, transmission, sheen, iridescence, or anisotropy.6364**NEVER** set `SRGBColorSpace` on normal maps, roughness maps, metalness maps, or any data texture -- this corrupts the data and causes incorrect lighting. ONLY set `SRGBColorSpace` on diffuse/color/emissive textures.6566**NEVER** forget to call `material.dispose()` and `texture.dispose()` when removing objects -- GPU memory leaks accumulate and crash the application.6768**NEVER** set `linewidth > 1` on `LineBasicMaterial` -- it is silently ignored on most platforms due to WebGL limitations. ALWAYS use `Line2` + `LineMaterial` from `three/addons/lines/` for thick lines.6970**ALWAYS** set `material.needsUpdate = true` after changing properties that affect shader compilation (e.g., toggling `flatShading`, changing `side`, adding/removing texture maps at runtime).7172**ALWAYS** set `wrapS` and `wrapT` to `RepeatWrapping` when using `texture.repeat` values other than `(1, 1)` -- the default `ClampToEdgeWrapping` does NOT tile textures.7374---7576## MeshStandardMaterial (PBR)7778The recommended material for most 3D scenes. Uses physically-based metalness/roughness workflow.7980```javascript81import { MeshStandardMaterial, TextureLoader, SRGBColorSpace, RepeatWrapping } from 'three';8283const loader = new TextureLoader();84const material = new MeshStandardMaterial({85 color: 0xffffff,86 roughness: 0.7, // 0 = mirror, 1 = fully rough87 metalness: 0.0, // 0 = dielectric, 1 = metal88 map: null, // Diffuse/albedo texture89 roughnessMap: null, // Per-pixel roughness90 metalnessMap: null, // Per-pixel metalness91 normalMap: null, // Surface normal perturbation92 normalScale: new Vector2(1, 1),93 aoMap: null, // Ambient occlusion (requires uv2)94 aoMapIntensity: 1.0,95 emissive: 0x000000, // Emissive color96 emissiveMap: null, // Emissive texture97 emissiveIntensity: 1.0,98 envMap: null, // Environment reflection map99 envMapIntensity: 1.0,100 bumpMap: null, // Grayscale height map101 bumpScale: 1.0,102 displacementMap: null, // Vertex displacement map103 displacementScale: 1.0,104 displacementBias: 0.0,105 alphaMap: null, // Per-pixel transparency106 lightMap: null, // Baked lighting (requires uv2)107 lightMapIntensity: 1.0,108 flatShading: false,109 wireframe: false,110 fog: true111});112```113114---115116## MeshPhysicalMaterial (Advanced PBR)117118Extends `MeshStandardMaterial` with ALL its properties, plus:119120| Property | Type | Default | Description |121|----------|------|---------|-------------|122| `clearcoat` | `float` | `0.0` | Clear coat layer intensity (0-1) |123| `clearcoatRoughness` | `float` | `0.0` | Clear coat roughness |124| `clearcoatMap` | `Texture` | `null` | Clear coat intensity map |125| `clearcoatNormalMap` | `Texture` | `null` | Clear coat normal map |126| `transmission` | `float` | `0.0` | Physically-based transparency (0-1) |127| `transmissionMap` | `Texture` | `null` | Transmission map |128| `thickness` | `float` | `0.0` | Volume thickness for transmission |129| `thicknessMap` | `Texture` | `null` | Thickness map |130| `ior` | `float` | `1.5` | Index of refraction (1.0-2.333) |131| `attenuationDistance` | `float` | `Infinity` | Light attenuation distance in volume |132| `attenuationColor` | `Color` | `white` | Light attenuation tint |133| `sheen` | `float` | `0.0` | Sheen layer intensity (fabric-like) |134| `sheenColor` | `Color` | `0x000000` | Sheen tint color |135| `sheenRoughness` | `float` | `1.0` | Sheen roughness |136| `iridescence` | `float` | `0.0` | Thin-film interference (0-1) |137| `iridescenceIOR` | `float` | `1.3` | Iridescence index of refraction |138| `iridescenceThicknessRange` | `[float, float]` | `[100, 400]` | Thin-film thickness range (nm) |139| `anisotropy` | `float` | `0.0` | Anisotropic reflection strength |140| `anisotropyRotation` | `float` | `0.0` | Anisotropy rotation (radians) |141| `specularIntensity` | `float` | `1.0` | Specular layer intensity |142| `specularColor` | `Color` | `white` | Specular tint color |143| `dispersion` | `float` | `0.0` | Chromatic dispersion (rainbow effect) |144| `reflectivity` | `float` | `0.5` | Reflectivity at normal incidence |145146---147148## Texture System149150### Color Space Rules (Critical)151152| Map Type | Color Space | Channels Used |153|----------|-------------|---------------|154| `map` (diffuse/albedo) | `SRGBColorSpace` | RGB(A) |155| `emissiveMap` | `SRGBColorSpace` | RGB |156| `lightMap` | `SRGBColorSpace` | RGB |157| `envMap` | `SRGBColorSpace` | RGB |158| `sheenColorMap` | `SRGBColorSpace` | RGB |159| `specularColorMap` | `SRGBColorSpace` | RGB |160| `normalMap` | `NoColorSpace` | RGB |161| `roughnessMap` | `NoColorSpace` | G channel |162| `metalnessMap` | `NoColorSpace` | B channel |163| `aoMap` | `NoColorSpace` | R channel |164| `bumpMap` | `NoColorSpace` | R channel |165| `displacementMap` | `NoColorSpace` | R channel |166| `alphaMap` | `NoColorSpace` | R channel |167| `clearcoatMap` | `NoColorSpace` | R channel |168| `clearcoatRoughnessMap` | `NoColorSpace` | R channel |169| `clearcoatNormalMap` | `NoColorSpace` | RGB |170| `transmissionMap` | `NoColorSpace` | R channel |171| `thicknessMap` | `NoColorSpace` | R channel |172| `iridescenceMap` | `NoColorSpace` | R channel |173| `iridescenceThicknessMap` | `NoColorSpace` | R channel |174| `sheenRoughnessMap` | `NoColorSpace` | R channel |175| `anisotropyMap` | `NoColorSpace` | RG channels |176| `specularIntensityMap` | `NoColorSpace` | A channel |177178**Rule**: Diffuse/emissive/color textures = `SRGBColorSpace`. ALL data textures = `NoColorSpace`. Getting this wrong causes washed-out or over-saturated rendering.179180### Texture Loaders181182| Loader | Format | Import |183|--------|--------|--------|184| `TextureLoader` | PNG, JPG, WebP | `three` core |185| `CubeTextureLoader` | 6x PNG/JPG cube maps | `three` core |186| `RGBELoader` | .hdr (Radiance HDR) | `three/addons/loaders/RGBELoader.js` |187| `EXRLoader` | .exr (OpenEXR HDR) | `three/addons/loaders/EXRLoader.js` |188| `KTX2Loader` | .ktx2 (GPU compressed) | `three/addons/loaders/KTX2Loader.js` |189190### Wrapping Modes191192| Constant | Description |193|----------|-------------|194| `ClampToEdgeWrapping` | Edge texels stretched (default) |195| `RepeatWrapping` | Texture tiles/repeats |196| `MirroredRepeatWrapping` | Tiles with alternating mirror |197198### Filter Modes199200| Constant | Type | Description |201|----------|------|-------------|202| `NearestFilter` | Mag/Min | Pixelated, crisp (retro, toon gradients) |203| `LinearFilter` | Mag/Min | Smooth interpolation |204| `LinearMipmapLinearFilter` | Min | Trilinear filtering (default, best quality) |205206### Texture Properties207208| Property | Type | Default | Description |209|----------|------|---------|-------------|210| `wrapS` / `wrapT` | `number` | `ClampToEdgeWrapping` | Wrapping mode |211| `magFilter` | `number` | `LinearFilter` | Magnification filter |212| `minFilter` | `number` | `LinearMipmapLinearFilter` | Minification filter |213| `anisotropy` | `number` | `1` | Anisotropic filtering (max = `renderer.capabilities.getMaxAnisotropy()`) |214| `repeat` | `Vector2` | `(1, 1)` | UV repeat count |215| `offset` | `Vector2` | `(0, 0)` | UV offset |216| `rotation` | `number` | `0` | UV rotation in radians |217| `center` | `Vector2` | `(0, 0)` | Center of rotation |218| `flipY` | `boolean` | `true` | Flip vertically on upload |219| `colorSpace` | `string` | `NoColorSpace` | Color space interpretation |220| `generateMipmaps` | `boolean` | `true` | Auto-generate mipmaps |221| `needsUpdate` | `boolean` | `false` | Trigger GPU re-upload |222223### flipY Rules224225- `flipY = true` (default): Correct for loaded image textures (PNG, JPG)226- `flipY = false`: ALWAYS use for `WebGLRenderTarget` textures, `DataTexture`, and framebuffer textures227228---229230## Material Disposal231232```javascript233// ALWAYS dispose materials and textures when removing objects234function disposeMesh(mesh) {235 if (mesh.material) {236 // Dispose all texture maps237 for (const key of Object.keys(mesh.material)) {238 const value = mesh.material[key];239 if (value && value.isTexture) {240 value.dispose();241 }242 }243 mesh.material.dispose();244 }245 if (mesh.geometry) {246 mesh.geometry.dispose();247 }248}249```250251---252253## needsUpdate Flag254255ALWAYS set `material.needsUpdate = true` after changing these at runtime:256- Toggling `flatShading`257- Changing `side` (FrontSide/BackSide/DoubleSide)258- Adding or removing a texture map (e.g., setting `map` from `null` to a texture)259- Changing `transparent` or `alphaTest`260- Toggling `wireframe`261- Any property that changes the compiled shader variant262263NEVER set `needsUpdate = true` every frame -- it forces expensive shader recompilation. ONLY set it once after the property change.264265For textures: set `texture.needsUpdate = true` after modifying `texture.image` data to trigger GPU re-upload.266267---268269## Toon Material Special Rule270271When using `MeshToonMaterial`, ALWAYS set `gradientMap.minFilter = NearestFilter` and `gradientMap.magFilter = NearestFilter`. Linear filtering blurs the discrete shading steps into smooth gradients, defeating the toon effect.272273---274275## Reference Links276277- [references/methods.md](references/methods.md) -- All material types with constructor signatures and key properties278- [references/examples.md](references/examples.md) -- Complete working examples (PBR, textures, multi-material)279- [references/anti-patterns.md](references/anti-patterns.md) -- What NOT to do, with explanations280281### Official Sources282283- https://threejs.org/docs/#api/en/materials/Material284- https://threejs.org/docs/#api/en/materials/MeshStandardMaterial285- https://threejs.org/docs/#api/en/materials/MeshPhysicalMaterial286- https://threejs.org/docs/#api/en/textures/Texture