注:文章譯自http://wgld.org/,原作者杉本雅広(doxas),文章中假設有我的額外說明,我會加上[lufy:],另外,鄙人webgl研究還不夠深入,一些專業詞語,假設翻譯有誤,歡迎大家指正。

本次的demo的執行結果

著色方法

上次介紹了反射光,反射光是實現光澤的必不可少的概念,到此為止,主要的光照效果都已經封裝完成了。
光照的效果主要就是擴散光,環境光和反射光三種方法,靈活運用這三種光照,應該就能實現非常逼真的照明效果了。
前幾篇一直在說光照,這次略微換個視點,看一下著色,著色是一個比較大的話題,這次講一下高氏著色和補色著色。

高氏著色(gouraud shading)

高氏著色從名字上看,是比較難明確詳細是什麼樣的著色的,這個高氏(gouraud)事實上是以研究該著色的Henri Gouraud來命名的。

lufy:高氏著色又叫高洛德著色或高氏渲染(Gouraud Shading):這是一種光影渲染技術也是眼下較為流行的著色方法,它可對3D模型各頂點的顏色進行平滑、融合處理,將每一個多邊形上的每一個點賦以一組色調值,同一時候將多邊形著上較為順滑的漸變色,使其外觀具有更強烈的實時感和立體動感,只是其著色速度比平面著色慢得多可是效果要好得多。

高氏著色能夠對多邊形的頂點之間的顏色進行補間,高氏著色的計算負荷並非太高,可是,能夠實現非常美麗的渲染,所以常常被使用。

對頂點間的顏色進行補間是什麼意思呢?

簡單的說,用高氏著色計算得到的終於的顏色情報,適用於所有頂點,而且對頂點和頂點之間的顏色進行補間處理,最後渲染模型。

使用高氏著色,想用少量的頂點渲染美麗的光照是非常難的。比方說,一個最簡單的三角形多邊形,三維空間中僅僅有這一個三角形,這個面就直接和光碰撞了。

放射性光源的時候(比方說燈泡),應該是三角形的中心就最亮,而頂點的部分要略微暗一些,可是高氏著色僅僅是在頂點之間進行顏色補間,所以無法凸顯三角形中間的亮點。
另外,由於是依據每一個頂點進行顏色補間,顏色變化的時候會出現鋸齒。這個鋸齒隨著頂點數的增多而逐漸消失,可是這麼做的話,高氏著色計算負荷小的優勢就沒有了,所以這是個難處理的地方。

細心的朋友可能會發現,這個站點中所有的demo,都是用的高氏著色。頂點著色器的光的強度和顏色的進行計算,然後僅僅是將終於算出的顏色傳給了片段著色器,這樣的依據每一個頂點來計算顏色的方法就是高氏著色。
以下是證據,眼下為止的demo中的顏色之間會存在鋸齒,會有一些不太自然的鏡面反射。


擴大之後看的話就比較清楚了吧,頂點數越少,這樣的現象就越明顯。

補色著色(phong shading)

理解了高氏著色之後,接著看補色著色。
像剛才說的那樣,相對高氏著色是對頂點之間的顏色進行補間處理,補色著色是對各個畫素進行顏色的補間處理。也就是說,計算量會比高氏著色增大非常多,可是能夠將渲染出顏色的細節。
補色著色的名字跟高氏著色一樣,都是以人名(Bui Tuong Phong)來命名的。使用補色著色的話,會克服高氏著色的弱點,即使頂點數少的時候也能得到非常自然的效果。

由於補色著色是在畫素之間對顏色進行補間,所以不會發生不自然的鋸齒。以下是和高氏著色的渲染效果做比較。

全然是同樣的頂點數,同樣的光源渲染出的補色著色和高氏著色。左邊是補色著色,不管陰影還是高亮的部分,都非常的美麗和自然。

補色著色的封裝

知道了高氏著色和補色著色兩者之間的不同,那麼就來看看補色著色的封裝吧。補色著色就是剛才說的那樣,在畫素之間進行顏色的補間處理,那麼眼下為止的在頂點著色器中進行的光照處理,所有要交給片段著色器。
詳細的說,追加一個處理,頂點著色器中的頂點的法線情報用varying變數傳給片段著色器,然後其它的光照處理所有移到片段著色器中。
首先看頂點著色器的程式碼。

>頂點著色器的程式碼

attribute vec3 position;
attribute vec3 normal;
attribute vec4 color;
uniform mat4 mvpMatrix;
varying vec3 vNormal;
varying vec4 vColor; void main(void){
vNormal = normal;
vColor = color;
gl_Position = mvpMatrix * vec4(position, 1.0);
}

和眼下為止的程式碼不同,新定義了一個叫做vNormal的varying變數,用來將法線情報傳給片段著色器。頂點的顏色情報和座標變換矩陣等地方不用變。
接著是片段著色器。

>片段著色器程式碼

precision mediump float;

uniform mat4 invMatrix;
uniform vec3 lightDirection;
uniform vec3 eyeDirection;
uniform vec4 ambientColor;
varying vec3 vNormal;
varying vec4 vColor; void main(void){
vec3 invLight = normalize(invMatrix * vec4(lightDirection, 0.0)).xyz;
vec3 invEye = normalize(invMatrix * vec4(eyeDirection, 0.0)).xyz;
vec3 halfLE = normalize(invLight + invEye);
float diffuse = clamp(dot(vNormal, invLight), 0.0, 1.0);
float specular = pow(clamp(dot(vNormal, halfLE), 0.0, 1.0), 50.0);
vec4 destColor = vColor * vec4(vec3(diffuse), 1.0) + vec4(vec3(specular), 1.0) + ambientColor;
gl_FragColor = destColor;
}

逆矩陣,光向量,視線向量等一直以來都在頂點著色器中使用的資料,全都移動到片段著色器中來了。另外,利用剛才在頂點著色器中定義的varying變數vNormal進行了計算。計算的方法和曾經一樣,沒有不論什麼改變。就是說,僅僅是把頂點著色器中的處理,放到了片段著色器中而已。
這次的變化,並沒有加入新的uniform變數,也就是說,javascript部分基本上不用變。
簡單的來說,高氏著色和補色著色的主要差別就在於,依據頂點處理還是依據畫素處理,儘管這麼說跟定義相比有些奇怪,可是這麼理解的話也沒什麼錯。

總結

這一次分別說了高氏著色和補色著色兩種著色,高氏著色的長處是計算量比較低,而和補色著色相比的話,渲染效果不太自然。
補色著色正好相反,計算量非常高,可是渲染效果非常完美。
究竟選擇那種方法,取決於模型的頂點數和須要的渲染效果,以及執行環境能夠承受的計算負荷。
實際應用中,依據利用的場景和描畫的模型,分別使用不同的方法是非常重要的。
這次也準備了demo,急著看執行效果的人能夠點選文章最後的連結來測試。

另外,補充一點,這次的demo中對圓環體的生成函式做了幾處改動,返回值是以物件的形勢返回的,能夠指定圓環體的顏色了。事實上,也並沒有做什麼其它特別的處理。

下次,介紹一下電光源。

用補色著色來渲染的圓環體

http://wgld.org/s/sample_012/

轉載請註明:轉自lufy_legend的部落格http://blog.csdn.net/lufy_legend