科普:零基礎了解3D遊戲開發

  • 2019 年 11 月 12 日
  • 筆記

學習最大的障礙就是未知,比如十八般兵器放在你面前都認不出來,又談何馳騁沙場。更何況3D遊戲開發本就是一個門檻不低的工作。本篇拋開引擎的結構,本着初次認知3D遊戲世界的邏輯,讓沒有3D基礎的開發者,通過本篇文章,對LayaAir 3D引擎的基礎功能以及3D基礎概念有一個概覽性認識。

至少,我們要了解3D世界的基礎都有哪些,然後再依據官方的文檔逐個深入學習掌握。

另外,本篇不僅對於有意3D遊戲開發的朋友有啟蒙入門的作用,即使是遊戲行業的非技術崗位工作者,也有着基礎概念的名詞科普作用。哪怕沒有任何開發基礎,讀完本篇也可以對3D遊戲開發有一個基礎的認知,對一些專業性名詞有一些理解,與3D遊戲研發工作者交流的時候,不再被當成技術文盲,可減少交流障礙。

一、場景與攝像機

場景就是遊戲中的3D世界,有了場景,才可以在場景中添加一切物體,包括攝像機。

而攝像機相當於3D遊戲世界的眼睛,通過攝像機,玩家才能看到遊戲中三維世界,看到場景中的各種物體。

所以,場景里最少要有一台攝像機。

當我們在寫3D遊戲的代碼時,要先在舞台中添加3D場景,添加3D攝像機。再寫其它代碼。

攝像機在3D場景中,可以是唯一的,也可以放置多台攝像機,比如在3D場景中出現的彈窗換裝面板,或者某些對戰遊戲的同屏需求時會用到多個攝像機。

這裡再順便提一下,攝像機成相效果,也分為透視和正交兩種。LayaAir引擎的3D攝像機默認是透視模式,這是一種模擬了人眼的視覺效果,近大遠小。

正交則沒有透視感,常用於一些2D與3D混合的遊戲或模型查看器等。

二、坐標系與坐標

坐標是3D空間世界的基礎之一,幹啥都離不開坐標,移動攝像機,定位,繪製圖形等等。

在學習LayaAir 3D時,我們需要了解兩個坐標,一個是位置坐標,另一個是UV坐標。

而了解這兩種坐標之前,我們先介紹一下空間笛卡爾直角坐標系。

空間笛卡爾直角坐標系是用經過相同原點的xyz三條互相垂直的坐標軸相交而構成。

坐標系的兩個軸正方向一致的情況下,因第三軸正方向相反,所以將坐標系分為左手坐標系與右手坐標系。

這兩種坐標系沒有好或不好,都應用的都比較廣泛,比如Unity等引擎採用的是左手坐標系,LayaAir等引擎採用的是右手坐標系。所以我們有必要理解什麼是左手坐標系與右手坐標系,以及兩者的區別。

兩種3D坐標系之所以用左右手分別命名,是為了便於記憶,分別用左手和右手三根手指的朝向,來代表三個坐標軸的正方向,這三個手指分別是拇指、食指、中指。

無論是左手還是右手,我們要記住,大拇指朝向的方向是x軸正方向,食指的朝向是y軸的正方向,中指的朝向是z軸的正方向。

現在我們面向屏幕,準備好雙手來擺造型。先將左右兩個手的食指(y軸)指向天空方向(在房間的就指天花板),然後將中指(z軸)沖前(立正站立時眼睛平視的方向),此時兩個手的中指應該都與食指保持90度垂直。然後,再伸出大拇指(x軸)與食指和中指都保持90度垂直。可以參照下圖手勢。

網絡中有不同的左右手坐標系統的說法和介紹,如果圖片和軸朝向與本篇介紹的不同,一般也都是攝像機角度的差異,不用管別的,學習LayaAir以本篇為準來理解記憶即可。

擺好後,我們會發現,在保持z軸和y軸正方向相同的情況下,x軸的正方向是相反的。這就是左手坐標系和右手坐標系的區別。LayaAir引擎unity導出插件就是以x軸取反來自動適配LayaAir引擎。所以,直接在unity里編輯導出,然後在LayaAir引擎中使用,是不需要手工對坐標進行轉換的。如果開發者一定要在LayaAir引擎項目中手動來調坐標,那需要注意左手坐標系與右手坐標系在x軸正方向的差異。

了解完坐標系,我們了解一下頂點。頂點可以理解為3D空間中的任意一個帶xyz坐標的位置點,但頂點不僅包含了坐標位置信息,還有UV、法線、顏色等信息。其它的先不講,我們繼續來了解UV。

UV其實也是坐標, 完整的說應該是UVW(由於xyz已經被頂點坐標軸佔用,所以另選三個字母表示), 這三個軸U是屏幕水平方向,V是屏幕垂直方向,W的方向是垂直於顯示器表面的,到目前為止,一般遊戲開發是用不上的,所以我們通常就會簡稱為UV。

去掉了W,那UV坐標就是一個2D平面坐標,UV坐標可用於模型紋理貼圖等(後面介紹紋理的時候還會提及)。

UV坐標的貼圖紋理向右和向下分別是U與V的坐標正方向。取值範圍是0-1,不管紋理圖片的像素是多少,3D美術製作軟件導出的模型頂點數據都會對應貼圖紋理的UV坐標,以保障渲染時的採樣正確。

相對於UV坐標最終會對應貼圖紋理上的像素點,頂點坐標則沒有恆定的計量單位,最小的單位是點,無論是現實世界還是3D世界,點都是一個基礎的抽象概念,他代表着一個單獨的個體,可以無限大,也可以無限小。所以,點可以是1個像素,也可以是1毫米、1納米、1千米等任意單位的基礎單元。最終頂點之間用什麼計量單位,通常由3D美術結合遊戲設計而設定,3D遊戲美術用的比較多的單位是米。所以程序的設定要與美術設定的單位保持統一,否則就會造成視覺效果上的過大或過小,出現與設計不符的效果。

三、三角面、網格、模型

模型是3D遊戲中可見物的基礎,比如人物,房屋,樹木,山川,河流等等,幾乎絕大多數可見物體都是以模型為基礎構成。

要進一步了解模型,我們先從三角形平面(簡稱三角面)開始,三角面是由三個頂點構成,是顯卡唯一能處理的基礎多邊形。之所以把三角面視為最基本的多邊形,其中一個重要原因是,由三個點構成的三角面一定是在同一個平面上,而四個或更多點構成的多邊形在三維空間中,不一定會在同一個平面上。

而網格( Mesh)則是由一個三角面或多個三角面拼接形成,是構建模型形狀的基礎。在LayaAir引擎中, 構成各種圖形形狀的三角面頂點數據以及三角面的索引數據集合就是網格,所以網格在遊戲運行時是不可見的,下圖是使用像素線精靈來表現模型的網格構成。

模型是由網格( Mesh)與材質( Material)組成。材質展開內容太多,先放一邊。從構成三維圖形形狀而言,我們可以理清以下關係,模型的基礎是網格,網格的基礎是三角面。三角面越多,模型可表現的細節越豐富。下圖正是40000面和4000面及400面的模型細節表現差異。細節表現比較豐富的,通常被稱為精模,細節表現相對較弱的,被稱為簡模。

到底使用精模還是簡模,這需要研發技術結合整體效果和遊戲硬件性能可承受的壓力情況向美術提出需求,在這一點上,移動端H5及小遊戲與手游APP標準可保持相等標準。

四、材質

之前講過,網格只是三維形狀的數據,網格形狀本身是不可見的。怎麼可見,那就需要材質( Material)了。

顧名思義,材質就是材料的質感。例如,木頭與金屬、玻璃與毛髮,從粗糙度、光澤度、反射、透明、顏色、紋理等等方面,不同的材料質感會明顯不同。

根據這些物體的差異,我們可以將材質劃分為很多種類,LayaAir引擎支持的材質分類為模型材質、天空材質、拖尾材質、粒子材質。(天空、拖尾、粒子尚未提及,我們先介紹模型材質。)

LayaAir引擎的模型材質還可以繼續劃分,分別為:

光照材質(BlinnPhongMaterial) 、

不受光材質(UnlitMaterial)、

特效材質(EffectMaterail)、

PBR標準材質(PBRStandardMaterial) 、

PBR高光材質(PBRSpecularMaterial) 、

水材質(WaterPrimaryMaterial)。

BlinnPhong材質是默認使用的標準感光材質,而UnlitMaterial材質恰恰相反,並不受光照影響,只顯示原貼圖的外觀圖像效果。

下圖中,圖左是光照材質( BlinnPhongMaterial)被光照射後的效果。圖右是同樣被光照射後的不受光材質( UnlitMaterial )效果。

特效材質(EffectMaterail) 是一種無需外部光照,通過混合模式讓自身產生一種光效視覺效果的材質,常用於特殊效果的製作,所以稱為特效材質。視覺效果如下圖所示。

PBR材質是一種基於物理渲染 (Physicallly Based Rendering) 的材質,通過模擬自然界的物理規律可以讓3D模型的質感更為真實,接近或還原現實世界中的質感。例如,下圖中的桶採用了PBR材質。

LayaAir引擎中,PBR材質主要分兩類,分別是PBR標準材質(PBRStandardMaterial)和PBR高光材質(PBRSpecularMaterial) 。PBR標準材質是金屬流的PBR材質表達,PBR高光材質是高光流的PBR材質表達。

水材質(WaterPrimaryMaterial)比較容易理解,是一種可以設置水面反射與波紋等具有水特性屬性的材質。如下圖所示:

五、紋理、貼圖、面片

紋理是指物體表面的外觀效果,表現為2D位圖形式。下圖為3D地球儀錶面的紋理。

貼圖簡單通俗的理解,就是將2D紋理貼到3D模型網格的過程。這個將3D頂點坐標與2D紋理的UV坐標映射對應的過程由引擎完成,開發者直接調用API,為材質設置對應的紋理即可。下圖左側為僅添加材質,而沒有設置貼圖的效果。下圖右側是對材質添加了紋理的已貼圖效果。

通過效果圖我們可以看出,儘管網格與材質已經可以讓模型在3D遊戲場景中可見了,但不對材質貼圖,沒有紋理的情況下,我們看到的只是不同質感的純色模型。有了紋理才有了真實豐富的外觀。所以紋理也是比較重要的一個知識點,如果展開講,紋理可以介紹很多。本篇不再詳述。

介紹到這裡,我們已能初步理解到紋理與貼圖的區別。然而,是很多時候,在文檔或口述交流的時候,很多人會把用於貼圖的紋理,也簡稱為貼圖。所以我們應該能理解到貼圖在某些應用場景下就是代指紋理。

之所以把面片放到紋理一起介紹,是因為對3D一知半解時,不少人會有一個誤區,認為面片就是在3D空間中放了一個2D紋理位圖。實際上,在三維空間中,哪怕只有一個三角形平面,也可以構成網格,可以設置材質,那這就是模型。所以面片,與其它多面體模型,本質上都是一樣的。在下圖中,我們在3D空間中看到的草地圖片,其實是這個草地面片材質的貼圖。

六、燈光、陰影、反射光

光源是3D場景中不可缺少的重要組成部分,網格和紋理決定了物體的形狀和外觀,光源則可以照明、可以產生陰影、還可以影響場景環境以及3D模型的顏色、亮度、氛圍等等。

3D中的光源就是燈光,其它如泛光、環境光等都是光效,而非光源。3D燈光有三種, 平行光(DirectionLight),點光(PointLight),聚光(SpotLight),LayaAir引擎不僅支持這些光源的任意類型,還支持在同一場景下任意添加多個不同類型的光源。下面簡單介紹一下這三種光的區別。

平行光是一種模擬大自然太陽光的燈光,光源來自無窮遠的位置,來自光源的光線始終都是平行的且沒有衰減。引擎中可設定光源方向,用於給全場景照亮。

點光是一種以光源點為中心,向四周呈發射狀的光源,光源點位於3D空間中的某個位置。類似於現實中的蠟燭光、篝火、家用電燈等發光的方式,這種光擁有照射範圍和衰減半徑。光照範圍之外的地方則處於無光的黑暗之中。

聚光與點光類似,都屬於位置光,也是位於3D空間的某個位置,也有照射範圍和衰減半徑,但是,與向四周發散的無方向點光不同,聚光則擁有光源方向,是一種呈錐形角度的光源,類似於現實中的手電洞、舞台聚光燈等光源效果。

陰影是燈光照射模型時產生的, 實時陰影隨着燈光角度、燈光強度、模型位置等變化而變化。能產生更加強烈的立體感與真實感。

反射光,是指光源在照射到3D模型上,反射產生的光效。為了模擬自然反射現象,根據不同材質,引擎對反射光會使用不同的光照模型,比如,BlinnPhong材質中使用了漫反射和鏡面反射模型。我們簡單來理解一下兩者的差異。

引擎中的漫反射主要是模擬材質表面粗糙不平的光學反射效果,理想的漫反射材質表面是完全不光滑且沒有光澤的,當光源照射到這種材質上,呈現出發散的反射效果。

引擎中的鏡面反射用於模擬光滑水平面的光學反射效果,是一種有方向反射,其反射方向以反射平面的法線為中心與入射方向的夾角對等。理想的高光反射材質是表面完全光滑的,比如像鏡子一樣。鏡面反射常用於閃閃發光的視覺效果,且會產生高亮的點狀光斑,所以鏡面反射有的時候也叫鏡面高光,如果LayaAir文檔材質篇中提到高光顏色或者高光貼圖,我們要能理解,這是指針對鏡面反射效果的高光顏色和高光貼圖。

基於漫反射和鏡面反射的光學現象,引擎中使用了多個光照模型,用於模擬自然光中的反射現象。本篇先揭開一點。暫且先有一個初步的認知。我們繼續來了解一些其它與光相關的概念。

七、加色法、環境光、泛光、光照貼圖

上一小節是介紹的3D燈光以及與燈光息息相關的光效。這個小節還是介紹光,但這些光不屬於照射光,只是看起來比較像是光的一些效果。我們將逐個了解LayaAir引擎中的一些其它光效。

首先是加色法光效,加色法光效可以讓材質本身就會有發光的效果,這是一種通過加色法模擬出來的光感,並非是受光照產生,比如前文中介紹過的特效材質。這種的自發光效果不會對周圍環境及其它模型產生影響,但會被背影色影響。

環境光類似於全局顏色濾鏡。設置白色等亮色,即便沒有光源,場景中也都能比較明亮。想表現陰天的感覺,也可以加入一些灰暗的環境光顏色。或者要表現夜視鏡效果等等,都可以通過環境光來設置。

泛光在LayaAir引擎中屬於後期效果。即便沒有光源的照射,也可以產生一種類似光暈疊加的效果。

光照貼圖是一種通過貼圖的方式模擬遊戲場景中的光影效果,也是遊戲中為了節省性能而常用的一種偽光照視覺效果的製作方式。下圖中的光效並非是通過燈光實現,是光照貼圖的效果。

八、Shader(着色器)

Shader 中文名為著色器, Shader本質上是一段採用GLSL着色語言編寫(着色語言好幾種,基於webGL只能用GLSL語言)在GPU上運行的程序 ,用於告訴圖形軟件如何計算和輸出圖像。Shader主要分兩類:頂點着色器和片段着色器(也叫片元着色器) 。

頂點着色器是用來處理頂點數據的程序,如頂點坐標、法線、顏色和紋理坐標。 它在每個頂點上調用,可將幾何圖形(例如:三角形)從一個位置轉換為另一個位置, 例如,用於頂點變換、紋理坐標生成、 紋理坐標變換等等。

片段着色器用來計算和填充每個像素的顏色,所以也稱為像素着色器。可用於插值的運算、 紋理存取、紋理應用 、 霧 、 色彩計算等。

LayaAir提供了自定義Shader功能,可以讓開發者實現一些引擎未曾提供的功能或者效果。Shader的實現有一定的門檻,新手先不要急着研究這個,先有個基礎的認知即可。

九、天空、粒子、拖尾

基於網格與材質組成了模型這一概念,理論上一切可見的形狀物體,都是模型。但依據開發的易用性,引擎會進一步對一些常用功能進行封裝,本節將繼續描述這些概念,比如天空、粒子系統、拖尾系統。

LayaAir模擬的3D天空,提供了兩種現成的網格,一種是立方體網格,這種天空稱為天空盒( SkyBox)。另一種是球形網格( SkyDome ),這種可稱為天空球或球形天空,當然,開發者也可以自定義其它的天空網格。

基於立方體網格的天空, 以6張無縫連接的材質紋理貼圖形成,類似盒子拆開平鋪。例如下圖的紋理,

球形網格的天空則採用1張紋理貼圖形成,該技術方案相較於天空盒,可以製作出完全相同的視覺效果,但球形網格的頂點要多於天空盒,性能的消耗自然要大一些。如果只有一張貼圖紋理的可以採用天空球的技術方案,否則建議採用天空盒方案。

另外,兩種3D天空技術方案的使用差別也與材質有關,LayaAir引擎中自帶了一個對應天空盒網格的天空盒材質(SkyBoxMaterial)、而天空球要麼使用不需要貼圖的程序化天空材質(SkyProceduralMaterial),要麼就使用模型材質,因為天空不受光照影響,最好使用不受光材質。

粒子是一組分散的微小物體集合,通過讓這些微小的物體按某種算法運動起來,從而實現諸如火焰、煙、爆炸、流水、等比較靈動的效果。粒子系統並不是一種繪製形式,而是一種動畫方法,粒子系統的作用是在粒子產生、運動、變化以及消失這個生命周期內去控制它們。LayaAir引擎的粒子系統包括了粒子發射器、粒子動畫器、和粒子渲染器等多個部分。

拖尾,顧名思義是拖在後面尾巴一樣的效果,常用於帶條狀3D特效,比如,刀光拖尾,跑酷小球遊戲的行動軌跡拖尾等。LayaAir引擎內置了拖尾系統和拖尾材質,方便開發者快捷使用3D拖尾。

十、3D物理系統、3D動畫系統

3D物理系統是通過模擬真實物理屬性的方式來計算重力、運動、旋轉、碰撞反饋等,LayaAir引擎內置了bullet 3D物理引擎。官網中有詳細的學習文檔。

動畫是交互式遊戲不可缺少的組成部分。LayaAir引擎中支持使用材質動畫,剛體動畫,攝像機動畫,骨骼動畫這幾種動畫類型。

其中,材質動畫是以改變材質的顏色與貼圖方式的動畫。

剛體動畫又稱為變換動畫,是指不改變模型頂點、材質的基礎上,只對模型進行旋轉、縮放、位移的動畫,比如,腳底光環、刀光等。剛體動畫也經常與材質動畫結合使用。

骨骼動畫也稱為蒙皮動畫,這種動畫主要是以改變模型頂點的方式產生動畫。

攝像機動畫是指通過改變攝像機位置而產生的動畫效果。

十一、3D基礎的常用數學概念

在之前的10個小節中,我們已經可以對3D遊戲和圖形開發,有了一個基礎的概念性認知。最後簡單介紹一些3D數學的基礎常用概念。例如:向量、 矩陣、 歐拉角、四元數、射線、包圍體。

1、向量

既有大小又有方向的量稱之為向量(物理學叫矢量),向量也有維度,例如,2維、3維、4維。與向量對應的是數量(物理學叫標量),數量是只有大小沒有方向的量。有的文章把數量理解為1維向量,而我們通常所指的向量是2維或以上維度,不包括1維。

在LayaAir引擎中,針對2維、3維、4維向量的封裝方法示例分別為:Vector2(1, 2) 、Vector3(1, 1, 3)、Vector4(1, 2, 3, 0.5) 。然而LayaAir引擎封裝的Vector方法,不僅可以作為向量的使用,還可以用於頂點坐標位置,或者表達顏色的時候使用。比如原點坐標Vector3(0, 0, 0),顏色值Vector3 (0.6, 0.6, 0.6) 、Vector4(0.9, 0.5, 0.1, 1)。

提到向量,再順帶理解一下分量,我們把一個向量分解成幾個方向的向量之和,那這些分解的向量就叫做該向量的分量(也稱為向量投影)。例如,某個向量坐標u為(5,10),那分解的向量坐標w1(5,0)和w2(0,10)都是向量坐標u的分量。在引擎中,我們也可以把向量元素視為分量,比如 Vector3( 0.6, 0.6, 0.5) ,有3個分量,其中的0.5稱為這個向量的第3個分量。

2、 矩陣

在線性代數中,矩陣是以行和列形式組織的矩形數字塊。如果把向量定義為1維數組,那麼矩陣就是2維數組。這裡不要把2維理解為2D,是指來自數組的行與列形成2維。以數組的角度去理解,那向量是數量的數組,矩陣則是向量的數組。

矩陣是在顯卡圖形API中直接用於描述方位的形式,可立即進行向量的旋轉。LayaAir引擎提供了3×3的旋轉矩陣Matrix3x3() 和4×4的變換矩陣Matrix4x4(),變換矩陣可用於平移、旋轉、縮放計算。

3、歐拉角、四元數

歐拉角與四元數都是用於旋轉計算的數學方法,剛剛介紹的矩陣明明也可以用於旋轉計算,為什麼要介紹這兩種呢?相對而言,3×3旋轉矩陣需要9個數,歐拉角只需3個數(3維向量),四元數只需要4個數(4維向量),明顯輕量了很多。那是不是歐拉角最優,也不盡然。儘管歐拉角內存佔用小,也更加易用,但歐拉角也有他特有的問題,那就是可能會導致萬向節死鎖。而四元數則相對於矩陣內存佔用小,也不受萬向節死鎖的困擾,而且在平滑插值方面只能是四元數才能完成。

4、射線

射線是只有一個端點無限延長形成的直的線,在LayaAir引擎中的射線 Ray是一個數據對象,擁有起點與發射方向兩個屬性。常用於基礎的碰撞檢測,也可以用於鼠標拾取。

5、包圍體

包圍體用於可見檢測計算,基本思想是體積稍大且結構簡單的包圍體來替代結構複雜的被包圍體,當進行檢測的時候,達到提高檢測效率的作用。比如,一旦檢測到包圍體被遮擋不可見,那無論包圍體內是什麼樣的模型,那全部不可見。LayaAir引擎中提供了盒狀包圍體( 包圍盒 )與球狀包圍體(包圍球)。

寫在最後

LayaAir在引擎官網中已經提供了大量的引擎文檔,尤其是3D文檔,示例DEMO,和API說明文檔。然而還是會碰到一些開發者在學習3D的時候無從下手,因此產生了本篇這個更為基礎的入門文檔,應該已經覆蓋了大多數基礎概念。希望大家在此文啟蒙性認知上,進一步學習引擎的使用,以及從本文中涉及到的未能充分理解的概念有針對性的深入研究學習。

本文僅作為一個基礎入門的文檔,儘可能去多覆蓋一些基礎概念,然而文檔寫作的過程中為了保持寫作邏輯的延續,對於一些基礎概念並沒有完全都介紹全面,比如法線、八叉樹、齊次坐標等概念並未講到。開發者可以在官網文檔的學習過程中,如果遇到一些陌生的詞語,儘可能先購買基礎的圖形學書籍或者在搜索引擎中找到適合的文章來補補課。也可以找到官網中QQ群管理員進行反饋,我們會針對引擎使用的文檔進行補充和完善。