首先需要知道什么是 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ù),如下:
3、renderer
渲染器決定了渲染的結(jié)果應(yīng)該畫在頁面的什么元素上面,并且以怎樣的方式來繪制。
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
好了,幾大概念簡單的說了,還不是很明白也不打緊,先看下最終的效果:

開始畫地球
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