首先看看我们今天要完成的结果图吧!
引言
嘿,程序员的浪漫是什么?是和代码谈一场永不分手的恋爱❤️。今天,我们不聊凡人,只聊高端的,聊聊如何用 WebGL 和 Three.js 在网页上撸出一个让人一眼爱上的3D地球!不仅如此,这还自带交互效果,鼠标一动,地球跟着转,丝滑到让人停不下来,朋友圈一发,立马“病毒式传播”😎。
🚀 为啥学3D?
最近我在刷小米汽车的官网,发现他们新发布的“小米su7”特别“炫技”!一打开就是各种3D交互页面,像这种带 WebGL 技术的内容,未来会越来越多地出现在 数字孪生、VR、游戏 等领域。于是我心想:这种潮流,必须跟上啊!你们也可以访问su7一起来吃吃细糠。
🧩 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>
🎉 效果:
你会看到一个简陋的绿色半圆,别急!这是你的第一步,先学会使用 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>
作用:
-
HTML 基础结构:
- 设置
<!DOCTYPE html>声明 HTML5 文档。 - 使用
<meta>标签确保页面在移动端设备上的显示效果良好。
- 设置
-
引入 Three.js:
https://unpkg.com/three@0.128.0/build/three.min.js是 Three.js 的官方 CDN,你可以通过它快速加载并使用 WebGL 功能。
-
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();
作用:
-
声明全局变量:
canvas:代表 HTML 中的<canvas>元素。camera:Three.js 中的透视相机,用于观察场景。scene:Three.js 的场景容器,所有 3D 对象都会添加到场景中。renderer:负责将 3D 场景渲染到canvas上。group:用来存放地球模型。mouseX和mouseY:保存鼠标的当前位置,用于控制相机的移动。
-
窗口中心点:
windowHalfX和windowHalfY用于计算鼠标相对于窗口中心的位置。
-
调用初始化与动画函数:
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);
}
作用:
-
初始化 Canvas:
- 获取 HTML 中的
<canvas>元素,用于 3D 渲染。
- 获取 HTML 中的
-
创建相机:
-
THREE.PerspectiveCamera是一种透视相机:- 第一个参数
60表示视角(FOV,角度值)。 - 第二个参数是宽高比,通常是
window.innerWidth / window.innerHeight。 - 第三个和第四个参数表示相机能看到的最近和最远的物体距离。
- 第一个参数
-
相机初始位置是
z = 500,也就是距离场景中心 500 个单位。
-
-
创建场景:
scene是 Three.js 的核心容器,用于存放 3D 对象。- 使用
scene.background设置背景色为白色。
-
创建组:
- 使用
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);
});
作用:
-
加载地球纹理:
- 使用
THREE.TextureLoader加载地球的表面图像(land_ocean_ice_cloud_2048.jpg)。 - 回调函数中,使用纹理生成材质
THREE.MeshBasicMaterial。
- 使用
-
生成球体:
-
使用
THREE.SphereGeometry创建球体几何模型:- 第一个参数是半径(200)。
- 第二和第三个参数分别是水平和垂直分段数,影响球体的精细度。
-
将几何体和材质组合成网格
THREE.Mesh,并添加到group中。
-
-
创建渲染器:
- 使用
THREE.WebGLRenderer渲染 3D 场景到canvas。 - 设置
antialias: true开启抗锯齿效果,增加画面平滑度。 - 调用
renderer.setSize()设置渲染的宽高。
- 使用
-
监听鼠标事件:
- 添加鼠标事件监听器,捕获鼠标的位置变化。
📄 代码片段 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);
}
作用:
-
鼠标事件:
onDocumentMouseMove():更新鼠标的当前位置,并用来影响相机的移动。mouseX和mouseY保存鼠标偏移量。
-
动画循环:
animate():通过requestAnimationFrame()递归调用自己,创建一个无限的渲染循环。
-
渲染逻辑:
- 根据鼠标位置调整相机位置,模拟地球跟随鼠标移动的效果。
- 通过修改
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地球更炫!
- 加大纹理分辨率:换上更高清的纹理图,让地球的海洋、沙漠看起来更加细腻。
- 添加光源:试试
THREE.DirectionalLight(),让太阳的光芒打在地球上,营造白天和黑夜的效果。 - 交互增强:加上鼠标滚轮缩放功能,用
camera.position.z来控制缩放比例。 - 加星空背景:可以用一个大球体当背景,贴上星空纹理图,完美还原宇宙场景!
🧑💻 写在最后
代码就是一门艺术,写代码的过程就像是在搭建一个独一无二的世界。这个3D地球项目,不仅能用在网站展示,还能成为抖音爆款交互效果的原型!
快试试看,自己用代码创作一个旋转地球吧!记得秀给朋友看,说不定你会收获一大波“程序员的崇拜”😎。
如果你有任何问题,留言区咱们唠嗑~ 👋