three.js 學習之自轉(zhuǎn)的地球

首先需要知道什么是 three.js。 簡單的說,three.js 是一個非常優(yōu)秀的 WebGL 開源框架, three(3d) + js(javaScript)。其開源項目的地址:

github: https://github.com/mrdoob/three.js

而 WebGL 是在瀏覽器中實現(xiàn)三維效果的一套規(guī)范。

在 three.js 中有幾大重要的概念需要先了解一下:

  • 場景(scene)
  • 相機(camera)
  • 渲染器(renderer)

關(guān)鍵:有了這三樣東西,我們才能夠使用相機將場景渲染到網(wǎng)頁上去`

1、scene

在 WebGL 世界里,場景是一個非常重要的概念,它是存放所有物體的容器。在 three.js 里面新建一個場景很簡單,new THREE.Scene 實例就好了。代碼如下:

var scene = new THREE.Scene();  // 場景只有一種

2、camera

  • 相機(camera)
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000) ;

PerspectiveCamera( fov, aspect, near, far ) 參數(shù)解析。

  • fov(Number): 仰角的角度
  • aspect(Number): 截平面長寬比,多為畫布的長寬比。
  • near(Number): 近面的距離
  • far(Number): 遠面的距離

圖解 THREE.PerspectiveCamera 參數(shù),如下:


image

3、renderer

渲染器決定了渲染的結(jié)果應(yīng)該畫在頁面的什么元素上面,并且以怎樣的方式來繪制。

 var renderer = new THREE.WebGLRenderer();
 renderer.setSize(window.innerWidth, window.innerHeight);
 document.body.appendChild(renderer.domElement);

好了,幾大概念簡單的說了,還不是很明白也不打緊,先看下最終的效果:

image

開始畫地球

1、導入 three.min.js 文件,可以下載到本地,也可以采用 cdn, 我這里采用的是下載下來的方式:

 <script src="assets/plus/threejs/three.min.js"></script>

或者

<script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>

2、準備渲染器 renderer 的 domElement 元素

<div id="canvas-frame"></div>

<style></style> 中加入 css:

 div#canvas-frame {
     border: none;
     cursor: pointer;
     width: 100%;
     height: 100vh;
     background-color: #EEEEEE;
}

3、實例化一個 scence 對象, 用來存放我們的地球?qū)嶓w。

// 場景
var scene;
function initScene() {
   scene = new THREE.Scene();
}

4、準備搭建 camera 的位置,和調(diào)節(jié)角度,在 three.js 里面采用給的是右手坐標系

// 相機
var camera;
function initCamera() {
   camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
   camera.position.x = -500;
   camera.position.y = 500;
   camera.position.z = -500;
}

這里采用的是透視相機。 視角越大,看到的場景越大,那么中間的物體相對于整個場景來說,就越小了。

5、準備渲染器 renderer

// 渲染器
var renderer;
function initThree() {
   width = document.getElementById('canvas-frame').clientWidth;
   height = document.getElementById('canvas-frame').clientHeight;
   // 實例化 THREE.WebGLRenderer 對象。
   renderer = new THREE.WebGLRenderer({
                        antialias: true,
                        alpha: true,
                        canvas: renderer
                      });
   // 設(shè)置 renderer 的大小
   renderer.setSize(width, height);
   // 掛載到準備的 domElement 上
   document.getElementById('canvas-frame').appendChild(renderer.domElement); 
   // Sets the clear color and opacity.
   renderer.setClearColor(0x000000, 1.0);
}

這里對 THREE.WebGLRenderer 實例的參數(shù)進行講解。

  • canvas - 渲染器繪制輸出的那個 canvas, 這對應(yīng)于下面的 domElement 屬性。如果沒有在設(shè)置,則會創(chuàng)建一個新的畫布元素。
  • antialias - 抗鋸齒化
  • alpha - alpha 緩沖區(qū)

6、畫地球啦,這里的地球其實就是在一個球體上貼上帶有地球紋路的貼紙。

// 地球
var earthMesh;
function initEarth() {
    // 實例化一個半徑為 200 的球體
   var earthGeo = new THREE.SphereGeometry(200, 100, 100);
   var earthMater = new THREE.MeshPhongMaterial({
            map: new THREE.TextureLoader().load('./assets/earth.jpg')
        });
   earthMesh = new THREE.Mesh(earthGeo, earthMater);
   scene.add(earthMesh);
}

7、給地球加上云層;

// 云
var cloudsMesh;
function initClouds() {

    // 實例化一個球體,半徑要比地球的大一點,從而實現(xiàn)云飄咋地球上的感覺
    var cloudsGeo = new THREE.SphereGeometry(201, 100, 100);
    
    // transparent 與 opacity 搭配使用,設(shè)置材質(zhì)的透明度,當 transparent 設(shè)為 true 時, 會對材質(zhì)特殊處理,對性能會有些損耗。
    var cloudsMater = new THREE.MeshPhongMaterial({
        alphaMap: new THREE.TextureLoader().load('./assets/clouds.jpg'),
        transparent: true,
        opacity: 0.2
    });
    
    cloudsMesh = new THREE.Mesh(cloudsGeo, cloudsMater);
    scene.add(cloudsMesh);
}

到這里地球就畫完了,但是,就像現(xiàn)實的世界一樣,如果你不給它打點光,世界就是漆黑一片的,所以接下來給我們的 scene 加點光吧。

8、給世界來點光,世界還你一片彩。

// 光源
var light;
function initLight() {
    // A light source positioned directly above the scene, with color fading from the sky color to the ground color. 
    // 位于場景正上方的光源,顏色從天空顏色漸變?yōu)榈孛骖伾?    //  var light = new THREE.HemisphereLight(0xffffbb, 0x080820, 1);
    // scene.add(light);
    
    // 環(huán)境光
    light = new THREE.AmbientLight(0xFFFFFF);
    light.position.set(100, 100, 200);
    scene.add(light);
    
    // 平行光
    // 位置不同,方向光作用于物體的面也不同,看到的物體各個面的顏色也不一樣
    // light = new THREE.DirectionalLight(0xffffbb, 1);
    // light.position.set(-1, 1, 1);
    // scene.add(light);
}

這里采用的是環(huán)境光,其它注釋了的兩種光的效果也不錯哦~
直到這里,地球就畫出來了,但是我們的題目是畫一顆自轉(zhuǎn)的地球,那我們?nèi)绾巫屗约恨D(zhuǎn)起來呢?我們繼續(xù)往下看。

9、引入一個控制器,這里如果你足夠厲害自己寫也可以哦,我采用的開源的。

 <script src="assets/plus/threejs/js/controls/OrbitControls.js"></script>
 // 載入控制器
 var controls = new THREE.OrbitControls(camera, renderer.domElement);

10、定義地球和云層自轉(zhuǎn)的動畫,速度不一樣會更像哦。這里說說為什么循環(huán)動畫使用的是 requestAnimationFrame, 而不是更熟知的 setInterval?setInterval 是到點就往任務(wù)隊列里插,是 JS 引擎的定時器方法;requestAnimationFrame 是跟著瀏覽器的繪制走,瀏覽器每次重繪的時候調(diào)用,是 DOM 引擎提供的方法。

function animate() {
  controls.update();
  // 地球自轉(zhuǎn)
  earthMesh.rotation.y -= 0.002;
  // 漂浮的云層
  cloudsMesh.rotation.y -= 0.005;
  cloudsMesh.rotation.z += 0.005;
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

自轉(zhuǎn)的地球到這里就大功告成啦~

完整的代碼見:https://github.com/jiangyuzhen/three-earth

Tips: 有的小伙伴克隆上面的代碼后, 用雙擊 index.html 的方式看不到效果,可以自己搭一個靜態(tài)服務(wù)或者試試 anywhere (隨啟隨用的靜態(tài)文件服務(wù)器):

步驟如下:

// 全局安裝
npm i anywhere -g 

// 文件根目錄下執(zhí)行
anywhere

相關(guān)資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 老于一向不喜歡參加同學聚會一類的活動??煳迨畾q的人了,弄那個干什么?他常跟家里人說,口氣里帶出點不屑。好像同學一詞...
    rong67閱讀 230評論 0 0
  • 這兩天一直在追CCTV9播放的一個記錄片叫《地球上的部落-尼羅河子孫》,講的是現(xiàn)在生活在非洲的幾個從尼羅河遷來的部...
    奔跑的馬齒莧閱讀 574評論 0 0
  • 樸素衣裳黑與白, 清音悅耳上高臺。 梅花遇爾枝頭唱, 定是家中喜訊來。
    歧黃學子閱讀 451評論 1 1
  • 我越來越相信,與文字的相遇也像與人的相遇一樣,對的時間遇到對的人,你才會有那種由心而發(fā)的感謝與欣喜。 2017年1...
    古樹螞蟻閱讀 1,094評論 43 51
  • 可以使用 //MARK: 或者 //MARK:說明 來代替 //MARK: 生成分割線點此看原版鏈接
    cuagain閱讀 314評論 0 0

友情鏈接更多精彩內(nèi)容