iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 14
2
Modern Web

寫給工程師的 WebGL 學習心得系列 第 14

[WebGL - Day14] Shadertoy - 加減乘除好吃驚、用 Shader 做遮罩

  • 分享至 

  • xImage
  •  

前兩天討論了畫圖的部分,今天討論加減乘除與遮罩


事前準備

為了方便處理加減乘除,先整理前幾天的程式碼:

float Circle(vec2 uv, vec2 p , float r, float blur){
    float d = length(uv-p);
    float c = smoothstep(r, r-blur, d);
    return c;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{

    vec2 uv = fragCoord/iResolution.xy;

    uv -= .5;
    uv.x *= iResolution.x / iResolution.y;

    
    float c1 = Circle(uv, vec2(-.2, 0.), .4, .2);
    
    vec3 col = vec3(c1);

    fragColor = vec4(col,1.0);
}

  • 先將畫圓的函式提出來
float Circle(vec2 uv, vec2 p , float r, float blur){
    float d = length(uv-p);
    float c = smoothstep(r, r-blur, d);
    return c;
}
  • 使用時提供 uv、位置、半徑、模糊邊緣
float c1 = Circle(uv, vec2(-.2, 0.), .4, .2);
vec3 col = vec3(c1);

Screen

用同樣的方法,畫上另一個圓

float c2 = Circle(uv, vec2(.2, 0.), .4, .2);
vec3 col = vec3(c2);

Screen

兩個圈只有命名與位置不同:
c1: 位置在中間偏左,uv.x -.2 的位置
c2: 位置在中間偏右,uv.x +.2 的位置


為什麼加減乘除好吃驚?

取了兩個圓圈之後,用這兩個圓圈來做運算

相加

想象中這兩個圓的相加
黑色+黑色 = 黑色 (0. + 0. 還是 0.)
白色+白色 = 白色 (1. + 1. 大於 1., 顯示白色)
毛邊+毛邊...應該是平平順順的結果吧
(想像畫面,用 Photoshop 來試做的話,也許像是濾色 Screen) 的結果
Screen

實際上取相加的結果:

float c1 = Circle(uv, vec2(-.2, 0.), .4, .2);
float c2 = Circle(uv, vec2( .2, 0.), .4, .2);    
vec3 col = vec3(c1+c2);

Screen

紅框內的形狀有些意外,
因為相加...所以結果是這樣
Screen

相減

同樣的,雖然知道運算邏輯,但相減的結果還是令人驚訝

vec3 col = vec3(c1-c2);

Screen

相乘

vec3 col = vec3(c1*c2);

Screen
覺得是加減乘除運算中最特別的一個
結果是兩個圖像的交集、兩個圖像共有的畫面,
也可當作 遮罩 使用

相除

vec3 col = vec3(c1/c2);

Screen
相除,同樣滿特別的

將 Photoshop 各種混合模式對應到這兩個圈時,很多結果很特別
由於是公式結果,一個個列出來的用意不大
有機會可以試試


遮罩

取自Photoshop 教學 - Make your first layer mask
Photoshop Mask

Photoshop 裡的遮罩功能
在製作遮罩的時候,會有一個白色畫面,
白色畫面會留著,黑色的會被遮掉

實際上用 Shader 運算遮罩效果的時候,將原圖乘上遮罩圖像即可


在 Shadertoy 實作遮罩

Shadertoy 有內建素材可以使用:
點選下方 iChannel0,選擇 Textures > Abstract 1

Shadertoy iChannel

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord/iResolution.xy;
    vec4 texture_pic = texture(iChannel0, uv);
    fragColor = vec4(texture_pic);
}

結果:
Shadertoy Texture

texture() 方法:
vec4 texture(sampler2D sampler, vec2 coord)
會回傳 vec4,因此可直接使用 fragColor 輸出


全部合在一起

先畫一個圓,放在畫面中間:

float c1 = Circle(uv, vec2(0., 0.), .4, .2);
fragColor = vec4(vec3(c1), 1.);

Result Circle

將圓與圖片相乘,取得遮罩結果:

vec4 texture_pic = texture(iChannel0, fragCoord/iResolution.xy);    
fragColor = texture_pic * c1;

Result Mask

本篇完整程式碼 (使用時需設定 iChannel0 的素材):

float Circle(vec2 uv, vec2 p , float r, float blur){
    float d = length(uv-p);
    float c = smoothstep(r, r-blur, d);
    return c;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{

    vec2 uv = fragCoord/iResolution.xy;

    uv -= .5;
    uv.x *= iResolution.x / iResolution.y;
 
    float c1 = Circle(uv, vec2(0., 0.), .4, .2);

    vec4 texture_pic = texture(iChannel0, fragCoord/iResolution.xy);    
    fragColor = texture_pic * c1;
}

與數學公式相關的部分會先到這篇,
接著會介紹一些 Shader 的特性


上一篇
[WebGL - Day13] Shadertoy - 畫圖 (2/2) 方形、smoothstep() 函數
下一篇
[WebGL - Day15] Shadertoy - 與使用者滑鼠互動
系列文
寫給工程師的 WebGL 學習心得30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言