可執行程序
藍奏雲網盤:https://italink.lanzous.com/ihqhQd9ntrg
效果
桌面壁紙——超真實水波紋效果
實現工具: Qt+OpenGL
實現功能
- 模擬水波:生成水面波形,完成水面的光照折射計算
- 窗口嵌入桌面
- 監視頂層窗口是否遮擋桌面,是就停止水紋的刷新
- 全局鼠標鉤子
原理
波形生成
把水面波形可以近似看作是一個以振源距離(dis)爲參數的正弦波,其中A爲最大振幅,F爲頻率,dis是當前點(xy)與振源的距離,本質上這是一個二元函數,通過這樣一個函數,我們能構造出如下效果的曲面:
其中半截面就是一個普通的正弦函數:
這樣就完成水面波形的計算了?很顯然沒這麼簡單,水面的波形並不只是一個簡單的正弦波(博主也不清楚細節),但是通過觀察一些水面效果,我們可以發現水波往往是隻顯示一小段圓環一樣的波形,並且隨着時間會向外部擴散。
所以我們要做什麼呢?
我們需要突出顯示正弦波的一小段,把其他部分抑制到幾乎爲0,顯示的這一段會隨着時間向外部擴散。我們可以通過改變最大振幅來實現這樣的效果,也就是說我們需要讓振幅不再是一個常量,而是一個函數,仔細想想,什麼函數才能滿足我們的需求呢?
當然是它——萬能的高斯函數
高斯函數中:
- a表示最大振幅(峯值)
- b表示對稱軸
- c與鍾狀的寬度有關
當a=1,b=10,c=2時,你能得到這樣的圖形
有了這個高斯函數,我們把它作爲正弦函數的最大振幅(也即是兩者相乘)
使用之前的參數,我們將會得到:
也就是大約會是這樣的波形
爲了做擴散,我們需要讓高斯函數的對稱軸與時間(T)進行關聯,隨着時間推移,對稱軸也隨之增大,也就是成正比,我們可以增加另一個變量V來控制擴散的速度
再通過變量W控制波紋的寬度。
綜上,我們得到的水波紋的曲面方程是:
其中:
- A表示最大振幅
- V表示擴散速度
- T表示時間
- W表示寬度係數
- F表示頻率
水面折射計算
在這一步,我們將計算圖片上某一像素點的經過水麪折射後實際應該輸出的顏色,在OpenGL中,這部分代碼在片段着色器中完成(因此上一步也是在片段着色器中)。
計算法向量
我們通過水波的一個半截面來做演示,人的視線是從上往下,大致上觀察模型是這個樣子的(雖然說光線是從水到空氣再到人眼的,但爲了推導,我們反過來把光線看作是從人眼發出的)
我們需要計算圖片上某一像素點的經過水麪折射後實際對應紋理圖片的哪一位置
我們需要得到視線經過水麪折射後的的方向,要得到這個計算,必須得到視線在水面上對應點(平面)的法向量,通過法向量,我們才能完成入射方向->折射方向的計算
由於通過水麪我們是通過函數來構造的,按理說可以通過對函數求偏導來計算得到兩個切向量,把它們叉乘就得到了點平面的法向量,但函數其實是非常複雜的,求導之後函數變得非常龐大,計算也比較困難,因此我們用一個投機取巧的方式來計算點平面的法向量:
我們通過求點平面附近兩個不共線點的高度,組成兩個方向向量,通過對它們求叉乘來計算法向量,這樣得到是數據雖然不是很精確,但已經夠用了,且效率也不低。
計算折射光線的方向
GLSL提供了一個函數refract(入射向量,法向量,折射相對係數)來計算折射
因此,我們知道了入射向量(0,0,-1)和法向量,求折射向量其實是很簡單的,調用函數就行(水到空氣的折射係數爲4/3,約等於1.33)
計算座標偏移
得到折射向量之後,我們只需要把折射向量的進行拉伸使得z值等於實際高度(水面高度+波形高度),就能得出經過水麪折射後xy的偏移值,原來的座標+偏移座標就得到了水面折射後的座標,另外由於紋理座標的取值爲[0,1],因此我們還需要根據窗口寬度做一個座標標準化。
大功告成!
附上博主自己實現的片段着色器代碼:
#version 330 core
out vec4 FragColor;
uniform sampler2D texture;
uniform vec3 data[50]; //data傳遞(鼠標x,鼠標y,運行時間):支持多振源
uniform int data_size; //當前有效的data長度
uniform vec2 screen_size; //屏幕尺寸
uniform float frequency; //頻率
uniform float amplitude; //最大振幅
uniform float wave_width; //波紋的寬度
uniform float depth; //水平面距離背景圖片的深度
uniform float speed;
in vec2 TexCoord;
void main()
{
float height;
float upHeight;
float rightHeight;
for(int i=0;i<data_size;i++){
float time = data[i].z; //鼠標點擊後的時間
float dis = distance(data[i].xy,gl_FragCoord.xy); //鼠標位置到當前片段位置的距離
float amplit = amplitude*pow(2.74,-(dis-time*speed)*(dis-time*speed)/2/(wave_width*wave_width))*sin(dis*frequency); //計算當前片段的振幅:這裏利用高斯函數突出顯示當前時間所顯示的波形
height += amplit*sin(dis*frequency); //當前波形的高度
dis=distance(data[i].xy,gl_FragCoord.xy+vec2(0,1));
upHeight += amplitude*pow(2.74,-(dis-time*speed)*(dis-time*speed)/2/(wave_width*wave_width))*sin(dis*frequency)*sin(dis*frequency);
dis=distance(data[i].xy,gl_FragCoord.xy+vec2(1,0));
rightHeight += amplitude*pow(2.74,-(dis-time*speed)*(dis-time*speed)/2/(wave_width*wave_width))*sin(dis*frequency)*sin(dis*frequency);
}
vec3 up = vec3(0,1,upHeight-height);
vec3 right = vec3(1,0,rightHeight-height);
vec3 normal = cross(up,right);
vec3 view = vec3(0,0,-1);
vec3 re = refract(view,normal,1.33);
vec2 coordOffset = re.xy*((height+depth)/re.z)/screen_size;
FragColor = texture2D(texture,TexCoord+coordOffset);
}
........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................