MeshStandardMaterial

MeshStandardMaterial and Metalness-Roughness

MeshStandardMaterial is Normal Maps and PBR's metallic-roughness model, the one glTF uses. roughness runs from mirror (0) to matte (1), metalness from dielectric (0) to metal (1), and each has a texture form (roughnessMap, metalnessMap, beside map and normalMap). materialRow(), new in bookshelf.js, lines up one sphere per material, and addEnvironment() (Environment Maps) gives metals something to reflect:

Roughness 0 to 1 for a metal and for a dielectricHTML
<script src="three-map.js"></script>
<script type="module">
import * as THREE from 'three';
import { createStage, materialRow, addEnvironment, renderFrames } from './bookshelf.js';
for (const metalness of [1, 0]) {
  const stage = createStage({ width: 640, height: 125 });
  addEnvironment(stage.renderer, stage.scene, 0.4);
  materialRow(stage, [0, 0.2, 0.4, 0.6, 0.8, 1].map((roughness) =>
    new THREE.MeshStandardMaterial({ color: '#e09a10', metalness, roughness })));
  renderFrames(stage.renderer, stage.scene, stage.camera);
}
</script>
Browser output of Listing 5.11
Browser output of 11

Top, a gold-like metal; bottom, the same color as plastic; the room's reflection blurs as roughness rises. Real materials are 0 or 1 in metalness; values between suit only transitions such as rust on steel.

A metalness by roughness grid of MeshStandardMaterial spheres lit by RoomEnvironmentHTMLLive
<!doctype html>
<style>
  body { margin: 0; background: #f5f1e8; font: 12px system-ui, sans-serif; color: #263238; }
  canvas { display: block; max-width: 100%; }
  p { margin: 4px 8px; }
</style>
<script type="importmap">
{ "imports": {
  "three": "https://cdn.jsdelivr.net/npm/three@0.186.1/build/three.module.js",
  "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.186.1/examples/jsm/" } }
</script>
<p>Top: metalness 1 (gold). Bottom: metalness 0 (plastic). Roughness 0 → 1 from left to right.</p>
<script type="module">
import * as THREE from 'three';
import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.setSize(600, 250);
renderer.toneMapping = THREE.NeutralToneMapping;
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color('#fbf8f2');
const camera = new THREE.PerspectiveCamera(30, 600 / 250, 0.1, 50);
camera.position.set(0, -0.15, 5.6);

// Metals reflect their surroundings: a prefiltered RoomEnvironment gives them something to reflect
const pmrem = new THREE.PMREMGenerator(renderer);
scene.environment = pmrem.fromScene(new RoomEnvironment(), 0.04).texture;
pmrem.dispose();

const geometry = new THREE.SphereGeometry(0.34, 48, 24);
const roughnesses = [0, 0.2, 0.4, 0.6, 0.8, 1];
[1, 0].forEach((metalness, row) => {
  roughnesses.forEach((roughness, col) => {
    const sphere = new THREE.Mesh(geometry,
      new THREE.MeshStandardMaterial({ color: '#e09a10', metalness, roughness }));
    sphere.position.set((col - 2.5) * 0.85, row === 0 ? 0.45 : -0.45, 0);
    scene.add(sphere);
  });
});

// Roughness labels drawn onto a canvas texture strip
const canvas = Object.assign(document.createElement('canvas'), { width: 1024, height: 48 });
const g = canvas.getContext('2d');
g.font = '28px sans-serif';  g.textAlign = 'center';  g.fillStyle = '#263238';
roughnesses.forEach((r, i) => g.fillText(`r = ${r}`, 512 + (i - 2.5) * 145, 34));
const labels = new THREE.CanvasTexture(canvas);
labels.colorSpace = THREE.SRGBColorSpace;
const strip = new THREE.Mesh(new THREE.PlaneGeometry(5.12, 0.24), new THREE.MeshBasicMaterial({ map: labels, transparent: true, toneMapped: false }));
strip.position.y = -0.95;
scene.add(strip);

renderer.render(scene, camera);
</script>