2022-1-23 資深UI設計者
設計師需求中 3D 視覺平移到互動 H5 中的項目越來越多,three.js 和 PBR 工作流的結合卻一直沒有被系統化地整理。
和各位前端神仙一起做項目,也一起磕磕碰碰出了愛與痛的領悟。小小總結,希望 3D 去往 H5 的道路天塹變通途。
本手冊主要分為兩大部分:
Part 1 理論篇:主要讓設計師了解計算機到底是如何理解和實時渲染我們設計的 3D 項目,以及 three.js 材質和預期材質的對應關系。
Part 2 實踐篇:基于 three.js 的實現性,提供場景、材質貼圖的制作思路、以及 gltf 工作流,并動態討論項目常常遇到的還原問題。
本文主要面向剛接觸 3D 圖形學的設計師,僅截取了最常用的理論知識和大家一起學習;部分涉及技術美術或計算機圖形學的描述可能不甚嚴謹,希望大家多多交流討論哈。
其實無論 H5 開發用到的是哪種 webGL,設計相關的材質制作基本還是基于 PBR 思路進行的,所以這邊建議各位親可以先去閱讀一下 Substance 官方寶冊《The PBR Guide》。
設計師在還原 3D 類型的互動 H5 項目的時候一定想過這個宇宙終極問題:為什么 H5/Web 實現的 3D 效果和 C4D 里渲染出來的差異那么大?
其實這是我們對實時渲染引擎(UE、Unity、three.js 等)和離線渲染工具(Redshift、Octane、Vray 等)的差異存在誤解:一是離線渲染工具是基于真實光照環境來計算每顆像素的著色,實時渲染如果要實現這種效果需要耗費更多硬件基礎和算力去模擬光照(沒個好顯卡都開不動光追)。
雖然 UE5 的實時渲染技術和硬件兼容性已經讓大家大吃一驚,但在實際項目,尤其是需要兼容低端設備的 H5 來說,渲染能力還是相對有限的。二是對于游戲或 H5 互動網站實際應用來說,流暢的互動體驗優先級往往高于畫面精細度,所以犧牲視覺保性能也是常見情況。
圖 1-Octane 離線渲染效果 vs three.js 實時渲染效果:材質細節、全局光照及投影、以及抗鋸齒表現差距明顯
當實時渲染效果與設計預期差距過大時,設計師能多了解一些基礎的計算機圖形學,也許就能更好地和開發同學商討性價比更高的視覺實現和資源優化方案(以及更多 Battle 的籌碼)。
首先我們要知道計算機之所以能在 2D 屏幕上畫出 3D 的圖像,是因為有著色器(Shader)在繪制,它將我們三維空間里的模型與光照信息進行轉換,并光柵化為二維圖像。在計算機圖形學中,著色器是用于對圖像的材質(光照、亮度、顏色)進行處理的程式。
常用的著色器分為四種:像素/片元著色器(Pixel/Fragment Shader)、頂點著色器(Vertex Shader)、幾何著色器(Geometry Shader)、細分曲面著色器(Tessellation Shader)。
像素/片元著色器與頂點著色器(Vertex Shader)在 webGL 處理過程中都有使用,頂點著色器先將模型中每個頂點的位置、紋理坐標、顏色等信息進行轉換裝配,再由片元著色器對 3D 信息光柵化并轉換成 2D 屏幕信息。(關于著色器差異,感興趣的同學可以直接跳到附錄查看。)
著色器是怎么把頂點中所帶有光照、紋理等信息轉換并重建在二維圖像的像素中呢?GPU 中是透過不同的著色算法來實現的。
一種是獲取每個三角形的插值(Interpolate)來實現,這種方法稱作 Per Vertex Lighting,但是當三角型很大的時候,插值往往不夠精準。此時還可以引用另一種方法 Per Pixel Lighting,計算每個像素的光照信息,獲得更好的渲染效果,但是往往也帶來更大的計算量。
一般常見計算機圖形著色算法有三類:Flat Shading、Gouraud Shading、Phong Shading。這些算法雖然看起來和我們設計師沒啥關系,但事實上在后面了解 three.js 材質時,就會發現他們在呈現時的差異。
圖 2-Flat、Gouraud、Blinn-Phong 著色法比較 [ F1, ©?Stefano Scheggi ]
平直著色法 Flat Shading
這種著色法認為模型中所有面都是平的,同一個多邊形上的任意點的法線方向都相同。著色時,會優先選擇多邊形的第一個頂點或三角形的幾何中心計算顏色。這種著色法實踐上的效果很像低面模型,也比較適合使用在高速渲染的場景。值得注意的是,這種著色法難以做出平滑高光效果。
高洛德平滑著色法 Gouraud Shading
這是一種平滑的著色方法,在著色時會先計算三角形每個頂點的光照特性,利用雙線插值去補齊三角形區域內其他像素的顏色。這個著色法比起平直著色法增加了插值的細節,而且也比 Phong 著色法渲染單個像素的光照特性的性能要高。
但是在渲染高光時,可能會因為無法獲取精確的光照值而出現一些不自然的過渡(或 T 型連接容易被錯誤繪制),此時可以考慮對模型進行細分或使用漫反射材質。
Phong 平滑著色法 Phong Shading
與 Gouraud Shading 不同的是,它會對頂點的法線進行插值,并透過每個像素的法向量計算光照特性。這種做法能繪制出精致、精準的曲面,但是計算量較大。Blinn-Phong 是 Phong 的進階版,著色性能更好,且高光彌散更自然。
簡單了解計算機如何繪制 3D 圖形后,再來看看它要如何具體理解我們所設計的 3D 場景。
3D 轉換成 2D,也就是 3D 柵格化的過程中,每一個像素的顏色是需要基于它所在的環境計算出來,而基于被渲染物體表面某個點的光強度計算模型就被稱為光照明模型(Illumination Model)或光照模型(Light Model),透過計算光照模型所得到表面位置對應像素顏色的過程被稱為表面繪制(Surface Render)。
*請注意這里說的光照模型并不是指設計師理解的 3D 立體模型,而是指模型對象表面光照效果的數學計算模型。
影響光照模型的因素有兩大方面,一是本身給渲染物體材質設置的各種光學特性(顏色反射系數、表面紋理、透明度等),二是場景中光源光及環境光(場景中各個被照明對象的反射光)。
傳統光照模型都是對漫反射和鏡面反射的理想化模擬,如果要還原基于真實物理世界的效果,光照模型需要遵循能量守恒定律:一個物體能反射的光必然少于它接受的光。在實踐層面則表現為,一個漫反射更強且更粗糙的物體會反射更暗且范圍更大的高光,反之亦反。
圖 3-基于 PBR 的光照模型需要遵循能量守恒定律 [ F2, ©?Joe Wilson ]
光照模型與著色組合在不同的渲染需求下也會有不同的應用:
圖 4-真實感渲染及非真實感渲染對比 [ F3, ©?Autodesk ]
真實感渲染 Photorealistic Rendering
考慮到真實感渲染對硬件的依賴,目前 webGL 中使用的一般以簡單的局部光照模型為主(只計算光源對物體的光照效果,不計算物體間的相互影響,我們看到的“假反射”通常透過貼圖來進行模擬),根據反射形態,經典的光照模型有下列幾種:
這種模型的粗糙表面(如塑料、石材等)會將反射光從各個方向反射出去,而這種光反射也稱為漫反射。理想的漫反射體我們通常稱作郎伯反射體(Lambertian Reflectors),也就是我們熟悉的橡膠材質。
圖 5-漫反射模型與其他光照模型對比 [ F4, ©?ViroCore ]
這是一種以實驗及觀察為合成基礎的非物理模型。它的表面反射同時結合了粗糙表面漫反射和光滑表面鏡面反射,但 Phong 模型在高光處的表現有過渡瑕疵。
圖 6-Phong 鏡面反射模型視覺構成 [ F5 ]
是在 OpenGL 和 Direct3D 里默認的著色模型,一種調優后的非物理的 Phong 模型,頂點間的像素插值使用 Gouraud 著色算法,比 Phong 著色算法性能更好,而且高光效果也更平滑。
圖 7-Phong 及 Blinn-Phong 鏡面反射模型對比 [ F6 ]
如果你用過 C4D 的默認渲染器,那么一定在材質的反射通道設置中見過它倆。
這是相對高級的光照模型,不同于 Phong 和 Blinn-Phong 模型僅僅對漫反射及鏡面反射進行理想化模擬,這兩個光照模型基于不同物理材質加入了微表面(Microfacet)的概念,并考慮到表面粗糙度對反射的影響,對鏡面反射進行了調優,使得高光的長尾彌散更加自然,也是目前 PBR 渲染管線(Unity、UE)中較常用的光照模型。
圖 8-Phong、Blinn-Phong 與 GGX 鏡面反射模型對比 [ F7, ©?ridgestd ]
終于有一個設計師們常見的概念了。次表面散射是指光穿透不透明物體時(皮膚、液體、毛玻璃等)的散射現象。現實生活中,大部分物體都是半透明的,光會先穿透物體表面,繼而在物體內被吸收、多次反射、然后在不同的點穿出物體。以皮膚為例,只有大概 6%的反射是直接反射,而 94%的反射都是次表面散射。
BSSRDF(雙向次表面反射分布函數)是用于描述入射光在介質內部的光照模型,目前也被應用在最新的虛擬角色皮膚實時渲染中;但由于 SSS 材質的計算需要依賴深度/厚度數據,所以 webGL 對這種高級光照效果的還原程度還是相對有限的。
圖 9-Unity 中模擬次表面散射光照模型效果 [ F8, ©?Alan Zucconi ]
非真實感渲染 Unphotorealistic Rendering
也就是我們常說的 3 渲 2,非寫實渲染風格也是從人們對 3D 場景套以 2D 繪畫或自然媒體材質需求而演化過來的。因此非寫實渲染技術實際上是不同光照模型+不同著色處理共同作用的風格化輸出,目前也被大量應用在動畫及游戲中,像《英雄聯盟:雙城之戰》《蜘蛛俠:平行宇宙》都是頂級三渲二大作。
圖 10-在不同通道中混合應用真實感渲染及非真實感渲染效果 [ F9, ©?Polygon Runway]
卡通著色,一種最常見的以 3D 技術模擬扁平風格的著色形式,通常以極簡的顏色、漸變及明確的外框線等漫畫元素作為風格特征。
圖 11-Blender 中不同類型的 Toon Shader 效果 [ F10, ©?Blendernpr]
日本創意編程師 Misaki Nakano 制作了一個非常有趣的 Toon Shading H5 互動頁面,大家可以體驗一下不同著色形態下非常模型的視覺表現。點擊體驗: https://mnmxmx.github.io/toon-shading/dst/index.html
圖 12-Misaki Nakano 的 Toon Shader 互動網站 [ F11, ©?Misaki Nakano]
目前越來越多渲染器可支持設計師及工程師根據項目需求對著色進行定制化處理,以產出更具風格化和藝術化的著色效果。例如工業界插畫常用的冷暖著色(Gooch Shading),以及更具繪畫質感的素描著色(Hatching)及油畫水墨畫等自然媒體著色,都已經深入到了我們日常的創作之中。
圖 13-在 Unity 中,基于真實感渲染的貼圖效果與 NPR 水墨風格化著色效果對比 [ F11, ©?鄧佳迪]
說完真實感與非真實感渲染差異后,我們再來看看 Three.js 中的材質。
和許多渲染引擎一樣,除了原生材質外,webGL 的材質和著色都是可以根據需求進行定制的,但這往往會也帶來較高的開發成本及兼容性風險。考慮到 H5 項目的實際應用場景,下表羅列了 Three.js 原生材質的對比,包含了材質特性優勢、貼圖差異及適用場景,大家可以基于項目需求快速選擇并混合使用:
圖 15 – three.js 材質對比表
雖然著色、光照模型以及材質渲染對 3D 表現有著最為直觀的影響,但 3D 工作流仍有一個隱秘而關鍵的環節——色彩管理。
真實世界中按照物理定律,如果光的強度增加一倍,那么亮度也會增加一倍,這是線性的關系。理想狀態下,像素在顯示屏上的亮度也應為線性關系,才能符合人眼對真實世界的觀察效果(如圖 b:橫坐標為像素的物理亮度,縱坐標為像素顯示時的實際亮度)。
但是顯示器的成像由于電壓的影響,導致輸出亮度與電壓的關系是一個亮度等于電壓的 1.7-2.3 次冪的非線性關系,這就導致了當電壓線性變化時,亮度的變化在暗處轉換時變慢,如果顯示器不經過矯正,暗部成色也會整體偏暗(如圖 c)。目前大多數顯示器的 Gamma 值約為 2.2,所以也可以理解 Gamma2.2 是所有顯示器自帶的一個遺傳病。
圖 15-紅色上曲線=Gamma0.45=sRGB Space;綠色下曲線=Gamma2.2=顯示器真實成像缺陷;藍色斜線=Gamma1.0=Linear Space 真實物理世界線性關系
為了矯正顯示器的非線性問題(從圖 c 校正回圖 b),我們需要對它進行一個 2.2 次冪的逆運算(如圖 a),在數學上,這是一個約 0.45 的冪運算(Gamma0.45)。經過 0.45 冪運算,再由顯示器經過 2.2 次冪輸出,最后的顏色就和實際物理空間的一致了,這套校正的操作就是伽馬校正(Gamma Correction)。
而我們常見的 sRGB 就是 Gamma0.45 所在的色彩空間,是 1996 由微軟與惠普共同開發的標準色彩空間。當照片素材一開始儲存成 sRGB 空間,相當于自帶一個 Gamma0.45 的遺傳病抗體,當它被顯示器顯示時,就自動中和了顯示器 Gamma2.2 的缺陷,從而顯示出與物理世界相符的亮度。
另一個校正原因是因為人眼在接受光線時的敏感度也不是線性的,人對于暗部的感知更敏感,對高亮區域感知較弱,而且人眼感知光強度與光的物理強度也剛好是對數關系。為了在暗部呈現更多人眼可感知的細節,Gamma0.45 的色彩空間中(如圖 a),像素的實際亮度也會高于它的物理亮度。
圖 16-人眼感知光強度與發射光真實物理強度對比
上面那一大段確實有點繞,但也就說回來為什么建議渲染時使用線性空間(Linear Space)了。因為在計算機圖形中,著色器的運算基本上都是基于物理世界的光照模型來保證渲染真實性的,如果模型的紋理輸入值是非線性的(sRGB),那么運算的前提就不統一,輸出的結果自然就不那么真實了。
而在大多數工作流及渲染軟件中,大部分貼圖資源都是默認輸出 sRGB 的(設計師作圖環境一般也在 sRGB,所見即所得),而法線貼圖、光線貼圖等紋理(純數值類紋理,只用于計算)又是 Linear 的,這個部分就需要我們根據渲染引擎本身的特性,來判斷是否需要對不同的貼圖進行不同的“去 Gamma 化”處理了(WebGL、Unity、Octane 等)。
將所有貼圖進行去 Gamma 化,統一為 Linear 空間后,再在渲染輸出時由引擎統一進行 Gamma 校正,這個時候在顯示屏里顯示的就是接近真實世界的效果了。
更多色彩空間的實際效果比較,大家可以看下 Unity 的文檔:《Linear/Gamma 渲染比較》:https://docs.unity3d.com/Manual/LinearRendering-LinearOrGammaWorkflow.html
回到 H5 所用的 Three.js,它的著色器計算也是默認在 Linear 空間,如果最終渲染時不轉化為 sRGB,在設備顯示時可能會造成色彩失真。在 three.js 中色彩管理的工作流會根據導入模型 Asset 的差異而有所不同,如果貼圖與模型是分別導入場景,則建議可嘗試以下流程:
1. 輸入貼圖數據 sRGB to Linear: 含色彩的貼圖(基礎材質、環境、發光)設編碼為 sRGB(texture.encoding = sRGBEncoding),或將渲染設置 renderer.gammaInput 設為 True,可將原為 sRGB 的貼圖轉換為 Linear,而原純數值類貼圖(法線、凹凸等)仍舊保持 Linear;這一操作可保證貼圖輸入數據的正確性與統一性。
2. 刷新材質:當材質編碼類型被修改后,需要設置 Material.needsUpdate 為 True,以重新編譯材質。
3. 輸出渲染 Linear to sRGB: 校正渲染輸出值的 Gamma:
renderer.gammaOutput = true; renderer.gammaFactor = 2.2;以供顯示屏正確顯色。
《Part1-理論篇》就先告一段落啦,如果你偶發失眠,建議可以反復咀嚼延伸閱讀的內容。
《Part2-實踐篇》會繼續完善 three.js 場景、材質貼圖的制作思路、以及 gltf 工作流,并動態討論項目常常遇到的還原問題。
2022,咱們需求再見。
像素著色器 Pixel Shader
也稱為片元/片段著色器(Fragment Shader), 為二維著色器。它記錄了每一個像素的顏色、深度、透明度信息。最簡單的像素著色器可用于記錄顏色,像素著色器通常使用相同的色階來表示光照屬性,以實現凹凸、陰影、高光、透明度等貼圖。同時,他們也可以用來修改每個像素的深度(Z-buffering)。
但是在 3D 圖像中,像素著色器可能無法實現一些復雜的效果,因為它只能控制獨立的像素而并不含有場景中模型的頂點信息。不過,像素著色器擁有屏幕的坐標信息,可以依據屏幕或鄰近像素的的材質進行采樣并增強,例如,Cel Shader 的邊緣強化或一些后期的模糊效果。
頂點著色器 Vextex Shader
是最常見的 3D 著色器,他記錄了模型每個頂點的位置、紋理坐標、顏色等信息。它將每個頂點的 3D 位置信息轉換成 2D 屏幕坐標。頂點著色器可以處理位置、顏色、紋理的坐標,但是無法增加新的頂點。
幾何著色器 Geometry Shader
是最近新興的著色器,在 Direct3D 10 和 Open GL3.2 中被引用。這種著色器可以在圖元外生成新的頂點,從而轉換成新的圖元(例如點、線、三角等),而優勢也是在于可以直接在著色中增加模型細節,減低 CPU 負擔。集合著色器的常用場景包括點精靈(Point Sprite)生成(粒子動畫),細分曲面,體積陰影等。
細分曲面著色器 Tessellation Shader
在 OpenGL4.0 和 Direct3D 11 中出現,它可以在圖元內鑲嵌更多三角體。為傳統模型新增了兩個著色步驟(一是細分控制著色,又稱為 Hull Shader,二是細分評估著色,又稱為 Domain Shader),兩者結合可以讓簡單的模型快速獲得細分曲面。(例如,含細分曲面效果的模型加上置換貼圖就可以獲得極其逼真細膩的模型)
GL: Graphics Library, 圖形函數庫。
webGL:Web Graphics Library,Html 5 可接入的 3D 繪圖協議/函數庫,可以為 H5 Canvas 提供 3D 渲染的各類 API。
Z-Buffering:深度緩沖,3D 圖像在渲物體的時候,每一個生成的像素的深度會存儲在緩沖區中。如果另一個物體也在同一個像素中產生渲染結果,那么 GPU 會比較兩個物體的深度,優先渲染距離更近的物體,這個過程叫做 Z-Culling。當兩個物體靠很近的時候(16-bit),可能會出現 Z-Fighting,也就是交疊閃爍的現象,使用 24 或 32bit 的 Buffer 可以有效緩解。
Rendering Pipeline:渲染管線/渲染流水線/像素流水線,為 GPU 的處理工作流,是 GPU 負責給圖形配上顏色的專門通道。管線越多,畫面越流暢精美。
圖 17-渲染管道細節工作流 [ F12 ]
Rasterization:光柵化/點陣化/柵格化,就是將管線處理完的圖元轉換成一系列屏幕可視的像素,過程包括:圖元拼裝(Primitive assembly)-三角形遍歷(Triangle Traversal)- Pixel Processing-Merging。
文章來源:優設 作者:ISUX
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( m.91whvog3.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務