”;
Often you need to add text to your scene. In this chapter, let”s see how to add 2D and 3D text to our scene.
Draw Text to Canvas and Use as a Texture
This is the easiest way to add 2D text to your scene. you can create canvas using JavaScript andd add it to the dom.
const canvas = document.createElement(''canvas'') const context = canvas.getContext(''2d'')
The code above creates a canvas element, and we set the context to 2d. The canvas.getContext() method returns an object that provides methods and properties for drawing on the canvas, which it can use to draw text, lines, boxes, circles, and more.
context.fillStyle = ''green'' context.font = ''60px sans-serif context.fillText(''Hello World!'', 0, 60)
The fillText() is a method of a 2D drawing context. The fillText() method allows you to draw a text string at a coordinate with the fill (color) derived from the fillStyle you provided. You can set the font of the text using the font property.
The above code set the font to 60-pixel-tall san-serif and the fill style to green. The text ”Hello, World!” is drawn starting at the coordinates (0, 60).
// canvas contents are used for a texture const texture = new THREE.Texture(canvas) texture.needsUpdate = true
To create a texture from a canvas element, we need to create a new instance of THREE.Texture and pass in the canvas element we made. The code above creates a texture using the canvas (in this case, our text). The needsUpdate parameter of the texture is set to true. It informs Three.js that our canvas texture has changed and needs to be updated the next time the scene is rendered.
Now, create a plane geometry and add this as a texture to the material.
var material = new THREE.MeshBasicMaterial({ map: texture, side: THREE.DoubleSide, }) material.transparent = true var mesh = new THREE.Mesh(new THREE.PlaneGeometry(50, 10), material)
Using Text Geometry
THREE.TextGeometry is another type of geometry that generates text as a single geometry. It takes two arguments, text – the text you want to render, and other parameters.
Parameters
-
font − This is the name of the font.
-
size − Size of the text. Default is 100.
-
height − The height property defines the depth of the text; in other words, how far the text extrudes to make it 3D. This defaults to 50.
-
curveSegments − Number of points on the curves. Default is 12.
-
bevelEnabled − A bevel provides a smooth transition from the front of the text to the side. If you set this value to true, it adds a bevel to the rendered text. By default, it is false.
-
bevelThickness − If you”ve set bevelEnabled to true, it defines how deep the bevel is. Default is 10.
-
bevelSize − It determines how high the bevel is. Default is equal to 8.
-
bevelOffset − How far from text outline bevel starts. Default is 0.
-
bevelSegments − The number of bevel segments. Default is 3.
You need to use THREE.FontLoader to load fonts from their typeface.json files.
const loader = new THREE.FontLoader() loader.load(''fonts/helvetiker_regular.typeface.json'', function (font) { const geometry = new THREE.TextGeometry(''Hello Three.js!'', { font: font, size: 3, height: 0.2, curveSegments: 12, bevelEnabled: false, bevelThickness: 0.5, bevelSize: 0.3, bevelOffset: 0, bevelSegments: 5, }) })
Now, you should add some material to it and create a mesh.
const material = new THREE.MeshFaceMaterial([ new THREE.MeshPhongMaterial({ color: 0xff22cc, flatShading: true, }), // front new THREE.MeshPhongMaterial({ color: 0xffcc22 }), // side ]) const mesh = new THREE.Mesh(geometry, material) mesh.name = ''text'' scene.add(mesh)
Note − There is one thing you need to take into account when working with THREE.TextGeometry and materials. It can take two materials as an array: one for the front of rendered text and another for the side of the text. If you just pass in one material, it gets applied to both the front and the side.
Example
Now, you can see the text rendered to the scene. Check out the following example.
2d-text.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Three.js - 2d text</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: -applesystem, BlinkMacSystemFont, ''Segoe UI'', Roboto, Oxygen, Ubuntu, Cantarell, ''Open Sans'', ''Helvetica Neue'', sans-serif; } html, body { height: 100vh; width: 100vw; } #threejs-container { position: block; width: 100%; height: 100%; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.js"></script> </head> <body> <div id="threejs-container"></div> <script type="module"> // Adding 2d text to Three.js scene // Writing on canvas and then adding the canvas as a texture to material // GUI const gui = new dat.GUI() // sizes let width = window.innerWidth let height = window.innerHeight const size = 256 const container = document.querySelector(''#threejs-container'') const canvas = document.createElement(''canvas''), ctx = canvas.getContext(''2d'') function changeCanvas() { ctx.font = ''20pt Arial'' ctx.fillStyle = ''white'' ctx.fillRect(0, 0, canvas.width, canvas.height) ctx.fillStyle = ''black'' ctx.textAlign = ''center'' ctx.textBaseline = ''middle'' ctx.fillText(''Tutorialspoint!'', canvas.width / 2, canvas.height / 2) } // scene const scene = new THREE.Scene() scene.background = new THREE.Color(0x262626) // lights const ambientLight = new THREE.AmbientLight(0xffffff, 1) scene.add(ambientLight) const pointLight = new THREE.PointLight(0xffffff, 0.5) pointLight.position.x = 20 pointLight.position.y = 30 pointLight.position.z = 40 scene.add(pointLight) // camera const camera = new THREE.PerspectiveCamera(70, width / height, 1, 1000) camera.position.z = 500 scene.add(camera) // renderer const renderer = new THREE.WebGL1Renderer({ antialias: true }) renderer.setSize(width, height) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) container.append(renderer.domElement) renderer.render(scene, camera) // cube const texture = new THREE.Texture(canvas) const material = new THREE.MeshStandardMaterial({ map: texture }) const geometry = new THREE.BoxGeometry(200, 200, 200) const mesh = new THREE.Mesh(geometry, material) scene.add(mesh) canvas.width = canvas.height = size // responsiveness window.addEventListener(''resize'', () => { width = window.innerWidth height = window.innerHeight camera.aspect = width / height camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) renderer.render(scene, camera) }) // animation function animate() { requestAnimationFrame(animate) changeCanvas() texture.needsUpdate = true mesh.rotation.y += 0.01 renderer.render(scene, camera) } animate() </script> </body> </html>
Output
Example
Let us now take another example to see how to add 3D text in a scene.
3d-text.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Three.js - 3d text</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: -applesystem, BlinkMacSystemFont, ''Segoe UI'', Roboto, Oxygen, Ubuntu, Cantarell, ''Open Sans'', ''Helvetica Neue'', sans-serif; } html, body { height: 100vh; width: 100vw; } #threejs-container { position: block; width: 100%; height: 100%; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.js"></script> <head> <body> <div id="threejs-container"></div> <script type="module"> // Creating 3d text using Text Geometry in Three.js // GUI const gui = new dat.GUI() // sizes let width = window.innerWidth let height = window.innerHeight // scene const scene = new THREE.Scene() scene.background = new THREE.Color(0x262626) // lights const ambientLight = new THREE.AmbientLight(0xffffff, 1) scene.add(ambientLight) const pointLight = new THREE.PointLight(0xffffff, 0.5) pointLight.position.x = 20 pointLight.position.y = 30 pointLight.position.z = 40 scene.add(pointLight) // camera const camera = new THREE.PerspectiveCamera(30, width / height, 0.1, 1000) camera.position.set(0, 0, 50) const camFolder = gui.addFolder(''Camera'') camFolder.add(camera.position, ''z'').min(10).max(500).step(10) camFolder.open() function createMaterial() {} const loader = new THREE.FontLoader() // promisify font loading function loadFont(url) { return new Promise((resolve, reject) => { loader.load(url, resolve, undefined, reject) }) } async function doit() { const font = await loadFont(''https://threejs.org/examples/fonts/helvetiker_regular.typeface.json'') let text = ''Hello World !'' const geometry = new THREE.TextGeometry(text, { font: font, size: 3, height: 0.2, curveSegments: 12, bevelEnabled: true, bevelOffset: 0, bevelThickness: 0.5, bevelSize: 0.3, bevelSegments: 5 }) const material = [ new THREE.MeshPhongMaterial({ color: 0xff22cc, flatShading: true }), // front new THREE.MeshPhongMaterial({ color: 0xffcc22 }) // side ] const mesh = new THREE.Mesh(geometry, material) geometry.computeBoundingBox() geometry.computeVertexNormals() geometry.boundingBox.getCenter(mesh.position).multiplyScalar(-1) mesh.position.x = -geometry.boundingBox.max.x / 2 const parent = new THREE.Object3D() parent.add(mesh) scene.add(parent) const opts = geometry.parameters.options console.log(opts) const geoProps = { font: opts.font, size: opts.size, height: opts.height, curveSegments: opts.curveSegments, bevelEnabled: opts.bevelEnabled, bevelOffset: opts.bevelOffset, bevelThickness: opts.bevelThickness, bevelSize: opts.bevelSize, bevelSegments: opts.bevelSegments } console.log(geoProps) // GUI for exporimenting cube properties const props = gui.addFolder(''Properties'') props .add(geoProps, ''size'', 1, 30) .step(1) .onChange(redraw) .onFinishChange(() => console.dir(mesh.geometry)) props.add(geoProps, ''height'', 0, 30).step(0.1).onChange(redraw) props.add(geoProps, ''curveSegments'', 1, 30).step(1).onChange(redraw) props.add(geoProps, ''bevelEnabled'').onChange(redraw) props.add(geoProps, ''bevelOffset'', 0, 1).onChange(redraw) props.add(geoProps, ''bevelThickness'', 0, 3).onChange(redraw) props.add(geoProps, ''bevelSize'', 0, 3).onChange(redraw) props.add(geoProps, ''bevelSegments'', 1, 8).step(1).onChange(redraw) props.open() function redraw() { camera.position.set(0, 0, 80) let newGeometry = new THREE.TextGeometry(text, { font: geoProps.font, size: geoProps.size, height: geoProps.height, curveSegments: geoProps.curveSegments, bevelEnabled: geoProps.bevelEnabled, bevelOffset: geoProps.bevelOffset, bevelThickness: geoProps.bevelThickness, bevelSize: geoProps.bevelSize, bevelSegments: geoProps.bevelSegments }) mesh.geometry.dispose() mesh.geometry = newGeometry mesh.geometry.parameters.options.depth = 0.2 console.log(mesh.geometry.parameters.options) } } doit() // responsiveness window.addEventListener(''resize'', () => { width = window.innerWidth height = window.innerHeight camera.aspect = width / height camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) renderer.render(scene, camera) }) // renderer const renderer = new THREE.WebGL1Renderer({ antialias: true }) renderer.setSize(width, height) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) // animation function animate() { requestAnimationFrame(animate) renderer.render(scene, camera) } // rendering the scene const container = document.querySelector(''#threejs-container'') container.append(renderer.domElement) renderer.render(scene, camera) animate() </script> </body> </html>
Output
”;