ThreeJS簡介

近年來web得到了快速的發(fā)展。隨著HTML5的普及,網(wǎng)頁的表現(xiàn)能力越來越強大。網(wǎng)頁上已經(jīng)可以做出很多復(fù)雜的動畫,精美的效果。 但是,人總是貪的。那么,在此之上還能做什么呢?其中一種就是通過WebGL在網(wǎng)頁中繪制高性能的3D圖形。


OpenGL,WebGL到Three.js

OpenGL它是最常用的跨平臺圖形庫。
WebGL是基于OpenGL設(shè)計的面向web的圖形標(biāo)準(zhǔn),提供了一系列JavaScript API,通過這些API進(jìn)行圖形渲染將得以利用圖形硬件從而獲得較高性能。
Three.js是通過對WebGL接口的封裝與簡化而形成的一個易用的圖形庫。
簡單點的說法threejs=three + js,three表示3D的意思,js表示javascript的意思。那么合起來,three.js就是使用javascript 來寫3D程序的意思。而javascript的計算能力因為google的V8引 擎得到了迅猛的增強,做3D程序,做服務(wù)器都沒有問題。
WebGL門檻相對較高,需要相對較多的數(shù)學(xué)知識(線性代數(shù)、解析幾何)。因此,想要短時間上手WebGL還是挺有難度的。 Three.jsWebGL提供的接口進(jìn)行了非常好的封裝,簡化了很多細(xì)節(jié),大大降低了學(xué)習(xí)成本。并且,幾乎沒有損失WebGL的靈活性。
因此,從Three.js入手是值得推薦的,這可以讓你在較短的學(xué)習(xí)后就能面對大部分需求場景。

Three.js的學(xué)習(xí)問題

Three.js的入門是相對簡單的,但是當(dāng)我們真的去學(xué)的時候,會發(fā)現(xiàn)一個很尷尬的問題:相關(guān)的學(xué)習(xí)資料很少。
通常這種流行的庫都有很完善的文檔,很多時候跟著官方的文檔或官方的入門教程學(xué)習(xí)就是最好的路線。但Three不是的,它的文檔對初學(xué)者來說太過簡明扼要。
不過官方提供了非常豐富的examples,幾乎所有你需要的用法都在某個example中有所體現(xiàn)。但這些example不太適合用來入門,倒是適合入門之后的進(jìn)一步學(xué)習(xí)。
這里推薦一些相對較好的教程:

  • Three.js入門指南 :這是一份很好的Three.js 輕量級入門教程,作者文筆很好,基礎(chǔ)知識講解得簡明易懂。
  • Three.js開發(fā)指南(第一版中文版)
  • Learning Three.js- Second Edition
  • Learning Three.js:The JavaScript 3D Library for WebGL是現(xiàn)在不多的也是最好的Three.js入門書,比較全面地講解了Three.js的各種功能。 如果有能力的話,建議閱讀英文版第二版,出版于2015年,與現(xiàn)在的Three.js區(qū)別很小。 中文版翻譯自出版于2012年的原書第一版,大部分概念是適用的,但很多細(xì)節(jié)已經(jīng)有所改變。
  • Three.js入門教程 :這是對國外一份教程的翻譯,一共六篇文章。講解不多,更多的是展示各個基本功能怎么用。更適合有一些圖形基礎(chǔ)的同學(xué)。

當(dāng)然,實際的學(xué)習(xí)過程中這些資料肯定是不太夠的,遇到問題還是要自己去查資料。不過這里要提醒一下,Three.js的更新是相當(dāng)頻繁的,現(xiàn)在是r80版本,自2010年4月發(fā)布r1以來,這已經(jīng)是第72個版本了(中間有的版本號跳過了)。因此,在網(wǎng)上找到的資料有些可能是不適合當(dāng)前版本的,需要注意甄別(前面推薦的資料也都或多或少存在這樣的問題)。

剖析源目錄結(jié)構(gòu)

  1. 先去下載代碼,它的地址是: https://github.com/mrdoob/three.js。 如圖所示:
  2. 用解壓軟件解開剛才的源碼包,各個目錄如下所示:

    Build目錄:包含兩個文件,three.js 和three.min.js 。這是three.js最終被引用的文件。一個已經(jīng)壓縮,一個沒有壓縮的js文件。
    Docs目錄:這里是three.js的幫助文檔,里面是各個函數(shù)的api,可惜并沒有詳細(xì)的解釋。試圖用這些文檔來學(xué)會three.js是不可能的。
    Editor目錄:一個類似3D-max的簡單編輯程序,它能創(chuàng)建一些三維物體。
    Examples目錄:一些很有趣的例子demo,可惜沒有文檔介紹。對圖像學(xué)理解不深入的同學(xué),學(xué)習(xí)成本非常高。
    Src目錄:源代碼目錄,里面是所有源代碼。
    Test目錄:一些測試代碼,基本沒用。
    Utils目錄:存放一些腳本,python文件的工具目錄。例如將3D-Max格式的模型轉(zhuǎn)換為three.js特有的json模型。
    .gitignore文件:git工具的過濾規(guī)則文件,沒有用。
    CONTRIBUTING.md文件:一個怎么報bug,怎么獲得幫助的說明文檔。
    LICENSE文件:版權(quán)信息。
    README.md文件:介紹three.js的一個文件,里面還包含了各個版本的更新內(nèi)容列表。

Three.js中的一些概念

要在屏幕上展示3D圖形,思路大體上都是這樣的:
1、構(gòu)建一個三維空間
Three中稱之為場景(Scene)
2、選擇一個觀察點,并確定觀察方向/角度等
Three中稱之為相機(Camera)
3、在場景中添加供觀察的物體
Three中的物體有很多種,包括Mesh,Line,Points等,它們都繼承自O(shè)bject3D類
4、將觀察到的場景渲染到屏幕上的指定區(qū)域
Three中使用Renderer完成這一工作

Scene

場景是所有物體的容器,也對應(yīng)著我們創(chuàng)建的三維世界。

Camera

坐標(biāo)系

Camera是三維世界中的觀察者,為了觀察這個世界,首先我們要描述空間中的位置。 Three中使用采用常見的右手坐標(biāo)系定位。


三維投影

Three中的相機有兩種,分別是正投影相機THREE.OrthographicCamera和透視投影相機THREE.PerspectiveCamera。


正交投影與透視投影的區(qū)別如上圖所示,左圖是正交投影,物體發(fā)出的光平行地投射到屏幕上,遠(yuǎn)近的方塊都是一樣大的;右圖是透視投影,近大遠(yuǎn)小,符合我們平時看東西的感覺。
1)正交投影相機

:圖中的”視點”對應(yīng)著Three中的Camera。

這里補充一個視景體的概念:視景體是一個幾何體,只有視景體內(nèi)的物體才會被我們看到,視景體之外的物體將被裁剪掉。這是為了去除不必要的運算。

正交投影相機的視景體是一個長方體,OrthographicCamera的構(gòu)造函數(shù)是這樣的:

OrthographicCamera( left, right, top, bottom, near, far ) 

Camera本身可以看作是一個點,left則表示左平面在左右方向上與Camera的距離。另外幾個參數(shù)同理。于是六個參數(shù)分別定義了視景體六個面的位置。

可以近似地認(rèn)為,視景體里的物體平行投影到近平面上,然后近平面上的圖像被渲染到屏幕上。
2)透視投影相機


透視投影相機的視景體是個四棱臺,它的構(gòu)造函數(shù)是這樣的:

PerspectiveCamera( fov, aspect, near, far ) 

fov對應(yīng)著圖中的視角,是上下兩面的夾角。aspect是近平面的寬高比。在加上近平面距離near,遠(yuǎn)平面距離far,就可以唯一確定這個視景體了。
透視投影相機很符合我們通常的看東西的感覺,因此大多數(shù)情況下我們都是用透視投影相機展示3D效果。

Objects

有了相機,總要看點什么吧?在場景中添加一些物體吧。
Three中供顯示的物體有很多,它們都繼承自O(shè)bject3D類,這里我們主要看一下Mesh和Points兩種。
1)Mesh
我們都知道,計算機的世界里,一條弧線是由有限個點構(gòu)成的有限條線段連接得到的。線段很多時,看起來就是一條平滑的弧線了。
計算機中的三維模型也是類似的,普遍的做法是用三角形組成的網(wǎng)格來描述,我們把這種模型稱之為Mesh模型。


這是那只著名的斯坦福兔子。它在3D圖形中的地位與數(shù)字圖像處理領(lǐng)域中著名的lena是類似的。
看這只兔子,隨著三角形數(shù)量的增加,它的表面越來越平滑/準(zhǔn)確。
在Three中,Mesh的構(gòu)造函數(shù)是這樣的:

Mesh( geometry, material ) 

geometry是它的形狀,material是它的材質(zhì)。
不止是Mesh,創(chuàng)建很多物體都要用到這兩個屬性。下面我們來看看這兩個重要的屬性。
2)Geometry
Geometry,形狀,相當(dāng)直觀。Geometry通過存儲模型用到的點集和點間關(guān)系(哪些點構(gòu)成一個三角形)來達(dá)到描述物體形狀的目的。
Three提供了立方體(其實是長方體)、平面(其實是長方形)、球體、圓形、圓柱、圓臺等許多基本形狀;
你也可以通過自己定義每個點的位置來構(gòu)造形狀;
對于比較復(fù)雜的形狀,我們還可以通過外部的模型文件導(dǎo)入。
3)Material
Material,材質(zhì),這就沒有形狀那么直觀了。
材質(zhì)其實是物體表面除了形狀以為所有可視屬性的集合,例如色彩、紋理、光滑度、透明度、反射率、折射率、發(fā)光度。
這里講一下材質(zhì)(Material)、貼圖(Map)和紋理(Texture)的關(guān)系。
材質(zhì)上面已經(jīng)提到了,它包括了貼圖以及其它。
貼圖其實是‘貼’和‘圖’,它包括了圖片和圖片應(yīng)當(dāng)貼到什么位置。
紋理嘛,其實就是‘圖’了。
Three提供了多種材質(zhì)可供選擇,能夠自由地選擇漫反射/鏡面反射等材質(zhì)。
4)Points
講完了Mesh,我們來看看另一種Object——Points。
Points其實就是一堆點的集合,它在之前很長時間都被稱為ParticleSystem(粒子系統(tǒng)),r68版本時更名為PointCloud,r72版本時才更名為Points。更名主要是因為,Mr.doob認(rèn)為,粒子系統(tǒng)應(yīng)當(dāng)是包括粒子和相關(guān)的物理特性的處理的一套完整體系,而Three中的Points簡單得多。因此最終這個類被命名為Points。
5)Light
神說:要有光!
光影效果是讓畫面豐富的重要因素。
Three提供了包括環(huán)境光AmbientLight、點光源PointLight、 聚光燈SpotLight、方向光DirectionalLight、半球光HemisphereLight等多種光源。
只要在場景中添加需要的光源就好了。
6)Renderer
在場景中建立了各種物體,也有了光,還有觀察物體的相機,是時候把看到的東西渲染到屏幕上了。這就是Render做的事情了。
Renderer綁定一個canvas對象,并可以設(shè)置大小,默認(rèn)背景顏色等屬性。
調(diào)用Renderer的render函數(shù),傳入scene和camera,就可以把圖像渲染到canvas中了。

讓畫面動起來

現(xiàn)在,一個靜態(tài)的畫面已經(jīng)可以得到了,怎么才能讓它動起來?
很簡單的想法,改變場景中object的位置啊角度啊各種屬性,然后重新調(diào)用render函數(shù)渲染就好了。
那么重新渲染的時機怎么確定?
HTML5為我們提供了requestAnimFrame,它會自動在每次頁面重繪前調(diào)用傳入的函數(shù)。
如果我們一開始這樣渲染:

function render()
{
    renderer.render(scene, camera);
}

只需要改成這樣:

function render()
{
    requestAnimationFrame(render);
    object.position.x += 1;
    renderer.render(scene, camera);
}

object就可以動起來了!

舉個例子

下面我們用一個簡單的例子來梳理一下這個過程。
首先寫一個有Canvas元素的頁面吧。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>立方體</title>
    <script src="http://sqimg.qq.com/qq_product_operations/mma/javanli_test/lib/three.min.js"></script>
    <style type="text/css">
        html, body {
            margin: 0;
            padding: 0;
        }
        #three_canvas {
            position: absolute;
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <canvas id="three_canvas"></canvas>
</body>
</html>

下面來做Javascript的部分
首先初始化Renderer

function initRenderer() {
    width = document.getElementById('three_canvas').clientWidth;
    height = document.getElementById('three_canvas').clientHeight;
    renderer = new THREE.WebGLRenderer({
        //將Canvas綁定到renderer
        canvas: document.getElementById('three_canvas')
    });
    renderer.setSize(width, height);//將渲染的大小設(shè)為與Canvas相同
    renderer.setClearColor(0xFFFFFF, 1.0);//設(shè)置默認(rèn)顏色與透明度
}

初始化場景:

function initScene() {
    scene = new THREE.Scene();
}

初始化相機:

function initCamera() {
    //簡單的正交投影相機,正對著視口的中心,視口大小與Canvas大小相同。
    camera = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, 1, 1000);
    //設(shè)置相機的位置
    camera.position.x = 0;
    camera.position.y = 0;
    camera.position.z = 200;
    //設(shè)置相機的上方向
    camera.up.x = 0;
    camera.up.y = 1;
    camera.up.z = 0;
    //設(shè)置相機聚焦的位置(其實就是確定一個方向)
    camera.lookAt({
        x: 0,
        y: 0,
        z: 0
    });
}

要唯一確定一個相機的位置與方向,position、up、lookAt三個屬性是缺一不可的。
這里我們創(chuàng)建了一個正交投影相機,這里我將視景體大小與屏幕分辨率保持一致只是為了方便,這樣坐標(biāo)系中的一個單位長度就對應(yīng)屏幕的一個像素了。
我們將相機放在Z軸上,面向坐標(biāo)原點,相機的上方向為Y軸方向,注意up的方向和lookAt的方向必然是垂直的(類比自己的頭就知道了)。
下面添加一個立方體到場景中:

function initObject() {
    //創(chuàng)建一個邊長為100的立方體
    var geometry = new THREE.CubeGeometry(100, 100, 100);
    object = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial());
    scene.add(object);
}

注意我們使用了法向材質(zhì)MeshNormalMaterial,這樣立方體每個面的顏色與這個面對著的方向是相關(guān)的,更便于觀察/調(diào)試。
在這個簡單的demo里我不打算添加光影效果,而法向材質(zhì)對光也是沒有反應(yīng)的。 最后來創(chuàng)建一個動畫循環(huán)吧

function render() {
    requestAnimationFrame(render);
    object.rotation.x += 0.05;
    object.rotation.y += 0.05;
    renderer.render(scene, camera);
}

每次重繪都讓這個立方體轉(zhuǎn)動一點點。 當(dāng)頁面加載好時,調(diào)用前面這些函數(shù)就好了。

function threeStart() {
    initRenderer();
    initCamera();
    initScene();
    initObject();
    render();
}
window.onload = threeStart();

參考資料

WebGL中文網(wǎng) 強烈推薦!!
WebGL中文教程網(wǎng)

?著作權(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ù)。

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