three.js 制作太阳系统
最近学了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 制作太阳系统的更多相关文章
- 用JS制作一个信息管理平台完整版
前 言 JRedu 在之前的文章中,介绍了如何用JS制作一个实用的信息管理平台. 但是那样的平台功能过于简陋了,我们今天来继续完善一下. 首先我们回顾一下之前的内容. 1.JSON的基础知识 ...
- #3使用html+css+js制作网页 番外篇 使用python flask 框架 (II)
#3使用html+css+js制作网页 番外篇 使用python flask 框架 II第二部 0. 本系列教程 1. 登录功能准备 a.python中操控mysql b. 安装数据库 c.安装mys ...
- #3使用html+css+js制作网页 番外篇 使用python flask 框架 (I)
#3使用html+css+js制作网页 番外篇 使用python flask 框架(I 第一部) 0. 本系列教程 1. 准备 a.python b. flask c. flask 环境安装 d. f ...
- js制作带有遮罩弹出层实现登录小窗口
要实现的效果如下 点击“登录”按钮后,弹出登录小窗口,并且有遮罩层(这个名词还是百度知道的,以前只知道效果,却不知道名字) 在没有点击“登录”按钮之前登录小窗口不显示,点击“登录”按钮后小窗口显示,并 ...
- 基于node.js制作爬虫教程
前言:最近想学习node.js,突然在网上看到基于node的爬虫制作教程,所以简单学习了一下,把这篇文章分享给同样初学node.js的朋友. 目标:爬取 http://tweixin.yueyishu ...
- 利用css+原生js制作简易钟表
利用css+原生js制作简单的钟表.效果如下所示 实现该效果,分三大块:html.javascript.css html部分html部分比较简单,定义一个clock的div,内部有原点.时分秒针.日期 ...
- Node.js 操作 OSX 系统麦克风、扬声器音量
最近几年 Electron 很火,公司也正好有个项目想做跨平台客户端,大家研究了一下就选择了 Electron,第一次做 js 的项目遇到了不少坑,不过也都一点点解决了. 因为项目中需要对用户录音,H ...
- 利用JS模拟排队系统
我爱撸码,撸码使我感到快乐!大家好,我是Counter.今天给大家分享的是js模拟排队系统,刚开始有排队序列,序列里有vip用户和普通用户,vip用户永远位于普通用户的前面,只有当当前vip用户都办理 ...
- JS制作图片切换
<!DOCTYPE html> <html> <head> <title>纯JS制作简单的图片切换</title> <meta cha ...
随机推荐
- Running serveral https server on a single IP address
Nginx 在一个IP上配置多个https server时,默认只会发送默认server name的证书.这是由ssl 协议本身行为导致的:先建立ssl connection,后发送http请求.即n ...
- SCAU-1078 破密-数学的应用
另外一种方法和该题的题目在这位大佬的博客里 SCAU 1078 破密 还可以参考 https://blog.csdn.net/sinat_34200786/article/details/78 ...
- MyISAM与InnoDB两者之间区别与选择
一.MyISAM与InnoDB两者之间区别 1.MyISAM:默认表类型,它是基于传统的ISAM类型,ISAM是Indexed Sequential Access Method (有索引的顺序访问方法 ...
- python3 之 趣味数学题(爱因斯坦)
爱因斯坦曾出过这样一道有趣的数学题: 有一个长阶梯,若每步上 2 阶,最 后剩 1 阶; 若每步上 3 阶,最后剩 2 阶; 若每步上 5 阶,最后剩 4 阶; 若每步上 6 阶,最后剩 5 阶; 只 ...
- PyQt5的安装及测试(pycharm)
参考链接:https://www.cnblogs.com/pywjh/articles/9835931.html https://blog.csdn.net/SeekAndFindYou/ar ...
- Eclipse设置Working Set管理项目和detach合并分离窗口
当项目多了的时候,使用Working Set分组管理项目很有必要了,不然一大推项目在一起 找起来麻烦,看起来也难受~ 所以根据给项目不同分类就很有必要了. 之前myeclipse设置了,今天装了一 ...
- 《手把手教你》系列练习篇之6-python+ selenium自动化测试(详细教程)
1. 简介 前面文章我们了解了如何获取元素的text属性值,和判断元素是否显示在页面(is_displayed()方法),本文我们来学习下,判断一个控件是否被选中状态. 2. 验证控件是否被选中 还是 ...
- 实战webpack系列02
02. 开始使用webpack 1.1.安装 Webpack可以使用npm安装,新建一个空的练习文件夹(此处命名为webpack sample project),在终端中转到该文件夹后执行下述指令就可 ...
- Django如何启动源码分析
Django如何启动源码分析 启动 我们启动Django是通过python manage.py runsever的命令 解决 这句话就是执行manage.py文件,并在命令行发送一个runsever字 ...
- DNS服务反向解析实验
DNS域名解析服务是用于解析域名与ip地址对应关系的服务,功能上可以实现正向解析和反向解析 正向解析:根据主机名(域名)查找对应的IP地址. 反向解析:根据IP地址查找对应的主机名(域名). 下面我来 ...