




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
Three.js開發指南基于WebGL和HTML5在網頁上渲染3D圖形和動畫(第三版)目錄TOC\h\h第1章使用Three.js創建你的第一個三維場景\h1.1準備工作\h1.2獲取源碼\h1.3搭建HTML框架\h1.4渲染并查看三維對象\h1.5添加材質、光源和陰影效果\h1.6讓你的場景動起來\h1.7使用dat.GUI簡化試驗流程\h1.8場景對瀏覽器的自適應\h1.9總結\h第2章構建Three.js應用的基本組件\h2.1創建場景\h2.2幾何體和網格\h2.3選擇合適的攝像機\h2.4總結\h第3章學習使用Three.js中的光源\h3.1Three.js中不同種類的光源\h3.2基礎光源\h3.3特殊光源\h3.4總結\h第4章使用Three.js的材質\h4.1理解材質的共有屬性\h4.2從簡單的網格材質開始\h4.3高級材質\h4.4線性幾何體的材質\h4.5總結\h第5章學習使用幾何體\h5.1Three.js提供的基礎幾何體\h5.2總結\h第6章高級幾何體和二元操作\h6.1THREE.ConvexGeometry\h6.2THREE.LatheGeometry\h6.3通過拉伸創建幾何體\h6.4THREE.ParametricGeometry\h6.5創建三維文本\h6.6使用二元操作組合網格\h6.7總結\h第7章粒子和精靈\h7.1理解粒子\h7.2THREE.Points和THREE.PointsMaterial\h7.3使用HTML5畫布樣式化粒子\h7.4使用紋理樣式化粒子\h7.5使用精靈貼圖\h7.6從高級幾何體創建THREE.Points\h7.7總結\h第8章創建、加載高級網格和幾何體\h8.1幾何體組合與合并\h8.2從外部資源加載幾何體\h8.3導入三維格式文件\h8.4總結\h第9章創建動畫和移動攝像機\h9.1基礎動畫\h9.2使用攝像機\h9.3變形動畫和骨骼動畫\h9.4使用外部模型創建動畫\h9.5總結\h第10章加載和使用紋理\h10.1將紋理應用于材質\h10.2紋理的高級用途\h10.3總結\h第11章自定義著色器和后期處理\h11.1配置Three.js以進行后期處理\h11.2后期處理通道\h11.3使用THREE.ShaderPass自定義效果\h11.4創建自定義后期處理著色器\h11.5總結\h第12章在場景中添加物理效果和聲音\h12.1創建基本的Three.js場景\h12.2Physi.js材質屬性\h12.3Physi.js基礎形體\h12.4使用約束限制對象的移動\h12.5在場景中添加聲源\h12.6總結第1章使用Three.js創建你的第一個三維場景現代瀏覽器直接通過JavaScript就可以實現非常強大的功能。使用HTML5的標簽可以很容易地添加語音和視頻,而且在HTML5提供的畫布上可以添加具有交互功能的組件。現在,現代瀏覽器也開始支持WebGL。通過WebGL可以直接使用顯卡資源來創建高性能的二維和三維圖形,但是直接使用WebGL編程來從JavaScript創建三維動畫場景十分復雜而且還容易出問題。使用Three.js庫可以簡化這個過程。Three.js帶來的好處有以下幾點:·創建簡單和復雜的三維幾何圖形。·創建虛擬現實(VR)和增強現實(AR)場景。·在三維場景下創建動畫和移動物體。·為物體添加紋理和材質。·使用各種光源來裝飾場景。·加載三維模型軟件所創建的物體。·為三維場景添加高級的后期處理效果。·使用自定義的著色器。·創建點云(即粒子系統)。通過幾行簡單的JavaScript代碼,你可以創建從簡單三維模型到類似圖1.1(在瀏覽器中訪問\h//www.vill.ee/eye)所示的具有真實感的場景。本章將會通過示例來闡述Three.js的工作原理,但是不會對其中的技術細節進行深入探究,這些細節我們將會在后面的章節中介紹。本章主要涵蓋以下幾方面:·使用Three.js所需的工具。·下載本文檔所需的源碼和示例。·創建第一個Three.js場景。·使用材質、光源和動畫來完善第一個場景。·引入輔助庫以統計和控制場景。圖1.1首先將會對Three.js進行簡單的介紹,然后再講解第一個示例及其代碼。在開始之前我們先來看下當前主流瀏覽器對WebGL的支持情況,幾乎所有瀏覽器的桌面版和移動版均支持WebGL,唯一的例外是移動版迷你Opera瀏覽器(OperaMini),因為這個瀏覽器有一種特殊的工作模式,可以在Opera服務器端進行頁面渲染,而Opera服務器往往禁止運行JavaScript。不過從8.0版開始,OperaMini的默認工作模式已改為使用iOSSafari引擎渲染頁面,從而也可以很好地支持JavaScript和WebGL。但是新版OperaMini仍然可以被設置為不支持JavaScript的“迷你模式”(minimode)。除了IE的一些低版本瀏覽器,基本所有的現代瀏覽器都支持Three.js。如果想在低版本的IE瀏覽器上運行Three.js,你還需要做額外的操作。對于IE10和更低的版本,你可以安裝iewebgl插件,下載地址為\h/iewebgl/iewebgl。使用WebGL能夠創建出具有交互性的3D模型,而且這些模型在電腦和手機設備上都能夠很好地運行。本文檔主要使用Three.js提供的基于WebGL的渲染器。但是Three.js也提供了基于CSS3D的渲染器,使用其API能夠很容易地創建出三維場景,而且這個渲染器的優點在于幾乎所有手機和電腦上的瀏覽器都支持CSS3D,并且可以在三維空間內渲染HTML元素。第7章會進一步介紹如何使用CSS3D。通過本章的學習,你可以直接創建第一個三維場景,而且這個場景可以在上述的所有瀏覽器中運行。目前我們不會介紹太多Three.js的復雜特性,但是在本章結束的時候你能夠創建出如圖1.2所示的場景。圖1.2通過創建這個場景,你可以學到Three.js的基礎知識,并可以創建第一個動畫。在開始實現這個示例之前,我們會先介紹幾個工具,這些工具可以幫助你更方便地使用Three.js。我們還會介紹如何下載本文檔所用到的示例。1.1準備工作Three.js是一個JavaScript庫,所以你只需要一個文本編輯器和支持Three.js的瀏覽器就可以使用Three.js來創建WebGL應用。這里推薦如下幾款JavaScript文本編輯器:·VisualStudioCode:VisualStudioCode是微軟公司面向所有常見操作系統推出的一款免費編輯器。該編輯器能夠基于源程序里的類型和函數聲明以及導入庫,提供效果良好的語法高亮和代碼補全功能。同時它還具有簡潔明了的用戶界面,以及對JavaScript的完美支持。下載地址為\h/。·WebStorm:WebStorm是JetBrains公司旗下的一款JavaScript編輯工具。它支持代碼補全、自動部署和代碼調試功能。除此之外,WebStorm還支持GitHub和其他各種版本控制器。讀者可從\h///webstorm/下載一個試用版本。·Notepad++:Notepad++是Windows操作系統下的通用文本編輯器,它支持各種編程語言語法高亮度顯示,而且可以很容易地對JavaScript進行布局和格式化。Notepad++的下載地址為\h///。·SublimeText:SublimeText是一款對JavaScript支持非常好的文本編輯器。除此之外,SublimeText的一大亮點是支持多重選擇——同時選擇多個區域,然后同時進行編輯。這些功能提供了一個很好的JavaScript編程環境。SublimeText是一個收費閉源軟件,下載地址為\h///。除此之外,還有很多可以編寫JavaScript進而創建Three.js應用的開源和商用編輯器。還有一款基于云的代碼編輯平臺Cloud9,網址是\h//c9.io,該平臺可以連接GitHub賬號,由此可以直接獲取本文檔相關的代碼和示例。除了使用這些文本編輯器來運行本文檔相關的代碼和示例,Three.js自身也提供了在線場景編輯器,訪問地址為\h///editor。使用該編輯器,可以用圖形化方法創建Three.js場景。雖然現代瀏覽器基本都支持WebGL并能運行Three.js應用,但是本文檔所采用的是Chrome瀏覽器。因為Chrome是對WebGL支持最好的瀏覽器,并且擁有強大的JavaScript代碼調試功能。如圖1.3所示,使用調試器的斷點和控制臺功能可以快速地定位問題。在本文檔中,還會進一步介紹各種調試的方法和技巧。圖1.3Three.js就介紹到此,下面就開始獲取源碼并創建我們的第一個場景。1.2獲取源碼本文檔所有的源碼都可以從GitHub(\h/)獲取。GitHub是基于Git的在線代碼倉庫,你可以使用它來存儲、訪問源碼和進行版本控制。獲取GitHub上源碼的方式有以下兩種:·通過Git獲取代碼倉庫·下載并解壓縮檔案文件接下來會詳細講解這兩種方式。1.2.1通過Git獲取代碼倉庫Git是開源、分布式的版本控制系統,本文檔的示例都是基于Git進行創建和版本管理的,GitHub倉庫的訪問地址為\h/josdirksen/learning-threejs。如果你已經在操作系統中安裝了Git的客戶端,那么就可以使用git命令來克隆示例的代碼倉庫。如果你還沒有安裝,可以訪問\h//下載,或者使用GitHub公司自己為Mac或Windows系統提供的客戶端。在安裝完Git客戶端后,打開控制臺并在你想要存儲代碼的目錄中運行如下的命令:如圖1.4所示,代碼就開始下載了。圖1.4下載完畢后,在learning-threejs-third文件夾中會看到本文檔所用的所有的示例。1.2.2下載并解壓縮檔案文件如果你不想使用Git的方式從GitHub上獲取源碼,那么還可以在GitHub上下載檔案文件。在瀏覽器上訪問\h/josdirksen/learning-threejs-third,點擊右側的Cloneordownload按鈕。如圖1.5所示。解壓文件到指定的目錄,這樣就可以獲取所有的示例了。圖測試示例現在你已經下載或者克隆了示例源碼,下面我們就來測試示例是否能夠正常工作,進而了解工程的目錄結構。本文檔的示例是按照章節進行組織的。如果要運行本文檔的示例,你可以使用瀏覽器打開HTML文件,或者安裝本地Web服務器。第一種方法對于簡單的示例是可行的,但是如果示例中需要下載外部資源時,比如模型或者紋理圖像,那么僅僅使用瀏覽器打開HTML文件是行不通的。這個時候,我們就需要本地Web服務器來確保外部資源正確加載。接下來我們會介紹幾種安裝本地服務器的方式,如果你無法安裝本地服務器但使用Chrome或Firefox瀏覽器,那么我們也會介紹如何禁用安全性檢測來運行示例。接下來,我們將會介紹幾種安裝本地服務器的方式,依據系統的配置,你可以選擇最合適的方式。1.適用于Unix/Mac系統的基于Python的Web服務器大部分的Unix/Linux/Mac系統默認安裝了Python,在示例源碼目錄中運行如下的命令就可以將本地Web服務器啟動起來了。在你下載了源碼的目錄中執行上述命令。2.基于NPM的Web服務器如果你已經在使用Node.js了,那么你肯定已經安裝了NPM。使用NPM,有兩個方式可以快速地搭建本地Web服務器:第一種方式是使用http-server模塊,如下所示:第二種方式是使用simple-http-server,如下所示:第二種方式的缺點在于無法自動地顯示目錄列表,而第一種方式是可以的。3.Mac/Windows上的輕量級服務器——Mongoose如果你還沒有安裝Python或者NPM,那么還有一個簡單、輕量級的Web服務器——Mongoose。首先,從\h/p/mongoose/downloads/list下載你的系統所支持的二進制安裝文件。如果你使用的是Windows系統,那么將下載好的二進制文件復制到示例所在的目錄,雙擊即可啟動一個運行于該目錄下的Web服務器。對于其他的操作系統,則須將下載的二進制文件復制到指定的目錄中,但是啟動的方式不是雙擊,而是通過命令行的方式,如圖1.6所示。圖1.6在這兩種情況下都會在8080端口啟動一個本地Web服務器。本文檔的示例目錄如圖1.7所示。圖1.7點擊各章節的目錄就可以獲取相應章節的示例。在本文檔講解提到某個示例時會指出示例的名稱和所在的文件夾,這樣你就可以找到該示例的源代碼以便測試運行或自行研究。4.禁用Firefox和Chrome的安全性檢測如果你使用的是Chrome瀏覽器,有種方式可以禁用安全性設置,這樣就可以在沒有Web服務器的情況下查看示例。需要注意的是,應盡量避免用下面的方法訪問真正的網站,因為這樣做會使瀏覽器向各種惡意代碼敞開大門。用下面的命令可以啟動Chrome瀏覽器同時禁用所有安全特性。·對于Windows操作系統:·對于Linux操作系統:·對于MacOS操作系統:通過這種方式啟動Chrome瀏覽器就可以直接運行本地文件系統中的示例。對于Firefox瀏覽器來說,還需要其他的配置。打開Firefox瀏覽器并在地址欄內輸入about:config會看到圖1.8所示的頁面。圖1.8在該頁面中點擊“I’llbecareful,Ipromise!”按鈕,然后就會列出所有用于調整Firefox的屬性。在搜索框中輸入security.fileuri.strict_origin_policy,并將其值修改為false。如圖1.9所示。圖1.9這時候就可以使用Firefox瀏覽器直接運行本文檔的示例了。到現在為止,你應該已經安裝了Web服務器或者禁用了瀏覽器的安全性設置,那么就開始創建第一個三維場景吧。1.3搭建HTML框架首先我們將會創建空的HTML框架,后面的示例將在這個框架的基礎上完成。具體如下所示:你應該已經發現了,這個框架是個僅包含一些基本元素的HTML網頁。在<head>標簽中列出了示例所使用的外部JavaScript庫,在這里至少要包含Three.js庫。此外,這里還包含一個控制器庫TrackballControls.js。有了它便可以利用鼠標任意移動攝像機,以便從不同角度觀察場景。在<head>標簽中最后一個被包含的JavaScript文件是本章的示例程序,文件名為01-01.js。最后,在<head>標簽中我們還添加了幾行CSS代碼,這些CSS代碼用于移除Three.js場景網頁中的滾動條。在<body>標簽中我們只添加了一個<div>元素,當我們寫Three.js代碼時,會把Three.js渲染器的輸出指向這個元素。在框架網頁的最后還有少量JavaScript代碼。這些代碼將在網頁加載完成后被自動調用,我們利用這個機會調用init()函數。init()函數也在01-01.js文件中定義,它將為Three.js場景做必要的初始化設置。不過在本章中,init()函數暫時僅僅向控制臺窗口打印當前Three.js的版本信息。在瀏覽器中打開本章示例代碼文件并觀察控制臺窗口,可以看到如圖1.10所示的內容。圖1.10在<head>元素中包含Three.js的源代碼。Three.js有兩個不同的版本:·three.min.js:這個版本的JS庫一般應用于網上部署Three.js時。該版本是使用UglifyJS壓縮過的,它的大小是普通Three.js版本的四分之一。本文檔示例所使用的是2018年7月發布的Three.jsr95版本。·three.js:這個是普通的Three.js庫。為了便于進行代碼調試和理解Three.js的源碼,本文檔的示例使用的都是這個庫。接下來,我們將會創建第一個三維對象并將其渲染到已經定義好的<div>元素中。1.4渲染并查看三維對象在這一步,我們將會創建第一個場景并添加幾個物體和攝像機。我們的第一個示例將會包含表1.1所列對象。表1.1下面將會通過代碼示例(帶注釋的代碼在文件chapter-01/is/01-02.js中)來解釋如何創建場景并渲染三維對象:在瀏覽器中將示例打開,看到的結果和我們的目標,即本章開始時所展示的那張渲染圖接近,但效果還有些差距。目前的效果如圖1.1所示。圖1.11接下來將會對代碼進行分析,這樣我們就可以了解代碼是如何工作的:在代碼中,首先定義了場景(scene)、攝像機(camera)和渲染器(renderer)對象。場景是一個容器,主要用于保存、跟蹤所要渲染的物體和使用的光源。如果沒有THREE.Scene對象,那么Three.js就無法渲染任何物體,在第2章還會對THREE.Scene進行詳細介紹。示例中所要渲染的方塊和球體稍后將會添加到場景對象中。在示例中我們還定義了攝像機對象,攝像機決定了能夠在場景看到什么。在第2章,你還會進一步了解攝像機對象能夠接受的參數。接下來,我們定義了渲染器對象,該對象會基于攝像機的角度來計算場景對象在瀏覽器中會渲染成什么樣子。最后WebGLRenderer將會使用電腦顯卡來渲染場景。如果你已經看了Three.js的源碼和文檔(網址為\h//),你會發現除了基于WebGL的渲染器外,還有其他的渲染器,比如基于HTMLcanvas的渲染器、基于CSS的渲染器,甚至還有基于SVG的渲染器。盡管它們也能夠渲染簡單的場景,但是不推薦使用,因為它們已經停止更新、十分耗CPU的資源,而且也缺乏對一些功能的支持,比如材質和陰影。在示例中,我們調用setClearColor方法將場景的背景顏色設置為接近黑色(newTHREE.Color(0X00000000)),并通過setSize方法設置場景的大小。使用window.innerWidth和window.innerHeight可將整個頁面窗口指定為渲染區域。到目前為止,我們已經創建了空白的場景、渲染器和攝像機,但是還沒有渲染任何東西。接下來將會在代碼中添加軸和平面:如代碼所示,我們創建了坐標軸(axes)對象并設置軸線的粗細值為20,最后調用scene.add方法將軸添加到場景中。接下來要創建平面(plane),平面的創建分為兩步來完成。首先,使用THREE.PlaneGeometry(60,20)來定義平面的大小,在示例中將寬度設置為60,高度設置為20。除了設置高度和寬度,我們還需要設置平面的外觀(比如顏色和透明度),在Three.js中通過創建材質對象來設置平面的外觀。在本例中,我們將會創建顏色為0xAAAAAA的基本材質(THREE.MeshBasicMaterial)。然后,將大小和外觀組合進Mesh對象并賦值給平面變量。在將平面添加到場景之前,還需要設置平面的位置:先將平面圍繞x軸旋轉90度,然后使用position屬性來定義其在場景中的位置。如果你對Mesh對象感興趣,那么可以查看第2章中的示例06-mesh-properties.html,該示例詳細介紹了旋轉和定位。最后,我們將平面添加到場景中。使用同樣的方式將方塊和球體添加到平面中,但是需要將線框(wireframe)屬性設置為true,這樣物體就不會被渲染為實體物體。接下來就是示例的最后一部分:現在,所有物體都已經添加到場景中的合適位置。在之前我們提到過,攝像機將決定哪些東西會被渲染到場景中。在這段代碼中,我們使用x、y、z的位置屬性來設置攝像機的位置。為了確保所要渲染的物體能夠被攝像機拍攝到,我們使用lookAt方法指向場景的中心,默認狀態下攝像機是指向(0,0,0)位置的。最后需要做的就是將渲染的結果添加到HTML框架的<div>元素中。我們使用JavaScript來選擇需要正確輸出的元素并使用appendChild方法將結果添加到div元素中。最后告訴渲染器使用指定的攝像機來渲染場景。接下來,我們還會使用光照、陰影、材質和動畫來美化這個場景。1.5添加材質、光源和陰影效果在Three.js中添加材質和光源是非常簡單的,做法和前一節講的基本一樣。首先我們在場景中添加一個光源(完整代碼請參見示例js/03-03.js)。代碼如下所示:通過THREE.SpotLight定義光源并從其位置(spotLight.position.set(-40,60,-10))照射場景。通過將castShadow屬性設置為true,THREE.js的陰影功能被啟用。此外,上面的代碼還通過設置shadow.mapSize、shadow.camera.far和shadow.camera.near三個參數來控制陰影的精細程度。有關光源屬性的更多細節將在第3章詳細介紹。如果這時候渲染場景,那么你看到的結果和沒有添加光源時是沒有區別的。這是因為不同的材質對光源的反應是不一樣的。我們使用的基本材質(THREE.MeshBasicMaterial)不會對光源有任何反應,基本材質只會使用指定的顏色來渲染物體。所以,我們需要改變平面、球體和立方體的材質:如代碼所示,我們將場景中物體的材質改為MeshLambertMaterial。Three.js中的材質MeshPhysicalMaterial和MeshStandardMaterial(以及被棄用的MeshPhongMaterical)在渲染時會對光源產生反應。渲染的結果如圖1.12所示,但是這還不是我們想要的結果。圖1.12雖然立方體和球體已經好看了很多,但是還缺少陰影的效果。由于渲染陰影需要耗費大量的計算資源,所以默認情況下Three.js中是不會渲染陰影的。為了渲染陰影效果,我們需要對代碼做如下修改:首先通過設置shadowMapEnabled屬性為“true”來告訴渲染器需要陰影效果。這時候如果查看修改的效果,那么你將會發現還是沒有任何區別,因為你還需要明確地指定哪個物體投射陰影、哪個物體接受陰影。在示例中,我們通過將相應的屬性設置為“true”來指定球體和立方體在地面上投射陰影。代碼如下所示:接下來我們還需要定義能夠產生陰影的光源。因為并不是所有的光源都能夠產生陰影,但是通過THREE.SpotLight定義的光源是能夠產生陰影的。我們只要將屬性castShadow設置為true就可以將陰影渲染出來了,代碼如下所示:這樣,場景中就有了光源產生的陰影,效果如圖1.13所示。仔細觀察01-03.js的源代碼會發現,這段程序還創建了一個擁有不同物體的場景。若將那些名為createXXX的函數的注釋去掉,并且刪除前面已經創建的立方體和球,場景中便會出現一些更復雜的物體。這些物體將展示出如圖1.13所示的更復雜的陰影。圖1.13圖1.14最后一個將要添加到場景中的效果是簡單動畫。在第9章中,你將會學習使用更高級的動畫。1.6讓你的場景動起來如果希望我們的場景動起來,那么首先需要解決的問題是如何在特定的時間間隔重新渲染場景。在HTML5和相關的JavaScriptAPI出現之前,是通過使用setInterval(function,interval)方法來實現的。比如,通過setInterval()方法指定某個函數每100毫秒調用一次。但是這個方法的缺點在于它不管瀏覽器當前正在發生什么(比如正瀏覽其他網頁),它都會每隔幾毫秒執行一次。除此之外,setInterval()方法并沒與屏幕的刷新同步。這將會導致較高的CPU使用率和性能不良。1.6.1引入requestAnimationFrame()方法幸運的是,現代瀏覽器通過requestAnimationFrame函數為穩定而連續的渲染場景提供了良好的解決方案。通過這個函數,你可以向瀏覽器提供一個回調函數。你無須定義回調間隔,瀏覽器將自行決定最佳回調時機。你需要做的是在這個回調函數里完成一幀繪制操作,然后將剩下的工作交給瀏覽器,它負責使場景繪制盡量高效和平順地進行。這個功能使用起來也非常簡單(完整源碼在04-04.js文件中),你只需要創建負責繪制場景的回調函數:在renderScene()方法中,requestAnimationFrame()方法又一次被調用了,這樣做的目的是保證動畫能夠持續運行。接下來我們還需要對代碼做的修改是:在場景創建完畢后,不再調用renderer.render()方法,而是調用renderScene()來啟動動畫,代碼如下:這時候如果運行代碼,效果和之前的示例相比沒有任何區別,這是因為我們還沒有為物體添加任何動畫效果。在添加動畫之前,我們先來介紹一個輔助庫,這個庫也是Three.js作者開發的,主要用于檢測動畫運行時的幀數。在動畫運行時,該庫可以在一個圖片中顯示畫面每秒傳輸幀數。為了能夠顯示幀數,首先我們需要在HTML的<head>標簽中引入這個輔助庫:然后初始化幀數統計模塊并將它添加到頁面上。上面的函數初始化幀數統計模塊,并用輸入的type參數來設置將要顯示的統計內容。它可以是:每秒渲染的幀數、每渲染一幀所花費的時間或者內存占用量。最后,在前面介紹過的init函數末尾調用上述函數來初始化統計模塊。由于initStats函數并不是本章示例所特有的操作,因此它的實現代碼并不在本章的示例代碼中,而是像其他有用的輔助函數一樣保存在輔助函數庫util.js文件中。輔助函數庫在HTML頁面代碼的開始部分被引用。示例代碼為統計幀數顯示所做的最后一件事,是在renderScene函數中每渲染完一幀后,調用stats.update函數更新統計。添加完上述代碼之后再次運行示例,統計圖形將會顯示在瀏覽器左上方,如圖1.15所示。圖旋轉立方體引入requestAnimationFrame()方法并配置完統計對象之后,接下來就該添加動畫代碼了。在本節中,我們將擴展renderScene()方法來實現紅色立方體圍繞軸進行旋轉。代碼如下所示:看起來是不是很簡單?我們所做的只是在每次調用renderScene()時使得每個坐標軸的rotation屬性增加0.02,其效果就是立方體將圍繞它的每個軸進行緩慢的旋轉。在下一節中我們將讓藍色球體彈跳起來,這個實現起來也不是特別難。1.6.3彈跳球為了讓小球彈跳起來,只需要在renderScene()方法中添加如下代碼即可:旋轉立方體時我們修改的是rotation屬性;而讓小球彈跳起來,我們所要修改的是球體在場景中的位置(position)屬性。我們的目的是讓小球依照一條好看的、光滑的曲線從一個地方跳到另一個地方,如圖1.16所示。圖1.16為了實現這個效果,我們需要同時改變球體在x軸和y軸的位置。Math.cos()和Math.sin()方法使用step變量就可以創建出球體的運行軌跡。在這里不具體展開解釋它們是怎么工作的,現在你只需要知道step+=0.04定義了球體彈跳的速度就可以,在第8章中還會詳細介紹這些方法是如何用于實現動畫的。圖1.17展示的就是球體在彈跳中的效果。圖1.17在結束本章之前,我還想在場景中引入幾個輔助庫。可能你已經發現,在創建類似三維場景和動畫時,我們需要嘗試很多次才能夠確定最合適的速度和顏色。如果有一個GUI(可視化圖形界面)允許我們在運行期間修改這些屬性,那么事情就會變得很簡單。幸運的是,這樣的GUI是存在的。1.7使用dat.GUI簡化試驗流程Google員工創建了名為dat.GUI的庫(相關文檔見\h///p/dat-gui/),使用這個庫可以很容易地創建出能夠改變代碼變量的界面組件。在本章最后,將會使用data.GUI庫為我們的示例添加用戶操作界面,使得我們可以:·控制小球彈跳的速度;·控制立方體的旋轉。就像引入統計對象一樣,首先我們需要在HTML的<head>標簽中添加這個庫,代碼如下所示:接下來我們需要定義一個JavaScript對象,該對象將保存希望通過dat.GUI改變的屬性。在JavaScript代碼中添加如下的JavaScript對象:在這個JavaScript對象中,我們定義了兩個屬性——this.rotationSpeed和this.bouncingSpeed,以及它們的默認值。接下來需要將這個JavaScript對象傳遞給data.GUI對象,并設置這兩個屬性的取值范圍,如下所示:立方體旋轉速度(rotationSpeed)和球體彈跳速度(bouncingSpeed)的取值范圍為0~0.5。現在需要做的就是在renderScene()中直接引用這兩個屬性,這樣當我們在dat.GUI中修改這兩個屬性的值時,就可以影響相應物體的旋轉速度和彈跳速度。代碼如下所示:現在運行這個示例(05-control-gui.html)時,你就會看到一個可以控制彈跳速度和旋轉速度的用戶界面。如圖1.18所示。圖1.18讀者應該還記得在本章開頭時創建的框架頁面代碼中,我們引用了TrackballControl.js文件。該文件用于實現利用鼠標移動攝像機,以便以不同角度觀察場景。這一點將在第9章詳細介紹。該文件同樣需要初始化。由于它需要響應文檔對象模型(DOM)元素的事件,它的初始化代碼必須出現在下面代碼中的appendChild函數調用之后。initTrackballControls函數也定義于util.js文件中,它的具體實現將在本文檔后面章節中詳細介紹。最后,與幀數統計模塊相似,TrackballControl.js庫也需要在render函數渲染完一幀后更新。至此本章的代碼便已完成。再次打開05-control-gui.html文件時,可以通過按下鼠標左鍵并移動鼠標來轉動攝像機,以便從不同角度觀察場景。此外,按S鍵可以拉近或拉遠攝像機,按D鍵可以平移攝像機。如圖1.19所示。后續章節中的所有實踐都將使用這個庫來移動攝像機。在運行這個示例并改變瀏覽器大小的時候,你可能已經發現場景是不會隨著瀏覽器大小的改變而自動做出調整的。那么在接下來的小節中,我們會添加本章的最后一個特性來解決這一問題。圖1.191.8場景對瀏覽器的自適應當瀏覽器大小改變時改變攝像機是很容易實現的。首先我們需要做的就是為瀏覽器注冊一個事件監聽器,如下所示:這樣,每當瀏覽器尺寸改變時onResize()方法就會被執行。在onRaise()方法中需要更新攝像機和渲染器,代碼如下:對于攝像機,需要更新它的aspect屬性,這個屬性表示屏幕的長寬比;對于渲染器,需要改變它的尺寸。最后我們需要將變量camera、renderer和scene的定義移到init()方法的外面,這樣其他的方法(如onResize()方法)也可以訪問它們。代碼如下所示:運行示例06-screen-size-change.html并改變瀏覽器的大小,就可以看到實際的效果。1.9總結本章到此結束。在這一章里你學到了如下內容:如何搭建開發環境,如何獲取本文檔相關的源碼和示例;使用Three.js渲染場景時,首先需要做的是創建THREE.Scene對象,添加攝像機、光源和需要渲染的物體;如何給場景添加陰影和動畫效果;添加輔助庫dat.GUI和stats.js創建用戶控制界面和快速獲取場景渲染時的幀數。在下一章中我們將會進一步擴展這個示例,你將會學到更多Three.js中非常重要的場景構建模塊。第2章構建Three.js應用的基本組件在第1章中我們介紹了Three.js庫的基礎知識。通過示例展示了Three.js是如何工作的,然后創建了第一個完整的Three.js應用。在本章中我們將會深入了解Three.js庫,介紹構建Three.js應用的基本組件。通過本章你將了解以下內容:·在Three.js應用中使用的主要組件。·THREE.Scene對象的作用。·幾何圖形和網格是如何關聯的。·正交投影攝像機和透視投影攝像機的區別。我們首先來介紹如何創建場景并添加對象。2.1創建場景在第1章中我們已經創建了一個THREE.Scene,想必你已經了解了Three.js庫的基礎知識。我們可以看到,一個場景想要顯示任何東西,需要表2.1所示三種類型的組件。表2.1THREE.Scene對象是所有不同對象的容器,但這個對象本身沒有那么多的選項和函數。THREE.Scene對象有時被稱為場景圖,可以用來保存所有圖形場景的必要信息。在Three.js中,這意味著THREE.Scene保存所有對象、光源和渲染所需的其他對象。有趣的是,場景圖,顧名思義,不僅僅是一個對象數組,還包含了場景圖樹形結構中的所有節點。每個你添加到Three.js場景的對象,甚至包括THREE.Scene本身,都是繼承自一個名為THREE.Object3D的對象。一個THREE.Object3D對象也可以有自己的子對象,你也可以使用它的子對象來創建一個Three.js能解釋和渲染的對象樹。2.1.1場景的基本功能了解一個場景功能的最好方法就是看示例。在本章的源代碼中,你可以找到一個名為01-basic-scene.html的例子。我將使用這個例子來解釋一個場景所擁有的各種方法和選項。當我們在瀏覽器中打開這個示例的時候,其效果大致如圖2.1所示。請記住除了鼠標之外,鍵盤上的A、S和D鍵也可用于在渲染場景中轉向、縮放和平移。圖2.1這跟我們在第1章中看到的例子非常像。盡管這個場景看上去有點兒空蕩蕩,但其實它已經包含了好幾個對象。通過下面的源代碼可以看到,我們使用THREE.Scene對象的scene.add(object)方法添加了一個THREE.Mesh對象(你看到的平面)、一個THREE.SpotLight對象(聚光燈光源)和一個THREE.AmbientLight對象(環境光)。渲染場景的時候,THREE.Camera對象會自動地被Three.js添加進來。但是我們手動添加它會是一個更好的實踐,尤其是當你需要處理多個攝像機的時候。部分源碼如下:在深入了解THREE.Scene對象之前,先說明一下你可以在這個示例中做些什么,然后我們再來看代碼。在瀏覽器中打開01-basic-scene.html示例,看看右上角的那些控件。如圖2.2所示。圖2.2通過這些控件,你可以往場景中添加方塊、移除最后一個添加到場景中的方塊以及在瀏覽器控制臺中顯示當前場景中的所有對象。控件區的最后一項顯示了當前場景中所有對象的數量。你可能會發現場景在啟動的時候就已經包含了4個對象,它們是地面、環境光、點光源和我們之前提到的攝像機。讓我們從最簡單的addCube方法開始逐一了解控件區的所有方法。現在這段代碼應該很容易讀懂,因為這里沒有引入很多新的概念。當你點擊addCube按鈕的時候,一個新的THREE.BoxGeometry對象就會被創建,它的長、寬和高都是一個從1到3之間的隨機數。除了尺寸是隨機的,這個方塊的顏色和位置也是隨機的。這段代碼里的新東西是我們使用name屬性為整個方塊指定了一個名字。方塊的名字是在cube后面加上當前場景中對象的數量(即scene.children.length)。給對象命名在調試的時候是很有用的,而且還可以直接通過名字來獲取場景中的對象。如果使用Three.Scene.getObjectByName(name)方法,可以直接獲取場景中名為name的對象,然后可以執行一些比如改變位置的操作。你或許想知道最后一行代碼的作用,我們的控制界面就是使用numberOfObjects變量來顯示場景中對象數量的。所以,無論什么時候添加或者刪除對象,我們都要將該變量設置為更新后的數量。在控制界面中能夠調用的另一個方法是removeCube()。顧名思義,點擊removeCube按鈕,將會移除最后一個添加到場景中的方塊。代碼實現如下所示:在場景中添加對象使用的是add()方法,而從場景中移除對象就要使用remove()方法。由于Three.js將子對象保存在數組中(最新的對象保存在數組的最后),所以我們可以使用THREE.Scene對象的children屬性來獲取最后一個添加到場景中的對象,children屬性將場景中的所有對象存儲為數組。在移除對象時,我們還需要檢查該對象是不是THREE.Mesh對象,這樣做的原因是避免移除攝像機和光源。當我們移除對象之后,需要再次更新控制界面中表示場景中對象數量的屬性numberOfObjects。控制界面上的最后一個按鈕的標簽是outputObjects。你或許已經發現在點擊該按鈕后什么都沒有發生。因為這個按鈕的功能是在瀏覽器的控制臺中打印出場景中的所有對象信息,如圖2.3所示。圖2.3我們使用的是內置的console對象在瀏覽器控制臺日志中輸出對象信息,代碼如下所示:這樣做對于代碼調試是非常有用的,尤其是當你為對象命名時。它對查找某個特定對象相關的問題是非常有用的。例如,對象cube-17(如果你已經知道對象的名字,就可以使用console.log(scene.getObjectByName("cube-17"))來輸出對應的信息。輸出結果如圖2.4所示。圖2.4目前為止,我們已經學習了如下一些和場景相關的方法:·THREE.Scene.Add:用于向場景中添加對象·THREE.Scene.Remove:用于移除場景中的對象·THREE.Scene.children:用于獲取場景中所有的子對象列表·THREE.Scene.getObjectByName:利用name屬性,用于獲取場景中特定的對象這些方法是和場景相關的重要方法,通常情況下這些方法就可以滿足大部分需求了。但是,還有幾個輔助方法可能會被用到,請看下面的示例代碼片段。如你在第1章中所看到的,我們使用了render循環來渲染場景。該循環代碼如下所示:在這里,我們使用了THREE.Scene.traverse()方法。我們可以將一個方法作為參數傳遞給traverse()方法,這個傳遞來的方法將會在每一個子對象上執行。由于THREE.Scene對象存儲的是對象樹,所以如果子對象本身還有子對象,traverse()方法會在所有的子對象上執行,直到遍歷完場景樹中的所有對象為止。我們使用render()方法來更新每個方塊的旋轉狀態(我們特意忽略了表示地面的plane對象)。我們還可以使用for循環或者forEach來遍歷children屬性數組來達到同樣的目的,因為只向THREE.Scene增加對象且沒有創建嵌套結構。在我們深入討論THREE.Mesh和THREE.Geometry對象之前,先來介紹THREE.Scene對象的兩個屬性:fog(霧化)和overrideMaterial(材質覆蓋)。2.1.2給場景添加霧化效果使用fog屬性就可以為整個場景添加霧化效果。霧化效果是:場景中的物體離攝像機越遠就會變得越模糊。如圖2.5所示。為了更好地觀察霧化效果,可以利用鼠標推進或拉遠攝像機,這樣就可以觀察物體是如何受霧化效果的影響。在Three.js中為場景添加霧化效果是很簡單的,在定義完場景后只要添加如下代碼即可:圖2.5我們在這里定義一個白色霧化效果(0xffffff)。后面的兩個參數是用來調節霧的顯示,0.015是near(近處)屬性的值,100是far(遠處)屬性的值。通過這兩個屬性可以決定霧化開始和結束的地方,以及加深的程度。使用THREE.Fog創建的對象,霧的濃度是線性增長的,除此之外還有另外一種添加霧化效果的方法,定義如下:在這個方法中不再指定near和far屬性,只需要設置霧的顏色(0xffffff)和濃度(0.01)即可。需要注意的是,該方法中霧的濃度不再是線性增長的,而是隨著距離呈指數增長。2.1.3使用overrideMaterial屬性我們要介紹的最后一個場景屬性是overrideMaterial。當設置了overrideMaterial屬性后,場景中所有的物體都會使用該屬性指向的材質,即使物體本身也設置了材質。當某一個場景中所有物體都共享同一個材質時,使用該屬性可以通過減少Three.js管理的材質數量來提高運行效率,但是實際應用中,該屬性通常并不非常實用。該屬性的使用方法如下所示:使用了上述代碼中顯示的overrideMaterial屬性之后,場景的渲染結果如圖2.6所示。圖2.6從圖中可以看出,所有的立方體都使用相同的材質和顏色進行渲染。在這個示例中,我們用的材質是THREE.MeshLambertMaterial,而且使用該材質類型,還能夠創建出不發光但是可以對場景中的光源產生反應的物體。在第4章中你將會學到更多關于這種材質的內容。在本節中我們介紹了Three.js中最核心的概念:場景。關于場景我們需要記住的是:它是在渲染時你想使用的所有物體、光源的容器。表2.2列出了THREE.Scene中最常用的方法和屬性。表2.2在下一節中,我們將會對可以添加到場景中的物體作詳細介紹。2.2幾何體和網格在前面的例子中我們已經使用了幾何體和網格。比如在向場景中添加球體時,代碼如下所示:我們使用THREE.SphereGeometry定義了物體的形狀、使用THREE.MeshBasicMaterial定義了物體的外觀和材質,并將它們合并成能夠添加到場景中的網格(THREE.Mesh)。在這一節中將進一步介紹什么是幾何體和網格。2.2.1幾何體的屬性和方法Three.js提供了很多可以在三維場景中使用的幾何體。圖2.7是04-geometries示例的截圖,該圖展示了Three.js庫中可用的標準幾何體。圖2.7在第5章和第6章中我們將會深入討論Three.js提供的所有基本幾何體和高級幾何體。在這一節中,我們主要介紹什么是幾何體。像其他大多數三維庫一樣,在Three.js中幾何體基本上是三維空間中的點集(也被稱作頂點)和將這些點連接起來的面。以立方體為例:·一個立方體有8個角。每個角都可以用x、y和z坐標點來定義,所以每個立方體在三維空間中都有8個點。在Three.js中,這些點稱為頂點。·一個立方體有6個面,每個角有一個頂點。在Three.js中,每個面都是包含3個頂點的三角形。所以,立方體的每個面都是由兩個三角形面組成的。當你使用Three.js庫提供的幾何體時,不需要自己定義幾何體的所有頂點和面。對于立方體來說,你只要定義長、寬、高即可。Three.js會基于這些信息在正確的位置創建一個擁有8個頂點和12個三角形面的立方體。盡管可以使用Three.js提供的幾何體,但是你仍然可以通過定義頂點和面來自定義創建幾何體。創建幾何體的方法如下代碼所示:上述代碼展示了如何創建簡單的立方體。在vertices數組中保存了構成幾何體的頂點,在faces數組中保存了由這些頂點連接起來創建的三角形面。如newTHREE.Face3(0,2,1)就是使用vertices數組中的點0、2和1創建而成的三角形面。需要注意的是創建面的頂點時的創建順序,因為頂點順序決定了某個面是面向攝像機還是背向攝像機的。如果你想創建面向攝像機的面,那么頂點的順序是順時針的,反之頂點的順序是逆時針的。在這個示例中,我們使用THREE.Face3元素定義立方體的6個面,也就是說每個面都是由兩個三角形面組成的。在Three.js以前的版本中,可以使用四邊形來定義面。到底是使用四邊形還是三角形來創建面,在三維建模領域里一直存在比較大的爭議。基本上,大家都習慣于用四邊形來創建面,因為它比三角形更容易增強和平滑。但是對于渲染器和游戲引擎來說,使用三角形更加容易,因為三角形渲染起來效率更高。有了這些頂點和面,我們就可以創建一個新的THREE.Geometry的實例對象,然后將vertices數組賦值給vertices屬性,將faces數組賦值給faces屬性。最后我們需要做的就是在創建的幾何體上執行computeFaceNormals()方法,當該方法執行時,Three.js會決定每個面的法向量,法向量用于決定不同光源下的顏色。基于幾何體,我們就可以創建網格了。我已經創建了一個例子,你可以嘗試修改頂點的位置來體驗一下。在示例05-custom-geometry.html中,你可以修改立方體的每個頂點并能夠看到相應的面是如何變化的。如圖2.8所示(按H鍵來隱藏GUI)。圖2.8這個示例和其他示例一樣,都有一個render循環。無論何時修改了頂點的屬性,立方體都會基于修改后的值重新進行渲染。出于性能方面的考慮,Three.js認為組成網格的幾何體在整個生命周期內是不會改變的,而且對于大部分的幾何體而言,這個假設是成立的。為了使我們的示例工作,我們還需要在render循環中添加如下的代碼:在循環中的第一行,我們將組成網格的幾何體的vertices屬性值指向一個更新后的頂點數組。如果頂點數組vertices沒有更新,不需要重新配置這些面,因為它們仍然連接到原來的頂點。如果頂點被更新了,我們還需要告訴幾何體頂點需要更新,在代碼中是將verticesNeedUpdate屬性設置為true來實現這一點的,最后需要調用computeFaceNormals()方法來重新計算每個面,從而完成整個模型的更新。我們將要介紹的最后一個關于幾何體的函數是clone()。我們說過幾何體可以定義物體的形狀,添加相應的材質后就可以創建出能夠添加到場景中并由Three.js渲染的物體。通過clone()方法我們可以創建出幾何體對象的拷貝。為這些拷貝對象添加不同的材質,我們就可以創建出不同的網格對象。在示例05-custom-geometry.html里,你可以在控制界面的頂端看到一個clone按鈕。如圖2.9所示。圖2.9如果點擊clone按鈕就可以按照幾何體當前的狀態創建出一個拷貝,而且這個新對象被賦予了新的材質并被添加到場景中。實現這個功能的代碼是非常簡單的,但是由于我使用的材質導致代碼看起來有點復雜。首先我們先看一下綠色材質的實現代碼:如你所看到的,我們使用的不是一個材質,而是由兩個材質構成的數組。這樣做的原因是,除了顯示綠色透明的立方體外,我還想顯示一個線框。因為使用線框可以很容易地找出頂點和面的位置。當然,Three.js支持使用多種材質來創建網格。你可以使用SceneUtils.createMulti-MaterialObject()方法來達到這個目的。代碼如下所示:這個方法創建的并不是一個THREE.Mesh對象實例,而是為materials數組中每個指定的材質創建一個實例,并把這些實例存放在一個組里(THREE.Object3D對象)。你可以像使用場景中的對象那樣使用這個組,如添加網格、按名稱獲取對象等。如果要為這個組中所有的子對象添加陰影,我們可以這樣做:現在,我們繼續討論clone()函數:點擊clone按鈕,這段JavaScript代碼就會被調用。這里我們復制立方體的第一個子對象。請記住,mesh變量包含兩個THREE.Mesh子對象:基于兩個不同材質創建的。通過這個復制的幾何體我們創建了一個新的網格,并命名為mesh2。使用translate()方法移動這個新創建的網格,刪除之前的副本(如果存在)并把這個副本添加到場景中。在前面的章節中,我們使用THREE.SceneUtils對象的createMultiMaterialObject()方法為幾何體添加了線框。在Three.js中還可以使用THREE.WireframeGeometry來添加線框。假設有一個幾何體對象名為geom,可以通過下面代碼基于geom創建一個線框對象:然后,基于新建的線框對象創建一個Three.LineSegments對象并將它添加到場景中:最后便可以利用它來繪制線框了,并且還可以像下面代碼那樣設置線框的寬度:關于Three.js中幾何體的知識,我們暫時就學習到這里。2.2.2網格對象的屬性和方法我們已經知道,創建一個網格需要一個幾何體,以及一個或多個材質。當網格創建好之后,我們就可以將它添加到場景中并進行渲染。網格對象提供了幾個屬性用于改變它在場景中的位置和顯示效果。下面我們來看下網格對象提供的屬性和方法,具體見表2.3。表2.3我們同樣準備了一個示例,你可以修改這些屬性的值來感受下效果。當你在瀏覽器中打開示例06-mesh-properties.html時,可以看到一個下拉菜單。通過該下拉菜單你就可以修改屬性的值,并立即看到修改后的效果,如圖2.10所示。圖2.10下面來逐一講解這些屬性和方法,先從position屬性開始。通過這個屬性你可以設置對象在x、y和z軸的坐標。對象的位置是相對于它的父對象來說的,通常父對象就是添加該對象的場景,但有的時候可能是THREE.Object3D對象或其他THREE.Mesh對象。在第5章討論對象組合時我們再來討論這個問題。有三種方式用于設置對象的位置。第一種是直接設置坐標,代碼如下所示:也可以一次性地設置x、y和z坐標的值:還有第三種方式。position屬性是一個THREE.Vector3對象,這意味著我們可以像下面這樣設置該對象:效果圖如圖2.11所示。圖2.11但是如果現在移動該對象組,會發現其位移值保持不變。在第5章中我們還會深入討論這種父子關系,以及對象組是如何影響變換(如縮放、旋轉和平移)的。下一個我們將要介紹的是rotation(旋轉)屬性。在本章和前一章中我們已經多次使用這個屬性了,通過這個屬性可以設置對象繞軸的旋轉弧度。我們可以像設置position屬性那樣來設置rotation屬性。在數學上物體旋轉一周的弧度值為2π,所以可以用如下三種方式設置旋轉:如果想使用度數(0到360)來設置旋轉,那么需要對度數做如下轉換:你可以通過示例06-mesh-properties.html來體驗該屬性。屬性列表中還沒有討論的屬性是scale(縮放)。從名字我們就已經知道該屬性是用來做什么了。該屬性讓我們可以沿指定軸縮放對象。如果設置的縮放值小于1,那么物體就會縮小,如圖2.12所示。圖2.12如果設置的縮放值大于1,那么物體就會變大,如圖2.13所示。圖2.13在本章中將要繼續討論的是網格的translate()方法。使用translate()方法你可以改變對象的位置,但是該方法設置的不是物體的絕對位置,而是物體相對于當前位置的平移距離。假設在場景中有個球體,其位置為(1,2,3)。如果我們想讓這個對象相對于x軸平移4個單位:translateX(4),那么物體的位置就會變為(5,2,3)。如果我們想重置物體的位置為原來的位置,可以調用translateX(-4)。在示例06-mesh-properties.html中有個translate菜單項,通過這個菜單項你可以體驗這個功能。只要設置沿x、y和z軸方向的平移距離,然后點擊translate按鈕,你就可以看到物體依照這三個值平移到一個新的位置。最后一個可以使用的是菜單項右上角的visible屬性。當你點擊visible菜單項時,會發現立方體消失了,如圖2.14所示。圖2.14當你再次點擊visible按鈕時,立方體又再次出現了。在第5章和第7章中,我們還會進一步介紹網格和幾何體,以及如何使用這些對象。2.3選擇合適的攝像機Three.js庫提供了兩種不同的攝像機:正交投影攝像機和透視投影攝像機。在第3章中將會詳細介紹如何使用這些攝像機,所以在本章中只會介紹一些比較基礎的內容。值得注意的是,Three.js還提供了一些非常特殊的攝像機用于支持3D眼鏡和VR設備。由于它們與本章將要講述的基礎攝像機的工作方式類似,因此本文檔不會深入介紹這些特殊攝像機。如果你只需要簡單VR攝像機(即標準的立體視覺效果),可以使用THREE.StereoCamera將左右眼畫面并排渲染,或者也可以使用其他特殊攝像機渲染視差屏障式的(例如3DS提供的設備)3D圖像,或者是傳統的紅藍重疊式的3D圖像。此外,Three.js還實驗性地支持WebVR這一被瀏覽器廣泛支持的標準(更多信息請參考\h/developers/)。為了啟用這一支持,只需要設置renderer.vr.enabled=true;,后續工作Three.js會為你做好。在Three.js的官方網站可以找到有關這一屬性值以及其他WebVR相關特性的示例:\h/examples/。下面將會使用幾個示例來解釋正交投影攝像機和透視投影攝像機的不同之處。2.3.1正交投影攝像機和透視投影攝像機在本章的示例中有個名為07-both-cameras.html的例子。當你打開該示例時,會看到如圖2.15所示的結果。圖2.15這就是透視視圖,也是最自然的視圖。正如你所看到的,這些立方體距離攝像機越遠,它們就會被渲染得越小。如果我們使用另外一種攝像機——正交投影攝像機,對于同一個場景你將會看到如圖2.16所示的效果。使用正交投影攝像機的話,所有的立方體被渲染出來的尺寸都是一樣的,因為對象相對于攝像機的距離對渲染的結果是沒有影響的。這種攝像機通常被用于二維游戲中,比如《模擬城市4》和早期版本的《文明》。如圖2.17所示。圖2.16圖2.17在我們的示例中,大部分使用的是透視投影攝像機,因為這種攝像機的效果更貼近真實世界。在Three.js中改變攝像機是很簡單的,當你點擊07-both-cameras.html示例中的switchCamera按鈕時,下面的代碼將會被執行:THREE.PerspectiveCamera和THREE.OrthographicCamera的創建方法是不一樣的。首先我們先來看下THREE.PerspectiveCamera,該方法接受的參數如表2.4所示。表2.4這些屬性結合到一起影響你所看到的景象,如圖2.18所示。攝像機的fov屬性決定了橫向視場。基于aspect屬性,縱向視場也就相應地確定了。near屬性決定了近面距離,far屬性決定了遠面距離。近面距離和遠面距離之間的區域將會被渲染。圖2.18如果要配置正交投影攝像機,我們需要使用其他的一些屬性。由于正交投影攝像機渲染出的物體大小都是一樣的,所以它并不關心使用什么長寬比,或者以什么樣的視角來觀察場景。當使用正交投影攝像機時,你要定義的是一個需要被渲染的方塊區域。表2.5列出了正交投影攝像機相應的屬性。表2.5所有這些屬性可以總結為圖2.19。圖將攝像機聚焦在指定點上到目前為止,我們已經介紹了如何創建攝像機,以及各個參數的含義。在前面一章中,我們也講過攝像機需要放置在場景中的某個位置,以及攝像機能夠看到的區域將會被渲染。通常來說,攝像機會指向場景的中心,用坐標來表示就是position(0,0,0)。但是我們可以很容易地改變攝像機所指向的位置,代碼如下所示:在我們的示例中,攝像機是可以移動的,而且它所指向的位置標記一個紅點,如圖2.20所示。圖2.20如果你打開示例08-cameras-lookat.html,就會發現場景正從左向右移動。其實場景并沒有移動,而是攝像機從不同點(屏幕中央的紅點)拍攝場景,其帶來的效果就是場景從左向右移動。在該示例中,你還可以切換到正交投影攝像機;你會看到改變攝像機拍攝位置所帶來的效果和使用透視投影攝像機的效果是相同的。有意思的是,不管攝像機拍攝的位置如何改變,正交投影攝像機拍攝出來的所有立方體大小都是一樣的。如圖2.21所示。圖2.21當使用lookAt()方法時,可以在某個特定的位置設置攝像機。使用該方法還可以讓攝像機追隨場景中的某個物體。由于THREE.Mesh對象的位置都是THREE.Vector3對象,所以可以使用lookAt()方法使攝像機指向場景中特定的某個網格。你所需要做的就是輸入如下代碼:camera.lookAt(mesh.position)。如果在render循環中執行該代碼,你所看到的效果就是攝像機隨著物體的移動而移動。2.4總結在本章中我們介紹了THREE.Scene的所有屬性和方法,并解釋了如何使用這些屬性來配置主場景。我們還展示了如何使用THREE.Geometry對象或者使用Three.js內置的幾何體來創建幾何體。最后我們介紹了如何配置Three.js提供的兩種攝像機:透視投影攝像機使用接近真實世界的視角來渲染場景,而正交投影攝像機提供了一種在游戲中被廣泛采用的偽三維效果。我們還介紹了Three.js中的幾何體是如何工作的。現在你就可以很簡單地創建你自己的幾何體了。在下一章中,我們將會介紹Three.js庫提供的各種不同光源。你將會學到各種不同光源的行為,如何創建和配置這些光源,以及它們對特定材質的影響。第3章學習使用Three.js中的光源在第1章中,我們學習了Three.js的基礎知識,而在上一章,我們對場景中最重要的部分進行了一些深入的了解,包括幾何體、網格和攝像機。你可能已經注意到,盡管燈光也是場景中十分重要的一部分,但是在之前的章節中卻略過了。沒有光源,渲染的場景將不可見(除非你使用基礎材質或線框材質)。Three.js中包含大量的光源,每一個光源都有特別的用法,所以我們會用一整章來闡述不同光源的詳情,并為下一章材質的使用做準備。WebGL本身并不支持光源。如果不使用Three.js,則需要自己寫WebGL著色程序來模擬光源。查閱使用WebGL從頭開始模擬光源的推薦資料請訪問如下網址:\h/en-US/docs/Web/WebGL/Lighting_in_WebGL。在本章中你將學到以下幾個主題:·Three.js中可用的光源。·特定光源使用的時機。·如何調整和配置所有光源的行為。·簡單地介紹如何創建鏡頭光暈。在本文檔所有的章節中,有大量的示例可以用來試驗光源的行為。本章的示例代碼可以在提供的源碼的chapter-03文件夾中找到。3.1Three.js中不同種類的光源Three.js中有許多不同種類的光源,每種光源都有特別的行為和用法。在本章中,將討論表3.1中所列光源。表3.1本章主要分為兩部分內容。首先,我們先看一下基礎光源:THREE.AmbientLight、THREE.PointLight、THREE.SpotLight和THREE.DirectionalLight。所有這些光源都是基于THREE.Light對象擴展的,這個對象提供公用的功能。以上提到的光源都是簡單光源,只需一些簡單的配置即可,而且可用于創建大多數場景的光源。在第二部分,我們將會看到一些特殊用途的光源和效果:THREE.HemisphereLight、THREE.AreaLight和THREE.LensFlare。只有在十分特殊的情況下才會用到這些光源。3.2基礎光源我們將從最基本的THREE.AmbientLight光源開始。3.2.1THREE.AmbientLight在創建THREE.AmbientLight時,顏色將會應用到全局。該光源并沒有特別的來源方向,并且THREE.AmbientLight不會生成陰影。通常,不能將THREE.AmbientLight作為場景中唯一的光源,因為它會將場景中的所有物體渲染為相同的顏色,而不管是什么形狀。在使用其他光源(如THREE.SpotLight或THREE.DirectionalLight)的同時使用它,目的是弱化陰影或給場景添加一些額外的顏色。理解這點的最簡單方式就是查看chapter-03文件夾下的例子01-ambient-light.html。在這個例子里,可以使用一個簡單的用戶界面來修改添加到場景中的THREE.AmbientLight光源。請注意,在這個場景中,也使用了THREE.SpotLight光源來照亮物體并生成陰影。從如圖3.1所示的截圖里,你可以看到我們使用了第1章中的場景,并且THREE.AmbientLight的顏色和強度是可調的。在這個例子中,可以關閉聚光燈來查看只有THREE.AmbientLight光源的效果。圖3.1我們在這個場景中使用的標準顏色是#606008。這是該顏色的十六進制表示形式。前兩個值表示顏色的紅色部分,緊接著的兩個值表示綠色部分,而最后兩個值表示藍色部分。在該例的用戶界面中顯示的是顏色的十進制值。在這個例子里,我們使用一個非常暗淡的灰色,用來弱化網格對象在地面上生硬的投影。通過右上角的菜單,你可以將這個顏色改成比較明顯的黃橙色:rgb(190,190,41),這樣所有對象就會籠罩在類似陽光的光輝下,如圖3.2所示。圖3.2正如圖3.2所示,這個黃橙色應用到了所有的對象,并在整個場景中投下了一片橙色的光輝。使用這種光源時要記住:用色應該盡量保守。如果你指定的顏色過于明亮,那么你很快就會發現畫面的顏色過于飽和了。除了顏色之外,還可以為環境光設置強度值。這一參數決定了光源THREE.AmbientLight對場景中物體顏色的影響程度。如果將該參數調小,則光源對顏色的影響會很微弱。如果將該值調大,則整個場景會變得過于明亮。實際效果如圖3.3所示。圖3.3既然我們已經知道了THREE.AmbientLight光源能做什么,接下來學習如何創建和使用THREE.AmbientLight光源。下面幾行代碼展示了如何創建THREE.AmbientLight光源,以及如何將該光源與我們前幾章已見過的GUI控制菜單關聯起來。創建THREE.AmbientLight光源非常簡單。由于THREE.AmbientLight光源不需要指定位置并且會應用到全局,所以只需使用newTHREE.AmbientLight("#606008")來指定顏色(十六進制),并用scene.add(ambientLight)將此光源應用到整個場景。環境光類的構造函數還有一個可選參數intensity,用于指定光的強度。上面的代碼并沒有指定強度值,則該值使用默認值1。在這個例子里,將THREE.AmbientLight光源的顏色和強度綁定到控制菜單。為此,可以使用與前面章節相同的配置方法。唯一需要改變的是調用gui.addColor(…)函數而不是gui.add(…)函數。該方法會在控制菜單里添加一個選項,在這個選項里可以直接改變傳入的顏色變量。在代碼中,你可以看到我們使用了dat.GUI控制菜單的onChange功能:gui.addColor(…).onChange(function(e){…})。通過這個函數,我們告訴dat.GUI控制菜單在每次顏色改變的時候調用傳入的函數。對于本例來講,我們會在這個函數里將THREE.AmbientLight光源的顏色設置為一個新值。最后我們通過類似方法確保控制菜單中intensity選項的任何修改都會作用于場景中的環境光對象。使用THREE.Color對象在講述下一個光源之前,我們先簡單介紹一下THREE.Color對象。在Three.js中需要(例如為材質、燈光等)指定顏色時,可以使用THREE.Color對象,也可以像我們在設置環境光時所做的那樣,以一個字符串指定顏色。此時Three.js將基于該字符串自動創建一個THREE.Color對象。實際上Three,js在構造THREE.Color對象時非常靈活,它可以基于下面所列的任何一種方式來完成:·無參數構造:newTHREE.Color()這種構造形式會創建一個代表白顏色的對象。·十六進制數值:newTHREE.Color(0xababab)這種構造形式會將十六進制值轉換為顏色分量值并基于此構造顏色對象。這是最佳的顏色對象構造形式。·十六進制字符串:newTHREE.Color("#ababab"),此時Three.js會將字符串當作CSS顏色字符串去解釋,并構造顏色對象。·RGB字符串:顧名思義,這種構造形式需要為每個RGB分量指定亮度值,其具體形式可以是newTHREE.Color("rgb(255,0,0)")或者newTHREE.Color("rgb(100%,0%,0%)")。·顏色名稱:可以使用Three.js能夠識別的顏色名稱字符串,例如newTHREE.Color("skyblue")。·HSL字符串:如果相比RGB,你更熟悉HSL色域,也可
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 體育場所安全檢查AI應用行業深度調研及發展項目商業計劃書
- 2025年中國易拉罐裝封口機組市場調查研究報告
- 2025年中國插接式聚苯夾芯板墻板市場調查研究報告
- 法庭授權委托書
- 2025年中國彩芯螺絲批4支裝市場調查研究報告
- 2025年中國頭孢克洛干混懸劑市場調查研究報告
- 2025年湖北省武漢市外國語學校七下英語期中統考模擬試題含答案
- 2025年中國化纖連衣裙市場調查研究報告
- 2025年中國烏龜形按摩器市場調查研究報告
- 加拿大海外教育機構勞務合同及學生生活輔導協議
- 海鮮水產電商商業計劃書
- 托育轉讓合同協議書
- 2025江西中考:政治必背知識點
- 裝飾音在樂理考試中的應用試題及答案
- 購犬協議書范本
- 通信汛期安全生產課件
- 物業工程服務意識培訓
- 提高分級護理的巡視率
- 中國心力衰竭診斷和治療指南(2024)解讀
- 失重致血管細胞衰老和心臟代謝異常及干預策略的研究
- 醫藥采購管理技巧分享
評論
0/150
提交評論