javascript js WebGL WebGL2 後期處理特效之點擊水波紋漣漪例子

来源:https://www.cnblogs.com/weihexinCode/p/18339931
-Advertisement-
Play Games

先來看結果圖(轉.gif掉幀了): 完整源碼分享網址: https://share.weiyun.com/Vpkp5KP3 1 首先初始化用到的所有圖片: 1 const images = [ 2 "./img/girls.jpg", 3 "./img/ball.png", 4 "./img/wat ...


先來看結果圖(轉.gif掉幀了): 

 

 

完整源碼分享網址: https://share.weiyun.com/Vpkp5KP3     1 首先初始化用到的所有圖片:
 1 const images = [
 2     "./img/girls.jpg",
 3     "./img/ball.png",
 4     "./img/water.jpg", 
 5     "./img/spriteX8.png",
 6 
 7     //8張雪碧圖, 在main()中合成一張圖
 8     "./img/sprites/0.png",
 9     "./img/sprites/1.png",
10     "./img/sprites/2.png",
11     "./img/sprites/3.png",
12     "./img/sprites/4.png",
13     "./img/sprites/5.png",
14     "./img/sprites/6.png",
15     "./img/sprites/7.png",
16 ]
17 
18 { //init images
19     let len = 0;
20     for(let i = 0; i < images.length; i++) {
21         const image = new Image();
22         image.onload = () => {
23             if(len++ === images.length - 1) main();
24         }
25         image.src = images[i];
26         images[i] = image;
27     }
28 }

 

2 初始化渲染器

1 const renderer = new Renderer();
2 renderer.setSize();
3 document.body.appendChild(renderer.domElement);
4 console.log(renderer);

 

3 先往渲染器裡面丟一個背景

const background = new Object2D(new GeometryRect(innerWidth, innerHeight), new Material(new Texture(images[0], FormatRGB), false));
renderer.append(background);

 

3 再往渲染器丟一個實例化版本的雪碧圖(精靈圖)

 1 //將上面載入好的0-7張圖打包成一張圖
 2 const si = 4, len = 8;
 3 const context = ElementUtils.createContext(images[si].width * len, images[si].height, true);
 4 for(let i = 0; i < len; i++){
 5     context.drawImage(images[i+si], images[i+si].width * i, 0);
 6 }
 7 
 8 
 9 //創建 InstancedSprite 實例化雪碧圖
10 const instancedSprite = new InstancedSprite(
11     new GeometryRect(images[si].width, context.canvas.height), 
12     new Material(new Texture(context.canvas, FormatRGBA), true),
13     2, false, len, 0
14 );
15 
16 
17 //初始化所有實例(2個)的位置
18 for(let i = 0; i < instancedSprite.len; i++){
19     instancedSprite.translateI(i, instancedSprite.geometry.width * i, 0);
20 }
21 
22 
23 //
24 renderer.append(instancedSprite);
25 
26 
27 //補間 每 120 毫秒更換一次
28 const instancedSpriteTween = new TweenCache({x: 0}, {x: 1}, 120, () => { 
29     instancedSprite.offset += 1;
30     instancedSpriteTween.reverse();
31     instancedSpriteTween.start();
32 }, true);

 

4 創建後期處理(就是水波紋特效)

const imageSource = new ImageSource(renderTargetGeometry.width, renderTargetGeometry.height, null); //第三個參數必須為null

const renderTargetGeometry = new GeometryRect(renderer.domElement.width, renderer.domElement.height);

const renderTargetMaterial = new MaterialShader({

    vertexCode: defaultShaderCode.texture1.vertex, //使用預設的頂點著色器
        
        //水波紋主要實現代碼(原理很簡單就是偏移uv坐標): 
    fragmentCode: `#version 300 es
        precision mediump float; //highp, mediump, lowp
        uniform vec2 uSize;
        uniform sampler2D uImage;
        uniform vec2 uOrigin;
        uniform vec2 uRange;
        uniform float uScale;
        uniform float uLife;
        uniform float uTime;
        in vec2 vPos;

        out vec4 outColor;
        const float PI = 3.141592653589793;
        vec2 uv;

        float atan2(float y, float x) {
            if(x > 0.0){return atan(y / x);}
            if(x < 0.0){
                if(y >= 0.0){return atan(y / x) + PI;}
                return atan(y / x) - PI;
            }
            if(y > 0.0){return PI;}
            if(y < 0.0){return -PI;}
            return 0.0;
        }

        void main() {
            vec2 newPos = vPos - uOrigin;
            float _d = newPos.x * newPos.x + newPos.y * newPos.y;
            if(_d < 0.001 || _d < uRange.x * uRange.x || _d > uRange.y * uRange.y){
                uv = vPos / uSize;
                uv.y = 1.0 - uv.y;
                outColor = texture(uImage, uv);
            } else {
                float s = sqrt(_d);
                float d = (1.0 - uScale) * s;
                float r = atan2(vPos.y, vPos.x);
                vec2 uv = (vPos + ((1.0 - s / uRange.y) * uLife) * vec2(cos(r) * sin(d - uTime) / d, sin(r) * sin(d - uTime) / d)) / uSize;
                uv.y = 1.0 - uv.y;
                outColor = texture(uImage, uv);
            }
        }
    `,

    uniforms: {
        uImage: new Texture(imageSource),
        uOrigin: [innerWidth / 2, innerHeight / 2], //擴散原點
        uRange: [1, 200], //0: 擴散最小半徑, 1: 擴散最大半徑;
        uScale: 0.6, //值越大波就越寬
        uLife: 200, //值越大起伏就越大
        uTime: 0,
    },
});

//把 Object2D 當作渲染目標
renderer.createRenderTarget(new Object2D(renderTargetGeometry, renderTargetMaterial));

 

5 屏幕點擊事件

 1 var isRenderTarget = false;
 2 
 3 const renderTargetTween = new TweenCache({x: 0, y: 0}, {x: 0, y: 0}, 1000, () => isRenderTarget = false);
 4 
 5 renderer.domElement.addEventListener("click", e => {
 6         //重置水波紋的擴散原點
 7     renderTargetMaterial.uniforms.uOrigin[0] = e.offsetX;
 8     renderTargetMaterial.uniforms.uOrigin[1] = e.offsetY;
 9 
10         //重置水波紋的style
11     renderTargetTween.origin.x = 200;
12     renderTargetTween.origin.y = 0.6;
13     renderTargetTween.end.x = 0;
14     renderTargetTween.end.y = 0;
15 
16         //允許在動畫迴圈中繪製水波紋
17     renderTargetTween.start();
18     isRenderTarget = true;
19 });

 

6 動畫迴圈

 1 //loop
 2 new AnimateLoop(() => {
 3         //更新實例雪碧圖的Tween
 4     instancedSpriteTween.update();
 5 
 6         //渲染器的正常繪製
 7     if(isRenderTarget === false) renderer.redraw();
 8 
 9     else {
10         //繪製後期處理(水波紋特效)
11         renderTargetTween.update();
12         renderTargetMaterial.uniforms.uLife = renderTargetTween.origin.x;
13         renderTargetMaterial.uniforms.uTime += renderTargetTween.origin.y;
14         renderer.redrawRenderTarget();
15     }
16 }).play();

 

//完整源碼分享網址: https://share.weiyun.com/Vpkp5KP3  
   1 import { Box, Matrix3, Vector2 } from './Utils.js';
   2 import { Shape, ShapeUtils, SplineCurve } from './TwoUtils.js';
   3 
   4 const BlendEquationAdd = [0, -1];
   5 
   6 const BlendDefault = [6, 7, -1, -1],
   7 BlendAdd = [1, 1, -1, -1],
   8 BlendSub = [0, 3, 0, 1],
   9 BlendMultiply = [0, 2, 0, 6];
  10 
  11 const ModePoints = "POINTS",
  12 ModeLineStrip = "LINE_STRIP",
  13 ModeLineLoop = "LINE_LOOP",
  14 ModeLines = "LINES",
  15 ModeTriangleStrip = "TRIANGLE_STRIP",
  16 ModeTriangleFan = "TRIANGLE_FAN",
  17 ModeTriangles = "TRIANGLES";
  18 
  19 const FormatAlpha = 0,
  20 FormatLuminance = 2,
  21 FormatLuminanceAlpha = 4,
  22 FormatRGB = 12,
  23 FormatRGBA = 14;
  24 
  25 const PixelStoreiFlipY = 2,
  26 PixelStoreiPremultiplyAlpht = 3;
  27 
  28 
  29 /* test defaultShaderCode.texture2_blend
  30     const geometry = new GeometryRect(200, 200); //二維的矩形
  31 
  32     const sstruet = new Structure({
  33         vertexCode: defaultShaderCode.texture2_blend.vertex,
  34         fragmentCode: defaultShaderCode.texture2_blend.fragment,
  35 
  36         attributes: {
  37             aPos: new Attribute(2, geometry.vertices),
  38         },
  39 
  40         uniforms: {
  41             uPMat: renderer.projectionMatrix,
  42             uMat: new Matrix3().translate(100, 100).toArray(), 
  43             uSampler: images[2], //不透明的背景圖
  44             uSampler1: images[4], //透明的圓球
  45             opacity: 1,
  46             ratio: 0.5,
  47             uSize: [geometry.width, geometry.height],
  48         },
  49 
  50         indices: geometry.indices,
  51     });
  52 
  53     renderer.append(sstruet).redraw();
  54 */
  55 
  56 /* test defaultShaderCode.texture2_after
  57     const geometry = new GeometryRect(200, 200); //二維的矩形
  58 
  59     const sstruet = new Structure({
  60         vertexCode: defaultShaderCode.texture2_after.vertex,
  61         fragmentCode: defaultShaderCode.texture2_after.fragment,
  62 
  63         attributes: {
  64             aPos: new Attribute(2, geometry.vertices),
  65         },
  66 
  67         uniforms: {
  68             uPMat: renderer.projectionMatrix,
  69             uMat: new Matrix3().translate(100, 100).toArray(), 
  70             uSampler: images[2],
  71             uSampler1: images[3], 
  72             damp: 1,
  73             uSize: [geometry.width, geometry.height],
  74         },
  75 
  76         indices: geometry.indices,
  77     });
  78 
  79     renderer.append(sstruet).redraw();
  80 */
  81 
  82 /* test defaultShaderCode.texture2_WaterRefract
  83     const geometry = new GeometryRect(innerWidth, innerHeight); //二維的矩形
  84     const sstruet = new Structure({
  85         vertexCode: defaultShaderCode.texture2_WaterRefract.vertex,
  86         fragmentCode: defaultShaderCode.texture2_WaterRefract.fragment,
  87 
  88         attributes: {
  89             aPos: new Attribute(2, geometry.vertices),
  90         },
  91 
  92         uniforms: {
  93             uPMat: renderer.projectionMatrix,
  94             uMat: new Matrix3().toArray(), 
  95             textureMatrix: new Matrix3().toArray(), 
  96             uSampler: images[5], //waterColor.jpg
  97             uSampler1: images[5], //waterNormal.jpg
  98             uColor: [0, 0.5, 0], //綠色
  99             uTime: 0,
 100             uSize: [geometry.width, geometry.height],
 101         },
 102 
 103         indices: geometry.indices,
 104     });
 105 
 106     function loop() {
 107         sstruet.uniforms.uTime -= 0.05;
 108         renderer.redraw();
 109     }
 110 
 111     renderer.append(sstruet);
 112     new AnimateLoop(loop).play();
 113 */
 114 
 115 
 116 const defaultShaderCode = {
 117     color_v4: {
 118         vertex: `
 119             attribute vec2 aPos;
 120             uniform mat3 uPMat;
 121             uniform mat3 uMat;
 122             void main() {
 123                 gl_Position.xyz = uPMat * uMat * vec3(aPos, 1.0);
 124                 gl_Position.w = 1.0;
 125             }
 126         `,
 127         fragment: `
 128             precision mediump float; //highp, mediump, lowp
 129             uniform vec4 uColor;
 130             void main() {
 131                 gl_FragColor = uColor;
 132             }
 133         `,
 134     },
 135     texture1: {
 136         vertex: `#version 300 es
 137             in vec2 aPos;
 138             uniform mat3 uPMat;
 139             uniform mat3 uMat;
 140             out vec2 vPos;
 141             void main() {
 142                 vPos = aPos;
 143                 gl_Position.xyz = uPMat * uMat * vec3(aPos, 1.0);
 144                 gl_Position.w = 1.0;
 145             }
 146         `,
 147         fragment: `#version 300 es
 148             precision mediump float; //highp, mediump, lowp
 149             uniform sampler2D uImage;
 150             uniform vec2 uSize;
 151             in vec2 vPos;
 152             out vec4 outColor;
 153             void main() {
 154                 outColor = texture(uImage, vPos / uSize);
 155             }
 156         `,
 157     },
 158     texture1_sprite: {
 159         vertex: `#version 300 es
 160             in vec2 aPos;
 161             uniform mat3 uPMat;
 162             uniform mat3 uMat;
 163             out vec2 vPos;
 164             void main() {
 165                 vPos = aPos;
 166                 gl_Position.xyz = uPMat * uMat * vec3(aPos, 1.0);
 167                 gl_Position.w = 1.0;
 168             }
 169         `,
 170         fragment: `#version 300 es
 171             precision mediump float; //highp, mediump, lowp
 172             uniform sampler2D uImage;
 173             uniform float uLen;
 174             uniform float uOffset;
 175             uniform vec2 uSize;
 176             in vec2 vPos;
 177             out vec4 outColor;
 178             void main() {
 179                 outColor = texture(uImage, vec2(vPos.x / (uSize.x * uLen) + 1.0 / uLen * uOffset, vPos.y / uSize.y));
 180             }
 181         `,
 182     },
 183     texture1_Instanced: {
 184         vertex: `#version 300 es
 185             in vec2 aPos;
 186             in mat3 uIMat;
 187             uniform mat3 uPMat;
 188             uniform mat3 uMat;
 189             out vec2 vPos;
 190             void main() {
 191                 vPos = aPos;
 192                 gl_Position.xyz = uPMat * uMat * uIMat * vec3(aPos, 1.0);
 193                 gl_Position.w = 1.0;
 194             }
 195         `,
 196         fragment: `#version 300 es
 197             precision mediump float; //highp, mediump, lowp
 198             uniform sampler2D uImage;
 199             uniform vec2 uSize;
 200             in vec2 vPos;
 201             out vec4 outColor;
 202             void main() {
 203                 outColor = texture(uImage, vPos / uSize);
 204             }
 205         `,
 206     },
 207     texture1_Instanced_points: {
 208         vertex: `#version 300 es
 209             in vec2 aPos;
 210             in mat3 uIMat;
 211             uniform mat3 uPMat;
 212             uniform mat3 uMat;
 213             uniform float uSize;
 214             void main() {
 215                 gl_Position.xyz = uPMat * uMat * uIMat * vec3(aPos, 1.0);
 216                 gl_Position.w = 1.0;
 217                 gl_PointSize = uSize;
 218             }
 219         `,
 220         fragment: `#version 300 es
 221             precision mediump float; //highp, mediump, lowp
 222             uniform sampler2D uImage;
 223             out vec4 outColor;
 224             void main() {
 225                 outColor = texture(uImage, gl_PointCoord.xy);
 226             }
 227         `,
 228     },
 229     texture1_Instanced_sprite: {
 230         vertex: `#version 300 es
 231             in vec2 aPos;
 232             in mat3 uIMat;
 233             uniform mat3 uPMat;
 234             uniform mat3 uMat;
 235             out vec2 vPos;
 236             void main() {
 237                 vPos = aPos;
 238                 gl_Position.xyz = uPMat * uMat * uIMat * vec3(aPos, 1.0);
 239                 gl_Position.w = 1.0;
 240             }
 241         `,
 242         fragment: `#version 300 es
 243             precision mediump float; //highp, mediump, lowp
 244             uniform sampler2D uImage;
 245             uniform float uLen;
 246             uniform float uOffset;
 247             uniform vec2 uSize;
 248             in vec2 vPos;
 249             out vec4 outColor;
 250             void main() {
 251                 outColor = texture(uImage, vec2(vPos.x / (uSize.x * uLen) + 1.0 / uLen * uOffset, vPos.y / uSize.y));
 252             }
 253         `,
 254     },
 255     texture1_fog: {
 256         vertex: `
 257             attribute vec2 aPos;
 258             uniform mat3 uPMat;
 259             uniform mat3 uMat;
 260             varying vec2 vPos;
 261             void main() {
 262                 vPos = aPos;
 263                 gl_Position.xyz = uPMat * uMat * vec3(aPos, 1.0);
 264                 gl_Position.w = 1.0;
 265             }
 266         `,
 267         fragment: `
 268             precision mediump float; //highp, mediump, lowp
 269             uniform sampler2D uSampler;
 270             uniform vec4 uFogColor;
 271             uniform float uFogAmount;
 272             uniform vec2 uSize;
 273             varying vec2 vPos;
 274             void main() {
 275                 gl_FragColor = mix(texture2D(uSampler, vPos / uSize), uFogColor, uFogAmount);
 276             }
 277         `,
 278     },
 279     texture1_brightContrast: { //亮度對比度
 280         vertex: `
 281             attribute vec2 aPos;
 282             uniform mat3 uPMat;
 283             uniform mat3 uMat;
 284             varying vec2 vPos;
 285             void main() {
 286                 vPos = aPos;
 287                 gl_Position.xyz = uPMat * uMat * vec3(aPos, 1.0);
 288                 gl_Position.w = 1.0;
 289             }
 290         `,
 291         fragment: `
 292             precision mediump float; //highp, mediump, lowp
 293             uniform sampler2D uSampler;
 294             uniform float bright;
 295             uniform float contrast;
 296             uniform vec2 uSize;
 297             varying vec2 vPos;
 298             void main() {
 299                 gl_FragColor = texture2D(uSampler, vPos / uSize);
 300                 gl_FragColor.rgb += bright;
 301                 if(contrast > 0.0){
 302                     gl_FragColor.rgb = (gl_FragColor.rgb - 0.5) / (1.0 - contrast) + 0.5;
 303                 } else {
 304                     gl_FragColor.rgb = (gl_FragColor.rgb - 0.5) * (1.0 + contrast) + 0.5;
 305                 }
 306             }
 307         `,
 308     },
 309     texture1_color_ifv3: {
 310         vertex: `
 311             attribute vec2 aPos;
 312             uniform mat3 uPMat;
 313             uniform mat3 uMat;
 314             varying vec2 vPos;
 315             void main() {
 316                 vPos = aPos;
 317                 gl_Position.xyz = uPMat * uMat * vec3(aPos, 1.0);
 318                 gl_Position.w = 1.0;
 319             }
 320         `,
 321         fragment: `
 322             precision mediump float; //highp, mediump, lowp
 323             uniform sampler2D uSampler;
 324             uniform vec3 uColor;
 325             uniform vec2 uSize;
 326             varying vec2 vPos;
 327             void main() {

              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 今天遇到一個問題,在使用codemirror對兩條文本內容進行對比時,有同事反饋在它的電腦上會顯示成:前面一半是正常顯示差異內容,而後面就變成了全部是新增的。 像這樣: 預期的對比結果是這樣: 我們觀察用於對比的兩個文本,實際上上面的文本都是去掉後面括弧中的內容,對比結果不應該表現成全部刪除全部新增 ...
  • title: 使用 clearError 清除已處理的錯誤 date: 2024/8/5 updated: 2024/8/5 author: cmdragon excerpt: 摘要:“文章介紹了clearError函數的作用與用法,用於清除已處理的錯誤並可實現頁面重定向,提升用戶體驗。通過示例展示 ...
  • title: 使用 addRouteMiddleware 動態添加中間 date: 2024/8/4 updated: 2024/8/4 author: cmdragon excerpt: 摘要:文章介紹了Nuxt3中addRouteMiddleware的使用方法,該功能允許開發者動態添加路由中間件 ...
  • Vue2存在源碼可維護性差、性能問題和API相容性不足等缺點。Vue3通過monorepo管理、TypeScript開發、性能優化和引入Composition API等方式,顯著提升了源碼可維護性、編程體驗、TypeScript支持和邏輯復用實踐,從源碼、性能和語法API三方面進行了優化。 ...
  • 最近練習了一些前端演算法題,現在做個總結,以下題目都是個人寫法,並不是標準答案,如有錯誤歡迎指出,有對某道題有新的想法的友友也可以在評論區發表想法,互相學習 ...
  • Vue 3在編譯template過程中,會通過patchFlags優化虛擬DOM更新,提升性能。這些標誌通過位運算進行操作,包括動態文本、類、樣式、屬性、靜態提升等。patchFlags的使用極大地提高了diff演算法的效率。 ...
  • title: 使用 abortNavigation 阻止導航 date: 2024/8/3 updated: 2024/8/3 author: cmdragon excerpt: 摘要:在Nuxt3中,abortNavigation是一個輔助函數,用於路由中間件內阻止不符合條件的頁面訪問,實現許可權控 ...
  • 動態路由 動態菜單 //通過迴圈組件完成動態菜單 <el-menu active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical-demo" text-color="#fff" :collapse="is ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...