“教你用代码撸出一个性感的3D地球 🌍——附带抖音爆款WebGL指南”

1,149 阅读7分钟

首先看看我们今天要完成的结果图吧!

image.png

引言

嘿,程序员的浪漫是什么?是和代码谈一场永不分手的恋爱❤️。今天,我们不聊凡人,只聊高端的,聊聊如何用 WebGLThree.js 在网页上撸出一个让人一眼爱上的3D地球!不仅如此,这还自带交互效果,鼠标一动,地球跟着转,丝滑到让人停不下来,朋友圈一发,立马“病毒式传播”😎。


🚀 为啥学3D?

最近我在刷小米汽车的官网,发现他们新发布的“小米su7”特别“炫技”!一打开就是各种3D交互页面,像这种带 WebGL 技术的内容,未来会越来越多地出现在 数字孪生VR游戏 等领域。于是我心想:这种潮流,必须跟上啊!你们也可以访问su7一起来吃吃细糠。

image.png

于是,我研究了下如何用WebGL来撸一个“性感的3D地球”,并且还写了两个渐进式的HTML小案例!下面就带你一步步实现!

🧩 Step 1:用 Canvas 画个2D地球,热热身!

在WebGL的世界里,canvas 就是我们的舞台,而 context 就是我们的画笔。画个简单的2D地球,先给大家解解馋!

📄 HTML代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>2D Earth</title>
</head>
<body>
  <canvas id="webglcanvas"></canvas>
  <script>
    const canvas = document.getElementById("webglcanvas");
    const ctx = canvas.getContext("2d");

    // 设置Canvas宽高
    canvas.width = 800;
    canvas.height = 800;

    // 绘制一个半圆,代表地球
    ctx.beginPath();
    const x = canvas.width / 2;  // 圆心x坐标
    const y = canvas.height / 2; // 圆心y坐标
    const radius = 200;          // 半径
    ctx.arc(x, y, radius, 0, Math.PI * 2, false);
    ctx.fillStyle = "green";     // 地球颜色
    ctx.fill();
    ctx.strokeStyle = "blue";    // 边框颜色
    ctx.lineWidth = 5;
    ctx.stroke();
    ctx.closePath();
  </script>
</body>
</html>

🎉 效果:

image.png

你会看到一个简陋的绿色半圆,别急!这是你的第一步,先学会使用 canvas 标签,再掌握 beginPath()closePath() 的用法!

💡 Tips

  • ctx.beginPath()ctx.closePath() 是画图的开头和结尾,相当于“拿起笔”和“放下笔”。
  • Canvas 的 2D API 足够简单,但如果想要更酷炫的效果,还得靠 WebGL。

🌀 Step 2:撸一个360度旋转的3D地球!

如果说2D地球像素低,那3D地球就是“次世代画质”!下面这段代码用到了一个神器——Three.js,它是WebGL的封装库,简化了3D开发的复杂度。


📄 代码片段 1:HTML 和基本结构

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

作用

  1. HTML 基础结构

    • 设置 <!DOCTYPE html> 声明 HTML5 文档。
    • 使用 <meta> 标签确保页面在移动端设备上的显示效果良好。
  2. 引入 Three.js

    • https://unpkg.com/three@0.128.0/build/three.min.js 是 Three.js 的官方 CDN,你可以通过它快速加载并使用 WebGL 功能。
  3. Canvas 容器

    • <canvas id="webglcanvas"> 是渲染 3D 地球的主要舞台,Three.js 会使用这个 canvas 标签来绘制地球。

📄 代码片段 2:初始化变量与主函数

    let canvas, camera, scene, renderer, group;
    let mouseX = 0, mouseY = 0;
    const windowHalfX = window.innerWidth / 2;
    const windowHalfY = window.innerHeight / 2;

    init();
    animate();

作用

  1. 声明全局变量

    • canvas:代表 HTML 中的 <canvas> 元素。
    • camera:Three.js 中的透视相机,用于观察场景。
    • scene:Three.js 的场景容器,所有 3D 对象都会添加到场景中。
    • renderer:负责将 3D 场景渲染到 canvas 上。
    • group:用来存放地球模型。
    • mouseXmouseY:保存鼠标的当前位置,用于控制相机的移动。
  2. 窗口中心点

    • windowHalfXwindowHalfY 用于计算鼠标相对于窗口中心的位置。
  3. 调用初始化与动画函数

    • init():初始化场景、相机、纹理等内容。
    • animate():实现地球旋转的动画效果。

📄 代码片段 3:初始化函数

    function init() {
      // 初始化Canvas
      canvas = document.getElementById('webglcanvas');

      // 创建相机
      camera = new THREE.PerspectiveCamera(
        60, window.innerWidth / window.innerHeight, 1, 2000
      );
      camera.position.z = 500;

      // 创建场景
      scene = new THREE.Scene();
      scene.background = new THREE.Color(0xffffff);

      // 创建一个组
      group = new THREE.Group();
      scene.add(group);
    }

作用

  1. 初始化 Canvas

    • 获取 HTML 中的 <canvas> 元素,用于 3D 渲染。
  2. 创建相机

    • THREE.PerspectiveCamera 是一种透视相机:

      • 第一个参数 60 表示视角(FOV,角度值)。
      • 第二个参数是宽高比,通常是 window.innerWidth / window.innerHeight
      • 第三个和第四个参数表示相机能看到的最近和最远的物体距离。
    • 相机初始位置是 z = 500,也就是距离场景中心 500 个单位。

1605a6cc723740cfa41a07c5b083828e.png

  1. 创建场景

    • scene 是 Three.js 的核心容器,用于存放 3D 对象。
    • 使用 scene.background 设置背景色为白色。
  2. 创建组

    • 使用 THREE.Group 来管理多个物体(如地球网格和其他组件)。

📄 代码片段 4:加载地球纹理与渲染器

      // 加载地球纹理
      const loader = new THREE.TextureLoader();
      loader.load('land_ocean_ice_cloud_2048.jpg', function (texture) {
        const geometry = new THREE.SphereGeometry(200, 50, 50); // 球体
        const material = new THREE.MeshBasicMaterial({ map: texture }); // 材质
        const mesh = new THREE.Mesh(geometry, material); // 网格
        group.add(mesh);

        // 创建渲染器
        renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);

        // 监听鼠标事件
        document.addEventListener('mousemove', onDocumentMouseMove, false);
      });

作用

  1. 加载地球纹理

    • 使用 THREE.TextureLoader 加载地球的表面图像(land_ocean_ice_cloud_2048.jpg)。
    • 回调函数中,使用纹理生成材质 THREE.MeshBasicMaterial
  2. 生成球体

    • 使用 THREE.SphereGeometry 创建球体几何模型:

      • 第一个参数是半径(200)。
      • 第二和第三个参数分别是水平和垂直分段数,影响球体的精细度。
    • 将几何体和材质组合成网格 THREE.Mesh,并添加到 group 中。

  3. 创建渲染器

    • 使用 THREE.WebGLRenderer 渲染 3D 场景到 canvas
    • 设置 antialias: true 开启抗锯齿效果,增加画面平滑度。
    • 调用 renderer.setSize() 设置渲染的宽高。
  4. 监听鼠标事件

    • 添加鼠标事件监听器,捕获鼠标的位置变化。

📄 代码片段 5:鼠标事件与动画渲染

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

    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);
    }

作用

  1. 鼠标事件

    • onDocumentMouseMove():更新鼠标的当前位置,并用来影响相机的移动。
    • mouseXmouseY 保存鼠标偏移量。
  2. 动画循环

    • animate():通过 requestAnimationFrame() 递归调用自己,创建一个无限的渲染循环。
  3. 渲染逻辑

    • 根据鼠标位置调整相机位置,模拟地球跟随鼠标移动的效果。
    • 通过修改 group.rotation.y 实现地球的自转动画。
    • 调用 renderer.render(scene, camera) 渲染场景。

🎉 最终效果:

打开浏览器,你的3D地球会加载出来!可以用鼠标拖动,感受它的实时交互效果。看着它缓缓旋转,有种宇航员看地球的感觉,有没有?

💡 Tips

  • THREE.TextureLoader() 用于加载图片纹理,这里我使用了上传的高清地球纹理图。
  • THREE.SphereGeometry() 定义了球体的几何结构,你可以调整分段数来优化模型的精细度。
  • THREE.PerspectiveCamera() 是一种透视相机,模仿人眼视角,效果更真实。

🧐 两段代码有啥区别?

2D地球只是一个平面上的“静态绿球”,就像PPT中一个普通的圆。而3D地球不仅有球体的真实感,还能旋转交互,分分钟甩2D几条街!

用Three.js,你相当于化身3D世界的导演,控制镜头(camera)、场景(scene)、道具(mesh)、光影材质(material),一切尽在掌握之中。


🔥 升级玩法:让3D地球更炫!

  1. 加大纹理分辨率:换上更高清的纹理图,让地球的海洋、沙漠看起来更加细腻。
  2. 添加光源:试试 THREE.DirectionalLight(),让太阳的光芒打在地球上,营造白天和黑夜的效果。
  3. 交互增强:加上鼠标滚轮缩放功能,用 camera.position.z 来控制缩放比例。
  4. 加星空背景:可以用一个大球体当背景,贴上星空纹理图,完美还原宇宙场景!

🧑‍💻 写在最后

代码就是一门艺术,写代码的过程就像是在搭建一个独一无二的世界。这个3D地球项目,不仅能用在网站展示,还能成为抖音爆款交互效果的原型!

快试试看,自己用代码创作一个旋转地球吧!记得秀给朋友看,说不定你会收获一大波“程序员的崇拜”😎。


如果你有任何问题,留言区咱们唠嗑~ 👋

20200229174423_bzukt.jpg