The Material Hierarchy

Every material extends Material, which holds Depth, Culling, Blending's render state: side, transparent, opacity, blending, depthTest, depthWrite and alphaTest. The mesh materials differ in their lighting model:

Three.js 30,815 mesh materials, from cheapest to most capable
Material Lighting Use it for
MeshBasicMaterial None Unlit UI, baked lighting, wireframes
MeshLambertMaterial Diffuse only, per fragment since r144 Cheap matte surfaces
MeshPhongMaterial Blinn-Phong (Blinn-Phong) Legacy shiny surfaces
MeshToonMaterial Stepped by a gradientMap Cartoon shading
MeshStandardMaterial Metalness-roughness PBR (Metallic-Roughness) The default choice
MeshPhysicalMaterial PBR plus clearcoat, transmission, sheen Glass, car paint, fabric
MeshNormalMaterial, MeshDepthMaterial Debug output Checking normals and depth
ShaderMaterial Your GLSL (ShaderMaterial and TSL) Anything else

Share one material among many meshes. Changing a feature that alters the shader (adding a map, toggling vertexColors) needs material.needsUpdate = true so the program is rebuilt.

The same torus knot in eight mesh materials, from unlit Basic to Physical, Normal and DepthHTMLLive
<!doctype html>
<style>
  body { margin: 0; background: #f5f1e8; font: 12px system-ui, sans-serif; color: #263238; }
  #wrap { position: relative; width: 600px; max-width: 100%; }
  canvas { display: block; max-width: 100%; }
  .tag { position: absolute; width: 150px; text-align: center; }
</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>
<div id="wrap"></div>
<script type="module">
import * as THREE from 'three';

const wrap = document.getElementById('wrap');
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.setSize(600, 320);
wrap.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color('#fbf8f2');
const camera = new THREE.OrthographicCamera(-4, 4, 2.13, -2.13, 0.1, 20);
camera.position.set(0, 0, 8);
scene.add(new THREE.HemisphereLight('#ffffff', '#8d6e63', 0.8));
const sun = new THREE.DirectionalLight('#ffffff', 2.5);
sun.position.set(2, 3, 4);
scene.add(sun);

// A small gradient for MeshToonMaterial: three flat bands of light
const bands = new THREE.DataTexture(new Uint8Array([60, 160, 255]), 3, 1, THREE.RedFormat);
bands.minFilter = bands.magFilter = THREE.NearestFilter;
bands.needsUpdate = true;

const color = '#e09a10';
const materials = [
  ['MeshBasicMaterial', new THREE.MeshBasicMaterial({ color })],           // no lighting
  ['MeshLambertMaterial', new THREE.MeshLambertMaterial({ color })],       // diffuse only
  ['MeshPhongMaterial', new THREE.MeshPhongMaterial({ color, shininess: 80 })],
  ['MeshToonMaterial', new THREE.MeshToonMaterial({ color, gradientMap: bands })],
  ['MeshStandardMaterial', new THREE.MeshStandardMaterial({ color, roughness: 0.35, metalness: 0.2 })],
  ['MeshPhysicalMaterial', new THREE.MeshPhysicalMaterial({ color, roughness: 0.5, clearcoat: 1, clearcoatRoughness: 0.05 })],
  ['MeshNormalMaterial', new THREE.MeshNormalMaterial()],                  // debug: normals as colors
  ['MeshDepthMaterial', new THREE.MeshDepthMaterial()],                    // debug: distance
];
const geometry = new THREE.TorusKnotGeometry(0.4, 0.13, 128, 24);
const knots = materials.map(([name, material], i) => {
  const knot = new THREE.Mesh(geometry, material);     // one geometry shared by all eight
  const col = i % 4, row = Math.floor(i / 4);
  knot.position.set(-3 + col * 2, 0.95 - row * 2, 0);
  scene.add(knot);
  const tag = wrap.appendChild(document.createElement('div'));
  tag.className = 'tag';
  tag.textContent = name;
  tag.style.left = `${col * 150}px`;
  tag.style.top = `${row * 160 + 142}px`;
  return knot;
});
// Depth material maps near..far to white..black: tighten the camera range so it shows
camera.near = 7;  camera.far = 9;  camera.updateProjectionMatrix();

renderer.setAnimationLoop((time) => {
  knots.forEach((k) => { k.rotation.set(time / 3000, time / 2000, 0); });
  renderer.render(scene, camera);
});
</script>