外星圖像渲染語言?如何應用Shader 跟WebGL 達成絢麗視覺 ...
文章推薦指數: 80 %
如何應用Shader 跟WebGL 達成絢麗視覺效果. 2022 年7 月7 日; creativecoding-editor. 本篇文章老闆要來聊聊什麼是Shader 、把Shader 實作在專案中的經驗、以及如何 ...
跳至主要內容
本篇文章老闆要來聊聊什麼是Shader、把Shader實作在專案中的經驗、以及如何開始玩玩看Shader。
3D技術逐漸應用於網頁上,瞭解Shader就可以透過GPU,以更快的速度渲染出各式各樣有趣的視覺效果和互動,快跟著老闆看下去吧!
吳哲宇的創作SpikeMountains
閱讀完此篇文章,你會知道:
什麼是ShaderShader應用案例如何開始學習Shader
相關資源
Codrops:有很多網頁互動相關的資源,大家可以去挖寶Shadertoy:很多厲害的Shader作品TheBookofShaders:詳細地介紹ShaderTheBookofShaders提供的Shaders編輯器老闆自製p5的Shadertemplate不藏私分享給大家
Shader作品和必追蹤的藝術家
Madebyevan–webglwaterSayamaZachLieberman
Shader
老闆第一次接觸Shader,是在Codrops看到的WebGLDistortionHoverEffects這篇文章,第一印象覺得它根本就像是外星語言,因為它是非常底層的、類似C++的程式語言。
滑鼠滑過物件的互動,對網頁工程師來說,大概就是簡單地在css寫上&hover然後可能換個背景圖片和顏色,再加上transition。
但這篇文章中的Demo卻做出了各種讓人為之驚艷的效果,像是類似液體那樣ㄍㄡˊㄍㄡˊ的感覺、三角形漸層、稜鏡感、刷色感、鋸齒狀…等等。
老闆原本想說,這大概需要研究個兩三天用很多行的程式碼才寫得出來,殊不知點開它的code,發現做出這麼酷炫視覺效果的程式碼,嚴格上來說只有短短的六行!
大概就是這個部分:
//hover-effect.js
voidmain(){
vec4disp=texture2D(disp,vUv);
vec2dispVec=vec2(disp.r,disp.g);
vec2uv=0.5*gl_FragCoord.xy/(res.xy);
vec2myUV=(uv-vec2(0.5))*res.zw+vec2(0.5);
vec2distortedPosition1=myUV+getRotM(angle1)*dispVec*intensity1*dispFactor;
vec2distortedPosition2=myUV+getRotM(angle2)*dispVec*intensity2*(1.0-dispFactor);
vec4_texture1=texture2D(texture1,distortedPosition1);
vec4_texture2=texture2D(texture2,distortedPosition2);
gl_FragColor=mix(_texture1,_texture2,dispFactor);
}
`;
為了瞭解他如何運作,老闆接觸到Shadertoy這個網站,裡面有類似剛剛那種hover效果的超級進階版應用,像是用200行左右的程式碼做出超逼真海水,或者像這樣利用造點圖片加上扭曲旋轉效果即完成的銀河Galaxy。
Shadertoy上的範例作品銀河Galaxy
什麼是Shader?
Whatisafragmentshader?
Shadersareasetofinstructions,buttheinstructionsareexecutedallatonceforeverysinglepixelonthescreen.Thatmeansthecodeyouwritehastobehavedifferentlydependingonthepositionofthepixelonthescreen.Likeatypepress,yourprogramwillworkasafunctionthatreceivesapositionandreturnsacolor,andwhenit’scompileditwillrunextraordinarilyfast.-TheBookofShaders
Shader是繪製螢幕上內容的著色器,最重要的特性在於它是以每顆像素個別做渲染的方式運作,可以想像成活字印刷機,透過定義每顆像素在每個位置的表現組成一個完整畫面。
為什麼Shader渲染可以這麼快?
因為它不是用CPU,而是用GPU來運算。
CPU(中央處理器)通常被大家理解為是電腦的大腦,負責執行作業系統所需的指令與程序,它是線性的加工廠,一次可以處理一個工作。
而GPU(繪圖處理器)則是由許多更小也更專業的核心組成,所以我們就可以一次性地送出我們想處理的像素,一次性地處理完之後,再渲染出來。
用水管來比喻的話,CPU就像一根大水管,但它一次只能處理一顆像素,而我們有堆積如山的像素等著被處理;GPU則像是很多個水管並列,所以我們可以讓很多顆像素同時通過不同的小水管。
圖片來源:TheBookofShaders
但是問題來了,我們要怎麼告訴這些不同的小水管,每顆像素該如何做處理呢?
在撰寫Shaders時使用的語言是GLSL(OpenGLShadingLanguage),也稱做GLslang,是一個以C語言為基礎的高階著色語言。
它讓我們可以跟GPU溝通,安排每個小水管該負責什麼工作。
這也是讓Shaders看起來不是很平易近人的原因。
首先,為了讓每根小水管能夠同時獨立運作,它們彼此之間的資料會是單向且無法溝通的,就像上方圖片示意那樣,資料處理的方向必須是相同的,而且每根水管都沒有辦法知道彼此處理完的像素變成什麼樣子。
此外,因為GPU會讓工作接踵而至,換句話說會一直塞東西進水管,所以這些水管也就忙到沒辦法記得它們自己上一個工作的內容。
Eachthreadisnotjustblindbutalsomemoryless.Besidestheabstractionrequiredtocodeageneralfunctionthatchangestheresultpixelbypixeldependingonitsposition,theblindandmemorylessconstraintsmakeshadersnotverypopularamongbeginningprogrammers.-TheBookofShaders
HelloWorld
讓瀏覽器顯示HelloWorld通常是學新語言時會做的第一個練習,但是要在GPU領域渲染文字是件相對困難的事情,所以這個範例就用色塊來說明:
#ifdefGL_ES
precisionmediumpfloat;
#endif
uniformfloatu_time;
voidmain(){
gl_FragColor=vec4(0,0,0,0);//red,green,blue,alpha
}
接著也可以嘗試代入變數uniform
我們可以透過uniform從CPU發送資料到GPU,且透過uniform宣告的變數會是全域且獨特的,可以在所有的Shaders中讀取。
#ifdefGL_ES
precisionmediumpfloat;
#endif
uniformfloatu_time;
voidmain(){
gl_FragColor=vec4(abs(sin(u_time)),0.0,0.0,1.0);
//gl_FragColor=vec4(abs(sin(mod(u_time,0.5))),0.0,0.0,1.0);//例如這樣寫可以讓閃爍變快
}
在GLSL中有提供許多計算數值的functions,像是sin(),cos(),tan(),asin(),acos(),atan(),pow(),exp(),log(),sqrt(),abs(),sign(),floor(),ceil(),fract(),mod(),min(),max()andclamp()等等,我們可以用這些函式搭配時間做出會不斷變動的圖形。
gl_FragCoord
除了像上面的範例那樣,用uniform宣告同樣的input,再用defaultoutputvec4gl_FragColor呈現結果的做法外,GLSL也給了我們defaultinputvec4gl_FragCoord,其中儲存了每個水管正在處理的pixel或screenfragment的座標,有了這個資訊,我們就可以針對每個座標做個別的處理,而這個情況下所使用的變數就不會叫做uniform,而會稱作varying。
#ifdefGL_ES
precisionmediumpfloat;
#endif
uniformvec2u_resolution;
uniformvec2u_mouse;
uniformfloatu_time;
voidmain(){
vec2st=gl_FragCoord.xy/u_resolution;
//vec2st=gl_FragCoord.xy/u_mouse;//例如這樣可以用滑鼠改變漸層的位置
gl_FragColor=vec4(st.x,st.y,0.0,1.0);
}
在Shader裡面畫圖形是很困難的事情
因為用「點」連成「面」是一個相對高階的概念,在GLSL中如果要做出形狀,就得把每個邊的位置都計算出來之後再組合起來,才可以變成圖形。
所以就會需要很多角度、三角函數、指數等等的數學計算。
Shader可以做什麼?
把Shader做為材質來使用
TimeSwirlDNAMutation
可以用圖層的概念來想:基礎圖形+一些filter+扭轉座標=看起來就會像有躁點的漩渦。
把Shader用在3D的模型上
PlasmaPlanet
用Shaders渲染一顆3D的球,也可以根據滑鼠位置做變化。
綜合應用
MemoryLost
用p5.js畫一張動態圖片+把Shaders做成扭曲filter。
如果註解掉frag標籤下,voidmain(){}裡面的這三行程式碼,就可以得到沒有經過shader濾鏡的原始p5.js動態畫面:
distorted_st.x+=cnoise(vec3(st.x*5000.,st.y*3000.,u_time))/(1.+(sin(sqrt(st.y+u_time/20.)*50.)+1.)*500.)/2.;//電視雜訊1
distorted_st.y+=cnoise(vec3(st.x*5000.,st.y*3000.,u_time))/(1.+(sin(sqrt(st.y+u_time/10.)*50.)+1.)*1000.)/2.;//電視雜訊2
distorted_st.x+=sin(distorted_st.y*(50.+sin(st.x)*20.)+u_time)*distorted_st.y*distorted_st.y/10.;//X方向的扭曲
Shader就像是非常高功能的透鏡,但困難的點在於,我們要定義每個像素經過這個透鏡的行為。
與3D整合:Three.js–Displacementmap
3D軟體的渲染,像是Unreal、Vray、Octane等等軟體內的材質編輯器,跟Shader運用的概念都一樣,所以如果沒有要做到更底層的應用,使用Shader就像是在自討苦吃。
因為把Shader做為3D環境的材質來使用,勢必得考慮光影的渲染,例如光打到某個點上,材質會如何變化、入射方向、反光效果等等,會更加複雜。
例如要做出像磁磚獲木紋那樣凹凸的效果,除了貼上紋理之外,還需要告訴軟體根據這個紋理渲染對應的陰影。
Shader的displacementmap就是透過指定一個畫面,算出對應的陰影和光線反射,讓整個畫面看起來更真實。
應用案例
日本藝術家Sayama的創作
日本藝術家Sayama–200426
實務應用
所有技術最重要的還是要能夠應用,譬如工作室願意把它用到上線的專案中,它才有意義。
實務上老闆把Shader拿來畫OUTERNETS的Home和Aboutus,做出光暈和躁點效果,還有非常繽紛科幻可以跟滑鼠互動的旋轉球球。
Outernets
Outernets
Outernets–Aboutus
Outernets–Aboutus
墨雨工作室也嘗試把Shader應用在跟18天台灣生啤酒1起吃飯8!這個活動網頁上,做出啤酒噴灑出來的動態扭曲效果。
跟18天台灣生啤酒1起吃飯8!
如何開始學習Shader?
TheBookofShaders
這個網站用深入淺出的說明加上可以操作的範例,也提供了一個好用的編輯器(從網站首頁點選ExamplesGallery,再點擊“HelloWorld”下面的色塊),可以先從這邊熟悉Shader,之後再嘗試放到自己的專案中。
TouchDesigner
探索Shader也可以從TouchDesigner開始,它幫我們把各種模組都寫好,讓我們不用寫任何程式碼,只要載入不同的圖片和效果就可以玩出各式各樣的變化。
BananaTest
例如老闆之前在嘗試的時候,把香蕉經過transform再合成到背景上面。
Bananatest
題外話:各位如果對3D有興趣的話,可以去玩玩看Blender,它是開源的免費軟體。
在p5裡面玩Shader
ITP–p5jsshaders介紹了如何把p5和Shader結合使用,把Shader當成材質或者影像的即時處理。
老闆也在OpenProcessing製作了Shadertemplate,基礎的架設都已經完成了,歡迎fork之後自己玩玩看囉!
簡單的Demo
雜訊效果:可以用rand()給原本位置的像素一個隨機的位置資訊,就會讓畫面有看起來霧霧的效果。
//frag標籤中的第20行開始
voidmain(){
vec2st=var_vertTexCoord.xy/u_resolution.xy;
st.x+=rand(st);//霧霧的效果
st.x+=rand(st)/(1.+st.y*10.);//上面會霧霧的,但越下面會越平滑
vec3color=vec3(st.x,st.y,1.0);
floatd=distance(u_mouse,st);
color*=1.-d;
gl_FragColor=vec4(color,1.0);
}
扭曲效果:用sin()給y位置的資訊(但因為底圖沒有東西所以看不太出來效果)
//frag標籤中的第20行開始
voidmain(){
vec2st=var_vertTexCoord.xy/u_resolution.xy;
st.y+=sin(st.x/10.)/10.;//像這樣
vec3color=vec3(st.x,st.y,1.0);
floatd=distance(u_mouse,st);
color*=1.-d;
gl_FragColor=vec4(color,1.0);
}
範例testbubble根據左側的底圖,做完扭曲效果後就變成右側:
voidmain(){
vec2st=var_vertTexCoord.xy/u_resolution.x;
st.x+=rand(st)/5.;//模糊效果
st.y+=sin(st.x*50.)/10.;//扭曲效果
vec3color=vec3(0.);
floatang=atan(st.y-0.55,st.x-0.5);
floatr=sin(ang*5.+u_time*2.+u_mouse.y*3.+u_mouse.x*3.);
vec2displacemenetMap=vec2(cos(ang),sin(ang))*r/150.;
vec3spray=texture2D(tex0,st+displacemenetMap-vec2(0.,0.2)).rgb;
if(!u_mouse_pressed){
color+=spray;
}else{
color=vec3(displacemenetMap,0.5)*500.;
}
gl_FragColor=vec4(color,1.0);
}
也可以拿上一格留下的畫面做扭曲,看起來就會像液體效果。
結語
老闆覺得現在3D的趨勢應該會越來越往網頁發展,像Autodesk也出了Fusion360可以在網頁上製作3D物件,如果可以把這些效果應用在案子的網頁上,想必可以創作出更加吸睛的視覺。
五分鐘問答時間
Q.會開Shader課程嗎?
感覺有點難募資達標,有點太小眾了😂
Q.最近有看到什麼用Shader做的酷案例嗎?
可以在awwwards上找到很多厲害的範例!搭配p5.js或是three.js就可以用在像是carousel(輪播)或是其他扭曲的效果。
Q.NodeEditor怎麼做?
可以使用現成函式庫Rete.js,把自己的function做成可以給前端使用的介面。
但技術尚未非常成熟,用在實務要自己注意一下囉。
小範例:胎死腹中的文章產生器原本想說可以做一份教材,用模組編輯的方式組裝成A,B,C…多種不同的教材,就可以因材施教。
但發現沒有特別方便,而且概念其實也蠻類似現在的筆記工具Notion。
老闆貼心提示:CodePen不是工程師實務上會使用的
使用CodePen或者OpenProcessing等平台,主要是為了讓學生快速上手,不需要自己架設開發環境,如果想實作到production,還需要再去更進階了解JavaScript的模組化概念,以及使用Webpack或者Rollup之類的打包工具。
工商時間
互動藝術程式創作入門
《互動藝術程式創作入門》課程學生作品分享
Hahow課程作業成果
GoogleChrome恐龍離線小遊戲(廖書賢)夜空煙火(廖書賢)ColorfulRotateRect(laiBen)TheJungle(柯名陽)seawaves(Loxi)Instagram–ivavay.draw
課程加碼單元
文本分析–了解文字藝術:cloudandrain物理模擬–讓物件自然的落下碰種:alphabetblocks3D世界與物件–p5的WebGL應用:3dcameratexture、3dmodelsword、3ddemo
此篇直播筆記由幫手 Yuan 協助整理
3DGLSLJavaScriptp5.jsShaderShadertoytextureThree.jsTouchdesignerWebGL
上一Post
【互動網頁程式教學】活用GUIObject與繼承概念,完成Canvas物件導向的滑鼠拖曳互動
下一Post
【互動網頁設計網聚】DIGIWAVE案例分享-叁式技術美術長Hoba
相關文章
圓圓圈圈:利用迴圈呈現重覆的美
for迴圈,p5.js,互動藝術,互動藝術程式創作入門,重複
【互動網頁程式教學】活用GUIObject與繼承概念,完成Canvas物件導向的滑鼠拖曳互動
Canvas,GUIObject,互動網頁,物件導向
五月社群聚(下):張文瀚教你用數學作畫GLSLfragmentshader
Fragmentshader,GLSL,OpenProcessing,p5.js,Shader,Shadertoy,張文瀚
【Vue.js入門】一小時學會Vue.component,完成動態飯店房間清單
Component,Vue.js,動態網頁教學,旅館房間清單
PHPCodeSnippetsPoweredBy:XYZScripts.com
關於
資源與社群
入門資源
相關社群
教學
靈感
互動程式創作徵文賞
墨雨設計
延伸文章資訊
- 1外星圖像渲染語言?如何應用Shader 跟WebGL 達成絢麗視覺 ...
如何應用Shader 跟WebGL 達成絢麗視覺效果. 2022 年7 月7 日; creativecoding-editor. 本篇文章老闆要來聊聊什麼是Shader 、把Shader 實作在...
- 2WebGL - Shaders - Tutorialspoint
Shaders are the programs that run on GPU. Shaders are written in OpenGL ES Shader Language (known...
- 3学习WebGL之深入了解Shader - 简书
无论是Vertex Shader还是Fragment Shader,都有基本的代码框架。下面是本文使用的Vertex Shader。 attribute vec4 position; varyi...
- 4WebGL Shaders and GLSL
As mentioned in how it works WebGL requires 2 shaders every time you draw something. A vertex sha...
- 5Day 10 Web GL Shader介紹 - iT 邦幫忙
但OpenGL ES 與WebGL是只能使用shader,為什麼這就要從Graphic pipeline來看,. Graphic Pipeline就是指電腦運算資料,最後顯示在螢幕上的一個流程。...