電腦圖學-Shading

帽捲
Maochinn
Published in
11 min readJul 15, 2020

--

這邊先定義一下幾個容易搞混的名詞,Rendering, Shading, Shadowing, Lighting,當時花了一些時間才搞清楚。

Rendering

在其他文章應該已經有個具體的理解了,就是指從給vertex到最後計算成fragment的過程。

Shading

是Rendering之中的一個階段,就是指當我們rasterization完之後,要計算每個fragment的資訊的過程,通常我們會利用這個fragment的本來的資訊(法向量、材質...)來計算它最終在Color Buffer裡面的值,也就是這個fragment的顏色,那這個過程就是Shading。

Shadowing

特指產生影子這個效果的計算,所以可以算是Shading的其中一部份。

Lighting

通常只考慮光造成的效果的計算,也可以算是Shading的其中一部份。

所以如果看到renderer跟shader就可以理解renderer裡面會包含shader,而shader裡面通常會要用到light, shadow等等資訊。而我們通常講rendering蠻大一部份都是在講shading,而shading又有一大部分是lighting,所以這幾個詞在某些特定情況會感覺在混用。另外OpenGL 2.x之後就提供了shader來讓你寫關於shading的效果,但在OpenGL 1.x的部分shading都已經包含在pipeline裡面了,所以我們也只能調整參數,但這也讓我們比較好寫。

先講解一下為甚麼需要shading,其實就是我們的視覺經驗看東西會有明暗,因為只要有光就會有明暗,而就是因為有光我們才能看到東西,但是如果我們要畫一個立體圖形而它的材質顏色都是相同的,如果沒有shading那就會看不出其結構,只能感覺到是一個2D平面。

(left)with shading, (right)without shading

事實上,看似沒有shading其實只是shading的特例,也就是我們在場景的四面八方都放了燈光,這會造成每一面看起來都一樣,也就會看起來沒有shading的效果,而事實上,如果完全沒有shading,我們其實是什麼都看不見。

而Shading很明顯的我們需要定義Light、Material、Camera,而我們會把整個稱作Illumination Model。

Illumination Model

首先,無論是什麼樣的illumination model,我們通常都要定義光、物體的材質、相機,因為這就是物理上的光的產生者、介質、接受者,而如何利用這些定義好的數值近一步計算相機上看到的每個pixel,這就是illumination model,也就是說,就算數值完全一樣,不同的illumination model算出來的就不一樣,所以可以看到市面上不同的renderer渲染一樣的東西去產出不同的圖。

而這其中,又分為Local Illumination跟Global Illumination,前者就是單純的考慮燈->物體->相機,而後者則是會考慮燈->物體->...->物體->相機,可想而知,後者會得到更好的效果,也會有更加複雜的計算。具體來舉例的話就是影子的效果,local的考慮燈、要畫的物體、相機的話我們就不會考慮到要畫的物體與周圍物體之間的交互效果,而shadow就是考慮到物體擋住物體所造成的光照效果,所以這就是相對global的考慮了。

所以在OpenGL的fixed pipeline,也就是1.x版本中內建的illumination就是local illumination,但儘管是local illumination也分成好幾種,但首先我們要知道,local跟global是相對的概念,也就是台科大之於台北就是local,基隆之餘海大就是global(所以全球化就是全世界之於台灣是global),原則上沒有絕對的local跟global,也就是說local是依據global某種簡化而成的特例,但它可能足以達到想要達到的效果,舉例來說,global illumination model可能要考慮光、物體、被光照到的物體反射的光、相機,那我們的local illumination model就只考慮光、物體、相機,所以我們必然會失去掉一些效果,例如shadow、indirect lighting,但這樣的model簡化過,相對好計算。

所以如果我們回到shadow的例子來看,沒有shadow就是相對local的,而考慮了shadow就是global的,但其實我們知道,除了shadow還有閉塞(AO)、焦散(caustic)等等效果,如果說有絕對的global illumination,那就是我們眼睛看現實世界的效果,所以這個時候,有shadow的illumination就是local的了。

(left)local illumination, (right)global illumination

那就來具體談談OpenGL提供的local illumination,在談之前可以先看看三種local illumination,flat、Gouraud、Phong Shading,逍遙文在這篇有蠻清楚的解釋。

(a)flat shading, (b)Gouraud shading, (c)Phong shading

這三種其實都是基於Phong Shading Model(Phong Reflect Model)的,只是實作上不太一樣,但只要把面細分(subdivision)的夠細,那其實會有一樣的結果,這就是因為他們的reflect model是同一個。

簡單來說就是他們sample在畫面上單位不一樣,概念上來說,flat shading用face為單位,Guroud shading用vertex為單位,Phong shading用fragment為單位,但只有subdivide足夠密,face就會足夠接近vertex,vertex也會足夠接近fragment,所以你就會看到只要切的夠細,結果很像的。

Phong Shading Model

這個Model需要定義某個點,L,朝向光的方向,N,法向量,E,朝向相機的方向,R,光依據法向量算出來的反射方向,等等...。

Phong Lighting equation

很明顯的可以發現,他將整個lighting分成三個部分,diffuse, specular, ambient,而他利用了這個equation把model中的資訊計算出最終shading的結果。

Diffuse

其實應該叫他Diffuse Reflect(漫反射),也就是光照到越凹凸不平的東西它的diffuse會越高,也就是它會越平均的往外散射,另外,也會有人提到Diffuse light(漫射光),其實它是一種光,只是這種光不像雷射光那樣集中,而是非常平均的往外散射,所以感覺是非常像的。

Specular

Specular Reflect(鏡面反射),跟diffuse相對,如果是金屬、塑膠之類的specular就會相對高,它的效果就會像是繪畫中的高光一樣。

Ambient

這邊可以把它當作是環境光,主要就是除了diffuse跟specular以外的部分就會在這像裡面,而它的效果就像是沒有shading的物體,因為前面有提過沒有shading的物體實際上是受到來自四面八方差不多的光,所以每一面看起來都差不多,那ambient也就做了相同假設,假設這個環境有同個顏色的光在四面八方漫射,那結果就會是看起來像是2D的物體。

這邊就不展開來細講了,因為更加詳細清楚的說明在網路上有很多,這邊只說明一些概念上的東西。

這邊稍微提一下,你可能又會疑問怎麼這邊shading跟lighting好像在混用,首先,根據Phong shading model,我們知道需要L、N、E、R才能shading某個點,而這些資訊要怎麼使用就得利用各種不同的equation,而這邊提到的Lighting equation就是透過這個equation和Shading model的資訊去計算lighting的結果,但這邊我們的shading只包含lighting的效果,所以我們可以說用這個equation可以算出最終的shading結果,因為前面有提到,這個model是簡化過的,我們只考慮了lighting,反過來說,也是因為lighting對於視覺效果來講最重要,所以我們可以大膽的將global illumination model簡化為這樣的local illumination。

值得一提的是,其實我們常常會把equation也算到model裡面,因為equation怎麼寫往往會影響到model怎麼設計,反過來也是,這兩者都包含在廣義上的illumination model裡面。

在OpenGL,其實只有實作flat、Gouraud shading,它對應到就是glShadeModel(GL_FLAT)跟glShadeModel(GL_SMOOTH),我們就直接來看看例子吧。

Light

這邊要注意要記得寫glEnable(GL_LIGHTING)把光照開啟,如果我們要設定第0個光,我們必須先用glEnable告訴GL要把GL_LIGHT0開啟(所以說GL就是一個狀態機,不然我們就可以直接設值進去),這邊總共能夠設多少光就要看電腦,接下來就可以利用glLight設定光的相關參數,利用glLightModel來設定一些光的全域參數。

而實際上,光又分成directional, point, spot light,實作可以參考這篇

Material

首先要用glEnable開啟能夠設置Material,然後用glColorMaterial、glColor、glMaterial來設定Material參數,然後在每個vertex也要記得用glNormal來設定法向量。

原則上,這樣就可以做出flat、Gouraud shading,那更好的Phong Shading呢?那就需要用所謂的Programmable pipeline,也就是OpenGL 2.x之後版本所提供的shader,而這個就是讓使用者可以自己設計illumination model,GL的shader則是要用GLSL來寫,只要利用shader,我們可以把很多運算送到GPU計算,就可以更快速的render,也可以做更複雜的render。詳細的shader就等之後在寫吧

--

--