zoukankan      html  css  js  c++  java
  • three.js 郭先生制作太阳系

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

    图片有点多,先放三张,相比于上一个版本,这个版本制作更加细致,动画更加流畅。那么下面分析一下主要代码。

    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, //实际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;
    }

    创建太阳网格方法如下

    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();
    },

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

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

  • 相关阅读:
    万科郁亮:不赚最后一枚铜板,不盯竞争对手
    京东到底是家零售企业 还是家互联网公司?
    Google Shopping对卖家开放 或抗衡亚马逊
    网易大裁员,善变的丁磊开始焦虑了
    菜鸟物联网战略引领行业数字化升级
    入淘创业的新赛道:淘宝自运营覆盖50万商家
    腾讯的人工智能大战已然打响!
    冷链物流市场三个重要的发展趋势
    有人的地方就有江湖,来看看这三个男生和闲鱼的故事
    CSS布局-垂直居中问题
  • 原文地址:https://www.cnblogs.com/vadim-web/p/13389368.html
Copyright © 2011-2022 走看看