最近学了three.js,想拿来练练手,喜欢宇宙,于是亲手撸代码来完成这个,为了更真实,于是查了一些相关资料。
1. 距离太阳由近及远分别是【水星,金星,地球,火星,木星,土星,天王星,海王星】
2. 他们分别到太阳的距离为5791, 10820, 14960, 22794, 77833, 142940, 287099, 450400(单位万千米)
3. 他们的半径分别为2440, 6052, 6371, 3397, 71492, 60268, 25559, 24766(千米)
4. 他们的公转周期分别为88, 225, 365, 687, 4329, 10767, 30769, 60152(天)
5. 他们的自转周期分别为58,243,1, 1, 0.41, 0.42, 0.64, 0.65,
好了除了八大行星都已经调查好了,接下来八大行星都将按照真实比例绘制,(由于周期相差过大,遂正比于1/2次方)

1.绘制八大行星

绘制行星很容易,直接看代码

shuixing = renderMesh("shuixing", 0);
jinxing = renderMesh("jinxing", 1);
diqiu = renderMesh("diqiu", 2);
huoxing = renderMesh("huoxing", 3);
muxing = renderMesh("muxing", 4);
tuxing = renderMesh("tuxing", 5);
tianwangxing = renderMesh("tianwangxing", 6);
haiwangxing = renderMesh("haiwangxing", 7);
scene.add(shuixing);
scene.add(jinxing);
scene.add(diqiu);
scene.add(huoxing);
scene.add(muxing);
scene.add(tuxing);
scene.add(tianwangxing);
scene.add(haiwangxing);
function renderMesh(name, num) {
let texture = new THREE.TextureLoader().load("http://www.bettersmile.cn:90/three_code/assets/textures/planets/"+name+".jpg");
let geometry = new THREE.SphereGeometry(radiuses[num] * RADIUS, 50, 50);
let material = new THREE.MeshBasicMaterial({map: texture});
let mesh = new THREE.Mesh(geometry, material);
mesh.position.x = distances[num] * DISTANCE + SUNRADIUS * RADIUS;
return mesh;
}

在绘制的同时,我们还固定了他们的位置哦,

2.绘制小行星带

八大行星都绘制好了,怎么能少了小行星带呢?由于小行星带都是不规则的石头,这里我们使用上一节的ConvexGeometry()渲染。

let asteroidTexture = new THREE.TextureLoader().load("http://www.bettersmile.cn:90/three_code/assets/textures/planets/asteroid.jpg");
asteriods = renderAsteriod(asteroidTexture);
scene.add(asteriods);
function renderAsteriod(texture) {
let asteroid = new THREE.Geometry();
let asteroidMate = new THREE.MeshBasicMaterial();
for(var i=0; i<20000; i++) {
let points = [];
let rad = Math.pow(Math.random(), 3) * ASTERIODRADIUS;
for(var j=0; j<30; j++) {
points.push(new THREE.Vector3(Math.random() * RADIUS * rad, Math.random() * RADIUS * rad, Math.random() * RADIUS * rad))
}
var asteroidGeom = new THREE.ConvexGeometry(points); var asterMesh = new THREE.Mesh(asteroidGeom, asteroidMate);
//2.17-3.64 * 14960 = 32450 - 54450
let dis = (Math.random() * 22000 + 32450) * DISTANCE + SUNRADIUS * RADIUS;
let angle = Math.random() * Math.PI * 2;
asterMesh.position.x = dis * Math.sin(angle);
asterMesh.position.y = Math.random() * ASTERIODRADIUS * RADIUS * 4 - ASTERIODRADIUS * RADIUS * 2;
asterMesh.position.z = dis * Math.cos(angle); asterMesh.updateMatrix();
asteroid.merge(asterMesh.geometry, asterMesh.matrix);
}
let mesh = new THREE.Mesh(asteroid, new THREE.MeshLambertMaterial({map: texture, emissive: 0x484137}));
return mesh;
}

我们渲染了20000个小行星,这里小行星带距离太阳2.17~3.64个天文单位,一天文单位为14960万千米。

3.加下来我们绘制太阳,月球,土星环

绘制太阳,月球和土星环(土星环P了好久),相对容易,太阳设置在原点,月球围绕地球,土星环围绕土星,

let taiyangTexture = new THREE.TextureLoader().load("http://www.bettersmile.cn:90/three_code/assets/textures/planets/sun.jpg");
let yueqiuTexture = new THREE.TextureLoader().load("http://www.bettersmile.cn:90/three_code/assets/textures/planets/yueqiu.jpg");
let tuxinghuanTexture = new THREE.TextureLoader().load("http://www.bettersmile.cn:90/three_code/assets/textures/planets/tuxinghuan.png");
let taiyangGeom = new THREE.SphereGeometry(SUNRADIUS * RADIUS, 50, 50);
let taiyangMate = new THREE.MeshBasicMaterial({map: taiyangTexture});
let yueqiuGeom = new THREE.SphereGeometry(MOONRADIUS * RADIUS, 50, 50);
let yueqiuMate = new THREE.MeshBasicMaterial({map: yueqiuTexture});
tuxinghuan = renderTuxinghuan(tuxinghuanTexture);
tuxinghuan.position.copy(tuxing.position);
scene.add(tuxinghuan);
taiyang = new THREE.Mesh(taiyangGeom, taiyangMate);
yueqiu = new THREE.Mesh(yueqiuGeom, yueqiuMate);
yueqiu.position.set((distances[2] * DISTANCE + SUNRADIUS * RADIUS) + MOONDISTANCE * DISTANCE, 0, 0);
scene.add(taiyang);
scene.add(yueqiu);
function renderTuxinghuan(texture) {
let geom = new THREE.RingGeometry(16, 24, 50, 10, 0, Math.PI * 2);
let mate = new THREE.MeshLambertMaterial({emissive: 0xaa8766, transparent:false, opacity: 0.8, map: texture, side: THREE.DoubleSide});
let ring = new THREE.Mesh(geom, mate);
ring.rotation.x = - Math.PI / 2;
ring.rotation.y = - Math.PI / 12;
return ring;
}
function initCanvas() {
let canvas = document.createElement('canvas');
canvas.width = 16;
canvas.height = 16;
let context = canvas.getContext('2d');
let gradient = context.createRadialGradient(canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2);
gradient.addColorStop(0, 'rgba(244,164,33,1)');
gradient.addColorStop(0.2, 'rgba(244,164,33,1)');
gradient.addColorStop(0.4, 'rgba(244,164,33,.6)');
gradient.addColorStop(1, 'rgba(0,0,0,0)');
context.fillStyle = gradient;
context.fillRect(0, 0, canvas.width, canvas.height);
return canvas;
} function initSunshine() {
let centerBallLite = new THREE.Sprite(new THREE.SpriteMaterial({
map: new THREE.CanvasTexture(initCanvas()),
blending: THREE.AdditiveBlending
}));
centerBallLite.scale.x = centerBallLite.scale.y = centerBallLite.scale.z = 250000 * RADIUS;
scene.add(centerBallLite);
}

这里我们的土星环使用了RingGeometry()几何体,太阳的光晕使用CanvasTexture()

4.让星球动起来

让所有星星动起来,使用自转和公转,这里需要一点三角函数的功底,

function allStarsSelfRotate() {
taiyang.rotation.y = 1 / Math.sqrt(25) * step1 * SELECYCLE;
yueqiu.rotation.y = 1 / Math.sqrt(30) * step1 * SELECYCLE;
shuixing.rotation.y = 1 / Math.sqrt(58.65) * step1 * SELECYCLE;
jinxing.rotation.y = - 1 / Math.sqrt(243) * step1 * SELECYCLE;
diqiu.rotation.y = step1 * SELECYCLE;
huoxing.rotation.y = step1 * SELECYCLE;
muxing.rotation.y = 1 / Math.sqrt(0.41) * step1 * SELECYCLE;
tuxing.rotation.y = 1 / Math.sqrt(0.42) * step1 * SELECYCLE;
tianwangxing.rotation.z = 1 / Math.sqrt(0.64) * step1 * SELECYCLE;
haiwangxing.rotation.y = 1 / Math.sqrt(0.65) * step1 * SELECYCLE;
asteriods.rotation.y = 1 / 50 * step1 * PUBLICCYCLE;
step1 ++;
} function allStarsPublicRotate() {
shuixing.position.set(rotating(0).x,0,rotating(0).z);
jinxing.position.set(rotating(1).x,0,rotating(1).z);
diqiu.position.set(rotating(2).x,0,rotating(2).z);
huoxing.position.set(rotating(3).x,0,rotating(3).z);
muxing.position.set(rotating(4).x,0,rotating(4).z);
tuxing.position.set(rotating(5).x,0,rotating(5).z);
tianwangxing.position.set(rotating(6).x,0,rotating(6).z);
haiwangxing.position.set(rotating(7).x,0,rotating(7).z);
tuxinghuan.position.copy(tuxing.position);
yueqiu.position.set(
(distances[2] * DISTANCE + SUNRADIUS * RADIUS) * Math.cos(step2 / Math.sqrt(durations[2]) * PUBLICCYCLE) +
(MOONDISTANCE * DISTANCE) * Math.sin(step2 / Math.sqrt(10) * PUBLICCYCLE),
0,
- (distances[2] * DISTANCE + SUNRADIUS * RADIUS) * Math.sin(step2 / Math.sqrt(durations[2]) * PUBLICCYCLE) +
(MOONDISTANCE * DISTANCE) * Math.cos(step2 / Math.sqrt(10) * PUBLICCYCLE)
);
step2 ++;
}
function rotating(num) {
let x = (distances[num] * DISTANCE + SUNRADIUS * RADIUS) * Math.cos(step2 / Math.sqrt(durations[num]) * PUBLICCYCLE);
let z = - (distances[num] * DISTANCE + SUNRADIUS * RADIUS) * Math.sin(step2 / Math.sqrt(durations[num]) * PUBLICCYCLE);
return {x, z};
}

全是简单的三角函数,呵呵

5.加上星空

星空我们直接使用PointsMaterial(),我们随机3000个点(点太多会很乱)。

function initSprites() {
let geom = new THREE.Geometry();
let mate = new THREE.PointsMaterial({
size: 0.2,
vertexColors: true,
color: 0xffffff,
transparent: true,
opacity: 0.6
})
for(var i=0; i<3000; i++) {
let x = Math.random() * 10000 - 5000;
let y = Math.random() * 10000 - 5000;
let z = Math.random() * 10000 - 5000;
if(x*x+y*y+z*z > 250000) {
var vector = new THREE.Vector3(x,y,z);
geom.vertices.push(vector);
geom.colors.push(new THREE.Color(0xffffff));
}
}
cloud = new THREE.Points(geom, mate);
scene.add(cloud);
}

x*x+y*y+z*z > 250000,为了让他们处在很远的地方,我们过滤掉离中心小于500的星星,所以剩下的应该不多。

6.加上tween动画和飞行相机

动画我们是先给每个星球一个镜头(毕竟球球平等,但是给了地球最好的贴图),然后俯瞰整个太阳系

function initTween() {
let pos = {x: 41, y: 17, z: -35, lx: 0, ly: 0, lz: 0};
let tween1 = new TWEEN.Tween(pos).to({x: 40.36, y: 0.29, z: 2.642, lx: 40.54, ly: 0, lz: 0}, 20 * ANIMATIONTIME);
tween1.easing(TWEEN.Easing.Linear.None);
let tween2 = new TWEEN.Tween(pos).to({x: 67.41, y: 0.43, z: -4, lx: 65.7, ly: 0, lz: 0}, 22 * ANIMATIONTIME);
tween2.easing(TWEEN.Easing.Linear.None);
let tween3 = new TWEEN.Tween(pos).to({x: 84.6, y: 0.91, z: -3.42, lx: 86.4, ly: 0, lz: 0}, 24 * ANIMATIONTIME);
tween3.easing(TWEEN.Easing.Linear.None);
let tween4 = new TWEEN.Tween(pos).to({x: 127.66, y: 0.26, z: -1.47, lx: 125.56, ly: 0, lz: 0}, 27 * ANIMATIONTIME);
tween4.easing(TWEEN.Easing.Linear.None);
let tween5 = new TWEEN.Tween(pos).to({x: 177.78, y: 1.64, z: -61.37, lx: 200.84, ly: 0, lz: 0}, 30 * ANIMATIONTIME);
tween5.easing(TWEEN.Easing.Linear.None);
let tween6 = new TWEEN.Tween(pos).to({x: 359.81, y: 11.44, z: -26.28, lx: 400.76, ly: 0, lz: 0}, 35 * ANIMATIONTIME);
tween6.easing(TWEEN.Easing.Linear.None);
let tween7 = new TWEEN.Tween(pos).to({x: 703.65, y: 34.43, z: -73.74, lx: 726.29, ly: 0, lz: 0}, 40 * ANIMATIONTIME);
tween7.easing(TWEEN.Easing.Linear.None);
let tween8 = new TWEEN.Tween(pos).to({x: 1441.76, y: 2.69, z: -26.5, lx: 1447.09, ly: 0, lz: 0}, 50 * ANIMATIONTIME);
tween8.easing(TWEEN.Easing.Linear.None);
let tween9 = new TWEEN.Tween(pos).to({x: 2262.5, y: 4.43, z: 17.22, lx: 2263.59, ly: 0, lz: 0}, 65 * ANIMATIONTIME);
tween9.easing(TWEEN.Easing.Linear.None);
let tween10 = new TWEEN.Tween(pos).to({x: -374, y: 452, z: -3.4, lx: 400.76, ly: 0, lz: 0}, 85 * ANIMATIONTIME);
tween10.easing(TWEEN.Easing.Linear.None); tween1.chain(tween2);
tween2.chain(tween3);
tween3.chain(tween4);
tween4.chain(tween5);
tween5.chain(tween6);
tween6.chain(tween7);
tween7.chain(tween8);
tween8.chain(tween9);
tween9.chain(tween10); var onUpdate = function () {
var px = this.x;
var py = this.y;
var pz = this.z;
var lx = this.lx;
var ly = this.ly;
var lz = this.lz; camera.position.set(px, py, pz);
camera.lookAt(new THREE.Vector3(lx, ly, lz))
}; tween1.onUpdate(onUpdate);
tween2.onUpdate(onUpdate);
tween3.onUpdate(onUpdate);
tween4.onUpdate(onUpdate);
tween5.onUpdate(onUpdate);
tween6.onUpdate(onUpdate);
tween7.onUpdate(onUpdate);
tween8.onUpdate(onUpdate);
tween9.onUpdate(onUpdate);
tween10.onUpdate(onUpdate);
tween1.delay(70 * ANIMATIONTIME);
tween2.delay(30 * ANIMATIONTIME);
tween3.delay(30 * ANIMATIONTIME);
tween4.delay(30 * ANIMATIONTIME);
tween5.delay(30 * ANIMATIONTIME);
tween6.delay(30 * ANIMATIONTIME);
tween7.delay(30 * ANIMATIONTIME);
tween8.delay(30 * ANIMATIONTIME);
tween9.delay(30 * ANIMATIONTIME);
tween10.delay(30 * ANIMATIONTIME);
tween1.start();
tween10.onComplete(function () {
off = true;
})
}

代码很长不过很好理解...
这样我们就完成了一个简单的太阳系。

想看demo的请移步至郭志强的博客

转载请注明原文地址 https://www.cnblogs.com/vadim-web/p/12077466.html

three.js 制作太阳系统的更多相关文章

  1. 用JS制作一个信息管理平台完整版

      前  言 JRedu 在之前的文章中,介绍了如何用JS制作一个实用的信息管理平台. 但是那样的平台功能过于简陋了,我们今天来继续完善一下. 首先我们回顾一下之前的内容.   1.JSON的基础知识 ...

  2. #3使用html+css+js制作网页 番外篇 使用python flask 框架 (II)

    #3使用html+css+js制作网页 番外篇 使用python flask 框架 II第二部 0. 本系列教程 1. 登录功能准备 a.python中操控mysql b. 安装数据库 c.安装mys ...

  3. #3使用html+css+js制作网页 番外篇 使用python flask 框架 (I)

    #3使用html+css+js制作网页 番外篇 使用python flask 框架(I 第一部) 0. 本系列教程 1. 准备 a.python b. flask c. flask 环境安装 d. f ...

  4. js制作带有遮罩弹出层实现登录小窗口

    要实现的效果如下 点击“登录”按钮后,弹出登录小窗口,并且有遮罩层(这个名词还是百度知道的,以前只知道效果,却不知道名字) 在没有点击“登录”按钮之前登录小窗口不显示,点击“登录”按钮后小窗口显示,并 ...

  5. 基于node.js制作爬虫教程

    前言:最近想学习node.js,突然在网上看到基于node的爬虫制作教程,所以简单学习了一下,把这篇文章分享给同样初学node.js的朋友. 目标:爬取 http://tweixin.yueyishu ...

  6. 利用css+原生js制作简易钟表

    利用css+原生js制作简单的钟表.效果如下所示 实现该效果,分三大块:html.javascript.css html部分html部分比较简单,定义一个clock的div,内部有原点.时分秒针.日期 ...

  7. Node.js 操作 OSX 系统麦克风、扬声器音量

    最近几年 Electron 很火,公司也正好有个项目想做跨平台客户端,大家研究了一下就选择了 Electron,第一次做 js 的项目遇到了不少坑,不过也都一点点解决了. 因为项目中需要对用户录音,H ...

  8. 利用JS模拟排队系统

    我爱撸码,撸码使我感到快乐!大家好,我是Counter.今天给大家分享的是js模拟排队系统,刚开始有排队序列,序列里有vip用户和普通用户,vip用户永远位于普通用户的前面,只有当当前vip用户都办理 ...

  9. JS制作图片切换

    <!DOCTYPE html> <html> <head> <title>纯JS制作简单的图片切换</title> <meta cha ...

随机推荐

  1. Java描述设计模式(23):访问者模式

    本文源码:GitHub·点这里 || GitEE·点这里 一.生活场景 1.场景描述 电竞是游戏比赛达到"竞技"层面的体育项目.利用电子设备作为运动器械进行的.人与人之间的智力对抗 ...

  2. docker容器访问宿主机的IP——以rocketmq管理工具为例

    在宿主机(MacOS系统)上运行了原生的RocketMQ服务,为了方便管理,需要以Docker方式运行RocketMQ的管理工具——rocketmq-console (项目地址:https://git ...

  3. day 39 盒模型 display 浮动

    一.盒模型 属性: width:内容的宽度 height:内容的高度 padding:内边距 内容到边框的距离 border:边框 margin:外边距 另一个边到另一个边的距离 盒模型的计算: 总结 ...

  4. vim介绍、颜色显示和移动光标、一般模式下移动光标及复制、剪切和粘贴

    第4周第4次课(4月12日) 课程内容: 5.1 vim介绍5.2 vim颜色显示和移动光标5.3 vim一般模式下移动光标5.4 vim一般模式下复制.剪切和粘贴 5.1 vim介绍 centos7 ...

  5. ASI和AFN的区别

    ASI总结 发送请求的2个对象 1.发送GET请求 ASIHttpRequest 2.发送POST请求 ASIFormDataRequest 二发送请求 1.同步请求 startSynchronous ...

  6. 10个常见的HTTP状态码

    目录 500 内部服务器错误 404 文件未找到 403 禁止访问 400 错误请求 401 未经授权 200 请求成功 206 部分内容 301 永久重定向 302 临时重定向 502 无效网关 H ...

  7. 第三章 学习Shader所需的数学基础(4)

    法线变换 法线(normal),也被称为法矢量(normal vector).在以前我们已经讲过如何使用变换矩阵来变换一个顶点或方向矢量,但法线是需要我们特殊处理的一种方向矢量.在游戏中,模型的顶点往 ...

  8. 请问1^x+2^x+3^x+\cdots +n^x的算式是什么呢?

    目录 总结 请问\(1^x+2^x+3^x+\cdots +n^x\)的算式是什么呢? 一.求和式\(\sum\limits_{i=1}^n{i}\)的算式 如何证明求和简式\(\sum_{i=1}^ ...

  9. C#中的委托和事件(二)

    引言 如果你看过了 C#中的委托和事件 一文,我想你对委托和事件已经有了一个基本的认识.但那些远不是委托和事件的全部内容,还有很多的地方没有涉及.本文将讨论委托和事件一些更为细节的问题,包括一些大家常 ...

  10. DateTime格式转换部分介绍

    DateTime与字符串转换: DateTime()与转换为字符串主要依靠DateTime().ToString(string format) 函数,以我的理解,参数format大体分为单个字母和多个 ...