Shader 彙整 | Creative Coding TW - 互動程式創作台灣站 https://creativecoding.in/category/tutorial/shader/ 蒐集互動設計案例、教學與業界資源,幫助你一起進入互動程式創作的產業 Sun, 17 Jul 2022 08:38:23 +0000 zh-TW hourly 1 https://wordpress.org/?v=6.2.2 https://creativecoding.in/wp-content/uploads/2022/03/cropped-cct-logo-icon-2-32x32.png Shader 彙整 | Creative Coding TW - 互動程式創作台灣站 https://creativecoding.in/category/tutorial/shader/ 32 32 外星圖像渲染語言?如何應用 Shader 跟 WebGL 達成絢麗視覺效果 https://creativecoding.in/2022/07/07/shader-webgl-intro/ Thu, 07 Jul 2022 08:32:00 +0000 https://creativecoding.in/?p=2909 想要在網頁中快速渲染出驚人的 3D 視覺效果和互動嗎?本篇文章老闆帶你快速入門了解 Shader、分享實作在專案中的經驗,就讓我們開始玩玩看 Shader 吧!

這篇文章 外星圖像渲染語言?如何應用 Shader 跟 WebGL 達成絢麗視覺效果 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
本篇文章老闆要來聊聊什麼是 Shader 、把 Shader 實作在專案中的經驗、以及如何開始玩玩看 Shader。 3D 技術逐漸應用於網頁上,瞭解 Shader 就可以透過 GPU ,以更快的速度渲染出各式各樣有趣的視覺效果和互動,快跟著老闆看下去吧!

吳哲宇的創作 Spike Mountains

閱讀完此篇文章,你會知道:

  • 什麼是 Shader
  • Shader 應用案例
  • 如何開始學習 Shader

相關資源

Shader 作品和必追蹤的藝術家


Shader

老闆第一次接觸 Shader,是在 Codrops 看到的 WebGL Distortion Hover Effects 這篇文章,第一印象覺得它根本就像是外星語言,因為它是非常底層的、類似 C++ 的程式語言。

滑鼠滑過物件的互動,對網頁工程師來說,大概就是簡單地在 css 寫上 &hover 然後可能換個背景圖片和顏色,再加上 transition 。但這篇文章中的 Demo 卻做出了各種讓人為之驚艷的效果,像是類似液體那樣 ㄍㄡˊ ㄍㄡˊ 的感覺、三角形漸層、稜鏡感、刷色感、鋸齒狀…等等。老闆原本想說,這大概需要研究個兩三天用很多行的程式碼才寫得出來,殊不知點開它的 code ,發現做出這麼酷炫視覺效果的程式碼,嚴格上來說只有短短的六行!

大概就是這個部分:

// hover-effect.js
void main() {
  vec4 disp = texture2D(disp, vUv);
  vec2 dispVec = vec2(disp.r, disp.g);

  vec2 uv = 0.5 * gl_FragCoord.xy / (res.xy) ;
  vec2 myUV = (uv - vec2(0.5))*res.zw + vec2(0.5);

  vec2 distortedPosition1 = myUV + getRotM(angle1) * dispVec * intensity1 * dispFactor;
  vec2 distortedPosition2 = 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
Shadertoy 上的範例作品銀河 Galaxy

什麼是 Shader ?

What is a fragment shader?

Shaders are a set of instructions, but the instructions are executed all at once for every single pixel on the screen. That means the code you write has to behave differently depending on the position of the pixel on the screen. Like a type press, your program will work as a function that receives a position and returns a color, and when it’s compiled it will run extraordinarily fast. - The Book of Shaders

Shader 是繪製螢幕上內容的著色器,最重要的特性在於它是以每顆像素個別做渲染的方式運作,可以想像成活字印刷機,透過定義每顆像素在每個位置的表現組成一個完整畫面。

為什麼 Shader 渲染可以這麼快?

因為它不是用 CPU ,而是用 GPU 來運算。 CPU (中央處理器)通常被大家理解為是電腦的大腦,負責執行作業系統所需的指令與程序,它是線性的加工廠,一次可以處理一個工作。而 GPU (繪圖處理器)則是由許多更小也更專業的核心組成,所以我們就可以一次性地送出我們想處理的像素,一次性地處理完之後,再渲染出來。

用水管來比喻的話, CPU 就像一根大水管,但它一次只能處理一顆像素,而我們有堆積如山的像素等著被處理; GPU 則像是很多個水管並列,所以我們可以讓很多顆像素同時通過不同的小水管。

圖片來源:The Book of Shaders
圖片來源:The Book of Shaders

但是問題來了,我們要怎麼告訴這些不同的小水管,每顆像素該如何做處理呢?

在撰寫 Shaders 時使用的語言是 GLSL (OpenGL Shading Language) ,也稱做 GLslang ,是一個以 C 語言為基礎的高階著色語言。它讓我們可以跟 GPU 溝通,安排每個小水管該負責什麼工作。

這也是讓 Shaders 看起來不是很平易近人的原因。

首先,為了讓每根小水管能夠同時獨立運作,它們彼此之間的資料會是單向且無法溝通的,就像上方圖片示意那樣,資料處理的方向必須是相同的,而且每根水管都沒有辦法知道彼此處理完的像素變成什麼樣子。此外,因為 GPU 會讓工作接踵而至,換句話說會一直塞東西進水管,所以這些水管也就忙到沒辦法記得它們自己上一個工作的內容。

Each thread is not just blind but also memoryless. Besides the abstraction required to code a general function that changes the result pixel by pixel depending on its position, the blind and memoryless constraints make shaders not very popular among beginning programmers. - The Book of Shaders

Hello World

讓瀏覽器顯示 Hello World 通常是學新語言時會做的第一個練習,但是要在 GPU 領域渲染文字是件相對困難的事情,所以這個範例就用色塊來說明:

#ifdef GL_ES
precision mediump float;
#endif

uniform float u_time;

void main() {
  gl_FragColor = vec4(0,0,0,0); // red, green, blue, alpha
}

接著也可以嘗試代入變數uniform

我們可以透過 uniform 從 CPU 發送資料到 GPU ,且透過 uniform 宣告的變數會是全域且獨特的,可以在所有的 Shaders 中讀取。

#ifdef GL_ES
precision mediump float;
#endif

uniform float u_time;

void main() {
  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() and clamp() 等等,我們可以用這些函式搭配時間做出會不斷變動的圖形。

gl_FragCoord

除了像上面的範例那樣,用 uniform 宣告同樣的 input ,再用 default output vec4 gl_FragColor 呈現結果的做法外, GLSL 也給了我們 default input vec4 gl_FragCoord ,其中儲存了每個水管正在處理的 pixel 或 screen fragment 的座標,有了這個資訊,我們就可以針對每個座標做個別的處理,而這個情況下所使用的變數就不會叫做 uniform ,而會稱作 varying 。

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

void main() {
  vec2 st = gl_FragCoord.xy/u_resolution;
  // vec2 st = gl_FragCoord.xy/u_mouse; // 例如這樣可以用滑鼠改變漸層的位置

  gl_FragColor = vec4(st.x,st.y,0.0,1.0);
}

在 Shader 裡面畫圖形是很困難的事情

因為用「點」連成「面」是一個相對高階的概念,在 GLSL 中如果要做出形狀,就得把每個邊的位置都計算出來之後再組合起來,才可以變成圖形。所以就會需要很多角度、三角函數、指數等等的數學計算。


Shader 可以做什麼?

把 Shader 做為材質來使用

可以用圖層的概念來想: 基礎圖形 + 一些 filter + 扭轉座標 = 看起來就會像有躁點的漩渦。

把 Shader 用在 3D 的模型上

用 Shaders 渲染一顆 3D 的球,也可以根據滑鼠位置做變化。

綜合應用

用 p5.js 畫一張動態圖片 + 把 Shaders 做成扭曲 filter。

如果註解掉 frag 標籤下, void main(){} 裡面的這三行程式碼,就可以得到沒有經過 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 – Displacement map

3D 軟體的渲染,像是 Unreal、Vray、Octane 等等軟體內的材質編輯器,跟 Shader 運用的概念都一樣,所以如果沒有要做到更底層的應用,使用 Shader 就像是在自討苦吃。因為把 Shader 做為 3D 環境的材質來使用,勢必得考慮光影的渲染,例如光打到某個點上,材質會如何變化、入射方向、反光效果等等,會更加複雜。

例如要做出像磁磚獲木紋那樣凹凸的效果,除了貼上紋理之外,還需要告訴軟體根據這個紋理渲染對應的陰影。 Shader 的 displacement map 就是透過指定一個畫面,算出對應的陰影和光線反射,讓整個畫面看起來更真實。

應用案例

日本藝術家 Sayama 的創作

日本藝術家 Sayama – 200426

實務應用

所有技術最重要的還是要能夠應用,譬如工作室願意把它用到上線的專案中,它才有意義。

實務上老闆把 Shader 拿來畫 OUTERNETS 的 Home 和 About us ,做出光暈和躁點效果,還有非常繽紛科幻可以跟滑鼠互動的旋轉球球。

Outernets

Outernets
Outernets

Outernets – About us

Outernets - About us
Outernets – About us

墨雨工作室也嘗試把 Shader 應用在 跟18天台灣生啤酒1起吃飯8! 這個活動網頁上,做出啤酒噴灑出來的動態扭曲效果。

跟18天台灣生啤酒1起吃飯8!
跟18天台灣生啤酒1起吃飯8!

如何開始學習 Shader ?

The Book of Shaders

這個網站用深入淺出的說明加上可以操作的範例,也提供了一個好用的 編輯器 (從網站首頁點選 Examples Gallery ,再點擊 “Hello World” 下面的色塊),可以先從這邊熟悉 Shader ,之後再嘗試放到自己的專案中。

Touch Designer

探索 Shader 也可以從 Touch Designer 開始,它幫我們把各種模組都寫好,讓我們不用寫任何程式碼,只要載入不同的圖片和效果就可以玩出各式各樣的變化。

Banana Test

例如老闆之前在嘗試的時候,把香蕉經過 transform 再合成到背景上面。

Banana test
Banana test

題外話:各位如果對 3D 有興趣的話,可以去玩玩看 Blender ,它是開源的免費軟體。

在 p5 裡面玩 Shader

ITP – p5js shaders 介紹了如何把 p5 和 Shader 結合使用,把 Shader 當成材質或者影像的即時處理。

老闆也在 OpenProcessing 製作了 Shader template ,基礎的架設都已經完成了,歡迎 fork 之後自己玩玩看囉!

簡單的 Demo

雜訊效果:可以用 rand() 給原本位置的像素一個隨機的位置資訊,就會讓畫面有看起來霧霧的效果。

// frag 標籤中的第 20 行開始
void main(){
  vec2 st = var_vertTexCoord.xy /u_resolution.xy;

  st.x += rand(st); // 霧霧的效果
  st.x += rand(st) / (1.+st.y*10.); // 上面會霧霧的,但越下面會越平滑

  vec3 color = vec3(st.x,st.y,1.0);
  float d = distance(u_mouse,st);
  color*=1.-d;
  gl_FragColor= vec4(color,1.0);
}

扭曲效果:用 sin() 給 y 位置的資訊(但因為底圖沒有東西所以看不太出來效果)

// frag 標籤中的第 20 行開始
void main(){
  vec2 st = var_vertTexCoord.xy /u_resolution.xy;

  st.y += sin(st.x/10.)/10.; // 像這樣

  vec3 color = vec3(st.x,st.y,1.0);
  float d = distance(u_mouse,st);
  color*=1.-d;
  gl_FragColor= vec4(color,1.0);
}

範例 test bubble 根據左側的底圖,做完扭曲效果後就變成右側:

void main(){
  vec2 st = var_vertTexCoord.xy /u_resolution.x;

  st.x += rand(st)/5.; // 模糊效果
  st.y += sin(st.x * 50.) /10. ; // 扭曲效果

  vec3 color = vec3(0.);
  float ang = atan(st.y-0.55,st.x-0.5) ;
  float r = sin(ang*5.+u_time*2.+u_mouse.y*3. +u_mouse.x*3.);
  vec2 displacemenetMap = vec2(cos(ang),sin(ang))*r /150. ;
  vec3 spray = 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. Node Editor 怎麼做?

可以使用現成函式庫 Rete.js ,把自己的 function 做成可以給前端使用的介面。但技術尚未非常成熟,用在實務要自己注意一下囉。

小範例:胎死腹中的 文章產生器 原本想說可以做一份教材,用模組編輯的方式組裝成 A, B, C… 多種不同的教材,就可以因材施教。但發現沒有特別方便,而且概念其實也蠻類似現在的筆記工具 Notion 。

老闆貼心提示: CodePen 不是工程師實務上會使用的

使用 CodePen 或者 OpenProcessing 等平台,主要是為了讓學生快速上手,不需要自己架設開發環境,如果想實作到 production ,還需要再去更進階了解 JavaScript 的模組化概念,以及使用 Webpack 或者 Rollup 之類的打包工具。


工商時間

互動藝術程式創作入門
互動藝術程式創作入門

《互動藝術程式創作入門》課程學生作品分享

Hahow 課程作業成果

課程加碼單元

此篇直播筆記由幫手 Yuan 協助整理

墨雨設計banner

這篇文章 外星圖像渲染語言?如何應用 Shader 跟 WebGL 達成絢麗視覺效果 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
五月社群聚(下):張文瀚教你用數學作畫 GLSL fragment shader https://creativecoding.in/2022/06/02/creative-coding-meetup-202205-changwenhan-shader/ Thu, 02 Jun 2022 02:21:00 +0000 https://creativecoding.in/?p=2837 第二次的 Creative Coding 社群聚,我們邀請到了聲音藝術家吳秉聖,以及 Team9 技術長、黑洞創造前端工程師及國立清華大學藝術學院的兼任教師張文瀚,下集由張文瀚介紹如何用數學作畫:fragment shader 的入門與應用。

這篇文章 五月社群聚(下):張文瀚教你用數學作畫 GLSL fragment shader 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
第二次的 Creative Coding 社群聚,上集由聲音藝術家、同時也是噪咖藝術的音樂統籌吳秉聖帶來聲音、光、裝置與創意程式的互動關係,本篇下集則是由張文瀚分享 fragment shader 的有趣創作思維。

張文瀚曾是清大藝術學院的兼任教師,教虛擬實境藝術,也是黑洞創造的前端工程師,自己開了一間 Team9 工作室擔任技術長,主要是在做遊戲,像是「文字遊戲」是只用文字做出來的一個解謎遊戲。

上一位講者吳秉聖分享的是如何用視覺化程式語言、軟體結合實體裝置,製作出互動的裝置作品(想閱讀上集的這邊請)。當大家談到 Creative Coding 通常都會直覺想到 p5.js 等等,叫電腦幫你畫出東西,慢慢組成漂亮的畫面,張文瀚介紹的則是 Creative Coding 的另一個面向、另一種 Creative Coding 的工具: GLSL 的 fragment shader,以及他跟 p5.js 相較之下的優劣勢。

如何叫電腦畫出一個圓?

先從圓的定義開始:「由距離特定座標 500px 以內的所有點集合而成的圖形」在這個畫面中的所有像素,若是離圓心 500px 以內的為黑色,不是的則維持白色。 在 p5.js 內甚至不用懂這個,只要跟 p5.js 說:「在畫布中央用黑色畫一個半徑為500的圓!」他就會幫你畫好了。

下一個問題,如何畫出一個圓,而圓內每個像素都是從黑到白的隨機顏色?

p5.js 畫不出來。

這就是 shader 派上用場的時候了!

像素等級的上色就交給 fragment shader (片段著色器),前提是要親自處理這些運算,了解數學、座標及空間的關係。 需要一些陣痛期才能轉換成 shader 的邏輯和思路,一旦上手之後就可以很順地做出細緻的作品。

為什麼會需要用到片段著色器?

如何用shader快速完成混合漸層效果

想像要做出如左圖這般混合漸層的效果,他的上色規則是甚麼?

對每個像素說,「你在越上面,就越綠;你在越右邊,就越紅。」 用程式替像素上色則變成:

for (var y=0; y < height; y++){
  for (var x=0; x < width; x++){
    var r = (x / width)*255;
    var g = (y / height)*255;
    var b = 0;
    pixels[y][x] = [r,g,b];
  }
}

如果一個畫布的長寬為 1920×1080,總共就有 2,073,600 個像素要著色,也就是為了要完成這一個漸層,這個迴圈程式碼總共要跑兩百萬次!如果只是畫一次,就算多花一點時間也沒關係,何況現在的硬體越來越強大,說久也其實不需要多久。

如果現在規則再加上一條「時間越推移,你就越藍」,而且要及時處理還能跑 60fps,1920 寬 x 1080 高 x 60 fps,每秒鐘得做1.2億次的著色指令!

CPU單執行緒,一次處理一件事
CPU單執行緒,一次處理一件事
CPU單執行緒,事情一多就塞車
CPU單執行緒,事情一多就塞車

像這樣的迴圈程式指令就像一個個的生產線,CPU的單執行緒邏輯,一次只能處理一件事情,東西一多,就會向右邊的圖一樣塞車。我們需要GPU圖形處理器的多執行緒邏輯,同時有無數跟管子並行處理。

Fragment Shader 片段著色器

片段著色器的著色工廠利用上千萬工人迅速完成圖案
片段著色器的著色工廠利用上千萬工人迅速完成圖案

片段著色器就像是一個著色工廠,用你制定好的統一規則,決定畫布裡每個像素的顏色,工廠裡的幾百萬個工人,每一個工人負責一個像素,只要工人依據規則(各種參數)對各自負責的像素著色,每人只要畫一筆,一幅畫就瞬間完成了。

優點:由於利用 GPU 並行處理,可以快速做出複雜的像素操作,某些複雜的數學運算可以直接使用硬體運算,跟電流一樣快速。

兩個最大的限制,第一個是盲視,每一個線程(工人)都是完全獨立的,無從得知其他線程的運算結果,更無法干預;第二個是無記憶,每一個線程只會知道此刻的狀況,不會記得上一刻的自己在做甚麼,每一幀都是完全獨立的。

回到原本的畫布問題,我們需要用 fragment shader ,對每個像素說:「你的紅與綠的程度是由你的 uv 所決定,而藍的程度則由時間推移所決定。」

uniform vec2 u_resolution;
uniform float u_time;

void main(){
  vec2 uv = gl_FragCoord.xy/u_resolution.xy;
  gl_FragColor = vec4(uv.x, uv.y, sin(u_time)*0.5*0.5, 1.);
}

你的每一個上色程度都是用 uv 決定,就像是每個像素的座標或是工人的名牌一樣,每個像素都有一個自己的 uv ,就可以指定它改變顏色。

Fragment shader 可以算是比較類似C語言的程式語言,撰寫著色器程式的思考模式要從單個像素的角度出發,而非畫布的整體。

以右邊的例子來說,就是對著每個像素說:

「你在畫布左半邊就是白色,右半邊就是黑色;但你跟滑鼠的距離若是在畫布大小 5% 內就是紅色。」

用 shader 寫出跟隨滑鼠移動的紅點
用 shader 寫出跟隨滑鼠移動的紅點
uniform vec2 u_resolution;
uniform vec2 u_mouse;

void main(){
  vec2 uv = gl_FragCoord.xy/u_resolution.xy;
  vec2 dist = uv - u_mouse.xy/u_resolution.xy;
  vec3 color = mix(
    vec3(step(uv.x, 0.5)),
    vec3(1,0,0),
    step(length(dist), 0.05)
  );
  gl_FragColor = vec4(color, 1.);
}

Shader 不可思議之最:空間折疊

若要在畫布上畫出一百個圓,最直覺的想法是用迴圈,但要畫的圓越多,指令要執行的次數越多,有沒有其他不用迴圈卻能達成同樣效果的方法?

利用簡單數學運算完成2x2的四個圓
利用簡單數學運算完成2×2的四個圓
利用簡單數學運算完成2x2的四個圓
利用簡單數學運算完成2×2的四個圓

在畫布中心畫一個圓形(上方左圖),並將水平與垂直線分別均分十等份,做 0.0 到 1.0 標號,接下來只需要一個數學運算 uv = fract(uv * 2.0 ); 取餘數的小數點(捨去整是數1),瞬間就能變成四個圓形(上方右圖),每一個方塊其實都是原本完整的 0.0 到 1.0 , 1.0 改成 0.0、1.2 變成 0.2,以此類推,x 和 y 都是相同邏輯。

我們只用了一個數學運算式便把一個圓形變成 2×2 四個,舉一反三,不費吹灰之力就可以變成 5×5、10×10、100×100 的畫面,無論在這個圖上渲染多少個圓,都不會消耗額外資源,僅僅改變數學運算裡的一個參數!效能的高低只要是看指令執行的多寡,像這個例子只有一行運算,完全不會有效能上的差異,連在手機上也可以跑,很多 shader 吃效能是因為畫面的細緻要求和大量的運算。

理論上,你可以擁有無線長寬、無限縮放的畫布,極限僅在於你的像素多寡而已。這個感覺像是你先看一個圓, zoom out 將攝影機往外拉,看到一百個,再往外拉,看到上萬個,用極少量的運算做到複雜的視覺效果。

但,如果只能在每個空間複製一模一樣的圖案,那就太單調了。讓每個小空間內都出現不同的變化需要另一個數學的運算:取 floor 把小數點去掉,進而得到他的 ID 身分證明,再依據該圓圈 ID 的 x 值做出圓形半徑改變。

live coding 一下:

首先在畫布中寫出一個圓,並製作出方才提到的空間折疊效果,然後再把圓的半徑拉出來指定,這個半徑會隨著 ID 的 x 值的不同而改變。如果把 uv 縮放得更誇張就可以看出差異,縮放 30 倍(下圖左)和 100 倍(下圖中)的效果已經明顯不同,可以利用這個方式製作許多不同的效果。若圓圈的大小還受 y 軸的影響,相乘會出現更不一樣的 pattern ;加上時間的參數,就變成了動態。

依據x值改變圓半徑,再縮放30倍
依據x值改變圓半徑,再縮放30倍
依據x值改變圓半徑,再縮放100倍
依據x值改變圓半徑,再縮放100倍
依據x值改變圓半徑,再加上y值參數
依據x值改變圓半徑,再加上y值參數

Shader 除了從全白的畫布開始畫之外,也可以當作濾鏡使用,一個範例是這個網站http://filters.pixijs.download/dev/demo/index.html,可以靠右側的控制器改變顏色、曝光、模糊、風格化等,這是 shader 實務上最常用到的應用方式。

Pixi JS 網站範例截圖
Pixi JS 網站範例截圖

如果想用 shader 創作,可以從哪個裡找到學習資源呢?

第一個是 Shadertoy 老牌的創作平台,使用純粹的 fragment shader 而無法結合其他語法,所有神人都在這裡,你在這裡會看到很多匪夷所思到無法想像是怎麼做出來的作品,尤其又以 3D 為大宗,主要也可能是因為 Ray Marching 這個技術特別流行,大家嘗試了很多在 2D 畫布中渲染 3D 物體。

另一個創作平台是大家更熟悉的 OpenProcessing,可以用 p5.js 結合 shader 作創作,也可以使用 vertex shader + fragment shader,可以自由上傳或讀取自己的素材,達到更多不同的效果,但要小心沒有 GLSL 的語法上色,因 WebGL 版本較舊,不支援部分語法,手機支援度也較差,有視覺顯示或是無法運算等問題。 因為可以結合 p5.js ,張文瀚近期也開始改在這個平台上創作和發表作品,也做了他的 shader template 可以直接 fork 一版來做你的創作。

張文瀚<Out of bounds>作品截圖
張文瀚<Out of bounds>作品截圖,https://openprocessing.org/sketch/1540595

有參加第一次社群聚的人看到這件作品應該不陌生,這件是張文瀚上次的共創主題「宇宙」的作品。後來張文瀚也製作了一篇如何從零開始做出這件作品的教學,歡迎大家參考! 看似複雜但程式碼其實很少,只有 37 行,即使是初學者也可以透過教學文章慢慢踏入 shader 領域。對張文瀚來說,撰寫 shader 的成就感最主要來自於「僅用少少的 code 跟簡單的數學運算就可以達到絢麗的視覺效果」。

Shader 學習資源

台灣目前沒有太多中文的 shader 學習資源,不過 The Book of Shaders 即是針對入門者打造的教學網站,有翻譯成簡體中文的版本,且可以即時做範例,是最推薦的學習管道。

The Art of Code:從初學實作到進階理論都有的 Youtube 頻道,也主要針對 shadertoy 上作品的實作,全英文

Inigo Quilez 頻道:Shader 界宗師,以前貌似在皮克斯工作,動畫裡用到大量的 shader, Youtube 頻道裡多數為進階理論和 live coding,全英文

Inigo Quilez 網站:更深奧的理論與實作文章,全英文

 Inigo Quilez 在 Shadertoy 上的頻道截圖
Inigo Quilez 在 Shadertoy 上的頻道截圖

讓大家看一下 Inigo Quilez 在 Shadertoy 上的頻道,乍看真的無法相信這些細緻五官的人、風景、蝸牛等等都是用一行行的程式碼製作而成的,對於也還算初學的張文瀚在研究程式碼的時候,真的看不懂任何一行 code ,但這些作品真真確確是透過這些加減和數學運算組合而成的。

張文瀚個人作品分享

互動動態網站<體感溫差>
互動動態網站<體感溫差>截圖

第一件是替藝術家展覽製作的互動動態網站<體感溫差>,核心概念是使用 shader 當作濾鏡製作出熱像儀的效果以及熱像軌跡,左上角顯示滑過軌跡上的顏色所對應的溫度。

字畫產生器成果截圖
字畫產生器成果截圖

第二件則是文字遊戲延伸出來的字畫產生器,用純文字組成畫面,也另外開發一個小工具,方便大家做宣傳圖和素材。這個網站可以非常即時地將影片、影像轉換成文字,顯示的內文、字型、模式等都可以自由調整。

其他的作品歡迎來張文瀚的 Shadertoy 頁面 以及 Open Processing 頁面 觀看玩耍。

張文瀚的個人網頁>>https://changwenhan.com/

五月社群聚共創主題:<山>

張文瀚<And As The Sun Goes Down>

是一個靜態 shader 作品,使用到先前提到的 Ray Marching 的技術,這個山坡是用數學式所描述出來的 3D 物體,讀一張影像素材,用素材上的像素決定他的突起程度,去掉這一個步驟的話就是很一般、很光滑的 mapping,由素材本身的複雜度去決定成品最終的樣貌。 因為本身並不擅長顏色搭配,通常一件作品就保守用兩到三個顏色決定色調。

Jennifer

Jennifer共創作品

自由接案 js 工程師,「山」這個主題想到Open Processing上水墨畫的山,齊柏林在淡水的看見台灣展覽,有很多台灣的照片,所以決定做台灣的地形,月世界。

從沒有真正創作過,一開始想到是用遞迴樹(recursive tree)的方法,從稜線開始畫,但線條會相互重疊,變得很不自然,不是山稜線該有的樣子,所以認為需要改用面而非線去畫;接著在搜尋其他更好的製作方法時,找到主打資料處理、數據視覺化的 Observable 平台,參考了其中網友發表模擬珊瑚碎形的作法(網頁連結),回頭調整作品。

哲宇<Mountain & water>

吳哲宇 <Mountain & Water>
吳哲宇 <Mountain & Water> https://openprocessing.org/sketch/1519323

使用 noise 做不同層次的疊加,有一個 x 從左到右,在 y 上疊很多不同的sin 及 cos;一個大的perlin noise再乘上一個波,增加疏密的變化;另外一個比較有趣的手法,山脈往下長的這個效果是使用 mainGraphics.image(mainGraphics,0,2) 把祝張圖往下畫,上面再多疊一條又一條的線,整體畫面就呈現一直往下長的動態效果。

2022年5月也是第二次的 Creative Coding 社群聚就在這邊到一個段落了,如果還沒有看過上集由聲音藝術家吳秉聖帶來聲音、光、裝置與創意程式的人趕快點擊閱讀,這次因為疫情飆升、台北又下大雨而沒有太多的人來現場交流實在可惜,希望下一次有機會能夠在現場見到喜愛用 Creative Coding 創作的你們!

還不知道如何開始踏入 Creative Coding 嗎?那 Hahow 課程 <互動藝術創作程式入門>再適合你不過了,快加入2000位同學的行列,一起學習互動藝術創作吧!

墨雨設計banner

整理編輯:Chia 編

這篇文章 五月社群聚(下):張文瀚教你用數學作畫 GLSL fragment shader 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>