如何在Three.js场景上方添加2D文本图层?
在Three.js 3D场景上方添加2D文本图层的几种方法
嘿,要在你的Three.js 3D场景上加2D文本图层其实很简单,我给你分享两种最常用的实现方式:
方法一:用普通HTML元素叠加(最简单)
这种方法不需要额外引入Three.js扩展,直接利用CSS绝对定位把HTML文本元素放在Three.js渲染的Canvas上方即可,适合快速实现静态文本需求。
修改后的完整代码:
<html> <head> <title>First page.</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <link href="/errordocs/style/general.css" rel="stylesheet" type="text/css"> <script src="https://threejs.org/build/three.js" crossorigin="anonymous"></script> <style> body { margin: 0; } canvas { width: 100%; height: 100%; position: absolute; top: 0; left: 0; } /* 2D文本图层样式 */ .text-overlay { position: absolute; top: 20px; left: 20px; color: white; font-size: 24px; z-index: 10; /* 确保在Canvas上方 */ pointer-events: none; /* 可选:让鼠标事件穿透文本,不影响Three.js交互 */ } </style> </head> <body> <!-- 2D文本元素 --> <div class="text-overlay">这是3D场景上方的2D文本</div> <script> var scene, camera, renderer; var geometry, material, mesh; init(); animate(); function init() { scene = new THREE.Scene(); scene.background = new THREE.Color( 0x222222 ); camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.01, 100 ); camera.position.z = 1; geometry = new THREE.SphereGeometry( 0.1, 20, 20 ); material = new THREE.MeshNormalMaterial(); mesh = new THREE.Mesh( geometry, material ); scene.add( mesh ); renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); } // 添加动画循环让球体动起来(可选) function animate() { requestAnimationFrame( animate ); mesh.rotation.x += 0.01; mesh.rotation.y += 0.02; renderer.render( scene, camera ); } </script> </body> </html>
关键点说明:
- 给Canvas设置
position: absolute,让文本元素可以正确叠加在其上方 - 文本元素的
z-index要大于Canvas(默认Canvas无z-index,设置10足够保证层级) pointer-events: none是可选设置,如果你的3D场景需要鼠标交互,这个属性可以让鼠标点击穿透文本,直接作用到Three.js场景上
方法二:用Three.js的CSS2DRenderer(贴合Three.js生态)
如果你希望文本能和3D场景有更紧密的关联(比如后续要让文本跟着3D物体移动),可以用Three.js官方提供的CSS2DRenderer,它专门用来创建可关联3D空间的2D标签。
修改后的完整代码:
<html> <head> <title>First page.</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <link href="/errordocs/style/general.css" rel="stylesheet" type="text/css"> <!-- 引入CSS2DRenderer相关脚本 --> <script src="https://threejs.org/examples/js/renderers/CSS2DRenderer.js"></script> <script src="https://threejs.org/build/three.js" crossorigin="anonymous"></script> <style> body { margin: 0; } canvas { width: 100%; height: 100% } /* 文本标签样式 */ .label { color: white; font-size: 24px; padding: 8px; background: rgba(0,0,0,0.5); border-radius: 4px; } </style> </head> <body> <script> var scene, camera, renderer, labelRenderer; var geometry, material, mesh; init(); animate(); function init() { scene = new THREE.Scene(); scene.background = new THREE.Color( 0x222222 ); camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.01, 100 ); camera.position.z = 1; // 创建球体 geometry = new THREE.SphereGeometry( 0.1, 20, 20 ); material = new THREE.MeshNormalMaterial(); mesh = new THREE.Mesh( geometry, material ); scene.add( mesh ); // 创建WebGLRenderer renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); // 创建CSS2DRenderer和文本标签 labelRenderer = new THREE.CSS2DRenderer(); labelRenderer.setSize( window.innerWidth, window.innerHeight ); labelRenderer.domElement.style.position = 'absolute'; labelRenderer.domElement.style.top = '0'; document.body.appendChild( labelRenderer.domElement ); // 创建文本元素 var textElement = document.createElement('div'); textElement.className = 'label'; textElement.textContent = '这是CSS2DRenderer创建的2D文本'; // 创建CSS2DObject并添加到场景 var label = new THREE.CSS2DObject(textElement); // 设置标签位置(这里放在球体上方一点的位置) label.position.set(0, 0.2, 0); scene.add(label); } function animate() { requestAnimationFrame( animate ); mesh.rotation.x += 0.01; mesh.rotation.y += 0.02; // 同时渲染WebGL场景和2D标签 renderer.render( scene, camera ); labelRenderer.render( scene, camera ); } </script> </body> </html>
关键点说明:
- 需要额外引入
CSS2DRenderer.js脚本 CSS2DObject可以把普通HTML元素包装成Three.js的场景对象,支持设置3D空间位置- 动画循环里需要同时调用
renderer.render()和labelRenderer.render(),才能同时渲染3D场景和2D文本
两种方法都能实现你的需求:如果只是要固定在场景上方的静态文本,方法一足够简单;如果需要文本和3D元素有交互关联,方法二更合适。
内容的提问来源于stack exchange,提问作者dàhóngpāo




