在Three中提供2D和3Dcss渲染器供用户使用,如果你希望将二维或三维物体和基于HTML的标签相结合,则这一渲染器将十分有用。在这里,各个DOM元素也被包含到一个CSS2DObject或CSS3DObject实例中,并被添加到场景图中。
目录
1. CSS2DRenderer
1.1 构造函数
1.2 方法
2. CSS3DRenderer
2.1 构造函数
2.2 方法
3. CSS2DRenderer实现地月旋转
CSS2DRenderer是CSS3DRenderer(CSS 3D渲染器)的简化版本,唯一支持的变换是位移。
如果你希望将三维物体和基于HTML的标签相结合,则这一渲染器将十分有用。在这里,各个DOM元素也被包含到一个CSS2DObject实例中,并被添加到场景图中。
例如官方他提供的标签案例(label):
通过HTML及CSS设置标签样式,并绑定至Three创建的物体中:
同理还有molecules分子案例:
返回一个包含有渲染器宽和高的对象。
使用camera渲染scene。
将渲染器的尺寸调整为(width, height).
CSS3DRenderer用于通过CSS3的transform属性, 将层级的3D变换应用到DOM元素上。 如果你希望不借助基于canvas的渲染来在你的网站上应用3D变换,那么这一渲染器十分有趣。 同时,它也可以将DOM元素与WebGL的内容相结合。
然而,这一渲染器也有一些十分重要的限制:
因此,CSS3DRenderer仅仅关注普通的DOM元素,这些元素被包含到了特殊的对象中(CSS3DObject或者CSS3DSprite),然后被加入到场景图中。
例如Three官方提供的元素周期表案例:
返回一个包含有渲染器宽和高的对象。
使用perspective camera渲染scene。
将渲染器尺寸重新调整为(width, height)。
通过使用二维css渲染器实现官方地月围绕旋转及label标签的显示:
实现原理:
1)导入CSS2DRenderer, CSS2DObject;
2)添加提示标签;
3)实例化标签为CSS2DObject;
4)设置标签Object的位置;
5)将标签添加至物体中;
6)实例化css2d渲染器。
main.js:
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import {
CSS2DRenderer,
CSS2DObject,
} from "three/examples/jsm/renderers/CSS2DRenderer.js";
let camera, scene, renderer, labelRenderer;
const clock = new THREE.Clock();
const textureLoader = new THREE.TextureLoader();
let moon;
let chinaLabel;
const raycaster = new THREE.Raycaster();
init();
animate();
// 创建射线
function init() {
const EARTH_RADIUS = 1;
const MOON_RADIUS = 0.27;
camera = new THREE.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
0.1,
200
);
camera.position.set(0, 5, -10);
scene = new THREE.Scene();
// 设置直线光源
const dirLight = new THREE.DirectionalLight(0xffffff);
dirLight.position.set(0, 0, 1);
scene.add(dirLight);
const light = new THREE.AmbientLight(0xffffff, 0.5); // soft white light
scene.add(light);
// 设置地球实体
const earthGeometry = new THREE.SphereGeometry(EARTH_RADIUS, 16, 16);
const earthMaterial = new THREE.MeshPhongMaterial({
specular: 0x333333,
shininess: 5,
map: textureLoader.load("textures/planets/earth_atmos_2048.jpg"),
specularMap: textureLoader.load("textures/planets/earth_specular_2048.jpg"),
normalMap: textureLoader.load("textures/planets/earth_normal_2048.jpg"),
normalScale: new THREE.Vector2(0.85, 0.85),
});
const earth = new THREE.Mesh(earthGeometry, earthMaterial);
// earth.rotation.y = Math.PI;
scene.add(earth);
//设置月球实体
const moonGeometry = new THREE.SphereGeometry(MOON_RADIUS, 16, 16);
const moonMaterial = new THREE.MeshPhongMaterial({
shininess: 5,
map: textureLoader.load("textures/planets/moon_1024.jpg"),
});
moon = new THREE.Mesh(moonGeometry, moonMaterial);
scene.add(moon);
// 添加提示标签
const earthDiv = document.createElement('div');
earthDiv.className = "label";
earthDiv.innerHTML = "地球";
const earthLabel = new CSS2DObject(earthDiv);
earthLabel.position.set(0,1,0);//相对于父级元素的位置
earth.add(earthLabel);
// 中国
const chinaDiv = document.createElement('div');
chinaDiv.className = "label1";
chinaDiv.innerHTML = "中国";
chinaLabel = new CSS2DObject(chinaDiv);
chinaLabel.position.set(-0.3,0.5,-0.9);
earth.add(chinaLabel);
console.log(chinaLabel)
// 月球
const moonDiv = document.createElement('div');
moonDiv.className = "label";
moonDiv.innerHTML = "月球";
const moonLabel = new CSS2DObject(moonDiv);
moonLabel.position.set(0,0.3,0);
moon.add(moonLabel);
// 实例化css2d的渲染器
labelRenderer = new CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(labelRenderer.domElement)
//设置样式
labelRenderer.domElement.style.position = 'fixed';
labelRenderer.domElement.style.top = '0px';
labelRenderer.domElement.style.left = '0px';
labelRenderer.domElement.style.zIndex = '10';//设置层级
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, labelRenderer.domElement);
controls.minDistance = 5;
controls.maxDistance = 100;
//
window.addEventListener("resize", onWindowResize);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
const elapsed = clock.getElapsedTime();
moon.position.set(Math.sin(elapsed) * 5, 0, Math.cos(elapsed) * 5);
// 通过射线设置标签隐藏
const chinaPosition = chinaLabel.position.clone();
// 计算出标签跟摄像机的距离
const labelDistance = chinaPosition.distanceTo(camera.position);
// 检测射线的碰撞
// chinaLabel.position
// 向量(坐标)从世界空间投影到相机的标准化设备坐标 (NDC) 空间。
chinaPosition.project(camera);
raycaster.setFromCamera(chinaPosition,camera);
const intersects = raycaster.intersectObjects(scene.children,true)
// console.log(intersects)
// 如果没有碰撞到任何物体,那么让标签显示
if(intersects.length == 0){
chinaLabel.element.classList.add('visible');
}else{
// if(labelDistance)
const minDistance = intersects[0].distance;
console.log(minDistance,labelDistance)
if(minDistance
实现效果: