Three.js實現太陽系八大行星的自轉公轉

一. Three.js框架簡介

Three.js是用javascript編寫的WebGL第三方庫,運用three.js框架寫3D程序,就如同在現實生活中觀察一個3D場景同樣,讓人置身其中。介紹three.js必須提到它的三大組件,Scene,Camera,Render。它們是整個框架的基礎,有了這三個組件才能將物體渲染到網頁上,實現整個場景的搭建。javascript

場景(scene)

顧名思義,就是用來放置全部的元素。css

var scene = new THREE.Scene();  //創建場景
複製代碼

相機(camera)

相機,咱們要在哪一個位置,如何去看這些元素。 相機分爲多種,不展開介紹,這裏咱們使用的是 透視相機java

var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 10000); //設置相機爲 角度60度,寬高比,最近端Z軸爲1,最遠端Z軸爲10000
複製代碼

咱們能夠經過一張來自three.js文檔中的圖片來了解這些屬性web

渲染器(render)

當把場景中的全部內容準備好後,就能夠對場景進行渲染,表示咱們怎樣來繪製這些元素。 渲染器也分爲多種,這裏使用的是WebGLRenderer;canvas

var renderer = new THREE.WebGLRenderer();
複製代碼

具體步驟:創建元素->定義相機->搭建場景->將元素和相機放入場景中->渲染場景 具體代碼咱們會在後面介紹,而後讓咱們先瞅一眼效果圖。bash

二. 基本初始化

這裏直接在CDN上引入three.js <script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>框架

注:由於某些行星的大小,轉速,距離差距過大,因此進行了一些不平衡調整。 下面將一一分析這些元素是如何放入的。函數

1.canvas

咱們沒有把場景直接掛載到body中,而是在body中放置了一個canvas畫布,在其上顯示。webgl

2.背景

咱們沒有作3D的旋轉背景,而是直接放了一張背景圖做爲小太陽系的背景。這張背景圖是直接在canvas中放置的。ui

<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;
        }
複製代碼

但若是隻是這樣簡單的操做是沒有用的,由於在添加渲染器後,會默認添加一個背景顏色爲黑色。因此要在渲染器中設置它的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放入咱們渲染器中的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顆行星參數由於太長了在這裏就不給出了,但參數的設置原理都是同樣的
            }
複製代碼

簡要解釋一下:

var loader = new THREE.TextureLoader();是定義了一個材質紋理加載器

var geometry = new THREE.SphereGeometry(250, 20, 20);創建一個球體模型,球體半徑爲250,水平分割面的數量20,垂直分割面的數量20。

var mesh = new THREE.Mesh(geometry, material);網孔對象

具體做用就是建立一個球體元素,先構建框架,在用行星的平面圖將它包裹起來,就造成了一顆行星,再把這顆行星添加到組裏,以後再把組添加到場景裏。這裏就構建單個元素的過程。

那麼爲何太陽直接添加到組裏,而水星要用兩個組層級添加,且給它的位置設偏移呢。咱們來到第三節。

三. 自轉同時公轉

旋轉方式:咱們要實現旋轉功能有三種方式 1.旋轉照相機 2.旋轉整個場景(Scene) 3.旋轉單個元素。

由於咱們這裏每一個行星的自轉速度,公轉速度都不同。因此設置總體旋轉並不可行,因此要給每一個元素設置不一樣的旋轉屬性。

旋起色制:這裏介紹物體的rotation屬性,相對於自身旋轉。

例如:scene.rotation.y += 0.04; //整個場景繞自身的Y軸逆時針旋轉

進入正題

Scene中的全部元素使用rotation.y屬性,默認旋轉軸都爲這根Y軸,由於它們初始化Y軸就是這根軸。 因此讓太陽旋轉直接讓它的組旋轉就好了 group.rotation.y += 0.04;

而其它行星須要讓它們圍繞着太陽轉,就要先給它們自身設置一個位置偏移。例如水星:group1.position.x -= 300; 而此時設置group1.rotation.y屬性,它就會實現自轉。由於它的Y軸位置已經改變了。

那麼此時要想再實現公轉,在這個對象中是找不到默認Y軸這根線的。因此咱們給group1再設置了一個「父元素」groupParent1。 groupParent1.add(group1);

當咱們移動了group1時,groupParent1的位置是沒有變的,天然它的Y軸也不會變,又由於groupParent1包含了group1,因此旋轉groupParent1時,group1也會繞着初始的默認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.

相關文章
相關標籤/搜索