一、实现结果
使用Three.js实现裸眼3D地球仪
二、实当代码
代码如下:
- <!DOCTYPE html>
- <html>
- <head>
- <title>3D Earth</title>
- <style>
- body { margin: 0; }
- canvas { display: block; }
- </style>
- </head>
- <body>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
- <script>
- // 初始化场景、相机和渲染器
- const scene = new THREE.Scene();
- const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
- const renderer = new THREE.WebGLRenderer();
- renderer.setSize(window.innerWidth, window.innerHeight);
- document.body.appendChild(renderer.domElement);
- // 创建地球几何体
- const geometry = new THREE.SphereGeometry(5, 50, 50);
- // 加载纹理
- const textureLoader = new THREE.TextureLoader();
- const earthTexture = textureLoader.load('https://threejs.org/examples/textures/planets/earth_atmos_2048.jpg');
- const normalTexture = textureLoader.load('https://threejs.org/examples/textures/planets/earth_normal_2048.jpg');
- // 创建材质
- const material = new THREE.MeshPhongMaterial({
- map: earthTexture,
- normalMap: normalTexture,
- normalScale: new THREE.Vector2(0.8, 0.8),
- specular: new THREE.Color('grey'),
- shininess: 5
- });
- // 创建地球网格
- const earth = new THREE.Mesh(geometry, material);
- scene.add(earth);
- // 添加光照
- const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
- scene.add(ambientLight);
- const pointLight = new THREE.PointLight(0xffffff, 1.5);
- pointLight.position.set(10, 10, 10);
- scene.add(pointLight);
- // 设置相机位置
- camera.position.z = 15;
- // 添加自动旋转动画
- function animate() {
- requestAnimationFrame(animate);
- earth.rotation.y += 0.002;
- renderer.render(scene, camera);
- }
- // 处理窗口大小变化
- window.addEventListener('resize', onWindowResize, false);
- function onWindowResize() {
- camera.aspect = window.innerWidth / window.innerHeight;
- camera.updateProjectionMatrix();
- renderer.setSize(window.innerWidth, window.innerHeight);
- }
- // 添加鼠标交互
- let isDragging = false;
- let previousMousePosition = {
- x: 0,
- y: 0
- };
- document.addEventListener('mousedown', (e) => {
- isDragging = true;
- previousMousePosition = {
- x: e.clientX,
- y: e.clientY
- };
- });
- document.addEventListener('mousemove', (e) => {
- if (!isDragging) return;
- const deltaMove = {
- x: e.clientX - previousMousePosition.x,
- y: e.clientY - previousMousePosition.y
- };
- earth.rotation.y += deltaMove.x * 0.005;
- earth.rotation.x += deltaMove.y * 0.005;
- previousMousePosition = {
- x: e.clientX,
- y: e.clientY
- };
- });
- document.addEventListener('mouseup', () => {
- isDragging = false;
- });
- // 启动动画
- animate();
- </script>
- </body>
- </html>
复制代码 这个示例代码包含以下重要功能:
- 创建了一个基本的Three.js场景,包含:
- 球体几何图形
- 地球纹理贴图(颜色贴图和法线贴图)
- 光影结果(环境光 + 点光源)
- 重要特性:
- 地球主动迟钝旋转
- 支持鼠标拖拽交互旋转
- 相应式窗口大小调整
- 法线贴图实现表面细节
- 适当的光照结果
- 使用阐明:
- 必要网络连接加载纹理贴图
- 可以替换纹理贴图URL使用自界说贴图
- 通过调整SphereGeometry参数控制地球精度
- 修改rotation速率可以改变旋转速率
- 调整camera.position.z改变观察距离
- 扩展发起:
- 添加云层(使用透明贴图的第二个球体)
- 添加星空背景
- 添加标记点或国家界限
- 添加放大/缩小功能
- 添加旋转控制按钮
注意:由于纹理加载必要时间,初次加载可能会看到短暂的空白场景。现实使用时发起:
- 使用当地纹理文件
- 添加加载进度提示
- 使用更高分辨率的贴图
- 添加错误处理
可以将代码生存为HTML文件直接运行(必要网络连接),也可以部署到Web服务器使用当地资源。
三、重点代码片段
1. 地球材质创建(焦点渲染)
- // 加载纹理
- const textureLoader = new THREE.TextureLoader();
- const earthTexture = textureLoader.load('earth_texture.jpg');
- const normalTexture = textureLoader.load('earth_normal.jpg');
- // 创建材质
- const material = new THREE.MeshPhongMaterial({
- map: earthTexture, // 基础颜色贴图
- normalMap: normalTexture, // 法线贴图
- normalScale: new THREE.Vector2(0.8, 0.8), // 法线强度
- specular: new THREE.Color('grey'), // 高光颜色
- shininess: 5 // 高光强度
- });
复制代码
- 材质类型选择:
- 使用 MeshPhongMaterial(冯氏材质),这是实现光照交互的关键
- 支持高光反射结果,得当表现具有反光特性的地球表面
- 纹理映射:
- map:底子颜色贴图,直接表现地球表面图像
- normalMap:法线贴图,通过RGB值模拟表面凹凸细节(无需增加几何体复杂度)
- 材质参数:
- normalScale:控制法线贴图的强度(值越大凹凸感越强)
- specular + shininess:组合控制高光结果(金属感/塑料感调治)
- 性能优化:
- 纹理尺寸发起保持2的幂次(如1024x512),否则可能触发Three.js的主动缩放
- 可以添加 bumpMap 或 specularMap 实现更复杂的表面细节
2. 交互旋转实现(焦点交互)
- // 鼠标拖动交互
- let isDragging = false;
- let previousMousePosition = { x: 0, y: 0 };
- document.addEventListener('mousedown', (e) => {
- isDragging = true;
- previousMousePosition = { x: e.clientX, y: e.clientY };
- });
- document.addEventListener('mousemove', (e) => {
- if (!isDragging) return;
- const deltaMove = {
- x: e.clientX - previousMousePosition.x,
- y: e.clientY - previousMousePosition.y
- };
- earth.rotation.y += deltaMove.x * 0.005;
- earth.rotation.x += deltaMove.y * 0.005;
- previousMousePosition = { x: e.clientX, y: e.clientY };
- });
- document.addEventListener('mouseup', () => {
- isDragging = false;
- });
复制代码
- 交互原理:
- 通过监听鼠标变乱实现拖拽利用
- 计算两次鼠标位置的差值(deltaMove)转换为旋转量
- 数学转换:
- delta.x 影响 Y 轴旋转(程度拖动→左右旋转)
- delta.y 影响 X 轴旋转(垂直拖动→上下旋转)
- 0.005 是敏捷度系数,值越大拖动反应越敏捷
- 坐标系注意:
- Three.js使用右手坐标系,Y轴向上
- 旋转顺序遵循物体自身坐标系(可能导致万向节锁问题,复杂交互必要四元数)
- 性能优化:
- 使用 requestAnimationFrame 包管动画流畅性
- 避免在变乱回调中直接修改DOM
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |