這周學了好多。包括偽隨機數。柏林雜訊。
先說偽隨機數。偽隨機數我們用的是週期函式而不是那種由前一項乘乙個超大的數取餘數的方法。使用週期函式的好處就是可以讓其隨時間均勻變化。不過使用週期函式一定要保證週期非常長,不然就會出現重複的圖樣。
這是我在網上找到的乙個偽隨機函式:
cos(x * (12.9898) + y * (4.1414)) * 43758.5453
它使用x, y作為引數,剛好對應畫素的座標。(ps:發現好多glsl的例子都用類似的隨機函式,應該裡面蘊含了什麼數學吧。)
這個函式的週期應該挺長的, 會發現在cos的後面還乘上了乙個超大的數,這樣可以達到不錯的偽隨機效果,不過還需要很重要的一步。
最終的隨機函式是這樣的:
fract(cos(x * (12.9898) + y * (4.1414)) * 43758.5453)
fract這個glsl預定義的函式的作用是返回小數部分,會達到非常不錯的效果。
↑這是沒有加上fract的結果,因為所有大於1的值都變成1了。(gl中畫素的顏色值範圍是0.0-1.0)
↑這是加上fract的效果,看起來還不錯是吧。
ps:
在想隨機數的時候,我想人工智慧是不是其實是可以實現的呢。因為智慧型可能就是對乙個個小事件的反應,當這些對各種事情的反應多起來的時候,數量趨近於無窮,或者達到乙個閥值,就會表現出智慧型。因為人類的大腦說不定也是這樣,是不是也是對乙個個小事件的反應呢,我想是的,大腦裡面這種反應非常多,多到了乙個閥值,所以才會變現出「智慧型」,而自由意志應該就是量子隨機性造成的,而至於為什麼不覺得這種隨機不想是「隨機」的呢,而想是可控的呢?因為這些隨機性的東西都會經過乙個個在大腦中設定好的程式,被這樣處理過的資訊之後,看起來就變得「有序」了。(稍後你會看到上面這些這樣隨機的圖樣,最終會變成一幅不錯的圖畫)所以,人工智慧終有一天是會實現的,只要不斷地設定對各種事件的反應,讓它看起來「好像是智慧型的樣子呢」,當這種「好像是智慧型的樣子呢」多起來的時候,達到了乙個閥值,那麼這個東西就是真正的智慧型了,這裡可沒有雙引號。這裡也稍微的用一下數學裡面的極限思想了呢,0.999...這樣無窮下去,數學上的結果就是1。不過目前想要達到這個閥值,需要的是非常高效能的計算機還有聰明的程式設計師,至少前者還不能實現,在未來20年之後,估計就能實現看起來非常智慧型的人工智慧了。
哎呀,扯多了。
接下來是乙個次時代的火焰特效,所謂次時代就是20年前的特效。雖然不知道是不是真的是20年前,不過看起來像,哈哈。由淺入深嘛。慢慢地就會學到現代的技術了。
看起來還闊以吧。
接下來是柏林雜訊(perlin雜訊)了,ken perlin在2023年為電影創造了這種雜訊,它可以模擬自然的雲、火焰、水面等,為電影特效做出了功不可沒的貢獻,為此,他獲得了「奧斯卡技術成就獎」。
perlin雜訊就是n個函式的疊加,這n個函式滿足,下乙個的頻率是前乙個的兩倍,幅度是二分之一。而函式嘛,當然是選擇我們上面的偽隨機函式啦。
不過首先,我們要對螢幕的畫素分組。我的分組是250*250個一組。 也就是這250*250個畫素共享同乙個隨機的值。然後,對於每個小組,每個小組裡面的畫素,進行一次插值,(可以是線性插值(假如在a,,b兩點間插值,t(0<=t<=1)是距離a的距離比例,那麼t位置的值是(1 - t) * a + t * b,(1 - t)是插值函式),不過效果差,perlin本人推薦 3 * t * t - 2 * t * t * t,後來推薦..哎呦 這個好長,就不寫出來了)二維的插值是這樣的,首先取本小組的值和右邊小組的值在x方向插值得到a,然後是下面小組的值和右下小組的值在x方向插值得到b,最後就是a和b在y方向插值得到最終結果。
glsl裡面有預定義插值函式,線性的mix和平滑的smoothstep。
所以,**看起來是這樣的:
#define r 250
float noise(float x, float y)
看起來是這樣的:
哇..看起來好爽。
接下來就是perlin雜訊了, 請看**:
float fbm(float x, float y)
return total;
}
效果是這樣的:
我已經看到了一點雲的樣子了呢。
接下來,加點顏色,你可以自由發揮,這裡只是乙個例子:
t = float(_t);
float z = fbm(gl_fragcoord.x - t * 100, gl_fragcoord.y - t * 100);
float x = fbm(gl_fragcoord.x + t * 60, gl_fragcoord.y - t * 40);
float c = fbm(gl_fragcoord.x - t * 70, gl_fragcoord.y - t * 80);
vec3 color1 = vec3(1.0, 0.9, 0.0);
vec3 color2 = vec3(1.0, 0.0, 0.0);
vec3 color3 = vec3(0.0, 0.0, 0.0);
vec3 color4 = vec3(0.2, 0.2, 0.2);
vec3 color5 = vec3(0.0, 0.0, 0.6);
vec3 color6 = vec3(0.0, 0.6, 0.0);
gl_fragcolor = vec4(mix(color2, color1, z) + mix(color3, color4, x) - mix(color5, color6, c), 1.0);
就可以達到火焰特效了,要更加逼真的效果就需要不斷的嘗試顏色的組合,或者加入數學知識。
對了,漏了最重要的一點,就是怎麼向著色器裡面傳乙個值。
用到的是uniform技術。
在glsl**中,你只要這樣:
uniform int _t;
就可以宣告乙個_t的uniform變數。uniform在一次渲染中值不會改變,所有著色器都可以訪問這個值。程式也可以在每一幀時任意修改uniform的值。用這樣的語句:
glint location;
location = glgetuniformlocation(program, "_t");
gluniform1i(location, _t);
**以上參考:火焰特效是借鑑裡面的乙個特效,不過原文的位址我忘了t t。
好了。周記完畢,在最後送乙個小特效:
void main()
GLSL 著色器相關
一 頂點著色器 頂點著色器,根據應用程式的設計,只是選擇處理 1.視覺空間變換 模型,法線,紋理 2.主顏色和輔助顏色的計算生成 光照在攝像機座標系中進行實時光照計算 3.紋理座標計算。4.霧座標設定和處理。5.點大小。1 透視除法。硬體實現。2 視口對映變換。硬體實現。3 圖元裝配,在4d裁剪空間...
OpenGL中使用GLSL著色器
opengl中使用glsl著色器步驟 glsl既適用於頂點著色器,也適用於片段著色器。使用著色器物件的步驟 1 建立著色器物件 gluint glcreateshader glenum type 建立乙個著色器物件,type值必須是gl vertex shader或gl fragment shade...
GLSL 著色器的輸入輸出變數
int vertexcolorlocation glgetuniformlocation shaderprogram,uniformcolor gluseprogram shaderprogram gluniform4f vertexcolorlocation,0.0f 0.0f 0.0f 1.0f...