GLSL着色器周记02
生活随笔
收集整理的這篇文章主要介紹了
GLSL着色器周记02
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
GLSL著色器周記02
來源:網(wǎng)絡(luò) ?? 編輯:admin
| 這周學(xué)了好多。包括偽隨機(jī)數(shù)。柏林噪聲。 先說偽隨機(jī)數(shù)。偽隨機(jī)數(shù)我們用的是周期函數(shù)而不是那種由前一項(xiàng)乘一個(gè)超大的數(shù)取余數(shù)的方法。使用周期函數(shù)的好處就是可以讓其隨時(shí)間均勻變化。不過使用周期函數(shù)一定要保證周期非常長(zhǎng),不然就會(huì)出現(xiàn)重復(fù)的圖樣。 這是我在網(wǎng)上找到的一個(gè)偽隨機(jī)函數(shù): cos(x * (12.9898) + y * (4.1414)) * 43758.5453 它使用x, y作為參數(shù),剛好對(duì)應(yīng)像素的坐標(biāo)。(PS:發(fā)現(xiàn)好多GLSL的例子都用類似的隨機(jī)函數(shù),應(yīng)該里面蘊(yùn)含了什么數(shù)學(xué)吧。)? 這個(gè)函數(shù)的周期應(yīng)該挺長(zhǎng)的,?會(huì)發(fā)現(xiàn)在cos的后面還乘上了一個(gè)超大的數(shù),這樣可以達(dá)到不錯(cuò)的偽隨機(jī)效果,不過還需要很重要的一步。 最終的隨機(jī)函數(shù)是這樣的: fract(cos(x * (12.9898) + y * (4.1414)) * 43758.5453) fract這個(gè)glsl預(yù)定義的函數(shù)的作用是返回小數(shù)部分,會(huì)達(dá)到非常不錯(cuò)的效果。 ? ↑這是沒有加上fract的結(jié)果,因?yàn)樗写笥?的值都變成1了。(GL中像素的顏色值范圍是0.0-1.0)? ? ↑這是加上fract的效果,看起來還不錯(cuò)是吧。 PS: 在想隨機(jī)數(shù)的時(shí)候,我想人工智能是不是其實(shí)是可以實(shí)現(xiàn)的呢。因?yàn)橹悄芸赡芫褪菍?duì)一個(gè)個(gè)小事件的反應(yīng),當(dāng)這些對(duì)各種事情的反應(yīng)多起來的時(shí)候,數(shù)量趨近于無(wú)窮,或者達(dá)到一個(gè)閥值,就會(huì)表現(xiàn)出智能。因?yàn)槿祟惖拇竽X說不定也是這樣,是不是也是對(duì)一個(gè)個(gè)小事件的反應(yīng)呢,我想是的,大腦里面這種反應(yīng)非常多,多到了一個(gè)閥值,所以才會(huì)變現(xiàn)出“智能”,而自由意志應(yīng)該就是量子隨機(jī)性造成的,而至于為什么不覺得這種隨機(jī)不想是“隨機(jī)”的呢,而想是可控的呢?因?yàn)檫@些隨機(jī)性的東西都會(huì)經(jīng)過一個(gè)個(gè)在大腦中設(shè)定好的程序,被這樣處理過的信息之后,看起來就變得“有序”了。(稍后你會(huì)看到上面這些這樣隨機(jī)的圖樣,最終會(huì)變成一幅不錯(cuò)的圖畫)所以,人工智能終有一天是會(huì)實(shí)現(xiàn)的,只要不斷地設(shè)定對(duì)各種事件的反應(yīng),讓它看起來“好像是智能的樣子呢”,當(dāng)這種“好像是智能的樣子呢”多起來的時(shí)候,達(dá)到了一個(gè)閥值,那么這個(gè)東西就是真正的智能了,這里可沒有雙引號(hào)。這里也稍微的用一下數(shù)學(xué)里面的極限思想了呢,0.999...這樣無(wú)窮下去,數(shù)學(xué)上的結(jié)果就是1。不過目前想要達(dá)到這個(gè)閥值,需要的是非常高性能的計(jì)算機(jī)還有聰明的程序員,至少前者還不能實(shí)現(xiàn),在未來20年之后,估計(jì)就能實(shí)現(xiàn)看起來非常智能的人工智能了。 哎呀,扯多了。 接下來是一個(gè)次時(shí)代的火焰特效,所謂次時(shí)代就是20年前的特效。雖然不知道是不是真的是20年前,不過看起來像,哈哈。由淺入深嘛。慢慢地就會(huì)學(xué)到現(xiàn)代的技術(shù)了。 ? ? 看起來還闊以吧。 不知道gif能不能播放,不過gif畫質(zhì)太渣了,還是不用gif了。你就想想這個(gè)火焰是會(huì)動(dòng)的就行啦。 接下來是柏林噪聲(Perlin噪聲)了,Ken Perlin在1981年為電影創(chuàng)造了這種噪聲,它可以模擬自然的云、火焰、水面等,為電影特效做出了功不可沒的貢獻(xiàn),為此,他獲得了“奧斯卡技術(shù)成就獎(jiǎng)”。 Perlin噪聲就是n個(gè)函數(shù)的疊加,這n個(gè)函數(shù)滿足,下一個(gè)的頻率是前一個(gè)的兩倍,幅度是二分之一。而函數(shù)嘛,當(dāng)然是選擇我們上面的偽隨機(jī)函數(shù)啦。 不過首先,我們要對(duì)屏幕的像素分組。我的分組是250*250個(gè)一組。?也就是這250*250個(gè)像素共享同一個(gè)隨機(jī)的值。然后,對(duì)于每個(gè)小組,每個(gè)小組里面的像素,進(jìn)行一次插值,(可以是線性插值(假如在A,,B兩點(diǎn)間插值,t(0<=t<=1)是距離A的距離比例,那么t位置的值是(1 - t) * A + t * B,(1 - t)是插值函數(shù)),不過效果差,Perlin本人推薦 3 *?t * t - 2 * t * t * t,后來推薦..哎呦 這個(gè)好長(zhǎng),就不寫出來了)二維的插值是這樣的,首先取本小組的值和右邊小組的值在x方向插值得到a,然后是下面小組的值和右下小組的值在x方向插值得到b,最后就是a和b在y方向插值得到最終結(jié)果。 glsl里面有預(yù)定義插值函數(shù),線性的mix和平滑的smoothstep。 所以,代碼看起來是這樣的: #define r 250 float noise(float x, float y) { int base_x = int(floor(x / r)); // 小組的x編號(hào) int base_y = int(floor(y / r)); // 小組的y編號(hào) x = fract(x / r); // 像素在小組內(nèi)x方向的權(quán)值 y = fract(y / r);?// 像素在小組內(nèi)y方向的權(quán)值 float f_x = smoothstep(0, 1, x); // 平滑后的值 float f_y = smoothstep(0, 1, y); // 平滑后的值 return mix( mix(rand(float(base_x), float(base_y)), rand(float(base_x + 1), float(base_y)), f_x) // 第一次的x方向插值 , mix(rand(float(base_x), float(base_y + 1)), rand(float(base_x + 1), float(base_y + 1)), f_x) // 第二次的x方向插值 , f_y) // 最后的y方向插值 ; }? 看起來是這樣的: ? 哇..看起來好爽。 接下來就是Perlin噪聲了,?請(qǐng)看代碼: float fbm(float x, float y) { float total = 0.0, amplitude = 1.0; for (int i = 0; i < 4; i++) // 4個(gè)函數(shù)疊加 { total += noise(x, y) * amplitude;? x += x; ?// 頻率乘以2 y += y; ?// 頻率乘以2 amplitude *= 0.5; // 幅度乘以二分之一 } return total; }? 效果是這樣的: 我已經(jīng)看到了一點(diǎn)云的樣子了呢。 接下來,加點(diǎn)顏色,你可以自由發(fā)揮,這里只是一個(gè)例子: 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);? 就可以達(dá)到火焰特效了,要更加逼真的效果就需要不斷的嘗試顏色的組合,或者加入數(shù)學(xué)知識(shí)。 對(duì)了,漏了最重要的一點(diǎn),就是怎么向著色器里面?zhèn)饕粋€(gè)值。 用到的是uniform技術(shù)。 在glsl代碼中,你只要這樣: uniform int _t; ? 就可以聲明一個(gè)_t的uniform變量。uniform在一次渲染中值不會(huì)改變,所有著色器都可以訪問這個(gè)值。程序也可以在每一幀時(shí)任意修改uniform的值。用這樣的語(yǔ)句: GLint location; location = glGetUniformLocation(program, "_t"); glUniform1i(location, _t);? **以上參考:http://www.tuicool.com/articles/VFnAFbB?;鹧嫣匦墙梃bhttp://glslsandbox.com/里面的一個(gè)特效,不過原文的地址我忘了T T。 好了。周記完畢,在最后送一個(gè)小特效: void main()? { vec3 color = vec3(0.0, 0.0, 0.0); float angle = t * t * 0.1; vec2 q; q.x = p.x + cos(angle * 3.14 / 180) * 10; q.y = p.y + sin(angle * 3.14 / 180) * 10; float A = q.y - p.y; float B = p.x - q.x; float C = q.x * p.y - p.x * q.y; float rate; rate = A * gl_FragCoord.x + B * gl_FragCoord.y + C; rate = rate * rate; rate = rate / (A * A + B * B); rate = 100 / rate; color.x = rate * 0.0; color.y += rate * 0.0; color.z += rate * 0.8; float x, y; x = gl_FragCoord.x - 1366.0 / 2; y = gl_FragCoord.y - 768.0 / 2; rate = x * x + y * y; rate = sqrt(rate); int temp = _t % 20; rate -= (temp * temp); if(rate < 0) rate = -rate; rate *= rate; rate = 100 / rate; color.x = rate * 0.8; color.y += rate * 0.0; color.z += rate * 0.0; gl_FragColor = vec4(color, 1.0); }? |
總結(jié)
以上是生活随笔為你收集整理的GLSL着色器周记02的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GLSL 内建函数
- 下一篇: 为新手准备的 Codea 着色器(Sha