一. 概述
折射是自然界中常見的現象,當光從一種介質到另一種介質時會發生折射,在圖形學中利用折射可以實現很多效果使得效果更爲逼真如熱浪 狙擊鏡 水面等。
二. 實現思路
折射的實現方式有很多種有些方法是通過計算環境映射然後在運行時使用,但這種方式在場景中有很多折射表面時需要不同的環境映射因爲會損失效率。還有一種模擬水折射的方式是通過水麪上的集合信息生成折射圖,再由折射圖繪製水的折射,這種方案對水的繪製是分兩次繪製,對複雜場景仍然存在性能問題。本示例用一個簡單的方式近似模擬折射效果,用較小的代價實現近似折射效果。其基本思路即是: 利用RTT(render to texture)把現有的後臺緩存作爲一張帖圖,通過對該帖圖局部或者整體的紋理座標進行位移來模擬折射效果。
三. 實現方式
折射效果的實現主要分爲兩個步驟:第一步則是將場景繪製到一張紋理Texture(當然繪製的對象不包括折射對象)
第二步則是繪製折射對象,繪製折射對象時通過擾動過的紋理座標從Texture紋理中查找值來模擬折射效果。這個擾動可以通過法向量的XY(RG)通道乘以一個很小的值如0.005來作爲紋理座標的擾動值來實現。以下示例用折射原理實現火焰熱浪的熱擾動效果。
三. 具體代碼
Away3D關於RTT後處理可以利用濾鏡效果實現因此可以通過自己實現熱浪濾鏡HeatHazeFilter3D實現:
關於對紋理座標的擾動的Shader則是在Filter3DHeatHazeTask中實現
Shader實現先從擾動紋路中獲取數據歸一化到uv(0~1)範圍,再用uv乘以0.05作爲擾動值加上原來的uv座標作爲擾動後坐標從主紋理中採樣.
四. 實現效果:
增加熱浪效果之前
增加熱浪效果
五. 潛在問題及解決方法:
由於該折射實現方式是先將場景中對象繪製到紋路在繪製折射對象故而折射對象一定在最上層,但當相機與火焰(折射對象)之間存在其他對象(如一個盒子)時,盒子會作爲背景繪製與實際現象相違背,如下圖 圖中灰色方塊是在相機和火焰之間應該是木板遮擋部分火焰,但由於是先對場景中對象繪製再繪製火焰折射故繪製順序會被顛倒。
解決方法則是要設法將遮擋區域標記出來不對其進行擾動,具體作法可以利用渲染到紋理Texture的alpha通道標識當前區域是否被遮擋,初始時設置所有aplha值爲0繪製折射對象時將繪製區域alpha值設爲1此時由於深度測試只有可以被擾動的區域alpha值爲1此時只需修改shader,將最後一步的採樣代碼 "tex oc, ft0, fs0 <2d, nearest>\n"; 修改爲
tex ft2, ft0, fs0 <2d, nearest>\n tex ft3, v0, fs0 <2d, nearest>\n mul ft2, ft2, ft2.w mul ft3 ft3,(1-ft3.w)(僞代碼)
即擾動後數據* alpha + 擾動錢數據*(1-alpha) 由於只有未被遮擋區域alpha爲1也就實現了只對未被遮擋區域的折射效果處理。