本篇我們將完成圖中的地球畫面,從介紹貼圖開始。
B2C主要是行銷網站、企業形象網站、活動網站等等。有很多網站都會客製化地球,例如github.com首頁。
圖片來源
至於B2B,也會有地球的需求。主要是全球數位戰情室、航太科技、GIS畫面為主。
例如前端套件Cesium,就是以地球為主軸,提供快速建置視覺畫面的套件。
我以為這都是非常中二的東西,現實生活中不會出現,沒想到是我的上班業務範圍之一。
是這樣的,全球有很多大企業在全球設廠。若要能在全球監控各地工廠的生產情形,則以地球作為儀表板的主畫面是再完美不過的排場。全球戰情室並不是只有地球,但它是很重要的元素。
全球戰情室是有市場的,如果要成為前端3D視覺特效工程師,那個地球將是再好不過的作品與應用。
地球需要很多貼圖要素,是絕佳的實戰對象。除了顏色以外,還有高度,水面與陸地的光澤等等。本篇將透過地球來介紹貼圖的原理,以及實際運用。也會在日後的Shader介紹中留下基礎。
本篇會介紹貼圖原理,下一篇介紹地球實作,再下一篇將介紹前端互動。
貼圖在WebGL中,由vertexShader
與fragmentShader
共同打造。我這邊不多講,留著之後在「Day22: WebGL Shader—你好啊大哥哥,沒想到你可以到Shader來呢!」提到WebGL時再討論,但我嘗試解釋three.js之下的底層原理。
有先,要有一張材質圖跟貼圖的模型。
模型有錨點。
假設世界地圖是一張大型貼紙,那我們應該如何剪裁這張貼紙並貼到模型呢?最簡單粗暴的方式就是展開模型,對應到貼紙上,接著剪裁貼紙。
那這就表示,我們要先「記住」每一個錨點,應該對應到貼紙的哪裡。要如何「記住」這件事情呢?那就是把錨點的位置存在RAM中,而這個位置資訊是一個(X,Y)的座標。
所以說,錨點在3D空間中,除了有一個(X,Y,Z)座標以外,還有貼圖位置的(X,Y)座標了。早期的工程師發現有兩種(X,Y)系統會讓人搞混。
例如你同事告訴你X位置不對,到底是(X,Y,Z)中的X位置不對,還是(X,Y)中的X不對啊?為了分清楚這兩個東西,早期的工程師就稱貼圖的(X,Y)為(U,V)了,其實就是二維座標位置的意思。
總之,webGL得展開錨點,記住了所有錨點的UV位置。
你有很多方法可以展開錨點,這個動作就是拆UV,通常是在3D建模軟體拆,例如Maya, 3Ds Max, Blender等等,這是另一門學問。
附圖為Maya的UV Editor
順帶一提:展開錨點的方式很多,這都看拆UV的人是怎麼拆的。
WebGL現在知道錨點的UV位置,我們把焦點放回3D空間中。錨點既然知道自己對應到貼圖的哪個位置,接下來該怎麼辦呢?
先退回來補充:WebGL有兩種渲染器,一種是vertexShader
,每一個錨點會執行一次,另一種是fragmentShader
,每一個像素會執行一次。前面這些對應UV的步驟都由vertexShader
處理,接下來計算像素顏色的工作,由fragmentShader
處理。
附圖是fragmentShader
依據vertexShader
的錨點資料產生顏色的示意圖。
fragmentShader
每一個像素執行一次,一幀大約執行兩百萬次(1920x1280螢幕的話),當執行時,它可以找出該像素在錨點中的對應位置。假如說好了,現在執行的是側面中央偏下的像素,如下圖:
我們換這張圖表示:
那個就可以對應到UV座標的某處。
接著,「採樣」貼圖,計算出自己應該要呈現的顏色,呈現在螢幕中。
我們得到藍色,所以得知該像素應該呈現藍色。
依照這個邏輯,就可以把貼圖成現在模型上了。
由於以上的過程都經由GPU計算。早期的工程師,透過GPU,很輕鬆的就實現貼圖。
由於GPU實在太香了。我們上一次提到:錨點的運算很消耗計算資源,如果能減少錨點,並且用貼圖來取代建模的工作,就可以減少很多計算資源。
所以又衍生了各種除了RGBA顏色以外的貼圖,以下介紹:
用在哪裡?
上一篇提到,所有光源對物體的投影原理。然而在這個概念模型下,仍然不夠美術去控制光的細節。例如說:為了美術需要,3D場景中人物角色的「事業線」應該要再深一點(舉例啦)。透過這個貼圖,可以讓事業線不要那麼吸光,看起來就比較暗。
舉例說明
或是像下圖一樣減少臉頰的吸光。下圖是取自unity對AO Map的描述。實際上AO Map出現在很多地方,不是three.js專屬。每家的實際演算法也許不同,但道理是相同的。
又或者看下面的例子。物件的陰影被加深了。左邊是加上AO,右邊是沒有AO的成果。
概念
為通常「Light Backing」技術的貼圖。概念是:把光亮度儲存在材質圖上面。於是不用打光,也可以知道物體應該要多亮。
這是遊戲開發過程中很重要的用途,而three.js也有這樣的map操作。只可惜GLTF檔不支援lightmap,所以lightmap這部分需要額外處理。
下圖的完全沒有光源,一切都是光線映射貼圖踢出來的亮度。
原理
上一篇提到,點光反射時,會依照其內積的結果,作為光的強度。如果可以拿一個計算方式,去強化亮度的對比,那就可以呈現個亮晶晶的效果。
通常跟光滑貼圖合併運用。
金屬跟光滑搭配會有不同效果,下圖為three.js的金屬、光滑材質球分佈圖。最左邊那欄光滑程度是0,最右邊那欄光滑程度是1。最上面那列金屬程度是1,最下面那列金屬程度是0。這樣的分布能以下圖呈現:
基本上就是拿環境的畫面,將畫面貼在自己身上,形成反射的效果。這個效果對於視覺特效非常好用,在後續也會有專題介紹。
拿一張黑白圖片來使物件隆起。錨點會去採樣顏色——採樣到白色代表錨點應該隆起,採樣到黑色代表錨點不該隆起。如此一來,不需要自己建模,也可以讓貼圖幫你建模。
用途通常是製作地形的時候居多。
這種貼圖跟其他貼圖不太一樣的地方是:其他貼圖可以節省錨點的運用,但這種貼圖是基於錨點的。也就是說,如果錨點密度不夠,則高度的解析度也會不夠。
這貼圖修改了每一個像素反射光的法線。
分兩種:Bump貼圖與Normal貼圖。
Bump用黑白呈現視覺上隆起的程度,Normal用RGB傾斜法線。Bump如果套用在地球上,就會像這樣:
Bump Map比較好理解,至於Normal Map我用以下幾步驟來說明:
假設有一道平行光照在平面上
我們從中間用剖面圖來觀察平面。平面有光,它跟法線的內積結果假設都是0.6好了。
現在有一個normal貼圖長這樣:內含RGB通道,R越多代表法線向正X歪越多;G越多代表法線向正Y歪越多;B越多代表法線向正Z歪越多。
它改變了法線的方向。
法線方向改變了,它跟光方向的計算結果也改變了,最後造成亮度的計算結果呈現了變化。圖中,左邊兩塊因為法線接近光的方向,使得內積計算結果增加。右邊兩塊因為法線遠離光的方向,所以計算結果減少。
最後,我們看起來它就像是立體的,但實際上只是一個平面。
Normal要小心使用。一旦鏡頭視角太傾斜,Normal貼圖還是會出現破綻的
我們釐清了貼圖的原理
貼圖有很多種,包含:
將上面的貼圖實作到地球上,並且review程式碼。屆時將能夠產出自己的地球,就像文章一開始的預覽圖一樣。