外星圖像渲染語言?如何應用Shader 跟WebGL 達成絢麗視覺 ...

文章推薦指數: 80 %
投票人數:10人

如何應用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 關於 資源與社群 入門資源 相關社群 教學 靈感 互動程式創作徵文賞 墨雨設計



請為這篇文章評分?