用 shader effect 實現雨滴落水效果!Cocos Creator 3D

最近逛論壇時,看到一位大佬在分享各種 shader 特效。基於其中的水波 shader ,白玉無冰寫了一個玩水效果!

先一起看看效果~

用 shader effect 實現雨滴落水效果!Cocos Creator 3D

點選任意位置,會在該位置生成一個水紋,就像是雨水落在水窪中一樣~

如何使用 effect 檔案?新建一個 material ,Effect 屬性選擇 water , 接著將紋理圖片拖到相應引數。

用 shader effect 實現雨滴落水效果!Cocos Creator 3D

最後為你的模型節點選擇材料。

用 shader effect 實現雨滴落水效果!Cocos Creator 3D

水紋片元著色器實現原理:透過計算與點選點的距離和方向,用 sin 函式模擬水紋效果。透過計算點選時間戳和當前時間與距離,判斷是否新增水紋效果。再將多個點選點疊加起來,得到 texture 最終 uv 。 主要程式碼如下。

for(int i = 0; i < 10; i++){ vec2 uvDir = normalize(v_uv - center[i]。xy); float dis = distance(v_uv, center[i]。xy); float dis_time = center[i]。z - cc_time。x + dis * 3。0; if ( center[i]。z > 0。0 && dis_time < 0。0 && dis_time > -0。1 ){ uv += sin_A * uvDir * sin(sin_W * cc_time。x - dis * sin_D); }}o *= texture(mainTexture, uv);

如何獲取點選點?這裡需要用到射線檢測,如果對射線檢測不瞭解的話,可以參考

淺析射線檢測 raycast 的使用!Cocos Creator 3D

透過射線檢測,會返回一個距離引數,再結合射線的起點和方向,可以計算出點選點的座標。參考程式碼如下。

this。_temp_v3。set(this。_ray。o);this。_temp_v3 = this。_temp_v3。add(this。_ray。d。clone()。multiplyScalar(item。distance));

這個座標是世界座標,還需要計算出在模型中的相對位置,數值範圍是 0~1。可以透過模型的最小、最大位置,計算出這個值。並將當前的渲染時間戳一併賦值。

const minPosition = item。node。worldPosition。clone()。add(this。model_plane。mesh。struct。minPosition);const maxPosition = item。node。worldPosition。clone()。add(this。model_plane。mesh。struct。maxPosition);this。_temp_v4。set((this。_temp_v3。x - minPosition。x) / (maxPosition。x - minPosition。x), (this。_temp_v3。z - minPosition。z) / (maxPosition。z - minPosition。z), director。root。cumulativeTime, 0)

如何傳值給 shader 中的 uniform 變數?可以透過 material 直接設定。

this。model_plane。material。setProperty(`center${this。_count++ % 10}`, this。_temp_v4);

當然還有一個效率更高的方法,直接使用 pass 的介面。

const pass = this。model_plane。material。passes[0];pass。setUniform(pass。getHandle(`center${this。_count++ % 10}`), this。_temp_v4);

既然用到了 shader ,順便講一下儲存限定字吧。attribute 只能出現在頂點著色器中,一般用來表示逐頂點資訊。uniform 變數是一個全域性變數,頂點著色器和片元著色器共用。varying 變數的任務是從頂點著色器向片元著色器傳輸資料。

用 shader effect 實現雨滴落水效果!Cocos Creator 3D

以上為白玉無冰使用 Cocos Creator 3D 實現“玩水效果”的技術分享。完整程式碼在公中號[白玉無冰]中。如果你有想法,歡迎留言分享!