vs Three.js Materials

StandardMaterial and PBRMaterial Compared with Three.js's Materials

Three.js 30,815 (Materials and PBR) splits by lighting model into many small classes; Babylon.js 89,603 keeps two large ones and turns features on by property. The concepts map closely:

Three.js materials and their closest Babylon.js equivalents
Three.js (Three.js) Babylon.js Notes
MeshBasicMaterial StandardMaterial with disableLighting Unlit color or texture
MeshLambertMaterial StandardMaterial, black specular Diffuse only
MeshPhongMaterial StandardMaterial Blinn-Phong with specularPower
MeshStandardMaterial PBRMetallicRoughnessMaterial glTF's core model
MeshPhysicalMaterial PBRMaterial Clear coat, sheen, anisotropy, transmission
ShaderMaterial ShaderMaterial Your own GLSL or WGSL
onBeforeCompile Material plugins Inject code into built-in shaders
TSL node materials NodeMaterial and its editor Graphs compiled to GLSL or WGSL

When porting, revisit light intensities: Three.js lighting has been physically based by default since r155, while StandardMaterial keeps Babylon's older falloff. onBeforeCompile patches a private shader string; Babylon's plugin hooks are a documented API. PBRMaterial's many switches cost a larger shader and a slower first compile, which material freezing (Freezing) and the effect cache (The Effect and Material Cache) offset.

Three.js's material classes recreated with StandardMaterial and PBRMaterial settingsHTMLLive
<!doctype html>
<style>
  body { margin: 0; background: #f7f3ec; }
  canvas { width: 100%; max-width: 600px; height: 360px; display: block; touch-action: none; }
</style>
<canvas id="view"></canvas>
<script src="https://cdn.jsdelivr.net/npm/babylonjs@9.28.0/babylon.js"></script>
<script src="https://cdn.jsdelivr.net/npm/babylonjs-gui@9.28.0/babylon.gui.min.js"></script>
<script>
const canvas = document.getElementById('view');
const engine = new BABYLON.Engine(canvas, true);
const scene = new BABYLON.Scene(engine);
scene.clearColor = BABYLON.Color4.FromHexString('#ebe5dbff');
const camera = new BABYLON.ArcRotateCamera('cam', -Math.PI / 2, 1.3, 7.2, new BABYLON.Vector3(0, -0.1, 0), scene);
camera.attachControl(canvas, true);
new BABYLON.DirectionalLight('key', new BABYLON.Vector3(0.5, -0.7, 0.6), scene).intensity = 1.4;
const fill = new BABYLON.HemisphericLight('fill', new BABYLON.Vector3(0, 1, 0), scene);
fill.intensity = 0.4;
fill.specular = BABYLON.Color3.Black();
const ui = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI('ui');

// Reflections for the PBR spheres come from a small procedural studio captured by a
// ReflectionProbe (the sandbox cannot download an .env file)
const probe = new BABYLON.ReflectionProbe('studio', 128, scene);
const studio = [[-7, 5, -7], [8, 3, -5], [0, 9, 5]].map(([x, y, z], i) => {
  const box = BABYLON.MeshBuilder.CreatePlane('softbox' + i, { width: 9, height: 4 }, scene);
  box.position.set(x, y, z);
  box.lookAt(BABYLON.Vector3.Zero());
  box.rotation.y += Math.PI;
  box.material = new BABYLON.StandardMaterial('panel' + i, scene);
  box.material.emissiveColor = new BABYLON.Color3(3, 3, 3);
  box.material.disableLighting = true;
  return box;
});
studio.forEach((mesh) => { mesh.isVisible = false; probe.renderList.push(mesh); });
probe.cubeTexture.onBeforeRenderObservable.add(() => studio.forEach((m) => { m.isVisible = true; }));
probe.cubeTexture.onAfterRenderObservable.add(() => studio.forEach((m) => { m.isVisible = false; }));
probe.refreshRate = BABYLON.RenderTargetTexture.REFRESHRATE_RENDER_ONCE;
scene.environmentTexture = probe.cubeTexture;

const teal = BABYLON.Color3.FromHexString('#2a9d8f');
const basic = new BABYLON.StandardMaterial('basic', scene);         // MeshBasicMaterial
basic.emissiveColor = teal;
basic.disableLighting = true;
const lambert = new BABYLON.StandardMaterial('lambert', scene);     // MeshLambertMaterial
lambert.diffuseColor = teal;
lambert.specularColor = BABYLON.Color3.Black();
const phong = new BABYLON.StandardMaterial('phong', scene);         // MeshPhongMaterial
phong.diffuseColor = teal;
phong.specularPower = 32;
const standard = new BABYLON.PBRMetallicRoughnessMaterial('standard', scene);   // MeshStandardMaterial
standard.baseColor = teal;
standard.metallic = 0.3;
standard.roughness = 0.35;
const physical = new BABYLON.PBRMaterial('physical', scene);        // MeshPhysicalMaterial
physical.albedoColor = teal;
physical.metallic = 0;
physical.roughness = 0.6;
physical.clearCoat.isEnabled = true;                                // a feature switched on by property

const ROWS = [[basic, 'MeshBasicMaterial', 'Standard + disableLighting'],
  [lambert, 'MeshLambertMaterial', 'Standard, black specular'],
  [phong, 'MeshPhongMaterial', 'StandardMaterial'],
  [standard, 'MeshStandardMaterial', 'PBRMetallicRoughness'],
  [physical, 'MeshPhysicalMaterial', 'PBRMaterial + clearCoat']];
ROWS.forEach(([material, three, babylon], i) => {
  const ball = BABYLON.MeshBuilder.CreateSphere(three, { diameter: 1, segments: 32 }, scene);
  ball.position.set((i - 2) * 1.5, (i % 2) * -0.5 + 0.25, 0);
  ball.material = material;
  const label = new BABYLON.GUI.TextBlock('', `${three}\n→ ${babylon}`);
  Object.assign(label, { color: '#333', fontSize: 11, resizeToFit: true });
  ui.addControl(label);
  label.linkWithMesh(ball);
  label.linkOffsetY = i % 2 ? 58 : -58;
});
const title = new BABYLON.GUI.TextBlock('', 'Three.js class  →  closest Babylon.js setup');
Object.assign(title, { color: '#555', fontSize: 14, height: '24px', top: '8px',
  verticalAlignment: BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP });
ui.addControl(title);
engine.runRenderLoop(() => scene.render());
addEventListener('resize', () => engine.resize());
</script>