
- Three.js 教程
- Three.js - 首頁
- Three.js - 簡介
- Three.js - 安裝
- Three.js - Hello Cube 應用
- Three.js - 渲染器和響應性
- Three.js - 響應式設計
- Three.js - 除錯和統計
- Three.js - 相機
- Three.js - 控制元件
- Three.js - 光照和陰影
- Three.js - 幾何體
- Three.js - 材質
- Three.js - 紋理
- Three.js - 繪製線條
- Three.js - 動畫
- Three.js - 建立文字
- Three.js - 載入 3D 模型
- Three.js - 庫和外掛
- Three.js 有用資源
- Three.js - 快速指南
- Three.js - 有用資源
- Three.js - 討論
Three.js - 建立文字
通常您需要在場景中新增文字。在本章中,讓我們看看如何在場景中新增 2D 和 3D 文字。
繪製文字到畫布並用作紋理
這是在場景中新增 2D 文字最簡單的方法。您可以使用 JavaScript 建立畫布並將其新增到 DOM 中。
const canvas = document.createElement('canvas') const context = canvas.getContext('2d')
上面的程式碼建立了一個畫布元素,我們將上下文設定為 2d。canvas.getContext() 方法返回一個物件,該物件提供用於在畫布上繪製的方法和屬性,它可以使用這些方法和屬性繪製文字、線條、框、圓圈等。
context.fillStyle = 'green' context.font = '60px sans-serif context.fillText('Hello World!', 0, 60)
fillText() 是 2D 繪製上下文的一種方法。fillText() 方法允許您在具有您提供的 fillStyle 派生的填充(顏色)的座標處繪製文字字串。您可以使用 font 屬性設定文字的字型。
以上程式碼將字型設定為 60 畫素高的 sans-serif,填充樣式設定為綠色。文字“Hello, World!”從座標 (0, 60) 開始繪製。
// canvas contents are used for a texture const texture = new THREE.Texture(canvas) texture.needsUpdate = true
要從畫布元素建立紋理,我們需要建立一個新的 THREE.Texture 例項並傳入我們建立的畫布元素。上面的程式碼使用畫布(在本例中為我們的文字)建立紋理。紋理的 needsUpdate 引數設定為 true。它通知 Three.js 我們的畫布紋理已更改,需要在下一次渲染場景時更新。
現在,建立一個平面幾何體並將其作為紋理新增到材質中。
var material = new THREE.MeshBasicMaterial({ map: texture, side: THREE.DoubleSide, }) material.transparent = true var mesh = new THREE.Mesh(new THREE.PlaneGeometry(50, 10), material)
使用文字幾何體
THREE.TextGeometry 是另一種幾何體型別,它將文字生成單個幾何體。它接受兩個引數,text - 您要渲染的文字,以及其他引數。
引數
font − 這是字型的名稱。
size − 文字的大小。預設為 100。
height − height 屬性定義文字的深度;換句話說,文字突出顯示以使其成為 3D 的程度。預設為 50。
curveSegments − 曲線上點的數量。預設為 12。
bevelEnabled − 倒角提供從文字正面到側面的平滑過渡。如果將此值設定為 true,則會向渲染的文字新增倒角。預設情況下,它是 false。
bevelThickness − 如果您已將 bevelEnabled 設定為 true,則它定義倒角的深度。預設為 10。
bevelSize − 它決定倒角的高度。預設為 8。
bevelOffset − 倒角距文字輪廓多遠開始。預設為 0。
bevelSegments − 倒角段的數量。預設為 3。
您需要使用 THREE.FontLoader 從其 typeface.json 檔案載入字型。
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, }) })
現在,您應該向其新增一些材質並建立一個網格。
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)
注意 − 在使用 THREE.TextGeometry 和材質時,您需要注意一件事。它可以將兩個材質作為陣列:一個用於渲染文字的正面,另一個用於文字的側面。如果您只傳入一個材質,它將應用於正面和側面。
示例
現在,您可以看到渲染到場景中的文字。檢視以下示例。
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>
輸出
示例
現在讓我們再舉一個例子,看看如何在場景中新增 3D 文字。
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>