CSS2DRenderer 是 Three.js 中一个用于将 2D HTML 元素渲染到 3D 场景中的工具。它允许你将普通的 HTML 元素(如
<div>或<span>)与 Three.js 中的 3D 对象结合,使得这些元素能够随着 3D 对象的变化(如旋转、缩放、平移)而进行相应的调整。
CSS2DRenderer 有三个方法
// CSS2DRenderer()
// 使用示例
<template>
<div id="parkingLot" ref="parkingLot">
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
const parkingLot = ref();
onMounted(async () => {
const DOMEl = parkingLot.value;
// 获取 DOMEl 的宽度和高度,以设置渲染器的大小。
const width = DOMEl.clientWidth;
const height = DOMEl.clientHeight;
const renderer = new THREE.WebGLRenderer();
renderer.setSize( width, height );
renderer.setPixelRatio( window.devicePixelRatio );
DOMEl.appendChild( renderer.domElement );
const scene = new THREE.Scene();
renderer.setClearColor(0xaaaaaa);
const camera = new THREE.PerspectiveCamera( 75, width / height, 0.1, 1000 );
camera.position.set( 10, 5, 20 );
camera.lookAt( 0, 0, 0 );
// 创建一个时钟对象,用于计时和获取场景中的时间
const clock = new THREE.Clock();
// 创建纹理加载器,用于加载纹理贴图
const textureLoader = new THREE.TextureLoader();
// 声明月球和标签渲染器对象
let moon, labelRenderer;
// 地球和月球的半径
const EARTH_RADIUS = 1;
const MOON_RADIUS = 0.27;
// 启用所有图层
camera.layers.enableAll();
// 创建一个定向光源,用于照亮场景
const dirLight = new THREE.DirectionalLight( 0xffffff, 3 );
dirLight.position.set( 0, 0, 1 ); // 设置光源的位置
dirLight.layers.enableAll(); // 启用所有图层
scene.add( dirLight ); // 将光源添加到场景中
// 创建一个坐标轴辅助对象,用于显示场景的坐标系
const axesHelper = new THREE.AxesHelper( 5 );
axesHelper.layers.enableAll(); // 启用所有图层
scene.add( axesHelper ); // 将坐标轴添加到场景中
// 创建地球的几何体和材质
const earthGeometry = new THREE.SphereGeometry( EARTH_RADIUS, 16, 16 );
const earthMaterial = new THREE.MeshPhongMaterial( {
specular: 0x333333, // 高光颜色
shininess: 5, // 高光强度
map: textureLoader.load( 'https://raw.githubusercontent.com/mrdoob/three.js/refs/heads/master/examples/textures/planets/earth_atmos_2048.jpg?raw=true' ), // 地球的纹理
specularMap: textureLoader.load( 'https://raw.githubusercontent.com/mrdoob/three.js/refs/heads/master/examples/textures/planets/earth_specular_2048.jpg?raw=true' ), // 地球的高光纹理
normalMap: textureLoader.load( 'https://raw.githubusercontent.com/mrdoob/three.js/refs/heads/master/examples/textures/planets/earth_normal_2048.jpg?raw=true' ), // 地球的法线纹理
normalScale: new THREE.Vector2( 0.85, 0.85 ) // 法线缩放
} );
earthMaterial.map.colorSpace = THREE.SRGBColorSpace; // 设置颜色空间为 sRGB
const earth = new THREE.Mesh( earthGeometry, earthMaterial ); // 创建地球网格
scene.add( earth ); // 将地球添加到场景中
// 创建月球的几何体和材质
const moonGeometry = new THREE.SphereGeometry( MOON_RADIUS, 16, 16 );
const moonMaterial = new THREE.MeshPhongMaterial( {
shininess: 5, // 高光强度
map: textureLoader.load( 'https://raw.githubusercontent.com/mrdoob/three.js/refs/heads/master/examples/textures/planets/moon_1024.jpg?raw=true' ) // 月球的纹理
} );
moonMaterial.map.colorSpace = THREE.SRGBColorSpace; // 设置颜色空间为 sRGB
moon = new THREE.Mesh( moonGeometry, moonMaterial ); // 创建月球网格
scene.add( moon ); // 将月球添加到场景中
// 启用地球和月球的所有图层
earth.layers.enableAll();
moon.layers.enableAll();
// 创建地球标签,并设置标签的内容和样式
const earthDiv = document.createElement( 'div' );
earthDiv.className = 'label';
earthDiv.textContent = 'Earth';
earthDiv.style.backgroundColor = 'transparent';
// 创建 CSS2DObject 来显示地球的标签
const earthLabel = new CSS2DObject( earthDiv );
earthLabel.position.set( 1.5 * EARTH_RADIUS, 0, 0 ); // 设置标签的位置
earthLabel.center.set( 0, 1 ); // 设置标签的中心点
earth.add( earthLabel ); // 将标签添加到地球上
earthLabel.layers.set( 0 ); // 设置标签的图层为 0
// 创建地球质量标签
const earthMassDiv = document.createElement( 'div' );
earthMassDiv.className = 'label';
earthMassDiv.textContent = '5.97237e24 kg';
earthMassDiv.style.backgroundColor = 'transparent';
// 创建 CSS2DObject 来显示地球质量的标签
const earthMassLabel = new CSS2DObject( earthMassDiv );
earthMassLabel.position.set( 1.5 * EARTH_RADIUS, 0, 0 ); // 设置标签的位置
earthMassLabel.center.set( 0, 0 ); // 设置标签的中心点
earth.add( earthMassLabel ); // 将标签添加到地球上
earthMassLabel.layers.set( 1 ); // 设置标签的图层为 1
// 创建月球标签,并设置标签的内容和样式
const moonDiv = document.createElement( 'div' );
moonDiv.className = 'label';
moonDiv.textContent = 'Moon';
moonDiv.style.backgroundColor = 'transparent';
// 创建 CSS2DObject 来显示月球的标签
const moonLabel = new CSS2DObject( moonDiv );
moonLabel.position.set( 1.5 * MOON_RADIUS, 0, 0 ); // 设置标签的位置
moonLabel.center.set( 0, 1 ); // 设置标签的中心点
moon.add( moonLabel ); // 将标签添加到月球上
moonLabel.layers.set( 0 ); // 设置标签的图层为 0
// 创建月球质量标签
const moonMassDiv = document.createElement( 'div' );
moonMassDiv.className = 'label';
moonMassDiv.textContent = '7.342e22 kg';
moonMassDiv.style.backgroundColor = 'transparent'; // 设置背景色为红色
// 创建 CSS2DObject 来显示月球质量的标签
const moonMassLabel = new CSS2DObject( moonMassDiv );
moonMassLabel.position.set( 1.5 * MOON_RADIUS, 0, 0 ); // 设置标签的位置
moonMassLabel.center.set( 0, 0 ); // 设置标签的中心点
moon.add( moonMassLabel ); // 将标签添加到月球上
moonMassLabel.layers.set( 1 ); // 设置标签的图层为 1
// 创建 CSS2DRenderer,用于渲染 2D 标签
labelRenderer = new CSS2DRenderer();
labelRenderer.setSize( width, height ); // 设置渲染器的尺寸
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '100px';
labelRenderer.domElement.style.left = '50%';
labelRenderer.domElement.style.transform = 'translateX(-50%)';
document.body.appendChild( labelRenderer.domElement ); // 将渲染器添加到文档中
// 创建 OrbitControls 实例,用于控制相机的视角
const controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0); // 设置相机的目标为场景的原点(0, 0, 0)
// 动画函数
function animate() {
requestAnimationFrame(animate); // 请求下一帧动画
controls.update(); // 更新 OrbitControls,使其与用户的操作保持同步
renderer.render(scene, camera); // 渲染场景
const elapsed = clock.getElapsedTime(); // 获取已过去的时间
moon.position.set( Math.sin( elapsed ) * 5, 0, Math.cos( elapsed ) * 5 ); // 设置月球的运动轨迹
labelRenderer.render( scene, camera ); // 渲染 2D 标签
}
animate(); // 启动动画
});
</script>
<style lang="scss" scoped="scoped">
#parkingLot {
width: 940px;
height: 940px;
border: 1px solid #ccc;
margin: 30px auto;
color: #fff;
}
</style>
方法
- getSize () : Object 返回一个包含有渲染器宽和高的对象。
- render ( scene : Scene, camera : Camera ) : undefined 使用camera渲染scene。
- setSize (width : Number, height : Number) : undefined 将渲染器的尺寸调整为(width, height).