一. Three.js框架簡介
Three.js是用javascript編寫的WebGL第三方庫,運用three.js框架寫3D程式,就如同在現實生活中觀察一個3D場景一樣,讓人置身其中。介紹three.js必須提到它的三大元件,Scene,Camera,Render。它們是整個框架的基礎,有了這三個元件才能將物體渲染到網頁上,實現整個場景的搭建。
場景(scene)
顧名思義,就是用來放置所有的元素。
var scene = new THREE.Scene(); //建立場景
複製程式碼
相機(camera)
相機,我們要在哪個位置,如何去看這些元素。 相機分為多種,不展開介紹,這裡我們使用的是 透視相機。
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 10000); //設定相機為 角度60度,寬高比,最近端Z軸為1,最遠端Z軸為10000
複製程式碼
我們可以通過一張來自three.js文件中的圖片來了解這些屬性
渲染器(render)
當把場景中的所有內容準備好後,就可以對場景進行渲染,表示我們怎樣來繪製這些元素。 渲染器也分為多種,這裡使用的是WebGLRenderer;
var renderer = new THREE.WebGLRenderer();
複製程式碼
具體步驟:建立元素->定義相機->搭建場景->將元素和相機放入場景中->渲染場景 具體程式碼我們會在後面介紹,然後讓我們先瞅一眼效果圖。
二. 基本初始化
這裡直接在CDN上引入three.js
<script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>
注:因為某些行星的大小,轉速,距離差距過大,所以進行了一些不平衡調整。 下面將一一分析這些元素是如何放入的。
1.canvas
我們沒有把場景直接掛載到body中,而是在body中放置了一個canvas畫布,在其上顯示。
2.背景
我們沒有做3D的旋轉背景,而是直接放了一張背景圖作為小太陽系的背景。這張背景圖是直接在canvas中放置的。
<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軸位置已經改變了。
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.