Building Custom PBR Materials with Babylon.js Node Material System
Learn how to create a custom emissive material in Babylon.js using the Node Material System—no GLSL required—complete with a code example, limits, and verification steps.
26 Feb 2026, 22:44 UTC

Quick answer: create a custom emissive material without writing GLSL
If you need a material that multiplies a texture by a constant color for emissive output, you can assemble the required nodes visually (or in code) using Babylon.js Node Material System. The system generates the underlying GLSL/WGSL shader for you, works for both WebGL and WebGPU backends, and avoids manual shader authoring.
Worked example: emissive texture × color multiplier
The following code creates a node material, connects a texture sample, a color constant, and a multiply block to the emissive input of a PBR material, then assigns it to a mesh.
// Assume `scene` and `engine` are already created
const mesh = BABYLON.MeshBuilder.CreateSphere("sphere", { diameter: 2 }, scene);
// 1️⃣ Create the node material
const nodeMaterial = new BABYLON.NodeMaterial("emissiveNodeMaterial", scene);
nodeMaterial.mode = BABYLON.NodeMaterialMode.PBR; // ensures PBR lighting
// 2️⃣ Nodes
const textureNode = new BABYLON.TextureNode();
textureNode.texture = new BABYLON.Texture("textures/emissive.png", scene);
const colorNode = new BABYLON.ColorNode();
colorNode.r = 0.8; // tweak emissive tint
colorNode.g = 0.2;
colorNode.b = 0.2;
const multiplyNode = new BABYLON.MultiplyBlock();
// 3️⃣ Connections: texture * color → emissive
textureNode.connectTo(multiplyNode, 0); // texture → multiply.x
colorNode.connectTo(multiplyNode, 1); // color → multiply.y
// 4️⃣ Connect multiply result to the PBR emissive input
multiplyNode.connectTo(nodeMaterial.emissiveColor);
// 5️⃣ Build the material (compiles the shader)
nodeMaterial.build();
// 6️⃣ Apply to mesh
mesh.material = nodeMaterial;
// Optional: view generated shader for debugging
nodeMaterial.debugMode = true; // opens inspector showing GLSL/WGSL
Explanation of the steps:
- Create a NodeMaterial in PBR mode so the system knows which inputs (baseColor, metallic, roughness, emissiveColor, etc.) are available.
- Instantiate nodes that represent the operations you need: a texture sampler, a constant color, and a multiply block.
- Connect nodes by linking output ports to input ports. The texture node outputs a
vec3RGB; the color node outputs anothervec3; the multiply block combines them component‑wise. - Route the result to the material’s
emissiveColorinput, which the PBR lighting model uses for self‑illumination. - Call
build()to compile the node graph into a shader. Until this is called, the material is not ready for rendering. - Assign the material to a mesh.
Limits and common pitfalls
- Version requirement – The Node Material System is stable from Babylon.js 4.0+. Older releases lack the
NodeMaterialclass or have incomplete node sets. - Shader size – Automatically generated shaders can be larger than hand‑written equivalents because the system adds boilerplate for all possible PBR paths. Profile with
engine.getGPUStats()if shader size becomes a concern. - Debugging difficulty – When a visual result looks wrong, you must inspect the generated shader (via
debugMode = true) or break the graph into smaller sub‑graphs to isolate the faulty node. - Missing nodes – Not every GLSL feature is exposed as a built‑in node (e.g., custom loop logic, complex noise functions). For those cases you must create a
CustomBlockor fall back to a standardShaderMaterial. - Common mistake – forgetting
build()– The material will appear black or show an error in the console because the shader program was never linked. Always callbuild()after wiring nodes. - Common mistake – wrong port types – Nodes are strongly typed; connecting a
floatoutput to avec3input without a conversion block will be silently ignored or produce a warning. UseVector3orFloatnodes with appropriateSplit/Combineblocks when needed. - Common mistake – disposing textures – If you replace the texture later, dispose the old texture to avoid GPU memory leaks:
oldTexture.dispose().
How to verify the result
- Run the scene in a browser and confirm the sphere shows the emissive tint where the texture is non‑black.
- Open the Babylon.js Inspector (
scene.debugLayer.show()) and select the material; the “Node Material” tab displays the graph and lets you toggle nodes on/off. - With
nodeMaterial.debugMode = true, the inspector also shows the generated GLSL (WebGL) or WGSL (WebGPU) code; verify that the multiply operation appears as expected. - Test on multiple browsers (Chrome, Firefox, Safari) to ensure both WebGL2 and WebGPU paths work; any fallback to WebGL1 will still run but may lack certain precision.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.