最近要寫個 web 交互式發光可交互的框架。沒查到啥好資料,自己一個人摸索了很久,有些失望,可是畢竟是探索過的東西,所以做個記錄,懷念我過去好多天掉的青絲(捂臉)。我在前面那篇博客里面已經介紹了如何讓用戶與 3D 場景中的組件交互(其實這個技術應該比較成熟了,只是我自己還不熟),所以這篇呢,主要是介紹一下 THREEJS 中的后期處理通道(ShaderPass)以及特效合成器(effectComposer),因為沒看到什么資料介紹 THREEJS 后期處理這塊兒的。如果有童鞋有更好的辦法或者建議或者想一起學習什么的,都可以留言,感覺學 WebGL 的不多,心塞塞。
首先簡單介紹一下后期處理通道(Pass),每個通道都是一個ShaderPass,也就是一個Shader,熟悉 GLSL 的 learner 都可以自定義ShaderPass,每個通道就類似於美圖秀秀的濾鏡的功能,能給你的畫面一些特效,比如發光、褐色、清新之類的。而特效合成器(effectComposer)就會把疊加在這個畫面上的所有通道(一個畫面可以疊加多個通道,類似於一個圖片用多個濾鏡)的結果計算並渲染出來,所以特效合成器也算是一個render。
THREEJS 的 github 的下載包中,有一個文件夾:three.js-master\examples\js\shaders,這個文件中存放着一些常用的着色器(shader),比如:FresnelShader(根據 Fresnel Reflection 原理)、SSAOShader(根據 SSAO 原理)等,都是依據計算機圖形學中知名的算法生成的,想深入了解 WebGL 着色器的同學可以看看源碼,都是一些現有公式的實現和應用。還有后期處理通道:three.js-master\examples\js\postprocessing:這個文件夾中包含一些常見的處理通道,比如:BloomPass、HDRPass、MaskPass等,其實都是從 OpenGL 的基礎上發展而來的,都是可以直接應用的“濾鏡”。
下面我們通過解決幾個問題來說明一下怎么應用這些 Shders 和 postProcessing Pass。
問題一:如何給 THREEJS 場景加背景圖片?
方法一:
直接給 canvas 所在的 div 設置背景圖片,這樣做就和 WebGL 渲染沒啥關系了,但是是最快的辦法,如果沒有其他要求的話。但是有一個問題就是,在這種背景下,你的 canvas 中添加后期通道處理的時候會出現一些問題。我這兒是在添加 outlinepass 的時候,div 背景圖片變暗了,甚至直接變成了黑色,兩者的 α 通道部分的功能沖突了。
方法二:
利用天空盒,也就是 THREEJS 的 立方體紋理(CubeTexture),這種立方體紋理其實就是造了一個超大的立方體盒子,用戶渲染的東西在盒子里面,盒子四面八方的紋理就是背景。示例:https://github.com/mrdoob/three.js/blob/master/examples/webgl_postprocessing_backgrounds.html
方法三:
在我看來這是最正經的解決辦法,這是原理:http://blog.csdn.net/xiaoge132/article/details/51448326。就是設置讓兩個渲染的場景疊加,一個是sceneBackground,一個是scene。sceneBackground 中渲染一個 Plane,這個 Plane 有一個正交相機 CameraBG,這個渲染出來的場景就是一個鋪滿整個窗口的背景。scene 中就用來渲染就要渲染的組件。這樣sceneBackground渲染的場景作為背景,scene中場景就是 3D 可視部分。因為是兩個場景,所以需要兩個渲染通道(renderPass),分別渲染各自的,然后由特效合成器疊加,呈現出最終結果。https://github.com/josdirksen/learning-threejs/blob/master/chapter-11/03-post-processing-masks.html,這個示例可以幫助大家理解。
問題二:如何讓整個場景發光?
了解計算機圖形學的同學應該都了解SSAO、HDR、Bloom、outLinePass等這些常見的場景發光算法。THREEJS 中也有現成的通道可以用,用戶可自定義調節場景參數,達到自己想要的效果。
大家可以自行查看 THREEJS 官方對應的示例:https://threejs.org/examples/。下面給出幾個加了通道的畫面對比:第一張:不疊加任何通道,第二張:添加Bloom通道,只是個簡單示例而已。

問題三:如何在3D場景中添加文字?
方法一:
直接將文字 P 在紋理上,簡單粗暴。
方法二:
利用 THREEJS 提供的 3D 文本模型(TextGeometry(text , parameters)),將文本渲染在場景中的任意地方,但是能使用的字體有限,three.js-master\examples\fonts,該文件夾下列出了所有可用的字體類型。
問題四:如何模擬 3D 場景中的物理效果?
在憤怒的小鳥中,小鳥遇到障礙物就會模擬碰撞后的相關“滾出”軌跡,那在 threejs 中如何實現這種效果呢。其實 THREEJS 官方給出了一個模擬物理碰撞的擴展庫:Physijs。這個庫其實是基於Ammo.js的,Ammo.js又是在 Bullet 物理引擎上發展而來的,Bullet 物理引擎是三大物理引擎之一,還是開源的,但是應用較少,資料也不多。有興趣的可以看看 Bullet 的官方 Wiki : http://bulletphysics.org/mediawiki-1.5.8/index.php/Hello_World。其實就是在 THREEJS 的 3D 組件外層添加了可檢測碰撞的 Shape ,然后模擬重力、受力、線速度、角速度等來使物體運動,都是根據物理公式實現的。
問題五:THREEJS 到底能做什么。有什么應用場景?
這也是我有疑問的地方,THREEJS 可以 web 端建模,展示,數據可視化,都能用到,然后呢?還能干什么,做 3D 試衣間?在網頁中嵌入 3D 可視化部分使頁面炫酷???其實我之前看到過一篇文章,大意是說 2D 可視化已經足夠了,3D 數據可視化只會給用戶帶來閱讀障礙,想想也覺得有道理。而且對於 WebGL,雖然現在慢慢的很多瀏覽器都支持了,可是各瀏覽器之間還是有差異,除了谷歌和火狐之外,其他瀏覽器都存在各種不支持的問題。除了環境之外,電腦的性能也是個問題,3D 可視化對於 CPU 和 GPU 的要求更高,至少我自己 PC 的顯卡就很差勁,其實對於大眾用戶來說,這也是個瓶頸。。希望以后 webGL 能有更廣泛的用途,而不只是展示。
