- 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>