空手造一个旋转的3d地球?Three.js的实战原来这么简单🤡🤡🤡

566 阅读5分钟

引言

本次我们将使用Three.js创建一个旋转的3D地球。

我们先看成果图:

QQ录屏20241225223403.gif

少说废话,正式开始!

OI1P-C.jpg

Three.js

我们先来了解一下Three.js

Three.js是一款基于原生WebGL封装通用Web 3D引擎。它让Web开发者能够轻松地创建复杂的3D图形和互动体验。通过掌握其核心概念——场景、摄像机、渲染器、几何体、材质、灯光以及动画和交互机制——你可以构建出丰富多彩的3D应用。

HTML结构 和 背景图

我们需要引入Three.js库。并以<canvas>元素作为渲染目标。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3D 地球</title>
    <!-- 引入Three.js库 -->
    <script src="https://unpkg.com/three@0.128.0/build/three.min.js"></script>
</head>
<body>
    <canvas id="webglcanvas"></canvas>
</body>
</html>

这是我在本例中使用到的背景图: land_ocean_ice_cloud_2048.jpg

JavaScript部分

准备“设备”

我们需要一些“设备”来协助我们拍摄3d地球

  • canvas:这是一个HTML <canvas>元素的引用,Three.js将使用它作为WebGL的绘图表面。所有渲染的3D内容都将绘制在这个画布上。
  • camera:代表虚拟摄像机的对象,决定了用户从哪个视角观看3D场景。摄像机的位置、方向和类型(如透视或正交)都会影响最终的视觉效果。
  • scene:场景是所有3D对象、灯光和其他元素的容器。它是3D世界的“舞台”,所有的物体都需要被添加到这个场景中才能被渲染出来。
  • renderer:负责将场景中的3D图形转换为2D图像并绘制在canvas上。Three.js支持多种渲染器,但最常用的是基于WebGL的WebGLRenderer
  • group:是一个THREE.Group对象,它可以用来组织多个3D对象作为一个整体进行变换(如移动、旋转)。这对于管理复杂的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();

初始化和设置3D场景的关键组件

接下来在init()函数中我们要干几件事

  • 获取DOM元素
canvas = document.getElementById('webglcanvas'); // 获取DOM 
  • 创建透视摄像机

Three中有很多种摄像机,我们在本次使用透视摄像机(PerspectiveCamera)。并设置相机距离scene的距离。

// 透视摄像机(PerspectiveCamera)
// 视野角度 宽高比(width/height 横屏) 近裁剪面距离 远裁剪面距离(1~2000 相机可见距离)
camera = new THREE.PerspectiveCamera(60,
window.innerWidth / window.innerHeight, 1, 2000); // 实例化 相机
// 相机离scene场景 500 个单位长度
camera.position.z = 500;   // 
  • 实例化场景和背景颜色
scene = new THREE.Scene(); // 实例化 场景
scene.background = new THREE.Color(0xffffff); // 背景色我们设置为白色
  • 创建组并将组添加到场景中

组可以容纳多个3D对象,便于管理和操作一组相关的物体。将组添加到场景中,使其成为渲染流程的一部分,任何添加到该组的对象都会被渲染器处理。

group = new THREE.Group();// 组
scene.add(group);   // 添加到场景
  • 加载纹理、创建3D地球模型(球体)、设置材质,并将这些元素添加到场景中,同时初始化渲染器和设置鼠标交互功能(鼠标移动事件)。
// 纹理加载器   TextureLoader 适用于异步加载标准的图像文件
let loader = new THREE.TextureLoader(); // 简单的加载器

// 加载纹理并创建3D地球(异步)
// 参数一: 图片路径      参数二:纹理加载完毕后执行回调函数
loader.load('land_ocean_ice_cloud_2048.jpg', function (texture) {
   // 创建球体几何体   参数: 半径  宽度分段数  高度分段数  (球心)
   let geometry = new THREE.SphereGeometry(200, 20, 20); // 球体
   
   // 设置材质  map指定刚才加载的纹理贴图 到球体上
   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
   });
   // 设置渲染器的尺寸与浏览器窗口一致,确保3D内容能够占据整个视窗
   renderer.setSize(window.innerWidth, window.innerHeight);
   
   // 添加鼠标移动事件监听器 影响摄像机的角度和地球的旋转  冒泡阶段监听事件
   document.addEventListener('mousemove', onDocumentMouseMove, false);
})
  • 鼠标移动事件

每当鼠标在页面上移动时,更新mouseXmouseY变量,它们表示鼠标相对于窗口中心的偏移量。

// 获取鼠标相对于窗口中心的具体位置
function onDocumentMouseMove(event) {
    // 正为右下 负为左上
    mouseX = event.clientX - windowHalfX;
    mouseY = event.clientY - windowHalfY;
}

动画循环

animate()函数是一个递归调用,利用requestAnimationFrame确保动画以每秒60帧的速度运行。每次调用时,它会执行render()函数,后者负责实际的渲染逻辑。

function animate() {
    // 递归 屏幕的刷帧率 60帧/s 
    // 浏览器API调用
    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);
     // 地球旋转 绕y轴 每次减小一点弧度
     group.rotation.y -= 0.002;
     // 调用渲染器的`render`方法,将当前状态下的场景和摄像机信息绘制到画布上
     renderer.render(scene, camera);
}

至此,我们已经完成了3d地球的制作!!

总结

通过3d地球的制作,我们学习到Three.js的核心概念和技术,包括场景管理、摄像机控制、几何体创建、材质应用以及渲染过程。此外,还结合了如何通过事件监听器实现基本的用户交互,使得3d地球可以响应用户的鼠标动作。

sdffs.jpg