Skip to content

Materials

A Material is what a surface looks like – color, texture, reflectivity, shader. Use the Material builder to construct one inline, reference an existing library material by id, or clone a library material and tweak it.

Kinds

Six factories. Pick the one that matches the look you need.

FactoryUse for
Material.unlit({...})Flat-shaded surfaces – UI, billboards, vertex-colored point clouds. Renders the same regardless of scene lighting.
Material.pbr({...})Realistic surfaces – metal, plastic, fabric. Responds to scene lighting.
Material.occlusion({...})Invisible itself but hides geometry behind it – holdouts, portals.
Material.customShader({...})Author-supplied Metal shader functions from a compiled .metal library.
Material.materialX({...})ShaderGraph material authored in Reality Composer Pro / .usda.
Material.video({...})Video texture playback.

Inline construction

Factory + options object reads naturally:

javascript
// Unlit – single flat color
const red = Material.unlit({ color: '#FF0000' });

// PBR – color + metalness + roughness, no textures
const gold = Material.pbr({
    color: '#FFD700',
    metalness: 1.0,
    roughness: 0.2
});

// PBR – textured
const brick = Material.pbr({
    color: '#FFFFFF',          // tints the texture
    map: 'brick-albedo.png',
    normalMap: 'brick-normal.png',
    roughnessMap: 'brick-rough.png'
});

Same chained, if you prefer:

javascript
const gold = new Material('pbr')
    .color('#FFD700')
    .metalness(1.0)
    .roughness(0.2);

Input shapes

Colorscolor, emissive, sheenColor, specularColor:

  • '#RRGGBB' or '#RRGGBBAA'
  • { r, g, b, a } with values in 0..1
  • { colorSpace: 'p3', hex: 'FF6600' }

Texturesmap, emissiveMap, normalMap, etc.:

  • URL string: 'https://.../texture.png'
  • Asset id string: 'libraryTextureId'
  • With a scale: { texture: 'urlOrId', scale: 0.5 }

Scalarsroughness, metalness, clearcoat, opacity, emissiveIntensity: plain numbers.

Library reference

Materials authored in the experience editor are referenced by id directly – no inline construction needed:

javascript
// Apply a library material to a mesh
await scene.createEntity(createMesh({
    ...,
    materials: ['myLibraryMaterialId']
}));

Or fetch one with scene.getMaterial(id) to inspect:

javascript
const mat = scene.getMaterial('myLibraryMaterialId');
console.log(mat); // → Material(pbr 'My Material' id=..., color=#FFAA00, roughness=0.3)

Clone → tweak → apply

To override a library material for a single entity (without mutating the library entry), clone it first:

javascript
const base = scene.getMaterial('redMatId');
const brighter = base.clone()
    .emissive('#FF0000')
    .emissiveIntensity(2);

await entity.representation.setMaterial(brighter);

.clone() deep-copies the material with a fresh id. The original library material is untouched.

ShaderGraph (MaterialX) parameters

ShaderGraph materials authored in Reality Composer Pro expose promoted inputs. Set constant values via setParameter(name, value, typeHint?):

javascript
const mat = scene.getMaterial('myShaderGraphMatId').clone()
    .setParameter('intensity', 0.6)
    .setParameter('tintColor', '#FF00FF', { type: 'color' })
    .setParameter('offset', [0.1, 0.2, 0], { type: 'vector3' });

The same setParameter works on customShader materials too – the Material auto-routes to the right options blob based on its kind.

Type hints override inferred types: { type: "float" | "int" | "vector2" | "vector3" | "vector4" | "color" | "boolean" | "string" }

For runtime variable bindings (slider drives a parameter), use entity.representation.bindMaterialParameter(parameterName, variableId) – different path, lives on the entity, ties into the variable system.

Runtime swap

Replace an entity's material at runtime:

javascript
// Cycle materials every 2 seconds
const palette = [
    Material.unlit({ color: '#4287F5' }),
    Material.pbr({ color: '#42F578', metalness: 0.5, roughness: 0.3 }),
    Material.unlit({ color: '#F54242' })
];
let i = 0;
scene.on('schedule', { interval: 2 }, async function() {
    i = (i + 1) % palette.length;
    await entity.representation.setMaterial(palette[i]);
});

setMaterial accepts a Material instance, a library ref-id string, or { id, target? }. setMaterials([...]) for multiple at once.

Introspection

javascript
console.log(material);                       // → Material(pbr id=..., color=#FF6600, roughness=0.3)
console.log(JSON.stringify(material, null, 2)); // → full Codable JSON

material.kind;          // → 'pbr'
material.id;            // → 'AB12CD34'
material.baseColor;     // → { color: { colorSpace: 'p3', hex: 'FF6600' } }
material.materialXOptions?.parameters; // → { intensity: { ... } } for materialX

For setter names that conflict with property names (roughness, opacity, clearcoat, emissiveIntensity), read via material.data.<field> – e.g. material.data.roughness?.scale.

Target

By default a material applies to all models on an entity. Override for multi-model entities:

javascript
Material.pbr({ color: '#FF0000' })
    .target({ type: 'firstModel' });

Material.pbr({ color: '#0000FF' })
    .target({ type: 'selectedModels', models: ['windshield'], materialSlots: [0] });