Three.js - Creating Text
Three.js - Creating Text
Section titled “Three.js - Creating Text”Displaying text is a common requirement in 3D scenes, whether for user interfaces, annotations, or artistic effects. There are several ways to achieve this in Three.js, each with its own advantages and disadvantages. We’ll explore three primary methods.
Method 1: HTML and CSS (The Recommended Way for UI)
Section titled “Method 1: HTML and CSS (The Recommended Way for UI)”The most flexible and highest-quality method for creating UI elements like labels and overlays is to use what the browser does best: rendering HTML and CSS. Three.js provides CSS2DRenderer and CSS3DRenderer to help you position regular HTML elements in your 3D scene.
- Pros: Crisp text at any resolution, full power of CSS for styling and animation, great for accessibility, clickable links and buttons.
- Cons: Elements are rendered on top of the 3D scene, not within it. They cannot be obscured by 3D objects or affected by scene lighting.
Implementation with CSS2DRenderer
Section titled “Implementation with CSS2DRenderer”import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js';
// 1. Setup the rendererconst labelRenderer = new CSS2DRenderer();labelRenderer.setSize(window.innerWidth, window.innerHeight);labelRenderer.domElement.style.position = 'absolute';labelRenderer.domElement.style.top = '0px';document.body.appendChild(labelRenderer.domElement);
// 2. Create the HTML elementconst p = document.createElement('p');p.textContent = 'Hello, World!';p.style.color = 'white';p.style.fontFamily = 'sans-serif';p.style.fontSize = '2em';
// 3. Create the CSS2DObjectconst label = new CSS2DObject(p);
// 4. Position it and add it to a 3D object or the scene// Position it on top of a cube, for examplelabel.position.set(0, 0.75, 0); // Position is relative to the parentcube.add(label);
// 5. Render in your animation loopfunction animate() { // ... renderer.render(scene, camera); // WebGL renderer labelRenderer.render(scene, camera); // CSS2D renderer}Method 2: 3D Text Geometry
Section titled “Method 2: 3D Text Geometry”For text that needs to exist as a true 3D object within your scene—to cast shadows, be affected by lights, and be obscured by other objects—you can use TextGeometry.
- Pros: Is a real 3D mesh, interacts with lighting and other objects, can have depth and beveling.
- Cons: Requires loading a special font file (
.typeface.json), can be heavy on performance due to high polygon count, text quality can degrade when viewed up close.
Implementation with TextGeometry
Section titled “Implementation with TextGeometry”This process involves loading a font, then using that font to generate the geometry.
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader.js';import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js';
const fontLoader = new FontLoader();
fontLoader.load( '/fonts/helvetiker_regular.typeface.json', // Path to a typeface.json font (font) => { const textGeometry = new TextGeometry( 'Three.js', { font: font, size: 0.5, height: 0.2, // Depth curveSegments: 12, bevelEnabled: true, bevelThickness: 0.03, bevelSize: 0.02, bevelOffset: 0, bevelSegments: 5 } );
// Center the geometry for easier positioning textGeometry.center();
const textMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff }); const textMesh = new THREE.Mesh(textGeometry, textMaterial); scene.add(textMesh); });Note: You can find typeface.json fonts in the Three.js examples repository, or convert your own TTF/OTF fonts using online tools.
Method 3: Text on a Canvas Texture
Section titled “Method 3: Text on a Canvas Texture”This is a hybrid approach. You draw text onto a 2D HTML5 Canvas and then use that canvas as a texture on a 3D plane (PlaneGeometry). It’s a highly performant way to display text that looks like it’s in the 3D world.
- Pros: Very performant, can be applied to any geometry, high quality text rendering from the 2D canvas API.
- Cons: Text is flat (part of a texture), requires careful management of texture updates if the text needs to change dynamically.
Implementation
Section titled “Implementation”// 1. Create a canvas element in memoryconst canvas = document.createElement('canvas');const context = canvas.getContext('2d');canvas.width = 512;canvas.height = 128;
// 2. Draw text on the canvascontext.fillStyle = '#444444'; // Backgroundcontext.fillRect(0, 0, canvas.width, canvas.height);context.font = 'Bold 48px sans-serif';context.fillStyle = 'white';context.textAlign = 'center';context.textBaseline = 'middle';context.fillText('Canvas Texture', canvas.width / 2, canvas.height / 2);
// 3. Create a texture from the canvasconst texture = new THREE.CanvasTexture(canvas);
// 4. Apply the texture to a materialconst material = new THREE.MeshBasicMaterial({ map: texture });const geometry = new THREE.PlaneGeometry(4, 1); // Aspect ratio matches canvasconst planeMesh = new THREE.Mesh(geometry, material);scene.add(planeMesh);If you need to update the text, you redraw on the canvas and then set texture.needsUpdate = true; to tell Three.js to re-upload the texture to the GPU.
Which Method to Choose?
Section titled “Which Method to Choose?”- For UI, HUDs, and annotations, use HTML/CSS (
CSS2DRenderer). - For 3D logos or text that must be part of the scene, use
TextGeometry. - For performant text on signs or surfaces within the world, use a Canvas Texture.