<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>2</title>
<style>
body {
margin: 0;
overflow: hidden;
/* 隐藏body窗口区域滚动条 */
}
canvas {
background-image: url('./imgs/star.jpg');
background-size: cover;
}
.label {
color: #fff;
font-size: 16px;
}
</style>
</head>
<body>
<script type="module">
import * as THREE from './libs/build/three.module.js';
import { OrbitControls } from './libs/jsm/controls/OrbitControls.js';
import { CSS2DRenderer, CSS2DObject } from './libs/jsm/renderers/CSS2DRenderer.js';
//声明全局变量
let camera, scene, renderer, labelRenderer;
let moon,earth;
let clock = new THREE.Clock();
//实例化纹理加载器
const textureLoader = new THREE.TextureLoader();
function init() {
//设定地球和月球的大小
const EARTH_RADIUS = 2.5;
const MOON_RADIUS = 0.27;
//实例化相机 透视相机
camera = new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,200);
camera.position.set(10,5,20);
//实例化场景
scene = new THREE.Scene();
//光源 添加聚光灯
const spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(0,0,10);
//光照强度。 缺省值 1
spotLight.intensity = 2;
//设置为 true 聚光灯将投射阴影
spotLight.castShadow = true;
scene.add(spotLight);
//光源 添加环境光
const ambLight = new THREE.AmbientLight(0xffffff);
ambLight.intensity = 0.3;
scene.add(ambLight);
//创建月球
const moonGometry = new THREE.SphereGeometry(MOON_RADIUS,16,16);
//一种用于具有镜面高光的光泽表面的材质
const moonMaterial = new THREE.MeshPhongMaterial({
//颜色贴图。默认为null。纹理贴图颜色由漫反射颜色.color调节。
//map: textureLoader.load('./imgs/02.jpg')
map: textureLoader.load('./textures/planets/moon_1024.jpg')
});
moon = new THREE.Mesh(moonGometry,moonMaterial);
moon.receiveShadow = true;
moon.castShadow = true;
scene.add(moon);
//创建地球
const earthGeometry = new THREE.SphereGeometry(EARTH_RADIUS,16,16);
const earthMaterial = new THREE.MeshPhongMaterial({
//高亮的程度,越高的值越闪亮。默认值为 30。
shininess: 5,
//map: textureLoader.load('./imgs/01.jpg'),
map: textureLoader.load('./textures/planets/earth_atmos_2048.jpg'),
//镜面反射贴图值会影响镜面高光以及环境贴图对表面的影响程度。默认值为null。
specularMap: textureLoader.load('./textures/planets/earth_specular_2048.jpg'),
normalMap: textureLoader.load('./textures/planets/earth_normal_2048.jpg')
});
earth = new THREE.Mesh(earthGeometry,earthMaterial);
earth.receiveShadow = true;
earth.castShadow = true;
scene.add(earth);
//创建地球和月球的标签
const earthDiv = document.createElement('div');
earthDiv.className = 'label';
earthDiv.textContent = 'Earch';
const eartchLabel = new CSS2DObject(earthDiv);
eartchLabel.position.set(0, EARTH_RADIUS + 0.5, 0);
earth.add(eartchLabel);
const moonDiv = document.createElement('div');
moonDiv.className = 'label';
moonDiv.textContent = 'Moon';
const moonLabel = new CSS2DObject(moonDiv);
moonLabel.position.set(0, MOON_RADIUS + 0.5, 0);
moon.add(moonLabel);
// 创建渲染器
renderer = new THREE.WebGLRenderer({
//canvas是否包含alpha (透明度)。默认为 false
alpha: true
});
//设置设备像素比。通常用于避免HiDPI设备上绘图模糊
// devicePixelRatio 返回当前显示设备的物理像素分辨率与CSS 像素分辨率之比。
// 此值也可以解释为像素大小的比率:一个 CSS 像素的大小与一个物理像素的大小。
// 简单来说,它告诉浏览器应使用多少屏幕实际像素来绘制单个 CSS 像素。
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth,window.innerHeight);
//渲染阴影
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
//标签渲染器
labelRenderer = new CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight)
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '0px';
labelRenderer.domElement.style.pointerEvents = 'none';
document.body.appendChild(labelRenderer.domElement)
//绑定控制和摄像头
const controls = new OrbitControls(camera,renderer.domElement);
}
let oldTime = 0;
function animate() {
const elapsed = clock.getElapsedTime();
moon.position.set(Math.sin(elapsed) * 5, 0, Math.cos(elapsed) * 5);
// 地球自转
var axis = new THREE.Vector3(0, 1, 0);
earth.rotateOnAxis(axis, (elapsed - oldTime) * Math.PI / 10);
renderer.render(scene, camera)
labelRenderer.render(scene, camera)
oldTime = elapsed;
requestAnimationFrame(animate)
}
init();
animate();
// 调整尺寸
window.onresize = function () {
camera.aspect = window.innerWidth / window.innerHeight;
//在大多数属性发生改变之后,你将需要调用.updateProjectionMatrix来使得这些改变生效。
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight)
}
</script>
</body>
</html>
踩坑
ThreeJs CSS2DRenderer、OrbitControls 鼠标事件问题
在ThreeJs3D场景中使用CSS2DRenderer渲染Html元素,OrbitControls 功能失效
原因分析:
CSS2DRenderer渲染器会在页面渲染出一个Div,里面包含自定义的html片段,默认情况下该Div或捕获页面的键盘、鼠标事件,导致OrbitControls的相关事件失效
处理方案:
方案1:修改css2DRenderer对应dom元素的pointerEvents属性为none:
css2DRenderer.domElement.style.pointerEvents = 'none';
方案2:修改OrbitControls关联的Dom元素为当前的css2DRenderer.domElement
const controls = new OrbitControls( camera, css2DRenderer.domElement );