Three.js实现太阳系八大行星自转与公转的完整教程
本文详细介绍如何使用Three.js框架在Web端实现太阳系八大行星的自转与公转动画。通过解析Scene、Camera和Renderer三大核心组件,结合Group层级嵌套技巧解决多行星不同速度的旋转问题,并提供完整的初始化与渲染代码示例,帮助开发者掌握WebGL 3D场景搭建与物体运动控制。
Three.js框架简介
一、Three.js框架简介
Three.js是一个基于JavaScript的WebGL第三方库。利用该框架开发3D程序,能够让用户仿佛置身于真实的3D场景中,获得沉浸式的视觉体验。在Three.js中,有三个核心基础组件:Scene(场景)、Camera(相机)和Render(渲染器)。只有正确配置这三个组件,才能将3D物体渲染到网页上,从而完成整个场景的构建。
场景(Scene)
顾名思义,Scene用于存放场景中所有的3D元素和对象。
var scene = new THREE.Scene(); //建立场景
相机(Camera)
相机决定了观察者的视角位置以及观看元素的方式。
Three.js支持多种相机类型,此处不作展开,本文示例使用的是透视相机(PerspectiveCamera)。
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 10000); //设置相机为 角度60度,宽高比,最近端Z轴为1,最远端Z轴为10000
可以通过Three.js官方文档中的一张示意图来直观理解这些属性的含义。

渲染器(Render)
当场景中的所有元素准备就绪后,需要调用渲染器来绘制这些元素,即确定如何将场景输出到屏幕。
渲染器也有多种类型,本示例中选用的是WebGLRenderer。
var renderer = new THREE.WebGLRenderer();
具体实现步骤包括:创建元素、定义相机、搭建场景、将元素和相机加入场景、最后执行渲染操作。
具体代码将在后文详细列出,在此之前,我们先来看一下最终的运行效果。
基本初始化设置
二、基本初始化设置
为了简化开发,这里直接通过CDN链接引入Three.js库文件。
<script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>
注意:由于各行星的大小、转速和距离差异巨大,为了视觉效果,代码中对部分参数进行了非真实比例的平衡调整。
接下来将逐一分析各个元素是如何被添加和配置的。
1. Canvas画布设置
我们没有直接将场景挂载到body元素中,而是在body内部放置了一个canvas画布,并将3D场景显示在该画布上。
2. 背景图片处理
为了简化处理,我们没有制作3D旋转背景,而是直接放置了一张静态背景图作为“小太阳系”的背景。这张背景图是直接绘制在canvas上的。
<canvas id="webglcanvas"></canvas>
renderer = new THREE.WebGLRenderer({ //定义渲染器
alpha: true, //让背景透明,默认是黑色,以显示我们自己的背景图
});
renderer.setClearAlpha(0);
//css文件
#webglcanvas {
background: url(./images/bg4.jpg) no-repeat;
background-size: cover;
}
然而,如果仅做上述简单操作是不够的,因为添加渲染器后,默认背景颜色为黑色。因此,需要在WebGLRenderer中设置alpha属性为true,使背景透明,从而显示出我们自定义的背景图片。
3. 定义基本组件
首先定义场景对象。
scene = new THREE.Scene(), //建立场景
接着定义相机的位置参数。
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1,10000); //设置相机为 角度60度,宽高比,最近端Z轴为1,最远端Z轴为10000
camera.position.z = 2000; //调整相机位置
camera.position.y = 500;
然后创建一个Group(组)对象。
Group可以视为元素的容器,用于将具有共同特征的元素归置在一起管理。
group = new THREE.Group(), //建立一个组
在第三节中,将解释为什么需要建立额外的16个组。
//下面这些组用来建立每个星球的父元素,以实现 八大行星不同速度的公转与自转
var group1 = new THREE.Group();
groupParent1 = new THREE.Group();
group2 = new THREE.Group();
groupParent2 = new THREE.Group();
group3 = new THREE.Group();
groupParent3 = new THREE.Group();
group4 = new THREE.Group();
groupParent4 = new THREE.Group();
group5 = new THREE.Group();
groupParent5 = new THREE.Group();
group6 = new THREE.Group();
groupParent6 = new THREE.Group();
group7 = new THREE.Group();
groupParent7 = new THREE.Group();
group8 = new THREE.Group();
groupParent8 = new THREE.Group();
定义渲染器。
WebGLRenderer中包含一个用于绘制输出的canvas对象,这里需要将之前设置的canvas对象赋值给渲染器的canvas属性。
var canvas = document.getElementById('webglcanvas'),
renderer = new THREE.WebGLRenderer({ //定义渲染器
alpha: true, //让背景透明,默认是黑色 以显示我们自己的背景图
canvas: canvas, //一个用来绘制输出的Canvas对象
antialias: true //抗锯齿
});
renderer.setSize(window.innerWidth, window.innerHeight); //设置渲染器的宽高
4. 初始化函数
在该函数中执行一系列初始化操作。
function init() { //用来初始化的函数
scene.add(group); //把组都添加到场景里
scene.add(groupParent1);
scene.add(groupParent2);
scene.add(groupParent3);
scene.add(groupParent4);
scene.add(groupParent5);
scene.add(groupParent6);
scene.add(groupParent7);
scene.add(groupParent8);
var loader = new THREE.TextureLoader();/*材质 纹理加载器*/
// 太阳
loader.load('./images/sun1.jpg', function (texture) {
var geometry = new THREE.SphereGeometry(250, 20, 20) //球体模型
var material = new THREE.MeshBasicMaterial({ map: texture }) //材质 将图片解构成THREE能理解的材质
var mesh = new THREE.Mesh(geometry, material); //网孔对象 第一个参数是几何模型(结构),第二参数是材料(外观)
group.add(mesh);//添加到组里
})
// 水星
loader.load('./images/water.jpg', function (texture) {
var geometry = new THREE.SphereGeometry(25, 20, 20) //球型
var material = new THREE.MeshBasicMaterial({ map: texture }) //材质 将图片解构成THREE能理解的材质
var mesh = new THREE.Mesh(geometry, material);
group1.position.x -= 300;
group1.add(mesh);
groupParent1.add(group1);
})
//其它7颗行星参数因为太长了在这里就不给出了,但参数的设置原理都是一样的
}
简要解释如下:
var loader = new THREE.TextureLoader(); 这行代码定义了一个材质纹理加载器。
var geometry = new THREE.SphereGeometry(250, 20, 20); 这行代码建立了一个球体模型,其中球体半径为250,水平分割面数量为20,垂直分割面数量也为20。
var mesh = new THREE.Mesh(geometry, material); 这行代码创建了一个网格对象(Mesh)。
其具体作用是:先创建一个球体框架,然后用行星的贴图纹理包裹该框架,从而形成一颗行星。最后将该行星添加到对应的组中,再将组添加到场景中。这就是构建单个行星元素的全过程。
那么,为什么太阳直接添加到组中,而水星等行星需要用到两个层级的组并设置位置偏移呢?这将在第三节中详细解答。
实现自转与公转
三、实现自转与公转
旋转机制:要实现旋转功能,通常有三种方式。
1. 旋转相机 2. 旋转整个场景(Scene) 3. 旋转单个元素。
由于每个行星的自转速度和公转速度各不相同,设置整体旋转并不可行,因此必须为每个元素单独设置旋转属性。
旋转机制详解:这里主要利用物体的rotation属性,实现物体相对于自身坐标系的旋转。
例如:
scene.rotation.y += 0.04; //整个场景绕自身的Y轴逆时针旋转
进入正题。

Scene中的所有元素默认使用rotation.y属性,初始Y轴即为旋转轴。因此,让太阳旋转只需直接旋转其所在的组即可group.rotation.y += 0.04;。
而对于其他行星,若要实现绕太阳公转,需先给它们自身设置位置偏移。例如水星:group1.position.x -= 300; 此时若设置group1.rotation.y属性,由于Y轴位置已改变,它将实现自转。

此时若想实现公转,在该对象中找不到默认的Y轴旋转线。因此,我们给group1设置了一个“父元素”groupParent1。groupParent1.add(group1);。
当我们移动group1时,groupParent1的位置保持不变,其Y轴自然也不变。由于groupParent1包含了group1,旋转groupParent1时,group1会绕着初始的默认Y轴旋转。设置这么多组的目的,正是为了实现每颗行星不同的速度,以及公转与自转的同时进行。

其他实现函数
四、其他实现函数
function render() {
renderer.render(scene, camera);
camera.lookAt(scene.position); //让相机盯着场景的位置 场景始终在中间
}
//设置公转
function revolution(){
groupParent1.rotation.y += 0.15;
groupParent2.rotation.y += 0.065;
groupParent3.rotation.y += 0.05;
groupParent4.rotation.y += 0.03;
groupParent5.rotation.y += 0.001;
groupParent6.rotation.y += 0.02;
groupParent7.rotation.y += 0.0005;
groupParent8.rotation.y += 0.003;
}
//设置自转
function selfRotation(){
group.rotation.y += 0.04;
group1.rotation.y += 0.02;
group2.rotation.y -= 0.005;
group3.rotation.y += 1;
group4.rotation.y += 1;
group5.rotation.y += 1.5;
group6.rotation.y += 1.5;
group7.rotation.y -= 1.5;
group8.rotation.y += 1.2;
}
function Animation() {
render();
selfRotation();
revolution();
requestAnimationFrame(Animation);
}
最后,再调用一下 init()和Animation()函数即可完成整个程序的运行。
总结
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对本站的支持。
定制 Quill.js 主题样式:修改默认 CSS 与添加自定义类名
2026-11-04 11:21:35
混淆JS代码怎么在线反混淆并格式化阅读
2026-11-03 21:46:39
JS在线编辑器代码报错怎么调试?控制台使用技巧
2026-11-03 21:24:56
从 marked.js 旧版本升级到最新版:API 变更与迁移指南
2026-11-03 17:38:17
JS富文本编辑器Quill与代码编辑器CodeMirror的区别及应用场景
2026-11-03 16:52:09
