Materials Guide
Materials in threepipe define the visual appearance of 3D objects, including properties like color, texture, reflectivity, transparency, and surface characteristics. Threepipe provides a comprehensive material system built on top of three.js materials with enhanced features for physically-based rendering (PBR), material extensions, and advanced configuration options.
Overview
Materials are self-contained objects that contain information about surface properties and can be applied to any 3D object in the scene, regardless of the geometry or shape. Threepipe's default workflow uses PBR (Physically Based Rendering) to achieve realistic material appearance.
Core Material Types
Physical Material
The PhysicalMaterial
is threepipe's primary material for realistic rendering, extending three.js MeshPhysicalMaterial
with additional features.
Key Features:
- Physically-based rendering (PBR) workflow
- Support for metallic/roughness workflow
- Advanced features like transmission, clearcoat, and sheen
- Material extension support
- UI configuration and serialization
Basic Usage:
import { PhysicalMaterial, Color, Vector2 } from 'threepipe'
const material = new PhysicalMaterial({
color: new Color(0xff0000), // Base color
metalness: 1.0, // 0 = dielectric, 1 = metallic
roughness: 0.1, // 0 = mirror, 1 = completely rough
transmission: 0.0, // For glass-like materials
thickness: 1.0, // Thickness for transmission
clearcoat: 0.0, // Clear coating layer
clearcoatRoughness: 0.0, // Roughness of clear coat
})
Advanced Properties:
const material = new PhysicalMaterial({
// Base properties
color: new Color(0xffffff),
map: baseColorTexture, // Base color texture
// PBR properties
metalness: 0.0,
roughness: 0.5,
metalnessMap: metalnessTexture,
roughnessMap: roughnessTexture,
// Normal mapping
normalMap: normalTexture,
normalScale: new Vector2(1, 1),
// Displacement
displacementMap: heightTexture,
displacementScale: 0.1,
displacementBias: 0.0,
// Ambient occlusion
aoMap: aoTexture,
aoMapIntensity: 1.0,
// Transmission (glass/transparent materials)
transmission: 0.0,
transmissionMap: transmissionTexture,
thickness: 1.0,
thicknessMap: thicknessTexture,
attenuationDistance: Infinity,
attenuationColor: new Color(0xffffff),
// Clearcoat (car paint, etc.)
clearcoat: 0.0,
clearcoatMap: clearcoatTexture,
clearcoatRoughness: 0.0,
clearcoatRoughnessMap: clearcoatRoughnessTexture,
clearcoatNormalMap: clearcoatNormalTexture,
clearcoatNormalScale: new Vector2(1, 1),
// Sheen (fabric-like materials)
sheen: 0.0,
sheenRoughness: 1.0,
sheenColor: new Color(0x000000),
sheenColorMap: sheenColorTexture,
sheenRoughnessMap: sheenRoughnessTexture,
// Iridescence
iridescence: 0.0,
iridescenceMap: iridescenceTexture,
iridescenceIOR: 1.3,
iridescenceThicknessRange: [100, 400],
iridescenceThicknessMap: iridescenceThicknessTexture,
// Anisotropy (requires AnisotropyPlugin)
// anisotropy: 0.0,
// anisotropyRotation: 0.0,
// anisotropyMap: anisotropyTexture,
})
Unlit Material
The UnlitMaterial
extends three.js MeshBasicMaterial
for flat, non-lighting dependent rendering.
Use Cases:
- UI elements and overlays
- Stylized/cartoon rendering
- Billboards and sprites
- Emissive materials
- Debug visualization
Basic Usage:
import { UnlitMaterial, Color } from 'threepipe'
const material = new UnlitMaterial({
color: new Color(0x00ff00),
map: texture, // Base texture
alphaMap: alphaTexture, // Alpha channel texture
opacity: 1.0, // Material opacity
transparent: false, // Enable transparency
alphaTest: 0.0, // Alpha testing threshold
})
Extended Shader Material
ExtendedShaderMaterial
provides a base for custom shader materials with material extension support.
import { ExtendedShaderMaterial } from 'threepipe'
const customMaterial = new ExtendedShaderMaterial({
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform vec3 color;
varying vec2 vUv;
void main() {
gl_FragColor = vec4(color, 1.0);
}
`,
uniforms: {
color: { value: new Color(0xff0000) }
}
})
There are more materials available in threepipe like LineMaterial
, LegacyPhongMaterial
, etc. Check the API Reference for more details.
In most cases for 3D Objects, its ideal to use the Physical or Unlit Materials as they provide the maximum compatibility across threepipe and other 3d engines. With the material extension system, you can add custom functionality to these materials without needing to create a custom shader material.
Creating Materials
In Code
Materials can be created programmatically and applied to objects:
import { Mesh, BoxGeometry, PhysicalMaterial, ThreeViewer } from 'threepipe'
// Create viewer
const viewer = new ThreeViewer({
canvas: document.getElementById('canvas')
})
// Create material
const material = new PhysicalMaterial({
color: 0xff0000,
metalness: 0.8,
roughness: 0.2
})
// Create geometry and mesh
const geometry = new BoxGeometry(1, 1, 1)
const mesh = new Mesh(geometry, material)
// Add to scene
viewer.scene.addObject(mesh)
Loading from Files
Materials are automatically created when loading 3D files:
// Load GLTF with materials
const model = await viewer.load('./model.glb')
// Access materials
const materials = viewer.assetManager.materialManager.getAllMaterials()
console.log('Loaded materials:', materials)
// Modify existing material
const material = materials[0] as PhysicalMaterial
material.metalness = 1.0
material.roughness = 0.1
material.setDirty() // Mark for update
In Blender
When creating materials in Blender for use with threepipe:
Use Principled BSDF: The standard shader for PBR materials
Connect textures properly:
- Base Color → Base Color input
- Roughness → Roughness input
- Metallic → Metallic input
- Normal Map → Normal input (through Normal Map node)
- Height/Displacement → Displacement output
Export Settings:
- Use glTF 2.0 format for best compatibility
- Enable "Export Materials" option
- Choose appropriate texture formats (PNG for alpha, JPEG for RGB)
Blender Node Setup Example:
[Image Texture] → [Base Color] → [Principled BSDF] → [Material Output]
[Image Texture] → [Roughness] → [Principled BSDF]
[Image Texture] → [Metallic] → [Principled BSDF]
[Image Texture] → [Normal Map] → [Normal] → [Principled BSDF]
In Other 3D Software
3ds Max:
- Use Physical Material or Arnold Standard Surface
- Connect maps to appropriate slots
- Export via glTF exporter
Maya:
- Use aiStandardSurface (Arnold) or StandardSurface
- Connect file nodes to material inputs
- Export using Maya2glTF or similar
Substance Painter:
- Use PBR workflow templates
- Export texture maps for threepipe:
- Base Color
- Roughness
- Metallic
- Normal
- Height
Rhino 3DM
- DO NOT export using glTF exporter. Use 3DM
- Load 3DM files directly in threepipe and export to optimized glb.
- Use PBR materials in Rhino or use Layers and assign materials in threepipe.
Material Extensions
Material extensions allow you to add custom functionality to materials without modifying the core material classes. This is particularly powerful for adding rendering effects, custom properties, or shader modifications.
Creating a Material Extension
import { MaterialExtension } from 'threepipe'
const customExtension: MaterialExtension = {
// Add custom uniforms
extraUniforms: {
tCustomTexture: { value: null },
uCustomValue: { value: 1.0 },
uTime: () => ({ value: performance.now() * 0.001 })
},
// Add shader defines
extraDefines: {
USE_CUSTOM_EFFECT: 1,
CUSTOM_ITERATIONS: () => Math.floor(Math.random() * 10)
},
// Add custom shader code
parsFragmentSnippet: `
uniform sampler2D tCustomTexture;
uniform float uCustomValue;
uniform float uTime;
vec3 customEffect(vec3 color) {
return color * (0.5 + 0.5 * sin(uTime));
}
`,
// Modify shader during compilation
shaderExtender: (shader, material, renderer) => {
// Insert custom code at specific points
shader.fragmentShader = shader.fragmentShader.replace(
'#include <output_fragment>',
`
gl_FragColor.rgb = customEffect(gl_FragColor.rgb);
#include <output_fragment>
`
)
},
// Extension priority (higher = applied later)
priority: 100,
// Custom cache key for shader compilation
computeCacheKey: (material, renderer) => {
return `custom_${material.uuid}_${renderer.info.programs?.length || 0}`
}
}
Registering Extensions
// Register extension globally
viewer.assetManager.materialManager.registerMaterialExtensions([customExtension])
// Register extension on specific material
material.registerMaterialExtensions([customExtension])
// Register during material creation
const material = new PhysicalMaterial({
color: 0xff0000,
customMaterialExtensions: [customExtension]
})
Built-in Extension Plugins
Threepipe includes several plugins that use material extensions:
- ClearcoatTintPlugin: Adds tinted clearcoat effects
- CustomBumpMapPlugin: Enhanced bump mapping
- SSAOPlugin: Screen-space ambient occlusion
- FragmentClippingExtensionPlugin: Fragment-level clipping
- ParallaxMappingPlugin: Relief parallax mapping
- AnisotropyPlugin: Anisotropic reflections
Material Chaining and Composition
Material extensions can be chained together to create complex effects:
// Create multiple extensions
const glowExtension: MaterialExtension = {
parsFragmentSnippet: `
uniform float uGlowIntensity;
vec3 addGlow(vec3 color) {
return color + vec3(uGlowIntensity);
}
`,
extraUniforms: {
uGlowIntensity: {value: 0.1}
}
}
const pulseExtension: MaterialExtension = {
parsFragmentSnippet: `
uniform float uTime;
vec3 addPulse(vec3 color) {
float pulse = 0.5 + 0.5 * sin(uTime * 2.0);
return color * pulse;
}
`,
extraUniforms: {
uTime: () => ({value: performance.now() * 0.001})
}
}
const combinedExtension: MaterialExtension = {
shaderExtender: (shader) => {
shader.fragmentShader = shaderReplaceString(
'#include <output_fragment>',
`
gl_FragColor.rgb = addGlow(gl_FragColor.rgb);
gl_FragColor.rgb = addPulse(gl_FragColor.rgb);
`, {prepend: true},
)
},
priority: 200 // Apply after other extensions
}
// Apply all extensions
material.registerMaterialExtensions([
glowExtension,
pulseExtension,
combinedExtension
])
Advanced Features
Transmission and Refraction
For glass and transparent materials:
const glassMaterial = new PhysicalMaterial({
transmission: 1.0, // Full transmission
thickness: 0.5, // Glass thickness
roughness: 0.0, // Smooth surface
metalness: 0.0, // Non-metallic
ior: 1.5, // Index of refraction
attenuationDistance: 0.5, // Light attenuation
attenuationColor: new Color(0.9, 0.95, 1.0), // Slight blue tint
})
Clearcoat Effects
For car paint and lacquered surfaces:
const carPaintMaterial = new PhysicalMaterial({
color: new Color(0x8B0000), // Dark red base
metalness: 0.9, // Metallic base
roughness: 0.5, // Somewhat rough base
clearcoat: 1.0, // Full clearcoat
clearcoatRoughness: 0.1, // Smooth clearcoat
})
Fabric Materials
Using sheen for fabric-like appearance:
const fabricMaterial = new PhysicalMaterial({
color: new Color(0x8B4513), // Brown fabric
metalness: 0.0, // Non-metallic
roughness: 0.8, // Rough surface
sheen: 1.0, // Full sheen effect
sheenColor: new Color(0.5, 0.5, 0.5), // White sheen
sheenRoughness: 0.3, // Moderate sheen roughness
})
Performance Considerations
Material Sharing
Share materials between objects to reduce memory usage:
const sharedMaterial = new PhysicalMaterial({ color: 0xff0000 })
// Use same material for multiple objects
const mesh1 = new Mesh(geometry1, sharedMaterial)
const mesh2 = new Mesh(geometry2, sharedMaterial)
Texture Sharing
Share textures to optimize loading and memory:
// Load texture once, use multiple times
const baseTexture = await viewer.load<ITexture>('./texture.jpg')
const material1 = new PhysicalMaterial({ map: baseTexture })
const material2 = new PhysicalMaterial({
map: baseTexture,
color: new Color(0.5, 0.5, 1.0) // Tint the texture
})
Material Updates
Use setDirty()
to mark materials for update:
material.color.setHex(0x00ff00)
material.roughness = 0.8
material.setDirty() // Trigger update
Best Practices
- Use PBR workflow: Stick to physically-based values for realistic results
- Texture resolution: Use appropriate texture sizes (power of 2)
- Material sharing: Reuse materials when possible for performance
- Extension organization: Keep extensions focused and modular
- Testing: Test materials under different lighting conditions
Debugging Materials
Material Inspector
Use the built-in UI to inspect material properties:
import { TweakpaneUiPlugin } from '@threepipe/plugin-tweakpane'
const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true))
ui.setupPluginUi(PickingPlugin)
// Material(and object) properties will appear in the UI when objects are selected
Examples
See the threepipe examples for practical material usage:
For more advanced material extension topics, see the Material Extension guide.