引言
随着Web技术的发展,创建具有互动性的3D内容变得越来越容易。Three.js是一个非常流行的JavaScript库,它简化了使用WebGL创建3D图形的过程。本文将详细介绍如何利用Three.js创建一个简单的3D地球仪,并解释每一步骤的意义和作用,即使你是前端开发的新手也能轻松上手。
什么是Three.js?
Three.js是一个用于在浏览器中创建和显示动画的3D计算机图形的跨浏览器JavaScript库。它使用HTML5 Canvas、SVG或WebGL来绘制图像。WebGL是基于OpenGL ES的一个API,允许网页通过JavaScript直接访问GPU加速功能,从而实现高性能的2D和3D图形渲染。
准备工作
首先,你需要确保你的项目中引入了Three.js库。你可以通过CDN链接的方式快速集成Three.js到你的HTML文件中,就像这样:
<script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>
注意:虽然这里使用的是r83版本,但推荐使用最新版的Three.js以获得最佳性能和最新的特性支持。
步骤1: 设置场景(Scene)
要开始构建3D世界,首先要设置一个场景。场景就像是一个容器,里面可以放置所有你想展示的对象(如地球)。
let scene = new THREE.Scene();
这行代码创建了一个新的场景实例。
步骤2: 配置相机(Camera)
接下来需要添加一个相机,这样才能从特定的角度查看我们的3D对象。我们通常使用THREE.PerspectiveCamera,它模拟了人类眼睛看到的效果。
let camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000);
camera.position.z = 500;
这里的参数分别表示视野角度、长宽比、近裁剪面距离和远裁剪面距离。最后设置相机的位置以便能够看到整个地球。
步骤3: 渲染器(Renderer)
为了让浏览器能显示3D内容,我们需要一个渲染器。Three.js提供了THREE.WebGLRenderer,这是最常用的渲染器之一。
let renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
这里设置了抗锯齿选项并调整大小以适应窗口尺寸,然后将其添加到DOM中。
步骤4: 加载纹理并创建地球模型
现在让我们加载一张图片作为地球的表面纹理,并用它创建一个球体。(相关图片也可以自己去网上找,设置要对应的路径就可以)
let loader = new THREE.TextureLoader();
loader.load('https://threejsfundamentals.org/threejs/resources/images/earth-day.jpg', function(texture) {
let geometry = new THREE.SphereGeometry(200, 20, 20);
let material = new THREE.MeshBasicMaterial({ map: texture });
earthMesh = new THREE.Mesh(geometry, material);
scene.add(earthMesh);
});
这段代码首先创建了一个纹理加载器,接着定义了球体的几何形状和材质,最后将它们组合成一个网格(Mesh),并添加到了场景中。
步骤5: 实现交互与动画
为了让用户可以通过鼠标移动来改变视角,我们监听了鼠标的移动事件,并根据其位置更新相机的位置。
function onDocumentMouseMove(event) {
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}
同时,为了使地球自转,我们在每一帧都稍微旋转地球模型。
if (earthMesh) { // 只有地球存在时才旋转
earthMesh.rotation.y -= 0.005;
}
步骤6: 渲染循环
最后,为了让这一切动起来,我们需要一个持续不断的渲染循环。通过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);
if (earthMesh) {
earthMesh.rotation.y -= 0.005;
}
renderer.render(scene, camera);
}
结论
通过上述步骤,我们已经成功地创建了一个可以交互且带有动画效果的3D地球仪。Three.js的强大之处在于它极大地降低了WebGL编程的复杂度,使得开发者可以专注于创意而非底层细节。希望这篇文章能帮助你入门Three.js,并激发你探索更多3D Web应用的兴趣。无论是游戏开发还是数据可视化,Three.js都能提供强大的支持。继续学习和实践,你会发现自己能够创造出令人惊叹的作品!
完整代码:
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>3D地球</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { display: block; }
</style>
</head>
<body>
<canvas id="webglcanvas"></canvas>
<script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>
<script>
let scene, camera, renderer;
let mouseX = 0, mouseY = 0;
let windowHalfX = window.innerWidth / 2;
let windowHalfY = window.innerHeight / 2;
let earthMesh = null; // 新增一个变量来保存地球对象
function init() {
// 创建场景
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
// 配置相机
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000);
camera.position.z = 500;
// 设置渲染器
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 加载纹理并创建地球模型
let loader = new THREE.TextureLoader();
loader.load('1.png', function(texture) {
let geometry = new THREE.SphereGeometry(200, 20, 20);
let material = new THREE.MeshBasicMaterial({ map: texture });
earthMesh = new THREE.Mesh(geometry, material); // 赋值给全局变量
scene.add(earthMesh);
});
// 监听鼠标移动事件
document.addEventListener('mousemove', onDocumentMouseMove, false);
// 监听窗口大小调整事件
window.addEventListener('resize', onWindowResize, false);
}
function onDocumentMouseMove(event) {
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
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);
// 地球自转
if (earthMesh) {
earthMesh.rotation.y -= 0.005;
}
// 渲染场景
renderer.render(scene, camera);
}
// 初始化并启动动画循环
init();
animate();
</script>
</body>
</html>