今天討論與使用者滑鼠互動
先前的文章提到, Shadertoy 有內建滑鼠輸入 iMouse
:
uniform vec4 iMouse;
iMouse 是 vec4
,也就是有 4
個值 (x, y, z, w)
在 howto 頁裡,沒有實際說明 iMouse 的四個值的意義,
而是在 Special Shadertoy features 這篇提到, iMouse 的.xy
跟.zw
的值
last mouse click
or current mouse drag
position.starting drag
position..zw
相當特別,
大於 0: starting drag position.
滑鼠放開的時候, .zw 會回傳負
的座標 (#註1)
Demo:mouse
這個 Demo 用 iMouse 實作了:
程式碼:
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
vec2 uv = (fragCoord.xy / iResolution.xy);
vec4 m = iMouse / iResolution.xyxy;
float m0 = (m.z > 0.0) ? 0.25 : 0.0;
float m1 = smoothbump(m.x,0.05,uv.x) *
smoothbump(m.y,0.05,uv.y);
float m2 = smoothbump(abs(m.z),0.05,uv.x) *
smoothbump(abs(m.w),0.05,uv.y);
fragColor = vec4(m1,m0,m2,1.0);
}
輸出時使用三個顏色表示滑鼠的各種狀態:
fragColor = vec4(m1, m0, m2, 1.0);
以下分項解說
滑鼠 mousedown 時是綠色,滑鼠放開時綠色消失
(為方便對照,再貼一次 Gif)
程式碼:
float m0 = (m.z > 0.0) ? 0.25 : 0.0;
fragColor = vec4(m1,m0,m2,1.0);
當 m.z > 0.0 時, m0 (G) 的值是 0.25
,輸出畫面會偏綠
m.z 值,對應滑鼠座標的 uv.x,
m.w 值,對應滑鼠座標的 uv.y
當滑鼠按下時,會取得點擊座標 uv.x (正值)
當滑鼠放開時,顯示為點擊座標 *-1
,此時 m.z 與 m.w 皆為負值
(乘上負1 在下方會補充說明)
當 m.z <= 0.0 時, m0 (G) 的值是 0.0
,畫面不輸出綠色
Shadertoy 使用這樣的方式判斷 mousedown 事件
滑鼠在 mousedown、mousemove、mouseup 時,紅點跟著畫面移動
(為方便對照,再貼一次 Gif)
程式碼:
float m1 = smoothbump(m.x,0.05,uv.x) *
smoothbump(m.y,0.05,uv.y);
fragColor = vec4(m1,m0,m2,1.0);
相較 m0、 m2 單純, m1 (R) 在 mousedown、mousemove、mouseup 時
皆顯示 滑鼠的座標
滑鼠在 mousedown 時,藍點出現在滑鼠最後 mousedown 的位置
滑鼠在 mouseup 時,藍點出現在滑鼠最後 mousedown 的位置
(為方便對照,再貼一次 Gif)
程式碼:
float m2 = smoothbump(abs(m.z),0.05,uv.x) *
smoothbump(abs(m.w),0.05,uv.y);
fragColor = vec4(m1,m0,m2,1.0);
m2(B) 使用 m.z 與 m.w 座標繪製位置,與 m0(G) 的情形類似
而 m.z 值得變化情形為 (m.w) 相同,對應的是 uv.y:
當滑鼠 mousedown 時,會取得點擊座標 uv.x (正值)
當滑鼠 mouseup 時,顯示為點擊座標 *-1
也因此要在畫面上顯示 mousedown 的座標,且在滑鼠放開時
點仍留在畫面上
因此需要使用 abs(m.z)
與 abs(m.w)
,取 m.z 與 m.w 的絕對值 (#註1)
左下角滑鼠座標,在滑鼠放開時顯示為點擊時座標 乘上-1
,
可實際於 Demo:iResolution, iMouse, iDate, etc 操作:
如錄製 Gif 左下角的兩次示意:
兩次示意的座標 (-150,-213) 與 (-136,-208),
在滑鼠點下與移動時維持在點下的座標
滑鼠放開時瞬間 乘上-1
,
若不特別處理,輸出結果可能會與想像不同
m1 與 m2 使用相乘的方式取點,
可參考:
[WebGL - Day14] Shadertoy - 加減乘除好吃驚、用 Shader 做遮罩
(示意分別為取 uv.x
, uv.y
, uv.x*uv.y
三種狀態)
既然 iMouse 是 Shadertoy 提供的方法,自然只有在 Shadertoy 裡可以使用
實際在寫 Shader 的程式時,也可能不一定會照著 Shadertoy 的 iMouse 實作
即使 iMouse 有些不直覺,
但在 Shadertoy 使用 iMouse 事件來模擬之後的結果,
也是相當有效的實作方式
例: