专栏首页郭先生的博客three.js 郭先生制作太阳系

three.js 郭先生制作太阳系

今天郭先生收到评论,想要之前制作太阳系的案例,因为找不到了,于是在vue版本又制作一版太阳系,在线案例请点击three.js制作太阳系(加载时间比较长,请稍等一下)。话不多说先看效果图

相比于上一个版本,这个版本制作更加细致,动画更加流畅。那么下面分析一下主要代码

1. 先介绍一下变量

这里查了一些资料radiuses、distances、pub_rotation、self_rotation、pitchs分别为八大行星半径比、到太阳的距离比、公转比、自转比、自转轴倾角比。

radiuses: [2440, 6052, 6371, 3397, 71492, 60268, 25559, 24766],
distances: [5791, 10820, 14960, 22794, 77833, 142940, 287099, 450400],
pub_rotation: [88, 225, 365, 687, 4329, 10767, 30769, 60152],
self_rotation: [58.65, 243, 1, 1, 0.41, 0.42, 0.64, 0.65],
pitchs: [0, 177, 23, 25, 3, 27, 98, 28],
sunObj: {
    radius: 60000//实际695500
},
moonObj: {
    distance: 800, //3实际90
    radius: 1737,
    pitchs: 5,
    self_rotation: 27.25,
    pub_rotation: 27.25
},
asteriodObj: {
    radius: 2000,//2000
    pub_rotation: 408
},

2. 引入星球的纹理贴图

由于星球的贴图加载比较慢,所以要在贴图加载之后,再进行后续操作。

let loader = new THREE.TextureLoader();
taiyangT = loader.load('/static/images/texture/planets/sun.jpg');
shuixingT = loader.load('/static/images/texture/planets/shuixing.jpg');
jinxingT = loader.load('/static/images/texture/planets/jinxing.jpg');
diqiuT = loader.load('/static/images/texture/planets/diqiu.jpg');
huoxingT = loader.load('/static/images/texture/planets/huoxing.jpg');
muxingT = loader.load('/static/images/texture/planets/muxing.jpg');
tuxingT = loader.load('/static/images/texture/planets/tuxing.jpg');
tianwangxingT = loader.load('/static/images/texture/planets/tianwangxing.jpg');
haiwangxingT = loader.load('/static/images/texture/planets/haiwangxing.jpg');
yueqiuT = loader.load('/static/images/texture/planets/yueqiu.jpg');
asteriodsT = loader.load('/static/images/texture/planets/asteriod.jpg');
tuxinghuanT = loader.load('/static/images/texture/planets/tuxingring.png');

3. 绘制星球,并在场景中添加

这里我们写了一个公共的方法createMesh,这个方法传两个参数贴图和索引,可以根据这个索引找到自转周期、公转周期距离等等。

shuixing = this.createMesh(shuixingT, 0);
jinxing = this.createMesh(jinxingT, 1);
diqiu = this.createMesh(diqiuT, 2);
huoxing = this.createMesh(huoxingT, 3);
muxing = this.createMesh(muxingT, 4);
tuxing = this.createMesh(tuxingT, 5);
tianwangxing = this.createMesh(tianwangxingT, 6);
haiwangxing = this.createMesh(haiwangxingT, 7);
taiyang = this.createTaiyang();
yueqiu = this.createYueqiu();

scene.add(shuixing);
scene.add(jinxing);
scene.add(diqiu);
scene.add(huoxing);
scene.add(muxing);
scene.add(tuxing);
scene.add(tianwangxing);
scene.add(haiwangxing);
scene.add(taiyang);
scene.add(yueqiu);

创建网格方法如下

createMesh(texture, index) {
    let sphere = new THREE.SphereGeometry(this.radiuses[index] * this.radius_ratio, 60, 30);
    let material = new THREE.MeshBasicMaterial({map: texture});
    let mesh = new THREE.Mesh(sphere, material);
    mesh.position.x = this.distance_ratio * this.distances[index];
    return mesh;
}

创建太阳网格方法如下

createTaiyang() {
    let sphere = new THREE.SphereGeometry(this.sunObj.radius * this.radius_ratio,  60, 30);
    let material = new THREE.MeshBasicMaterial({map: taiyangT});
    let mesh = new THREE.Mesh(sphere, material);
    mesh.add(this.createSunShine())
    return mesh;
}

创建月球网格方法如下

createYueqiu() {
    let sphere = new THREE.SphereGeometry(this.moonObj.radius * this.radius_ratio, 30, 20);
    let material = new THREE.MeshBasicMaterial({map: yueqiuT});
    let mesh = new THREE.Mesh(sphere, material);
    mesh.position.x = this.distance_ratio * this.moonObj.distance;
    let moon = new THREE.Object3D();
    moon.position.copy(diqiu.position);
    moon.add(mesh);
    return moon;
}

4. 星体自转和公转

在render函数中调用自转和公转函数,控制自转的属性就是mesh.rotation。控制公转的属性就是mesh.position。这里使用欧拉角和THREE.Math方法

selfRotate() {
    shuixing.rotation.copy(new THREE.Euler(THREE.Math.degToRad(this.pitchs[0]), Math.sqrt(1 / this.self_rotation[0]) * this.self_ratio * this.timeS, 0));
    jinxing.rotation.copy(new THREE.Euler(THREE.Math.degToRad(this.pitchs[1]), Math.sqrt(1 / this.self_rotation[1]) * this.self_ratio * this.timeS, 0));
    diqiu.rotation.copy(new THREE.Euler(THREE.Math.degToRad(this.pitchs[2]), Math.sqrt(1 / this.self_rotation[2]) * this.self_ratio * this.timeS, 0));
    huoxing.rotation.copy(new THREE.Euler(THREE.Math.degToRad(this.pitchs[3]), Math.sqrt(1 / this.self_rotation[3]) * this.self_ratio * this.timeS, 0));
    muxing.rotation.copy(new THREE.Euler(THREE.Math.degToRad(this.pitchs[4]), Math.sqrt(1 / this.self_rotation[4]) * this.self_ratio * this.timeS, 0));
    tuxing.rotation.copy(new THREE.Euler(THREE.Math.degToRad(this.pitchs[5]), Math.sqrt(1 / this.self_rotation[5]) * this.self_ratio * this.timeS, 0));
    tianwangxing.rotation.copy(new THREE.Euler(0, Math.sqrt(1 / this.self_rotation[6]) * this.self_ratio * this.timeS, THREE.Math.degToRad(this.pitchs[6]), 'ZYX'));
    haiwangxing.rotation.copy(new THREE.Euler(THREE.Math.degToRad(this.pitchs[7]), Math.sqrt(1 / this.self_rotation[7]) * this.self_ratio * this.timeS, 0));
    // yueqiu.children[0].rotation.copy(new THREE.Euler(THREE.Math.degToRad(this.moonObj.pitchs), Math.sqrt(1 / this.moonObj.self_rotation) * this.self_ratio * this.timeS, 0));
    yueqiu.position.copy(diqiu.position);
    yueqiu.rotation.copy(new THREE.Euler(THREE.Math.degToRad(this.moonObj.pitchs), Math.sqrt(1 / this.moonObj.self_rotation) * this.self_ratio * this.timeS, 0));
    asteriods.rotation.copy(new THREE.Euler(0, this.timeS * this.pub_ratio / this.asteriodObj.pub_rotation / 2, 0));
},
pubRotate() {
    shuixing.position.set(Math.cos(this.timeP * this.pub_ratio / this.pub_rotation[0]) * this.distance_ratio * this.distances[0], 0, -Math.sin(this.timeP * this.pub_ratio / this.pub_rotation[0]) * this.distance_ratio * this.distances[0]);
    jinxing.position.set(Math.cos(this.timeP * this.pub_ratio / this.pub_rotation[1]) * this.distance_ratio * this.distances[1], 0, -Math.sin(this.timeP * this.pub_ratio / this.pub_rotation[1]) * this.distance_ratio * this.distances[1]);
    diqiu.position.set(Math.cos(this.timeP * this.pub_ratio / this.pub_rotation[2]) * this.distance_ratio * this.distances[2], 0, -Math.sin(this.timeP * this.pub_ratio / this.pub_rotation[2]) * this.distance_ratio * this.distances[2]);
    huoxing.position.set(Math.cos(this.timeP * this.pub_ratio / this.pub_rotation[3]) * this.distance_ratio * this.distances[3], 0, -Math.sin(this.timeP * this.pub_ratio / this.pub_rotation[3]) * this.distance_ratio * this.distances[3]);
    muxing.position.set(Math.cos(this.timeP * this.pub_ratio / this.pub_rotation[4]) * this.distance_ratio * this.distances[4], 0, -Math.sin(this.timeP * this.pub_ratio / this.pub_rotation[4]) * this.distance_ratio * this.distances[4]);
    tuxing.position.set(Math.cos(this.timeP * this.pub_ratio / this.pub_rotation[5]) * this.distance_ratio * this.distances[5], 0, -Math.sin(this.timeP * this.pub_ratio / this.pub_rotation[5]) * this.distance_ratio * this.distances[5]);
    tianwangxing.position.set(Math.cos(this.timeP * this.pub_ratio / this.pub_rotation[6]) * this.distance_ratio * this.distances[6], 0, -Math.sin(this.timeP * this.pub_ratio / this.pub_rotation[6]) * this.distance_ratio * this.distances[6]);
    haiwangxing.position.set(Math.cos(this.timeP * this.pub_ratio / this.pub_rotation[7]) * this.distance_ratio * this.distances[7], 0, -Math.sin(this.timeP * this.pub_ratio / this.pub_rotation[7]) * this.distance_ratio * this.distances[7]);
}

5. 使用动画,提升逼格

这里使用了tween控制相机的position和lookat属性,实现空间穿梭的感觉。

initTween() {
    let pos = {x: 0, y: 0, z: -96, lx: 0, ly: 0, lz: 0};
    tween1 = new TWEEN.Tween(pos).to({x: 57.91, y: 0, z: -5, lx: 57.91, ly: 0, lz: 0}, 20 * this.animation_time);
    tween1.easing(TWEEN.Easing.Linear.None);
    tween2 = new TWEEN.Tween(pos).to({x: 108.2, y: 0, z: -13, lx: 108.2, ly: 0, lz: 0}, 22 * this.animation_time);
    tween2.easing(TWEEN.Easing.Linear.None);
    tween3 = new TWEEN.Tween(pos).to({x: 149.6, y: 0, z: -14, lx: 149.6, ly: 0, lz: 0}, 24 * this.animation_time);
    tween3.easing(TWEEN.Easing.Linear.None);
    tween4 = new TWEEN.Tween(pos).to({x: 227.94, y: 0, z: -6, lx: 227.94, ly: 0, lz: 0}, 27 * this.animation_time);
    tween4.easing(TWEEN.Easing.Linear.None);
    tween5 = new TWEEN.Tween(pos).to({x: 436.5, y: 0, z: -6, lx: 436.5, ly: 0, lz: 0}, 30 * this.animation_time);
    tween5.easing(TWEEN.Easing.Linear.None);
    tween6 = new TWEEN.Tween(pos).to({x: 778.33, y: 0, z: -112, lx: 778.33, ly: 0, lz: 0}, 34 * this.animation_time);
    tween6.easing(TWEEN.Easing.Linear.None);
    tween7 = new TWEEN.Tween(pos).to({x: 1429.4, y: 0, z: -155, lx: 1429.4, ly: 0, lz: 0}, 35 * this.animation_time);
    tween7.easing(TWEEN.Easing.Linear.None);
    tween8 = new TWEEN.Tween(pos).to({x: 2871, y: 0, z: -46, lx: 2871, ly: 0, lz: 0}, 36 * this.animation_time);
    tween8.easing(TWEEN.Easing.Linear.None);
    tween9 = new TWEEN.Tween(pos).to({x: 4504, y: 0, z: -46, lx: 4504, ly: 0, lz: 0}, 37 * this.animation_time);
    tween9.easing(TWEEN.Easing.Linear.None);
    tween10 = new TWEEN.Tween(pos).to({x: -600, y: 452, z: 0, lx: 778.33, ly: 0, lz: 0}, 38 * this.animation_time);
    tween10.easing(TWEEN.Easing.Linear.None);

    tween1.chain(tween2).onUpdate(onUpdate).delay(50 * this.animation_time).onStart(() => this.show1 = false).onComplete(() => this.show2 = true);
    tween2.chain(tween3).onUpdate(onUpdate).delay(50 * this.animation_time).onStart(() => this.show2 = false).onComplete(() => this.show3 = true);
    tween3.chain(tween4).onUpdate(onUpdate).delay(50 * this.animation_time).onStart(() => this.show3 = false).onComplete(() => this.show4 = true);
    tween4.chain(tween5).onUpdate(onUpdate).delay(50 * this.animation_time).onStart(() => this.show4 = false).onComplete(() => this.show5 = true);
    tween5.chain(tween6).onUpdate(onUpdate).delay(50 * this.animation_time).onStart(() => this.show5 = false).onComplete(() => this.show6 = true);
    tween6.chain(tween7).onUpdate(onUpdate).delay(50 * this.animation_time).onStart(() => this.show6 = false).onComplete(() => this.show7 = true);
    tween7.chain(tween8).onUpdate(onUpdate).delay(50 * this.animation_time).onStart(() => this.show7 = false).onComplete(() => this.show8 = true);
    tween8.chain(tween9).onUpdate(onUpdate).delay(50 * this.animation_time).onStart(() => this.show8 = false).onComplete(() => this.show9 = true);
    tween9.chain(tween10).onUpdate(onUpdate).delay(50 * this.animation_time).onStart(() => this.show9 = false).onComplete(() => this.show10 = true);
    tween10.onUpdate(onUpdate).delay(50 * this.animation_time).onStart(() => this.show10 = false);
    
    tween1.start();
},

主要代码差不多就是这样,像这样制作太阳系并不难,只要你敢想。

转载请注明地址:郭先生的博客

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【带着canvas去流浪(15)】threejs fundamentals翻译系列1-scene graph

    本文是three.js系列博文的一篇,第一篇文章是【three.js基础知识】,如果你还没有阅读过,可以从这一篇开始,页面顶部可以切换为中文或英文。

    大史不说话
  • three.js 曲线

    上几篇说了three.js的曲线,这篇来郭先生来说说three.js曲线,在线案例点击three.js曲线

    郭先生的博客
  • three.js 制作一个三维的推箱子游戏

    今天郭先生发现大家更喜欢看我发的three.js小作品,今天我就发一个3d版本推箱子的游戏,其实webGL有很多框架,three.js并不合适做游戏引擎,但是可...

    郭先生的博客
  • three.js 绘制3d地图

    这篇郭先生就来说说使用three.js几何体制作3D地图。在线案例点击3D中国地图

    郭先生的博客
  • three.js 自制骨骼动画(二)

    上一篇说了一下自制骨骼动画,这一篇郭先生使用帧动画让骨骼动画动起来。帧动画是一套比较完善的动画剪辑方法,详细我的api我们就不多说了,网上有很多例子,自行查找学...

    郭先生的博客
  • three.js 图形用户界面工具GUI

    今天郭先生来说一说three.js的一个图形用户界面工具gui,如下图,在线案例点击three.js-GUI。

    郭先生的博客
  • 教你如何用Three.js创造一个三维太阳系

    笔者认为Three.js是一个伟大的框架,为什么这样说,因为它可以让我们轻易创造三维世界,甚至好像笔者写这遍教程,可以创造一个太阳系,在这个三维世界里你就是创世...

    lizhenwen
  • three.js 制作魔方

    因为之前的几节讲了一些数学方法,例如Vector3、Matrix4、Euler还有Quaternion的知识。所以这篇郭先生就来说说用three.js怎么制作一...

    郭先生的博客
  • Three.js camera初探——转场动画实现

    three.js是用javascript写的基于webGL的第三方3D库,通过它可以在网页中进行3D建模,结合上TweenMax.js动画库,在网页中实现3D动...

    郭诗雅
  • three.js 着色器材质之初识着色器

    说起three.js,着色器材质总是绕不过的话题,今天郭先生就说一说什么是着色器材质。着色器材质是很需要灵感和数学知识的,可以用简短的代码和绘制出十分丰富的图像...

    郭先生的博客
  • three.js 着色器材质内置变量

    他们或者单个出现在着色器中,或者组团出现在着色器中,是着色器的灵魂。下面来分别说一说他们的意义和用法。

    郭先生的博客
  • 明星大咖集聚海尔思想宴,完美诠释智爱生活家

    2014年12月26日,海尔集团迎来了自己的30岁生日。30年间,一个青岛一隅的家电小厂,已经跃居全球首位,成为名副其实的家电业大咖。在"你的生活智慧,我的智慧...

    罗超频道
  • three.js 着色器材质之变量(二)

    上一篇郭先生在例子中用到了着色器变量中的uniform和varying。这节继续结合例子将一下attribute变量,在使用过程中也发现由于three.js的版...

    郭先生的博客
  • three.js 数学方法之Matrix3

    今天郭先生来说一说three.js的三维矩阵,这块知识需要结合线性代数的一些知识,毕业时间有点长,线性代数的知识大部分都还给了老师。于是一起简单的复习了一下。

    郭先生的博客
  • three.js之初探骨骼动画

    今后的几篇郭先生主要说说three.js骨骼动画。three.js骨骼动画十分有意思,但是对于初学者来说,学起来要稍微困难一些,官方文档比较少,网上除了用圆柱体...

    郭先生的博客
  • three.js 着色器材质之纹理

    今天郭先生说一说如何在three.js着色器中添加纹理,先看看今天要完成的效果,在线案例请点击着色器纹理。

    郭先生的博客
  • three.js 着色器材质之变量(一)

    上一篇说顶点着色器和片元着色器的皮毛,这篇郭先生说一说着色器变量,通过变量可以设置材质。先看看今天要做的如下图。在线案例请点击红绿灯。

    郭先生的博客
  • 如何实现一个3d场景中的阴影效果(threejs)?

    跟OpenGL不同,在threejs中实现一个阴影效果很简单,只需要简单的几个设置。

    程序你好
  • 中国发现银河系最大恒星级黑洞,质量是太阳的68倍

    中国科学家在银河系中发现了质量高于太阳68倍的巨大恒星级黑洞,这一发现可谓颠覆了以往人类对恒星演化过程的认知。

    镁客网

扫码关注云+社区

领取腾讯云代金券