Three.js实现太阳系八大行星的自转公转
Three.js 基础应用与行星系统模型
引言
Three.js 是一个用于编写WebGL三维程序的JavaScript库。它通过将 WebGL 和 JavaScript 结合在一起,使得开发者能够轻松地构建三维场景并将其展示在网页中。
基本组件
Three.js 的核心由三个主要组件构成:
Scene:用于搭建整个三维空间。
Camera:用于定义观察者的位置、视角及显示范围。
Render:负责将三维场景渲染为二维图像。
初始化过程
在HTML文件中引入 Three.js 库:
`html
创建基本元素:javascript
// 创建场景
var scene = new THREE.Scene();
// 定义相机
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 10000);
// 定义渲染器并配置属性
var renderer = new THREE.WebGLRenderer({
alpha: true,
canvas: document.getElementById('webglcanvas'),
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
// 添加渲染器到场景中,并将场景挂载到body上以显示背景图片
scene.add(renderer.domElement);
// 设置相机位置及显示背景图的位置参数
camera.position.z = 200;
camera.position.y = 50;
renderer.setClearAlpha(0);
// 添加背景图片(此处需自行添加)
行星系统构建 创建多个组(Group)用于组织各个天体及其组成部分:javascript
var group = new THREE.Group();
var groupParent1 = new THREE.Group();
var groupParent2 = new THREE.Group();
// ...创建其他组...
group.add(groupParent1);
group.add(groupParent2);
// ...将各组添加到主场景中...
加载并构建每个天体:javascript
loader.load('./images/sun.jpg', function (texture) {
const geometry = new THREE.SphereGeometry(25, 25, 25);
const material = new THREE.MeshBasicMaterial({ map: texture });
const mesh = new THREE.Mesh(geometry, material);
group.add(mesh);
return () => {
mesh.position.x -= 30;
return mesh;
};
});
loader.load('./images/water.jpg', function (texture) {
const geometry = new THREE.SphereGeometry(5, 5, 5);
const material = new THREE.MeshBasicMaterial({ map: texture });
const mesh = new THREE.Mesh(geometry, material);
mesh.position.x -= 37;
groupParent1.add(mesh);
return () => {
mesh.position.x += 37;
return mesh;
一. Three.js框架简介
Three.js是一种基于JavaScript的WebGL第三方库,在实际应用中可以通过采用three.js框架构建三维程序,并通过这一技术手段实现一个类似于在一个虚拟的三维环境中观察现实场景的效果。当向他人介绍three.js时,请特别提到其核心组件包括Scene、Camera和Render三个部分——这些组件构成了整个框架的基础架构,在此基础上才能实现对物体在网页上的渲染以及最终完成整个场景的设计与呈现过程
场景(scene)
顾名思义,就是用来放置所有的元素。
var scene = new THREE.Scene(); //建立场景
复制代码
相机(camera)
相机的位置和观察方式至关重要。由于篇幅限制和复杂性考量,在本示例中我们仅采用一种典型配置——具体的实现采用了透视投影技术的透视相机作为基础架构。# EasyCam(简要说明)
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();
复制代码
具体步骤如下:首先创建一个新元素;随后配置一个虚拟摄像头;接着构建虚拟环境;最后将创建好的物体与配置好的摄像头放置于构建的虚拟环境中并开始渲染该环境。关于代码的具体实现细节将在后续章节中详细讲解;通过预览效果图我们可以初步了解整体呈现效果。
二. 基本初始化
通过从网络资源中导入three.js库代码的方式,在CDN环境中加载三度空间(Three.js)模块以实现三维图形渲染功能。
注:值得注意的是,在考虑各行星的尺寸差异时 ... ,其运转速度以及间距存在较大差异 ... 。在发现各参数之间存在显著差异的情况下 ... ,我们采取了一些平衡性措施 ... 。接下来将详细探讨这些因素是如何被纳入计算模型的。
1.canvas
我们未将场景直接嵌入到body中,在body内设置了canvas画布区域用于展示。
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;
}
复制代码
然而仅进行如此基础的操作是不够的,在添加渲染器后系统会默认将其背景设置为黑色(参考WebGL相关文档),因此在渲染器中需要调整其alpha属性(WebGL渲染器及属性方法),使其背景透明从而能够展示出我们自定义的背景图
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 = 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实例并将其整合到我们的渲染器工作区中
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颗行星参数因为太长了在这里就不给出了,但参数的设置原理都是一样的
}
复制代码
简要解释一下:
通过调用新方法初始化了一个变量 loader 为 TextureLoader 的实例。其功能定位为材质纹理加载器。
使用var geometry = new THREE.SphereGeometry(半径: 400, 水平分割面数量: 16, 垂直分割面数量: 16)生成球体模型
var mesh = new THREE.Mesh(geometry, material);网孔对象。
该方法的主要作用在于生成一个球形元素。具体操作步骤如下:首先搭建基础架构,随后利用行星平面图将其包围,从而形成了一个完整的行星模型。接着将该行星加入组别中,并最终将其纳入整个场景中进行展示,整个过程体现了对单一元素的具体构造过程。
那么太阳为何能直接添加到组里?相比而言,在处理水星时,则需要多级设置,并为它设定特定的位置偏移量。我们即将进入下一阶段的学习。
三. 自转同时公转
旋转策略:我们可以通过以下三种方法实现旋转变换:
1.使用照相机进行自转
2.对完整场景进行环绕式变换
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);即可完成添加操作。
在移动了child group之后其parent group的位置并未改变因此它的Y轴坐标也保持不变由于parent group包含child group当旋转parent group时child group将围绕着初始设定的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()函数就OK了。
觉得有点意思的就点个?8.
