Material & Texture System
The Material & Texture System defines surface appearance properties for rendered objects. Materials control how objects respond to lighting, transparency, blending, and depth testing. Textures provide image data that materials can sample. The system bridges high-level material definitions to low-level shader programs through a compilation process that generates GLSL code based on material features.
For information about how materials are used in the rendering pipeline, see WebGL Rendering Pipeline. For shader program compilation details, see Shader Programs & Compilation. For geometry data that materials are applied to, see Geometry System.
Material Base Class
The Material class src/materials/Material.js17-660 defines the abstract base for all material types. It provides properties common to all rendering: blending modes, culling, depth testing, stencil operations, and clipping planes.
Core Material Properties
| Property Category | Properties | Purpose |
|---|---|---|
| Blending | blending, blendSrc, blendDst, blendEquation | Controls how object colors blend with framebuffer |
| Culling | side, shadowSide | Determines which face sides render |
| Depth | depthTest, depthWrite, depthFunc | Manages depth buffer operations |
| Stencil | stencilWrite, stencilFunc, stencilRef | Controls stencil buffer operations |
| Transparency | transparent, opacity, alphaTest, alphaHash | Manages transparency rendering |
| Clipping | clippingPlanes, clipIntersection, clipShadows | Defines clip plane behavior |
Material State Flags
Material.needsUpdate // Triggers recompilation
Material.version // Increments on disposal
Material.isMaterial // Type testing flagThe base class also defines callback hooks:
onBeforeCompile(shader, renderer)- Modifies shader before compilation src/materials/Material.js606-608customProgramCacheKey()- Extends cache key for program sharing src/materials/Material.js622-625
Sources: src/materials/Material.js1-660
Texture System
Texture Class Architecture
Texture Properties
The Texture class src/textures/Texture.js32-600 encapsulates image data and sampling parameters:
Core Texture Properties:
Texture Update Mechanism:
Textures use a needsUpdate flag to trigger GPU upload:
texture.needsUpdate = true; // Marks texture for re-uploadThe texture matrix combines offset, repeat, rotation, and center into a single Matrix3 transform src/textures/Texture.js458-482
Built-in Material Types
Three.js provides material types in ShaderLib src/renderers/shaders/ShaderLib.js9-355 Each material type maps to a shader ID used during compilation.
Material Type Mapping
Material Feature Support
| Material Type | Lighting | PBR | Textures | Special Features |
|---|---|---|---|---|
| MeshBasicMaterial | No | No | map, alphaMap, envMap, aoMap, lightMap, specularMap | Simple unlit rendering |
| MeshLambertMaterial | Yes (Lambertian) | No | + emissiveMap, bumpMap, normalMap, displacementMap | Diffuse lighting |
| MeshPhongMaterial | Yes (Blinn-Phong) | No | + specularMap | Specular highlights, shininess |
| MeshStandardMaterial | Yes | Yes | + roughnessMap, metalnessMap | Metallic-roughness PBR |
| MeshPhysicalMaterial | Yes | Yes | All standard + clearcoat, transmission, sheen, iridescence maps | Extended PBR features |
| MeshToonMaterial | Yes | No | + gradientMap | Cel-shaded rendering |
| MeshMatcapMaterial | No | No | matcap | Material capture lookup |
Material-to-Shader Compilation Pipeline
The compilation pipeline transforms high-level material definitions into cached shader programs. The WebGLPrograms class orchestrates this process.
Compilation Flow Diagram
Parameter Object Structure
The getParameters() function src/renderers/webgl/WebGLPrograms.js50-380 generates a comprehensive parameters object that drives shader generation:
Texture Feature Detection:
const HAS_MAP = !! material.map;
const HAS_MATCAP = !! material.matcap;
const HAS_ENVMAP = !! envMap;
const HAS_AOMAP = !! material.aoMap;
const HAS_LIGHTMAP = !! material.lightMap;
const HAS_BUMPMAP = !! material.bumpMap;
const HAS_NORMALMAP = !! material.normalMap;
const HAS_DISPLACEMENTMAP = !! material.displacementMap;
const HAS_EMISSIVEMAP = !! material.emissiveMap;
const HAS_METALNESSMAP = !! material.metalnessMap;
const HAS_ROUGHNESSMAP = !! material.roughnessMap;UV Channel Assignment:
For each texture, the system determines which UV attribute to use via getChannel() src/renderers/webgl/WebGLPrograms.js40-48:
parameters.mapUv = HAS_MAP && getChannel( material.map.channel );
parameters.alphaMapUv = HAS_ALPHAMAP && getChannel( material.alphaMap.channel );
parameters.normalMapUv = HAS_NORMALMAP && getChannel( material.normalMap.channel );
// ... etc for all texture typesThe channel value (0-3) maps to UV attributes (uv, uv1, uv2, uv3).
Material Property Flags:
parameters.flatShading = material.flatShading;
parameters.vertexColors = material.vertexColors;
parameters.vertexTangents = !! geometry.attributes.tangent && ( HAS_NORMALMAP || HAS_ANISOTROPY );
parameters.fog = !! fog;
parameters.useFog = material.fog === true;Shader Prefix Generation
The WebGLProgram constructor src/renderers/webgl/WebGLProgram.js412-1025 generates shader prefixes containing #define statements based on parameters:
Vertex Shader Prefix Example:
precision highp float;
#define SHADER_TYPE MeshStandardMaterial
#define SHADER_NAME MyMaterial
#define USE_MAP
#define MAP_UV uv
#define USE_NORMALMAP
#define NORMALMAP_UV uv
#define USE_TANGENT
#define USE_SKINNING
#define MORPHTARGETS_COUNT 4
// ... uniforms declarationsThe generation occurs in src/renderers/webgl/WebGLProgram.js473-669 for vertex shaders and src/renderers/webgl/WebGLProgram.js671-782 for fragment shaders.
Include Resolution:
Shader code uses #include <chunk_name> directives src/renderers/webgl/WebGLProgram.js243-276 which are recursively resolved from ShaderChunk:
function resolveIncludes( string ) {
return string.replace( includePattern, includeReplacer );
}
function includeReplacer( match, include ) {
let string = ShaderChunk[ include ];
return resolveIncludes( string ); // Recursive
}Material Uniforms and Updates
Uniform Structure
Materials define uniforms through UniformsLib src/renderers/shaders/UniformsLib.js1-256 collections merged per material type:
Uniform Update Process
The WebGLMaterials.refreshUniforms() function src/renderers/webgl/WebGLMaterials.js9-458 updates material uniforms before rendering:
Texture Uniform Updates:
function refreshTransformUniform( map, uniform ) {
if ( map.matrixAutoUpdate === true ) {
map.updateMatrix();
}
uniform.value.copy( map.matrix );
}Each texture type has an update path src/renderers/webgl/WebGLMaterials.js45-328:
if ( material.map ) {
uniforms.map.value = material.map;
refreshTransformUniform( material.map, uniforms.mapTransform );
}
if ( material.normalMap ) {
uniforms.normalMap.value = material.normalMap;
uniforms.normalScale.value.copy( material.normalScale );
refreshTransformUniform( material.normalMap, uniforms.normalMapTransform );
}Material Property Updates:
Standard material properties src/renderers/webgl/WebGLMaterials.js134-284:
uniforms.opacity.value = material.opacity;
if ( material.color ) {
uniforms.diffuse.value.copy( material.color );
}
if ( material.emissive ) {
uniforms.emissive.value.copy( material.emissive )
.multiplyScalar( material.emissiveIntensity );
}
if ( material.roughness !== undefined ) {
uniforms.roughness.value = material.roughness;
}
if ( material.metalness !== undefined ) {
uniforms.metalness.value = material.metalness;
}Physical Material Extensions:
MeshPhysicalMaterial adds additional uniforms src/renderers/webgl/WebGLMaterials.js286-414:
uniforms.clearcoat.value = material.clearcoat;
uniforms.clearcoatRoughness.value = material.clearcoatRoughness;
if ( material.iridescence > 0 ) {
uniforms.iridescence.value = material.iridescence;
uniforms.iridescenceIOR.value = material.iridescenceIOR;
// ... thickness min/max
}
if ( material.sheen > 0 ) {
uniforms.sheenColor.value.copy( material.sheenColor )
.multiplyScalar( material.sheen );
uniforms.sheenRoughness.value = material.sheenRoughness;
}
if ( material.transmission > 0 ) {
uniforms.transmission.value = material.transmission;
uniforms.thickness.value = material.thickness;
uniforms.attenuationDistance.value = material.attenuationDistance;
uniforms.attenuationColor.value.copy( material.attenuationColor );
}Material Serialization
JSON Export Format
The Material.toJSON() method src/materials/Material.js627-658 serializes materials to JSON, storing UUIDs for textures:
{
"uuid": "F3D1E2A4-B5C6-7D8E-9F0A-1B2C3D4E5F6A",
"type": "MeshStandardMaterial",
"name": "MyMaterial",
"color": 16777215, // 0xffffff
"roughness": 0.5,
"metalness": 0.8,
"map": "texture-uuid-1",
"normalMap": "texture-uuid-2",
"normalScale": [1, 1],
"emissive": 0,
"emissiveIntensity": 1.0,
"envMapIntensity": 1.0,
"side": 0, // FrontSide
"transparent": false,
"opacity": 1.0,
"depthTest": true,
"depthWrite": true
}MaterialLoader Parsing
The MaterialLoader class src/loaders/MaterialLoader.js43-380 reconstructs materials from JSON:
Type Instantiation:
createMaterialFromType( type ) {
const materialClass = {
'MeshBasicMaterial': MeshBasicMaterial,
'MeshLambertMaterial': MeshLambertMaterial,
'MeshPhongMaterial': MeshPhongMaterial,
'MeshStandardMaterial': MeshStandardMaterial,
'MeshPhysicalMaterial': MeshPhysicalMaterial,
// ... etc
}[ type ];
return new materialClass();
}Property Assignment:
The loader src/loaders/MaterialLoader.js111-380 assigns properties with type-specific handling:
if ( json.color !== undefined ) {
material.color.setHex( json.color );
}
if ( json.roughness !== undefined ) {
material.roughness = json.roughness;
}
if ( json.map !== undefined ) {
material.map = getTexture( json.map ); // Looks up by UUID
}
if ( json.normalScale !== undefined ) {
material.normalScale.fromArray( json.normalScale );
}Texture Reference Resolution:
Textures are resolved from a pre-loaded texture dictionary src/loaders/MaterialLoader.js113-125:
const textures = this.textures;
function getTexture( name ) {
if ( textures[ name ] === undefined ) {
warn( 'MaterialLoader: Undefined texture', name );
}
return textures[ name ];
}The ObjectLoader coordinates this by parsing textures first src/loaders/ObjectLoader.js207-208 then materials src/loaders/ObjectLoader.js208
Material Update Lifecycle
Trigger Conditions
Materials trigger recompilation when needsUpdate is set:
material.needsUpdate = true; // Forces shader recompilationThis occurs automatically when:
- Shadow map type changes src/renderers/webgl/WebGLShadowMap.js134-154
- Material type requires different shader features
- Custom shader code is modified via
onBeforeCompile
Version Tracking
Materials use version numbers for cache invalidation src/materials/Material.js69-75:
this.version = 0;
dispose() {
this.dispatchEvent( { type: 'dispose' } );
this.version++; // Invalidates cached programs
}Renderers track material versions to detect when uniform updates are needed.