以前的兩篇博客:html
[真實感海洋的繪製(一):基於統計學模型的水面模擬方法][http://www.cnblogs.com/hehao98/p/8544121.html]git
[真實感海洋的繪製(二):使用快速傅里葉變換加速波形計算][http://www.cnblogs.com/hehao98/p/8604163.html]github
根據上述兩篇博客,咱們已經獲得了真實感較高的水面波形和法向量。爲了節省所須要的頂點數目,須要將高度場和法線製做成貼圖傳入着色器,以便從較少的頂點就能渲染很大面積的海面。以後的任務就是對這些波形進行真實感的渲染。ide
首先,高度真實感的、基於真實物理的水面光照模型至關複雜,即便可以用計算機計算,也幾乎不可能實時地完成。所以,現有的實時水面渲染方法基本不會使用此類模型。本文的方法將採用只計算一次反射和折射的簡單模型。函數
首先咱們先畫出高中物理中的反射和折射模型:post
其中,\(\vec{v_i}\)是入射光向量,\(\theta_i\)是入射角,\(\vec{v_r}\)是反射光向量,\(\theta_r\)是反射角,\(\vec{v_t}\)爲折射光向量,\(\theta_t\)是折射角,\(\vec{n}\)是法線向量。其中,入射角和反射角相等。根據斯涅爾定律(Snell's Law),入射角和折射角知足以下關係
\[ n_i\sin\theta_i=n_t\sin\theta_t \]
其中,\(n_i\)和\(n_t\)分別爲入射介質和折射介質的折射率,對於空氣而言,\(n_i=1.00\),對於水而言,\(n_t=1.33\)(近似值)。spa
以上討論反映了在表面某一點的反射狀況和折射狀況。若是要知道這一點反射了哪裏的光,能夠從觀察點開始作一層光線追蹤,也就是假設攝像機在\(\vec{v_r}\)所指向的位置,反向計算出\(\vec{v_i}\)。以後咱們必須計算出\(\vec{v_i}\)光的顏色。通常的實現方法是把四周的場景預計算,存儲爲環境貼圖,而後就能夠根據\(\vec{v_i}\)向量值來計算出這一點的入射光顏色。對於開闊的海面而言,被反射的天然就是天空了。如圖所示。.net
固然,水面並非一面完美的鏡子。射入水面的入射光,一部分反射了回來,另外一部分在折射後進入了水面,與此同時,在水面處也有從水面下通過折射後又反射回來的光。在無限大的水面中,咱們能夠不考慮水下反射光的複雜性,單純將其假設爲某種固定的顏色。htm
對於水面上任何一點,最終攝像機收到的顏色是反射環境的顏色和折射出的水下顏色之和。對於不一樣的入射角\(\theta_i\),入射光反射的比例\(R\)和折射進入水面的比例\(T\)是不同的,可是知足\(R+T=1\)。這在物理上被稱做費舍爾效果(Fersnel Effect)。利用電磁學理論咱們能夠推導出\(R\)有以下的關係
\[ R=\frac{1}{2}\{\frac{\sin^2(\theta_t-\theta_i)}{\sin^2(\theta_t+\theta_i)}+\frac{\tan^2(\theta_t-\theta_i)}{\tan^2(\theta_t+\theta_i)}\} \]
當從空氣進入水的時候,入射角爲0度時\(R=0\),而後隨着角度變大而變大,當入射角爲90度時\(R=1\)。當從水進入空氣時則存在全反射的現象,當入射角大於某個角度後就會所有反射,沒有折射。blog
所以,對於水面任意一點,咱們獲得簡單的顏色計算公式
\[ Color = R * Color_{incident} + (1 - R) * Color_{deepWater} \]
就能夠完成水面的着色。
顯然,因爲計算資源的限制,咱們是不可能高精度繪製無限大的海面的。爲了節省計算資源,一種方法是使用LOD技術(Level Of Details),讓近處的網格頂點密度高、遠處的頂點密度低。若是有時間的話以後我會研究一下各類LOD技術。在這裏,咱們先使用一個偷懶的方法:加入薄霧。一方面能夠遮擋住遠處頂點網格的空缺,另外一方面能夠適當設置霧的顏色以便在遠處和天空盒融爲一體,最終可以得到足夠好的視覺效果。
要在計算機中實現霧其實很是簡單。霧能夠視爲一種疊加在已有物體上的顏色,這個顏色隨着距離變遠而加深,從而在有霧的場景中,一個像素點的顏色能夠表示以下
\[ Color = (1 - F(d)) * Color_{object} + F(d) * Color_{fog} \]
其中,\(F(d)\)是霧的參數函數,\(d\)是這個片元像素距離攝像機的距離,經過選取適當的參數函數,咱們能夠模擬出比較逼真的霧效果。我選取的參數函數以下
\[ F(d)=1 - e^{-cd} \]
相信學太高中數學的讀者都能畫出這個函數的圖像。其中,\(c\)是一個常量,其值越大,霧越濃,適當地調整參數能夠得到咱們想要的效果。
此外,爲了和天空盒的遠處相融合,咱們須要利用攝像機到片元的方向來取值,從天空盒邊緣取得適當的顏色來產生真實的霧效果。
代碼可見[https://github.com/hehao98/OceanSimulator]