- 三.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 像素高的无衬线字体,并将填充样式设置为绿色。文本“你好,世界!” 从坐标 (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 是另一种类型的几何图形,它将文本生成为单个几何图形。它需要两个参数,文本 - 要呈现的文本,以及其他参数。
参数
font - 这是字体的名称。
size - 文本的大小。默认值为 100。
height - height 属性定义文本的深度;换句话说,文本拉伸多远才能使其成为 3D。默认为 50。
curveSegments - 曲线上的点数。默认值为 12。
bevelEnabled - 斜角提供从文本正面到侧面的平滑过渡。如果将此值设置为 true,则会向渲染的文本添加斜角。默认情况下,它是错误的。
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 和材质时需要考虑一件事。它可以将两种材质作为一个数组:一种用于渲染文本的正面,另一种用于文本的侧面。如果您只传递一种材料,它将同时应用于正面和侧面。
例子
现在,您可以看到渲染到场景的文本。查看以下示例。
二维文本.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-文本.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>