Skip to content

BabylonJS - Materials

Materials define the surface appearance of your meshes. They determine how light interacts with the object, controlling its color, texture, shininess, transparency, and other visual properties. Applying different materials can make the same mesh look like wood, metal, plastic, glass, or anything else imaginable.

Babylon.js offers several types of materials, with the most important being StandardMaterial for general-purpose use and PBRMaterial (Physically Based Rendering) for achieving photorealistic results.

Standard Material (BABYLON.StandardMaterial)

Section titled “Standard Material (BABYLON.StandardMaterial)”

The StandardMaterial is a versatile material based on traditional Blinn-Phong lighting models. It’s relatively easy to use and offers good performance. You assign it to a mesh’s material property.

import * as BABYLON from '@babylonjs/core';
// Assuming 'scene' and 'myMesh' are defined
const myMaterial = new BABYLON.StandardMaterial("myStdMat", scene);
// --- Common Properties ---
// Color
myMaterial.diffuseColor = new BABYLON.Color3(1, 0, 0); // Red base color
// myMaterial.ambientColor = new BABYLON.Color3(0.1, 0.1, 0.1); // Color in ambient light
myMaterial.specularColor = new BABYLON.Color3(1, 1, 1); // Color of highlights (white is common)
myMaterial.emissiveColor = new BABYLON.Color3(0, 0.1, 0); // Color the object emits itself (glow)
// Texture (overrides diffuseColor if set)
// myMaterial.diffuseTexture = new BABYLON.Texture("textures/wood.jpg", scene);
// Shininess
myMaterial.specularPower = 64; // Higher values = smaller, sharper highlights
// Transparency
myMaterial.alpha = 0.8; // 1.0 is fully opaque, 0.0 is fully transparent
// Wireframe
// myMaterial.wireframe = true; // Show mesh edges instead of surfaces
// Backface Culling (performance optimization, hides back faces)
// myMaterial.backFaceCulling = false; // Set to false for planes or non-closed meshes
// Apply the material to the mesh
myMesh.material = myMaterial;

StandardMaterial supports various texture maps to add detail:

  • diffuseTexture: The main color/pattern texture.
  • ambientTexture: Adds color detail in ambient light.
  • specularTexture: Controls the color/intensity of specular highlights per pixel.
  • emissiveTexture: Defines areas that glow.
  • opacityTexture: Controls transparency per pixel (usually grayscale).
  • bumpTexture: Simulates surface detail (normal map) affecting lighting.
  • reflectionTexture: Adds reflections (often a CubeTexture or MirrorTexture).
  • refractionTexture: Simulates light bending through transparent materials like glass (requires a ReflectionProbe or CubeTexture).

PBR Materials (Physically Based Rendering)

Section titled “PBR Materials (Physically Based Rendering)”

PBR materials aim to simulate how light behaves in the real world, resulting in more realistic visuals across different lighting conditions. They are the recommended approach for modern, high-fidelity graphics. Babylon.js primarily uses the Metallic-Roughness workflow (PBRMetallicRoughnessMaterial), but also supports the Specular-Glossiness workflow (PBRSpecularGlossinessMaterial). PBRMaterial is a base class allowing more complex setups.

Key PBR Concepts (Metallic-Roughness):

  • baseColor: The underlying color of the material (like diffuse).
  • metallic: How ‘metal-like’ the surface is (0 for non-metals/dielectrics, 1 for metals). Controls reflection behavior.
  • roughness: How rough or smooth the surface is (0 for perfectly smooth/mirror-like, 1 for very rough/diffuse). Affects highlight sharpness and reflection clarity.
  • Image-Based Lighting (IBL): PBR heavily relies on scene.environmentTexture (often a .env or .hdr CubeTexture) for realistic ambient light and reflections.
// Create a PBR Metallic-Roughness material
const pbrMaterial = new BABYLON.PBRMetallicRoughnessMaterial("myPBRMat", scene);
// Base Color
pbrMaterial.baseColor = new BABYLON.Color3(0.8, 0.8, 0.8); // Light gray
// Or use a texture
// pbrMaterial.baseTexture = new BABYLON.Texture("textures/metal_basecolor.png", scene);
// Metallic
pbrMaterial.metallic = 0.9; // Mostly metallic
// Roughness
pbrMaterial.roughness = 0.2; // Quite smooth
// Make sure scene has an environment texture for realistic reflections!
// scene.environmentTexture = BABYLON.CubeTexture.CreateFromPrefilteredData("textures/environment.env", scene);
// Apply to mesh
myMesh.material = pbrMaterial;

PBR materials use specific texture maps:

  • baseTexture: Provides the base color.
  • metallicRoughnessTexture: Often packs metallic (e.g., blue channel) and roughness (e.g., green channel) into one texture for efficiency.
  • normalTexture: Standard normal map for surface detail.
  • ambientOcclusionTexture (or occlusionTexture): Adds subtle contact shadows.
  • emissiveTexture: Defines glowing areas.

The Fresnel effect describes how reflectivity changes based on the viewing angle. Surfaces are typically more reflective at grazing angles (when viewed edge-on) than when viewed head-on. Both StandardMaterial and PBRMaterial incorporate Fresnel effects.

On StandardMaterial, you can explicitly control Fresnel for diffuse, opacity, reflection, and emissive components using FresnelParameters objects.

// Example: Add reflection Fresnel to a StandardMaterial
myStdMaterial.reflectionTexture = reflectionProbe.cubeTexture; // Needs a reflection source
myStdMaterial.reflectionFresnelParameters = new BABYLON.FresnelParameters();
myStdMaterial.reflectionFresnelParameters.bias = 0.1; // Controls falloff near center
myStdMaterial.reflectionFresnelParameters.power = 2; // Controls sharpness of falloff
myStdMaterial.reflectionFresnelParameters.leftColor = BABYLON.Color3.White(); // Reflection color at grazing angle
myStdMaterial.reflectionFresnelParameters.rightColor = BABYLON.Color3.Black(); // Reflection color head-on

On PBRMaterial, Fresnel is calculated automatically based on physics principles (using factors like index of refraction, metallic property). You typically don’t set Fresnel parameters directly unless for very specific effects.

This demo shows two spheres side-by-side. One uses StandardMaterial, the other PBRMetallicRoughnessMaterial. Both attempt to look like red plastic. Note how they react differently to light and environment.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Babylon.js - Material Comparison</title>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js"></script> <!-- Needed for env texture -->
<style>
html, body { overflow: hidden; width: 100%; height: 100%; margin: 0; padding: 0; }
#renderCanvas { width: 100%; height: 100%; touch-action: none; }
</style>
</head>
<body>
<canvas id="renderCanvas"></canvas>
<script type="text/javascript">
const canvas = document.getElementById("renderCanvas");
const engine = new BABYLON.Engine(canvas, true);
const createScene = function () {
const scene = new BABYLON.Scene(engine);
// scene.clearColor = new BABYLON.Color4(0.2, 0.2, 0.25, 1.0);
// Environment Texture (Crucial for PBR)
try {
// Ensure 'textures/environment.env' exists
const envTexture = BABYLON.CubeTexture.CreateFromPrefilteredData("textures/environment.env", scene);
scene.environmentTexture = envTexture;
scene.createDefaultSkybox(envTexture, true, 1000, 0.3); // Add skybox using the env texture
} catch(err) {
console.error("Failed to load environment texture:", err);
scene.clearColor = new BABYLON.Color4(0.2, 0.2, 0.25, 1.0);
// Add basic light as fallback if env texture fails
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
light.intensity = 1.0;
}
const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2 * 1.2 , Math.PI / 2.5, 10, new BABYLON.Vector3(0, 1, 0), scene);
camera.attachControl(canvas, true);
camera.wheelPrecision = 100;
// Sphere 1: Standard Material (Red Plastic attempt)
const sphereStd = BABYLON.MeshBuilder.CreateSphere("sphereStd", { diameter: 2, segments: 32 }, scene);
sphereStd.position.x = -2;
sphereStd.position.y = 1;
const stdMat = new BABYLON.StandardMaterial("stdMat", scene);
stdMat.diffuseColor = new BABYLON.Color3(0.8, 0.1, 0.1); // Red
stdMat.specularColor = new BABYLON.Color3(0.9, 0.9, 0.9); // Strong white highlights
stdMat.specularPower = 48; // Relatively sharp highlights for plastic
// Optional: Add subtle reflection from environment
// stdMat.reflectionTexture = scene.environmentTexture;
// stdMat.reflectionFresnelParameters = new BABYLON.FresnelParameters();
// stdMat.reflectionFresnelParameters.bias = 0.8; // Less reflection head-on
sphereStd.material = stdMat;
// Sphere 2: PBR Material (Red Plastic attempt)
const spherePBR = BABYLON.MeshBuilder.CreateSphere("spherePBR", { diameter: 2, segments: 32 }, scene);
spherePBR.position.x = 2;
spherePBR.position.y = 1;
const pbrMat = new BABYLON.PBRMetallicRoughnessMaterial("pbrMat", scene);
pbrMat.baseColor = new BABYLON.Color3(0.8, 0.1, 0.1); // Red
pbrMat.metallic = 0.1; // Low metallic for plastic
pbrMat.roughness = 0.3; // Moderate roughness for plastic sheen
// PBR uses scene.environmentTexture automatically for reflections
spherePBR.material = pbrMat;
return scene;
};
const scene = createScene();
engine.runRenderLoop(function () { scene.render(); });
window.addEventListener("resize", function () { engine.resize(); });
</script>
</body>
</html>

This demo shows two red spheres against a realistic sky background (if the environment texture loads). The left sphere uses StandardMaterial, and the right sphere uses PBRMaterial. Observe how the PBR sphere likely shows more realistic reflections and highlights that interact naturally with the skybox environment, while the StandardMaterial sphere’s appearance is more dependent on the specific specularColor and specularPower values set. The PBR material often looks more grounded in the environment.

For the PBR material and skybox to work optimally, you need a pre-filtered environment cube map file (e.g., environment.env) located in a textures folder. You can generate these from HDR images using tools like the Babylon.js Sandbox or Lys.