前篇提到可由調整 uv 對應的圖來製作漣漪效果
第一步是控制滑鼠點下,讓圓圈出現在滑鼠點下的位置
程式碼:
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);
}
前文提到 iMouse 的 xy 值是滑鼠最後 點下
與 拖拉
的位置
last mouse click
or current mouse drag
position.實際上在 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);
starting drag
position.iMouse.zw 在拖拉的時候會回傳開始拖拉時的座標,
滑鼠放開的時候, .zw 會回傳開始拖拉時的座標 *-1
這段程式碼裡在滑鼠放開的時候剛開始點的座標會不見
,
就是這個原因
同樣的,為了不讓剛開始點的座標不見,需要將 iMouse.zw 取絕對值:
vec2 pStart = abs(m.zw / iResolution.xy);
滑鼠放開的時候,剛開始點的座標就留著了
與前例類似,新增一個 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);
在這個範例裡,我將三個座標上色:
滑鼠點下的座標: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;
...
}
if 判斷式:
目前畫方的公式裡,如果畫的方向相反
,不會有畫面
因此需要用 if 做判斷
這部分沒有太大的不同
uv.x += mask*.1;
vec4 color = texture(iChannel0, uv);
將 mask*.1
,主要是避免在 uv 運算後大於1
時可能發生的問題
(下圖為示意,在 Shadertoy 上,預設不會有這個問題)
是不是沒那麼困難呢? (我在實作時碰壁了滿久就是了)
雖然最後 在 PixiJS 實作時不會用到 iMouse
,
但 iMosue
在 uv 對應 時的 Debug 相當有幫助