在捕魚游戲項目中
希望使用shader豐富海洋背景效果
在網上找了幾個不同的效果
本文就寫一下使用折射效果的體會
效果視頻http://v.douyin.com/JfVfmU/
轉載請注明出處https://www.cnblogs.com/billyrun/articles/9222345.html
shader代碼如下
#ifdef GL_ES precision mediump float; #endif uniform float time; varying vec2 v_texCoord; uniform sampler2D u_normalMap; varying vec4 v_fragmentColor; vec3 waveNormal(vec2 p) { // 避免法線圖邊緣穿幫 // fract返回小數部分 mod取模 // 0.1 0.2 ... 0.9 1.0 0.9 ... 0.1 0.0 0.1 0.2 ... float x = mod(p.x , 2.0) < 1.0 ? fract(p.x) : 1.0 - fract(p.x); float y = mod(p.y , 2.0) < 1.0 ? fract(p.y) : 1.0 - fract(p.y); //vec3 normal = texture2D(u_normalMap, p).xyz; vec3 normal = texture2D(u_normalMap, vec2(x , y)).xyz; normal = -1.0 + normal * 2.0; normal.x *= 0.1; normal.y *= 0.1; return normalize(normal); //return vec3(0,0,1); } void main() { float timeFactor = 0.1; float offsetFactor = 0.5; float refractionFactor = 0.7; // simple UV animation vec3 normal = waveNormal(v_texCoord + vec2(time * 1.0 * timeFactor, time * 0.1 * timeFactor)); // simple calculate refraction UV offset vec2 p = -1.0 + 2.0 * v_texCoord; // 眼睛位置 位於中心點正上方 vec3 eyePos = vec3(0, 0, 10); vec3 inVec = normalize(vec3(p, 0) - eyePos); vec3 refractVec = refract(inVec, normal, refractionFactor); //根據入射向量,法線,折射系數計算折射向量 vec2 v_texCoordN = v_texCoord; v_texCoordN += refractVec.xy * offsetFactor; //v_texCoordN.x -= CC_Time.y*timeFactor *0.6; //移動水面貼圖,可選 gl_FragColor = texture2D(CC_Texture0, v_texCoordN); }
法線獲取函數
waveNormal函數返回每個紋理坐標所對應的法線
假設水面是純平的,那么每一處法線都豎直向上,即vec3(0,0,1)
為了達到較為逼真的效果,水面應該是起伏不平的
這里使用一張法線貼圖來提供數據
圖片每個像素的RGB值被用作法線坐標
圖片是藍色的,RGB約為0.1,0.1,1.0,對應法線坐標xyz就是基本豎直向上但略有波動
所以也不難理解
waveNormal中做了部分數值改動
x和y分量分別*=0.1是因為使用的紋理圖RG的值有點偏大,對應xy波動太劇烈
取模求余mod和fract保留小數部分是為了讓法線采樣坐標平滑的保持在0~1之間
避免穿幫的波動
因為雖然法線貼圖的采樣會使用gl.REPEAT,但從1.0增到0.0還是會出現明顯抖動
法線參數
參數基於片段的紋理坐標,並通過時間參數設置偏移
以上所設置的參數,會帶來較大的橫向波動和少量的縱向波動,適用於橫版游戲
反射計算
首先將紋理坐標從0~1轉換為-1~1的數值
然后根據假設的眼睛位置,計算光線方向
這里inVec與z軸的夾角是很小的
因為p的范圍是(-1,-1)~(1,1)
因此inVec與z軸的夾角范圍應該是0~8角度atan(1.414/10)
注意normalize會把方向向量變換為 單位向量
根據法線計算折射向量
這個向量會比0~8度還要小,物理學沒記錯的話應該是0~8*0.7左右
而refractVec的值因為是從單位向量inVec計算得來的,因此還是單位向量
大概范圍是(+-0.05 , +-0.05 , 0.9+)這樣
最后處理紋理采樣坐標,做偏移處理,可以看出來偏移的量很少,0.05的話也就是1/20
而且還乘了0.5
當法線始終豎直向上(0,0,1)時,可以比較一下原圖和使用反射后的區別
可以明顯看到,使用了折射之后,左右邊緣部分gl.CLAMP掉了(上下其實也會有,沒有在顯示區域內)
正是因為折射偏移的影響
而在同時使用法線貼圖和時間變換后
圖片會展現出良好的動態波動效果
當然,最后要記得把左右邊緣像上下底邊一樣,不要處於顯示區域內部
控制時間參數的變化可以明顯改變波動速度,操作十分簡單方便
目前設置法線數據可以使用以下api
參考文獻
http://www.cocoachina.com/bbs/read.php?tid-1693873-page-1.html