使用 Three.js 构建 3D 互动地球🌏(短文📖基础✍🏻)

3,697 阅读3分钟

引言

看见大佬制作的 小米su7(点击欣赏)的3D效果,不得不佩服,我什么时候也能做一个这样的效果呢?还得从基础做起,这篇文章来看看如何使用Three.js在网页上实现一个逼真的 3D 地球并加入互动效果。


制作思路

  1. 初始化 Three.js 的基本组件(场景、相机、渲染器)。
  2. 创建地球的几何体,并加载纹理为其赋予真实外观。
  3. 实现地球的自转动画。
  4. 添加鼠标事件监听,实现交互。
  5. 处理窗口大小变化的逻辑,确保兼容不同设备的视口。

引入 Three.js

首先,在 HTML 文件中引入 Three.js 库:

<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/build/three.min.js"></script>

实现步骤

1. 初始化场景、相机与渲染器

创建基础组件:

 let canvas, // 3d 容器
    camera, // 镜头
    scene, // 场景 
    renderer, // 渲染器
    group; // 组 
    // 物品
  let mouseX = 0, mouseY = 0; // mousemove 坐标
  let windowHalfX = window.innerWidth / 2;  // 球心
  let windowHalfY = window.innerHeight / 2;

使用 Three.js 创建一个基础 3D 环境:

function init() {
canvas = document.getElementById('webglcanvas'); // DOM 
    camera = new THREE.PerspectiveCamera(60,  
    window.innerWidth / window.innerHeight, 1, 2000); // 实例化 相机
    // 相机离scene场景
    camera.position.z = 500;

    scene = new THREE.Scene(); // 实例化 场景
    scene.background = new THREE.Color(0xffffff); // 背景色

    group = new THREE.Group();// 组
    scene.add(group);

renderer = new THREE.WebGLRenderer({
        canvas: canvas,
        antialias: true
      });
}

2. 创建地球模型

加载地球纹理,并将其映射到球体几何体上:

// 纹理加载器  这段代码添加在init()方法中
    let loader = new THREE.TextureLoader(); // 简单的加载器
    loader.load('地球.jpg', function(texture) {
      let geometry = new THREE.SphereGeometry(200, 20, 20); // 球体
      let material = new THREE.MeshBasicMaterial({ // 材质
        map: texture
      });
      let mesh = new THREE.Mesh(geometry, material); // 网格
      group.add( mesh );

地球图片(为上面代码第3行中的地球.jpg): 地球.jpg

3. 实现窗口大小自适应

处理窗口尺寸变化,确保画布自适应:

  renderer.setSize(window.innerWidth, window.innerHeight);  //添加到init()方法中

4. 添加鼠标交互

实现鼠标事件监听,通过鼠标移动调整相机位置:

document.addEventListener('mousemove', onDocumentMouseMove, false);// 这行代码添加到init()方法中

  function onDocumentMouseMove(event) {
    mouseX = event.clientX - windowHalfX;
    mouseY = event.clientY - windowHalfY;
  }

5. 实现地球自转动画

通过递归的 requestAnimationFrame 实现地球的旋转动画:

function animate() {
  requestAnimationFrame(animate);
  render();
}

function render() {
  camera.position.x += (mouseX - camera.position.x) * 0.05;
  camera.position.y += (mouseY - camera.position.y) * 0.05;
  camera.lookAt(scene.position);
  
  group.rotation.y -= 0.005; // 控制地球自转速度
  renderer.render(scene, camera);
}

6. 完整代码

将上述代码块整合:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>3D 地球</title>
  <!-- 画地球 选择框架 加速 -->
  <script src="https://unpkg.com/three@0.128.0/build/three.min.js"></script>
</head>
<body>
  <canvas id="webglcanvas"></canvas>
  <script>
  // 3d 地球
  // 3D 时间就是镜头拍出的世界,导演
  let canvas, // 3d 容器
    camera, // 镜头
    scene, // 场景 
    renderer, // 渲染器
    group; // 组 
    // 物品
  let mouseX = 0, mouseY = 0; // mousemove 坐标
  let windowHalfX = window.innerWidth / 2;  // 球心
  let windowHalfY = window.innerHeight / 2;
  init();
  animate();
  // 准备
  function init() {
    canvas = document.getElementById('webglcanvas'); // DOM 
    camera = new THREE.PerspectiveCamera(60,  
    window.innerWidth / window.innerHeight, 1, 2000); // 实例化 相机
    // 相机离scene场景
    camera.position.z = 500;

    scene = new THREE.Scene(); // 实例化 场景
    scene.background = new THREE.Color(0xffffff); // 背景色

    group = new THREE.Group();// 组
    scene.add(group);
    // 纹理加载器
    let loader = new THREE.TextureLoader(); // 简单的加载器
    loader.load('地球.jpg', function(texture) {
      let geometry = new THREE.SphereGeometry(200, 20, 20); // 球体
      let material = new THREE.MeshBasicMaterial({ // 材质
        map: texture
      });
      let mesh = new THREE.Mesh(geometry, material); // 网格
      group.add( mesh );
      // 渲染器 目标是canvas 
      renderer = new THREE.WebGLRenderer({
        canvas: canvas,
        antialias: true
      });
      renderer.setSize(window.innerWidth, window.innerHeight);
      // renderer.render(scene, camera);
      document.addEventListener('mousemove', onDocumentMouseMove, false);
    }) 

  }

  function onDocumentMouseMove(event) {
    mouseX = event.clientX - windowHalfX;
    mouseY = event.clientY - windowHalfY;
  }

  function animate() {
    // 递归 屏幕的刷帧率  60帧/s
    requestAnimationFrame(animate)
    render()
  }

  function render() {
    camera.position.x += (mouseX - camera.position.x) * 0.05;
    camera.position.y += (mouseY - camera.position.y) * 0.05;
    camera.lookAt(scene.position);
    // camera.lookAt(scene.position)
    group.rotation.y -= 0.005;
    renderer.render(scene, camera);
  }

  </script>
</body>
</html>

image.png

上传不了视频,可以将代码复制到本地查看效果。

结语

你已经掌握了使用 Three.js 构建一个 3D 地球的基础方法,让我们在以后的学习中向 小米su7进军。