Skip to content

BabylonJS - Dynamic Texture

DynamicTexture is a special type of texture in Babylon.js that allows you to draw on it using the standard HTML5 2D Canvas API. This is incredibly useful for generating textures on the fly, such as displaying text, drawing shapes, rendering UI elements, or creating procedural patterns directly onto a material.

Think of it as having a hidden 2D canvas associated with your texture. You can get the drawing context of this canvas, use familiar methods like fillText, strokeRect, beginPath, bezierCurveTo, drawImage, etc., and then update the texture to reflect your drawings on the 3D mesh.

You create a DynamicTexture by providing a name, options defining its size (width and height), the scene, and optionally whether mipmaps should be generated.

import * as BABYLON from '@babylonjs/core';
// Assuming 'scene' is defined
const textureWidth = 512;
const textureHeight = 256;
const generateMipMaps = true;
const myDynamicTexture = new BABYLON.DynamicTexture(
"dynamicTex",
{ width: textureWidth, height: textureHeight }, // Can also pass just size: 512
scene,
generateMipMaps
);

DynamicTexture provides a convenient drawText method for quickly rendering text onto the texture.

const text = "Hello Babylon!";
const x = 50; // X position on the texture canvas
const y = 100; // Y position on the texture canvas
const font = "bold 44px Arial"; // CSS font string
const color = "white"; // Text color
const canvasColor = "blue"; // Background color for the text area (can be 'transparent')
const invertY = true; // If true, Y is distance from top; if false, from bottom
const update = true; // If true, update the texture immediately
myDynamicTexture.drawText(text, x, y, font, color, canvasColor, invertY, update);

For more complex drawing, you can get the 2D rendering context of the texture’s underlying canvas using getContext(). This gives you access to the full HTML5 Canvas API.

// Get the 2D context
const ctx = myDynamicTexture.getContext();
// Now use standard canvas methods
ctx.fillStyle = "green";
ctx.fillRect(10, 10, 100, 50);
ctx.strokeStyle = "yellow";
ctx.lineWidth = 4;
ctx.strokeRect(120, 10, 80, 80);
ctx.beginPath();
ctx.moveTo(250, 30);
ctx.lineTo(350, 130);
ctx.lineTo(250, 130);
ctx.closePath();
ctx.fillStyle = "rgba(255, 0, 0, 0.7)"; // Red with transparency
ctx.fill();
ctx.stroke();
// IMPORTANT: After drawing with the context, you MUST call update()
// for the changes to appear on the 3D model.
myDynamicTexture.update();

Once created and drawn upon, you apply the DynamicTexture to a material just like any other texture (e.g., as a diffuseTexture).

// Assuming 'mesh' is defined
const material = new BABYLON.StandardMaterial("dynamicMat", scene);
material.diffuseTexture = myDynamicTexture;
mesh.material = material;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Babylon.js - Dynamic Texture Text</title>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<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.3, 0.3, 0.3, 1.0);
const camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2.5, 10, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
light.intensity = 0.9;
const box = BABYLON.MeshBuilder.CreateBox("box", { size: 3 }, scene);
// Create Dynamic Texture
const dynamicTexture = new BABYLON.DynamicTexture("dynamic texture", { width: 512, height: 256 }, scene, true);
// Apply texture to material
const material = new BABYLON.StandardMaterial("Mat", scene);
material.diffuseTexture = dynamicTexture;
box.material = material;
// Draw text onto the texture
const font = "bold 70px Arial";
dynamicTexture.drawText("Box Text", 80, 135, font, "green", "white", true, true);
// Draw text requires an update, but the last param 'true' handles it here.
// If drawing with context, call dynamicTexture.update() afterwards.
return scene;
};
const scene = createScene();
engine.runRenderLoop(function () { scene.render(); });
window.addEventListener("resize", function () { engine.resize(); });
</script>
</body>
</html>

This demo shows a simple cube rotating in the center. The cube’s surface is textured with a dynamically generated image: a white background with the text “Box Text” drawn in bold green Arial font.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Babylon.js - Dynamic Texture Canvas Drawing</title>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<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.1, 0.2, 0.3, 1.0);
const camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 4, 25, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
light.intensity = 0.8;
const ground = BABYLON.MeshBuilder.CreateGround("ground", { width: 15, height: 15 }, scene);
// Create Dynamic Texture (square)
const dynamicTexture = new BABYLON.DynamicTexture("dynamic texture", 512, scene, true);
// Apply texture to ground material
const material = new BABYLON.StandardMaterial("Mat", scene);
material.diffuseTexture = dynamicTexture;
ground.material = material;
// Get context and draw using Canvas API
const ctx = dynamicTexture.getContext();
// Clear background (optional)
ctx.fillStyle = "#4488AA"; // Bluish background
ctx.fillRect(0, 0, 512, 512);
// Draw a bezier curve (e.g., a heart shape)
ctx.beginPath();
ctx.moveTo(256, 150); // Start point slightly offset from center top
ctx.bezierCurveTo(256, 130, 230, 100, 190, 100); // Left top curve
ctx.bezierCurveTo(120, 100, 120, 180, 120, 180); // Left side curve
ctx.bezierCurveTo(120, 250, 190, 310, 256, 350); // Bottom point curve
ctx.bezierCurveTo(322, 310, 392, 250, 392, 180); // Right side curve
ctx.bezierCurveTo(392, 180, 392, 100, 332, 100); // Right top curve
ctx.bezierCurveTo(290, 100, 256, 130, 256, 150); // Connect back near start
ctx.closePath();
ctx.fillStyle = "red";
ctx.fill();
ctx.strokeStyle = "darkred";
ctx.lineWidth = 5;
ctx.stroke();
// Update the texture to show the drawing
dynamicTexture.update();
return scene;
};
const scene = createScene();
engine.runRenderLoop(function () { scene.render(); });
window.addEventListener("resize", function () { engine.resize(); });
</script>
</body>
</html>

This example displays a ground plane. The texture applied to the ground is generated dynamically. It shows a bluish background with a large red heart shape (drawn using bezier curves via the canvas context) in the center.

Updating a DynamicTexture, especially a large one, frequently (e.g., every frame) can impact performance as it involves CPU-side drawing and GPU texture uploads. Use it judiciously for elements that don’t change constantly or optimize the update frequency. For highly dynamic text or UI, consider using the Babylon.js GUI system, which is often more performant.