iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 27
1
Modern Web

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

[WebGL - Day27] Displacement Filter (2/3) 在 Shadertoy 上模擬與互動

  • 分享至 

  • xImage
  •  

前篇提到可由調整 uv 對應的圖來製作漣漪效果
Demo


滑鼠點下

第一步是控制滑鼠點下,讓圓圈出現在滑鼠點下的位置
程式碼:

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.xy / iResolution.xy;
    uv.x *= iResolution.x / iResolution.y;
    float mask = 0.;
    
    vec2 p =  iMouse.xy / iResolution.xy;
    p.x *= iResolution.x / iResolution.y;
    mask = Circle(uv, p, .2, .05);    
    
    fragColor = vec4(mask);
}

Mouse-1
前文提到 iMouse 的 xy 值是滑鼠最後 點下拖拉 的位置

  • iMouse.xy: last mouse click or current mouse drag position.
    ( Attention: these are integers, while pixels are between integers. )

實際上在 Shadertoy 的滑鼠互動是透過 iMouse 實作,
不用寫 mousedown()mousemove()mouseup()


滑鼠點下與放開

程式碼:

vec4 m = iMouse;
vec2 pEnd =  m.xy / iResolution.xy;
vec2 pStart =  m.zw / iResolution.xy;
pEnd.x *= iResolution.x / iResolution.y;
pStart.x *= iResolution.x / iResolution.y;
mask = Circle(uv, pEnd, .2, .05);    
mask += Circle(uv, pStart, .1, .05);

Mouse-2

  • iMouse.zw:
    大於 0: starting drag position.

iMouse.zw 在拖拉的時候會回傳開始拖拉時的座標,
滑鼠放開的時候, .zw 會回傳開始拖拉時的座標 *-1
這段程式碼裡在滑鼠放開的時候剛開始點的座標不見
就是這個原因

同樣的,為了不讓剛開始點的座標不見,需要將 iMouse.zw絕對值

vec2 pStart =  abs(m.zw / iResolution.xy);

Mouse-3
滑鼠放開的時候,剛開始點的座標就留著了


取與滑鼠拖拉反向的座標

與前例類似,新增一個 pEnd2 的變數,值是 pStart - (pEnd - pStart)
取得與滑鼠拖拉反向的座標

vec2 pEnd =  m.xy / iResolution.xy;
vec2 pStart =  abs(m.zw / iResolution.xy);
vec2 pEnd2 =  pStart - (pEnd - pStart);

vec3 col = vec3(0.0);
col = mix(col, vec3(1.0, 0.0, 0.0), Circle(uv, pStart, .1, .05));
col = mix(col, vec3(0.0, 1.0, 0.0), Circle(uv, pEnd, .1, .05));
col = mix(col, vec3(0.0, 0.0, 1.0), Circle(uv, pEnd2, .1, .05));

fragColor = vec4(col, 1.0);

Mouse-4
在這個範例裡,我將三個座標上色:
滑鼠點下的座標:pStart 的顏色是 vec3(1.0, 0.0, 0.0),紅色
滑鼠拖拉的座標:pEnd 的顏色是 vec3(0.0, 1.0, 0.0),綠色
滑鼠拖拉反向的座標:pEnd2 的顏色是 vec3(0.0, 0.0,1.0),藍色


畫成方的

在先前文章有討論畫方形,這個步驟裡將上一步的座標,改成畫方形

float Band(float t, float start, float end, float blur){
    float step1 = smoothstep(start - blur, start + blur, t);
    float step2 = smoothstep(end - blur, end + blur, t);
    return step1-step2;
}
float Rect(vec2 uv, float left, float right, float bottom , float top, float blur){
    float  band1 = Band(uv.x, left, right, blur);
    float  band2 = Band(uv.y, bottom, top, blur);
    return band1 * band2;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
   ...    
    if(pStart.x > pEnd.x){
        mask = (Rect(uv, pEnd.x, pEnd2.x, -0.4, 1.4, (pEnd2.x - pEnd.x)*0.5))*1.0;
    }else{
        mask = (Rect(uv, pEnd2.x, pEnd.x, -0.4, 1.4, (pEnd.x - pEnd2.x)*0.5))*1.0;
    }
    uv.x += mask;
    ...
}

Mouse-5
if 判斷式:
目前畫方的公式裡,如果畫的方向相反不會有畫面
因此需要用 if 做判斷


把圖放上去

這部分沒有太大的不同

uv.x += mask*.1;
vec4 color = texture(iChannel0, uv);

Mouse-6
將 mask*.1,主要是避免在 uv 運算後大於1 時可能發生的問題
(下圖為示意,在 Shadertoy 上,預設不會有這個問題)
UV Clamp

是不是沒那麼困難呢? (我在實作時碰壁了滿久就是了)


雖然最後 在 PixiJS 實作時不會用到 iMouse
iMosueuv 對應 時的 Debug 相當有幫助


上一篇
[WebGL - Day26] Displacement Filter (1/3) 原理
下一篇
[WebGL - Day28] Displacement Filter (3/3) 在 PixiJS 上完成互動
系列文
寫給工程師的 WebGL 學習心得30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
monkianer
iT邦新手 5 級 ‧ 2020-02-24 18:19:57

非常棒喔!

我要留言

立即登入留言