先來看結果圖(轉.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() {