javascript js WebGL WebGL2 后期处理特效之点击水波纹涟漪例子
先来看结果图(转.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() { 328 vec4 tex = texture2D(uSampler, vPos / uSize); 329 gl_FragColor = vec4(dot(tex.xyz, vec3(0.299, 0.587, 0.114)) * uColor, tex.w); 330 } 331 `, 332 }, 333 texture2_blend: { 334 vertex: ` 335 attribute vec2 aPos; 336 uniform mat3 uPMat; 337 uniform mat3 uMat; 338 varying vec2 vPos; 339 void main() { 340 vPos = aPos; 341 gl_Position.xyz = uPMat * uMat * vec3(aPos, 1.0); 342 gl_Position.w = 1.0; 343 } 344 `, 345 fragment: ` 346 precision mediump float; //highp, mediump, lowp 347 uniform sampler2D uSampler; 348 uniform sampler2D uSampler1; 349 uniform float opacity; 350 uniform float ratio; 351 uniform vec2 uSize; 352 varying vec2 vPos; 353 void main() { 354 vec2 uv = vPos / uSize; 355 gl_FragColor = opacity * mix(texture2D(uSampler, uv), texture2D(uSampler1, uv), ratio); 356 } 357 `, 358 }, 359 texture2_after: { 360 vertex: ` 361 attribute vec2 aPos; 362 uniform mat3 uPMat; 363 uniform mat3 uMat; 364 varying vec2 vPos; 365 void main() { 366 vPos = aPos; 367 gl_Position.xyz = uPMat * uMat * vec3(aPos, 1.0); 368 gl_Position.w = 1.0; 369 } 370 `, 371 fragment: ` 372 precision mediump float; //highp, mediump, lowp 373 uniform sampler2D uSampler; 374 uniform sampler2D uSampler1; 375 uniform float damp; 376 uniform vec2 uSize; 377 varying vec2 vPos; 378 vec4 when_gt(vec4 x, float y) { 379 return max(sign(x - y), 0.0); 380 } 381 void main() { 382 vec2 uv = vPos / uSize; 383 vec4 tex = texture2D(uSampler, uv); 384 tex *= damp * when_gt(tex, 0.1); 385 gl_FragColor = max(texture2D(uSampler1, uv), tex); 386 } 387 `, 388 }, 389 texture2_WaterRefract: { //水折射 390 vertex: ` 391 attribute vec2 aPos; 392 uniform mat3 uPMat; 393 uniform mat3 uMat; 394 varying vec2 vPos; 395 396 uniform mat3 textureMatrix; 397 varying vec3 vUvRefraction; 398 399 void main() { 400 vPos = aPos; 401 vec3 pos = vec3(aPos, 1.0); 402 vUvRefraction = textureMatrix * pos; 403 gl_Position.xyz = uPMat * uMat * pos; 404 gl_Position.w = 1.0; 405 } 406 `, 407 fragment: ` 408 precision mediump float; //highp, mediump, lowp 409 uniform sampler2D uSampler; 410 uniform sampler2D uSampler1; 411 uniform vec3 uColor; 412 uniform float uTime; 413 uniform vec2 uSize; 414 varying vec2 vPos; 415 416 varying vec3 vUvRefraction; 417 418 float blendOverlay(float base, float blend) { 419 return(base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend))); 420 } 421 422 vec3 blendOverlay(vec3 base, vec3 blend) { 423 return vec3(blendOverlay(base.r, blend.r), blendOverlay(base.g, blend.g),blendOverlay(base.b, blend.b)); 424 } 425 426 void main() { 427 vec2 uv = vPos / uSize; 428 float waveStrength = 0.5; 429 float waveSpeed = 0.03; 430 431 // simple distortion (ripple) via dudv map (see https://www.youtube.com/watch?v=6B7IF6GOu7s) 432 433 vec2 distortedUv = texture2D(uSampler1, vec2(uv.x + uTime * waveSpeed, uv.y)).rg * waveStrength; 434 distortedUv = uv.xy + vec2(distortedUv.x, distortedUv.y + uTime * waveSpeed); 435 vec2 distortion = (texture2D(uSampler1, distortedUv).rg * 2.0 - 1.0) * waveStrength; 436 437 // new vUvRef coords 438 439 vec4 vUvRef = vec4(vUvRefraction, 1.0); 440 vUvRef.xy += distortion; 441 442 vec4 base = texture2DProj(uSampler, vUvRef); 443 444 gl_FragColor = vec4(blendOverlay(base.rgb, uColor), 1.0); 445 446 //#include <tonemapping_fragment> 447 //#include <colorspace_fragment> 448 } 449 `, 450 }, 451 } 452 453 //返回是否时可用像素源 454 function isPixelSource(source) { 455 /* TypeArray: 456 Uint8Array 如果 type 是 gl.UNSIGNED_BYTE则必须使用 457 Uint16Array 如果 type 是 gl.UNSIGNED_SHORT_5_6_5, gl.UNSIGNED_SHORT_4_4_4_4, gl.UNSIGNED_SHORT_5_5_5_1, gl.UNSIGNED_SHORT 或ext.HALF_FLOAT_OES则必须使用 458 Uint32Array 如果type 是 gl.UNSIGNED_INT 或ext.UNSIGNED_INT_24_8_WEBGL则必须使用 459 Float32Array 如果type 是 gl.FLOAT则必须使用 460 */ 461 return ImageData.prototype.isPrototypeOf(source) || 462 ImageBitmap.prototype.isPrototypeOf(source) || 463 HTMLImageElement.prototype.isPrototypeOf(source) || 464 HTMLCanvasElement.prototype.isPrototypeOf(source) || 465 HTMLVideoElement.prototype.isPrototypeOf(source); 466 } 467 468 //翻转 points: [x, y, x1, y1, ...] => [x1, y1, x, y, ...]; 469 function reversePoints(points = [0, 0, 0, 0]) { 470 for(let i = 0, j = points.length - 1; i < j; i += 2, j -= 2){ 471 points[i] = points[j-1]; 472 points[i+1] = points[j]; 473 points[j] = points[i+1]; 474 points[j-1] = points[i]; 475 } 476 return points; 477 } 478 479 //value 是否是2的幂 480 function isPowerOf2(value) { 481 return (value & (value - 1)) === 0; 482 } 483 484 //array 的某个元素如果超出 Uint16Array 范围则立即返回true 485 function arrayNeedsUint32( array ) { 486 // assumes larger values usually on last 487 for ( let i = array.length - 1; i >= 0; -- i ) { 488 if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565 489 } 490 return false; 491 } 492 493 //平移顶点 494 function translateVertices(vertices, count, x, y) { 495 for(let i = 0; i < vertices.length; i += count){ 496 vertices[i] += x; 497 vertices[i + 1] += y; 498 } 499 } 500 501 //计算包围盒 502 function computeBBox(vertices, count) { 503 let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; 504 for(let i = 0, x, y; i < vertices.length; i += count){ 505 x = vertices[i]; 506 y = vertices[i + 1]; 507 minX = Math.min(x, minX); 508 minY = Math.min(y, minY); 509 maxX = Math.max(x, maxX); 510 maxY = Math.max(y, maxY); 511 } 512 return {x: minX, y: minY, x1: maxX, y1: maxY} 513 } 514 515 /** 516 * @returns {WebGL2RenderingContext} 517 */ 518 function createWebGL2(contextOption = Renderer.contextOption, glOption = Renderer.glOption){ 519 const canvas = document.createElement("canvas"); 520 const gl = canvas.getContext("webgl2", contextOption); 521 //gl.viewport(0, 0, width, height); 522 523 const clearColor = glOption.clearColor || {r: 0.45, g: 0.45, b: 0.45, a: 1} 524 gl.clearColor(Math.min(clearColor.r, 1), Math.min(clearColor.g, 1), Math.min(clearColor.b, 1), Math.min(clearColor.a, 1)); //清除颜色: r, g, b, a: 0 - 1; 对应 .clear(COLOR_BUFFER_BIT) 525 //gl.clear(gl.COLOR_BUFFER_BIT); //COLOR_BUFFER_BIT //颜色缓冲区 gl.DEPTH_BUFFER_BIT //深度缓冲区 STENCIL_BUFFER_BIT //模板缓冲区 526 //gl.getParameter(gl.COLOR_CLEAR_VALUE); //要获得当前的清除值,传入 COLOR_CLEAR_VALUE, DEPTH_CLEAR_VALUE 或 STENCIL_CLEAR_VALUE 常量 527 528 //gl.enable(gl.DEPTH_TEST); //启用深度 对应 .clear(DEPTH_BUFFER_BIT) 529 //gl.depthFunc(gl.LEQUAL); // Near things obscure far things 近覆盖远 530 //gl.clearDepth(1); // 设置深度缓冲区的值(0-1),默认为1 531 532 //gl.clearStencil(1) //设置模板缓冲区的值(0或1),默认0; 对应 .clear(STENCIL_BUFFER_BIT); 533 534 //gl.enable(gl.SCISSOR_TEST); //开启剪裁 535 //gl.scissor(x, y, width, height); //设置剪裁区域 536 537 //gl.colorMask(true, true, true, false); //禁启用: 红色通道, 绿色通道, 蓝色通道, 透明度(如果为false则不会绘制任何颜色即完全透明); 538 539 //混合 540 //gl.enable(gl.BLEND); // 启用混合, 默认透明部分用背景色覆盖 541 //gl.blendEquation(gl.FUNC_ADD); 542 543 //gl.blendFunc(gl.ONE, gl.ONE); //gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); 544 545 //gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); //将所有颜色乘以源 alpha 值, 将所有颜色乘以 1 减去源 alpha 值。 546 //gl.disable(gl.BLEND); //禁用混合 547 //gl.getParameter(gl.BLEND_SRC_RGB) == gl.SRC_COLOR; 548 //混合像素的方法: 549 550 //gl.drawElements(gl.TRIANGLES, obj2d.geometry.indices.length, gl.UNSIGNED_SHORT, 0); //gl.UNSIGNED_BYTE, gl.UNSIGNED_SHORT 551 //gl.drawArrays(mode, 0, geo.vertices.length / geo.vertexCount); 552 return gl; 553 } 554 555 function initExtensions(gl) { 556 // 启用了抗锯齿 557 if(Renderer.contextOption.antialias === true && !gl.getContextAttributes().antialias && gl.getExtension('WEBGL_multisample_2d_canvas')) { 558 gl.sampleCoverage = true; 559 gl.enable(gl.SAMPLE_ALPHA_TO_COVERAGE); 560 } 561 562 //扩展 WEBGL_multi_draw 563 /* const WEBGL_multi_draw = gl.getExtension('WEBGL_multi_draw'); 564 if (WEBGL_multi_draw) { 565 var multiDrawElementsWEBGL = gl.multiDrawElementsWEBGL.bind(gl); 566 // 准备你要绘制的元素的信息 567 var counts = []; //每个draw call的元素数量 568 var offsets = []; //每个draw call的起始偏移 569 // 调用 multiDrawElementsWEBGL 方法 570 multiDrawElementsWEBGL(gl.TRIANGLES, counts, gl.UNSIGNED_SHORT, offsets); 571 } */ 572 } 573 574 function createShader(gl, program, type, code) { 575 const shader = gl.createShader(type); //创建着色器 576 gl.shaderSource(shader, code); //绑定数据源 577 gl.compileShader(shader); //编译着色器 578 gl.attachShader(program, shader); //绑定着色器 579 if(gl.getShaderParameter(shader, gl.COMPILE_STATUS) === false){ 580 console.error(type, gl.getShaderInfoLog(shader), code); 581 gl.deleteShader(shader); 582 } 583 return shader; 584 } 585 586 function createProgram(gl, vertexShaderCode, fragmentShaderCode) { 587 if(!gl) return null; 588 const program = gl.createProgram(); 589 const vertexShader = createShader(gl, program, gl.VERTEX_SHADER, vertexShaderCode); 590 const fragmentShader = createShader(gl, program, gl.FRAGMENT_SHADER, fragmentShaderCode); 591 592 gl.linkProgram(program); //连接顶点着色器与片元着色器 593 if(gl.getProgramParameter(program, gl.LINK_STATUS) === false){ 594 console.error(gl.getProgramInfoLog(program)); 595 gl.deleteProgram(program); 596 return null; 597 } 598 599 return { 600 program: program, 601 vertexShader: vertexShader, 602 fragmentShader: fragmentShader, 603 }; 604 } 605 606 function compileUniform(gl, loc, n, v, t) { 607 //number 608 switch(typeof v[n]){ 609 case "number": 610 return () => gl.uniform1f(loc, v[n]); 611 612 case "object": 613 break; 614 615 default: return function(){}; 616 } 617 618 //vec2, vec3, vec4, Matrix3x3, Matrix4x4 619 if(Array.isArray(v[n]) === true){ 620 switch(v[n].length){ 621 case 2: 622 return () => gl.uniform2f(loc, v[n][0], v[n][1]); 623 624 case 3: 625 return () => gl.uniform3f(loc, v[n][0], v[n][1], v[n][2]); 626 627 case 4: 628 return () => gl.uniform4f(loc, v[n][0], v[n][1], v[n][2], v[n][3]); 629 630 case 9: 631 return () => gl.uniformMatrix3fv(loc, false, v[n]); 632 633 case 16: 634 return () => gl.uniformMatrix4fv(loc, false, v[n]); 635 } 636 } 637 638 //Material 639 /* if(Material.prototype.isPrototypeOf(v[n]) === true){ 640 const i = t.length, 641 obj = { 642 texture: gl.createTexture(), 643 source: v[n], 644 index: gl["TEXTURE"+i], 645 needupdate: false, 646 }; 647 648 t[i] = obj; 649 gl.activeTexture(obj.index); 650 gl.bindTexture(gl.TEXTURE_2D, obj.texture); 651 652 const material = v[n]; 653 obj.update = () => { 654 if(material.source !== null) updateTexture(gl, material); 655 } 656 Object.defineProperties(obj, { 657 source: {get: () => {return material.source;}}, 658 needupdate: {get: () => {return material.needupdate;}}, 659 }); 660 obj.update(); 661 return () => gl.uniform1i(loc, i); 662 } */ 663 664 //Attribute 665 if(Attribute.prototype.isPrototypeOf(v[n]) === true){ 666 switch(v[n].size){ 667 case 1: 668 return () => gl.uniform1fv(loc, v[n].value); 669 670 case 2: 671 return () => gl.uniform2fv(loc, v[n].value); 672 673 case 3: 674 return () => gl.uniform3fv(loc, v[n].value); 675 676 case 4: 677 return () => gl.uniform4fv(loc, v[n].value); 678 } 679 } 680 681 return function(){}; 682 } 683 684 function compileBuffer(gl, loc, att) { 685 const obj = { 686 vao: gl.createVertexArray(), 687 buffer: gl.createBuffer(), 688 size: att.size, 689 //loc: loc, //如果着色器中没有用到这个变量就会返回-1 690 value: att.value, 691 } 692 693 gl.bindVertexArray(obj.vao); 694 gl.bindBuffer(gl.ARRAY_BUFFER, obj.buffer); //指定 buffer 695 gl.bufferData(gl.ARRAY_BUFFER, obj.value, gl.STATIC_DRAW); //上传数据到指定的 buffer 696 gl.vertexAttribPointer(loc, att.size, gl.FLOAT, false, 0, 0); 697 gl.enableVertexAttribArray(loc); 698 699 return obj; 700 } 701 702 function resetBuffers(gl) { 703 gl.bindVertexArray(null); 704 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); 705 gl.bindBuffer(gl.ARRAY_BUFFER, null); 706 gl.bindTexture(gl.TEXTURE_2D, null); 707 } 708 709 function createBuffers(gl, vertices, indices) { 710 //索引 indices 711 var indexBuffer = null; 712 if(indices) { 713 indexBuffer = gl.createBuffer(); 714 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); 715 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); 716 } 717 718 //顶点 vertices 719 const vertexBuffer = gl.createBuffer(); 720 gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); //指定储存单元 721 gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); //gl.STATIC_DRAW: 写入一次,绘制多次(不能再次修改,可重复使用) 722 723 //纹理坐标 uvs 724 //const uvBuffer = gl.createBuffer(); 725 //gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer); 726 //gl.bufferData(gl.ARRAY_BUFFER, uvs, gl.STATIC_DRAW); 727 728 //const loc = gl.getAttribLocation(pro, "aPosition"); 729 730 //gl.vertexAttribPointer(loc, vertexCount, gl.FLOAT, false, 0, 0); 731 732 return { 733 indexBuffer: indexBuffer, 734 vertexBuffer: vertexBuffer, 735 //uvBuffer: uvBuffer, 736 } 737 } 738 739 function deleteBuffers(gl, buffers) { 740 if(!buffers) return; 741 for(let n in buffers){ 742 if(buffers[n]) gl.deleteBuffer(buffers[n]); 743 } 744 } 745 746 function updateTexture(gl, tex) { 747 //像素预处理 748 if(Array.isArray(tex.pixelStorei) === true) { 749 for(let i = 0, v; i < tex.pixelStorei.length; i++) { 750 v = Texture.pixelStoreis[tex.pixelStorei[i]]; 751 if(v !== undefined) gl.pixelStorei(gl[v], true); 752 } 753 } 754 755 if(ImageSource.prototype.isPrototypeOf(tex.source) === true){ 756 gl.texImage2D(gl.TEXTURE_2D, 0, gl[tex.format], tex.source.width, tex.source.height, 0, gl[tex.format], gl[tex.type], tex.source.data); 757 } else { 758 gl.texImage2D(gl.TEXTURE_2D, 0, gl[tex.format], gl[tex.format], gl[tex.type], tex.source); 759 } 760 761 //gl.getParameter(gl.MAX_TEXTURE_SIZE); 762 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); //LINEAR (default value)(线性的), NEAREST(最近的) 763 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); //REPEAT(重复), CLAMP_TO_EDGE(夹到边缘), MIRRORED_REPEAT(像镜子一样的重复?) 764 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 765 766 //mipmap 767 if(tex.mipmap === true){ // && isPowerOf2(tex.source.width) === true && isPowerOf2(tex.source.height) === true 768 gl.generateMipmap(gl.TEXTURE_2D); 769 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR); 770 } else { 771 //gl.LINEAR, gl.NEAREST, gl.NEAREST_MIPMAP_NEAREST, gl.LINEAR_MIPMAP_NEAREST, gl.NEAREST_MIPMAP_LINEAR (default value), gl.LINEAR_MIPMAP_LINEAR. 772 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 773 } 774 } 775 776 function proHandler(gl, pros, renderer, object2d) { 777 const isMS = MaterialShader.prototype.isPrototypeOf(object2d.material); 778 779 const result = { 780 cache: null, 781 uniforms: { 782 uPMat: renderer.projectionMatrix, 783 uMat: object2d.modelMatrix, 784 uSize: [object2d.geometry.width, object2d.geometry.height], 785 }, 786 } 787 788 if(isMS === false){ 789 result.uniforms.uImage = object2d.material.texture; 790 } else { 791 const properties = {}; 792 for(let n in object2d.material.uniforms){ 793 properties[n] = { 794 enumerable: true, 795 get: () => {return object2d.material.uniforms[n];}, 796 } 797 } 798 Object.defineProperties(result.uniforms, properties); 799 } 800 801 let proName = "", pro = null; 802 803 switch(object2d.constructor.name){ 804 case "Object2D": 805 proName = "texture1"; 806 807 if(isMS === false){ 808 pro = pros[proName]; 809 } else { 810 pro = createProgram(gl, object2d.material.vertexCode, object2d.material.fragmentCode); 811 proName = ""; 812 } 813 814 result.cache = new Cache(gl, proName, pro, object2d, gl[ModeTriangles]); 815 break; 816 817 case "Sprite": 818 proName = "texture1_sprite"; 819 820 if(isMS === false){ 821 pro = pros[proName]; 822 } else { 823 pro = createProgram(gl, object2d.material.vertexCode, object2d.material.fragmentCode); 824 proName = ""; 825 } 826 827 if(result.uniforms.uLen === undefined) result.uniforms.uLen = object2d.len; 828 if(result.uniforms.uOffset === undefined){ 829 Object.defineProperty(result.uniforms, "uOffset", { 830 enumerable: true, //编译时需要遍历 uniforms 831 get: () => {return object2d.offset;}, 832 }); 833 } 834 835 result.cache = new Cache(gl, proName, pro, object2d, gl[ModeTriangles]); 836 break; 837 838 case "Instanced": 839 proName = "texture1_Instanced"; 840 841 if(isMS === false){ 842 pro = pros[proName]; 843 } else { 844 pro = createProgram(gl, object2d.material.vertexCode, object2d.material.fragmentCode); 845 proName = ""; 846 } 847 848 result.cache = new CacheInstanced(gl, proName, pro, object2d, gl[ModeTriangles]); 849 break; 850 851 case "InstancedPoints": 852 proName = "texture1_Instanced_points"; 853 854 if(isMS === false){ 855 pro = pros[proName]; 856 } else { 857 pro = createProgram(gl, object2d.material.vertexCode, object2d.material.fragmentCode); 858 proName = ""; 859 } 860 861 if(Array.isArray(result.uniforms.uSize) === true){ 862 Object.defineProperty(result.uniforms, "uSize", { 863 enumerable: true, //编译时需要遍历 uniforms 864 get: () => {return object2d.pointSize;}, 865 }); 866 } 867 868 result.cache = new CacheInstanced(gl, proName, pro, object2d, gl[ModePoints]); 869 break; 870 871 case "InstancedSprite": 872 proName = "texture1_Instanced_sprite"; 873 874 if(isMS === false){ 875 pro = pros[proName]; 876 } else { 877 pro = createProgram(gl, object2d.material.vertexCode, object2d.material.fragmentCode); 878 proName = ""; 879 } 880 881 if(result.uniforms.uLen === undefined) result.uniforms.uLen = object2d.len1; 882 if(result.uniforms.uOffset === undefined){ 883 Object.defineProperty(result.uniforms, "uOffset", { 884 enumerable: true, //编译时需要遍历 uniforms 885 get: () => {return object2d.offset;}, 886 }); 887 } 888 889 result.cache = new CacheInstanced(gl, proName, pro, object2d, gl[ModeTriangles]); 890 break; 891 } 892 893 //if(isMS) Object.assign(result.uniforms, object2d.material.uniforms); 894 //console.log(result.uniforms); 895 return result; 896 } 897 898 /** 899 * @param {WebGL2RenderingContext} gl 900 */ 901 function createRenderTarget(gl, width, height) { 902 const texture = gl.createTexture(); 903 gl.bindTexture(gl.TEXTURE_2D, texture); 904 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); 905 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 906 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 907 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 908 909 // Create and bind the framebuffer 910 const frameBuffer = gl.createFramebuffer(); 911 gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer); 912 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); 913 914 //将一个 frameBuffer 复制到另一个 frameBuffer 915 //this.gl.blitFramebuffer(0, 0, this.viewPort.width, this.viewPort.height, 0, 0, this.viewPort.width, this.viewPort.height,this.gl.COLOR_BUFFER_BIT, this.gl.LINEAR); 916 917 918 //const renderBuffer = gl.createRenderbuffer(); 919 //gl.bindRenderbuffer(gl.RENDERBUFFER, renderBuffer); 920 921 //gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA8, width, height); 922 923 // 为渲染缓冲区指定存储数据的类型和尺寸 924 //gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height); 925 926 // 6. 将渲染缓冲区对象附加到帧缓冲区对象上 927 //gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, renderBuffer); 928 929 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 930 931 return { 932 texture: texture, 933 frameBuffer: frameBuffer, 934 //renderBuffer: renderBuffer, 935 } 936 } 937 938 939 940 941 /* glsl 一些内置函数: 942 abs 返回一个数的绝对值。 943 acos 返回一个数的反余弦。 944 asin 返回一个数的反正弦。 945 atan 返回一个数的反正切。 946 //atan2 返回从X轴到点(y,x)的角度(以弧度为单位)。 947 cos 返回一个数的余弦。 948 sin 返回一个数的正弦。 949 sqrt 返回一个数的平方根。 950 tan 返回一个数的正切。 951 round 将一个指定的数值表达式舍入到最近的整数并将其返回。 952 random 返回一个0和1之间的伪随机数。 953 parseFloat 返回从字符串转换而来的浮点数。 954 parseInt 返回从字符串转换而来的整数。 955 pow 返回一个指定幂次的底表达式的值。 956 step(float a, float x): a < x ? x : a; 957 clamp(float x, float min, float max): min > x ? min : min < x && max > x ? x : max; 返回三个值中的中间值 958 mix(vac4 color1, vec4 color2, float weight) 返回两种颜色的混合, color2 为 weight, color1 为 1 - weight 959 mod(float x, float y): x % y 960 961 exp 返回e的x次幂。 962 log 返回x的自然对数, 963 exp2 返回2的x次幂。 964 log2 返回x的2为底的对数, 965 966 inversesqrt 回1/xxx, 967 sign 返回数值的符号值。 968 969 texture2D(uSampler, gl_PointCoord.xy) gl_PointCoord 特殊变量能自动获取 points 的纹理坐标 970 */ 971 972 973 class Attribute { 974 975 /** 976 * @param {number} size 977 * @param {Array|TypeBufferArray} value 978 */ 979 constructor(size, value) { 980 this.size = size; 981 this.value = value; 982 } 983 984 } 985 986 987 /** Geometry 988 demo: 989 const width = 256, height = 256; 990 991 const geometry = new Geometry({ 992 aPosition: new Attribute(2, new Float32Array([ 993 width,0, 0,0, 0,height, 994 0,height, width,height, width,0, 995 ])), 996 }, width, height); 997 998 999 //顶点索引版本: 1000 const geometry = new Geometry({ 1001 aPosition: new Attribute(2, new Float32Array([ 1002 0,0, width,0, width,height, 0,height, 1003 ])) 1004 }, width, height); 1005 1006 geometry.setIndex([1,0,3, 3,2,1]); 1007 */ 1008 class Geometry { 1009 1010 #type = "UNSIGNED_SHORT"; //索引面的类型(初始化时自动选择设置); 可能的值有: UNSIGNED_SHORT|UNSIGNED_INT 1011 get type() {return this.#type;} 1012 1013 #offset = 0; //绘制几何体的偏移 1014 get offset() {return this.#offset;} 1015 1016 #indices = null; 1017 get indices() {return this.#indices;} 1018 1019 #w = 0; 1020 #h = 0; 1021 get width() {return this.#w;} 1022 get height() {return this.#h;} 1023 1024 /** 1025 * @param {{aPos: Attribute}} attributes 必须定义(面索用.setIndex()方法设置) 1026 * @param {Box} bbox 可选(如果未定义则在构造器中自动计算一次) 1027 */ 1028 constructor(attributes, w = 0, h = 0) { 1029 this.attributes = attributes; 1030 this.#w = w; 1031 this.#h = h; 1032 } 1033 1034 /** 1035 * 根据 this.attributes[attributeName] 的顶点设置边界大小 1036 * @param {string} attributeName 1037 */ 1038 computeSize(attributeName) { 1039 const att = this.attributes[attributeName]; 1040 if(Attribute.prototype.isPrototypeOf(att) === false) return; 1041 const obj = computeBBox(att.value, att.size); 1042 if(obj.x !== 0 || obj.y !== 0){ 1043 translateVertices(att.value, att.size, -obj.x, -obj.y); 1044 this.#w = Math.abs(obj.x1 - obj.x); 1045 this.#h = Math.abs(obj.y1 - obj.y); 1046 } else { 1047 this.#w = obj.x1; 1048 this.#h = obj.y1; 1049 } 1050 } 1051 1052 /** 1053 * 设置顶点索引 1054 * @param {[]|Uint16Array|Uint32Array} indices 1055 * @param {undefined|boolean} isu32 //如果 indices 已是类型数组可以忽略此参数 1056 * @returns 1057 */ 1058 setIndex(indices, isu32) { 1059 if(this.#indices !== null) return console.warn("不支持更改索引面"); 1060 1061 switch(indices.constructor.name){ 1062 case "Array": 1063 break; 1064 1065 case "Uint32Array": 1066 this.#type = "UNSIGNED_INT"; 1067 this.#indices = indices; 1068 return; 1069 1070 default: 1071 case "Uint16Array": 1072 this.#type = "UNSIGNED_SHORT"; 1073 this.#indices = indices; 1074 return; 1075 } 1076 1077 if(typeof isu32 !== "boolean"){ 1078 isu32 = false; 1079 for(let i = 0; i < indices.length; i++){ 1080 if(indices[i] < 65535) continue; 1081 isu32 = true; 1082 break; 1083 } 1084 } 1085 1086 if(isu32 === false) { 1087 this.#type = "UNSIGNED_SHORT"; 1088 this.#indices = new Uint16Array(indices); 1089 } else { 1090 this.#type = "UNSIGNED_INT"; 1091 this.#indices = new Uint32Array(indices); 1092 } 1093 } 1094 1095 } 1096 1097 1098 //矩形 1099 class GeometryRect extends Geometry { 1100 1101 constructor(width, height) { 1102 super({aPos: new Attribute(2, new Float32Array([0,0, width,0, width,height, 0,height]))}, width, height); 1103 this.setIndex([1, 0, 3, 3, 2, 1], false); 1104 } 1105 1106 } 1107 1108 1109 //圆形 1110 class GeometryCircle extends Geometry { 1111 1112 constructor(radius = 1, segments = 32, thetaStart = 0, thetaLength = Math.PI * 2) { 1113 segments = Math.max(3, segments); 1114 1115 let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; 1116 1117 const vertices = [0, 0]; 1118 for ( let s = 0, i = 3, segment; s <= segments; s ++, i += 3 ) { 1119 segment = thetaStart + s / segments * thetaLength; 1120 const x = radius * Math.cos( segment ), 1121 y = radius * Math.sin( segment ); 1122 vertices.push(x, y); 1123 minX = Math.min(x, minX); 1124 minY = Math.min(y, minY); 1125 maxX = Math.max(x, maxX); 1126 maxY = Math.max(y, maxY); 1127 } 1128 1129 const indices = []; 1130 for ( let i = 1; i <= segments; i ++ ) { 1131 indices.push( i, i + 1, 0 ); 1132 } 1133 1134 if(minX !== 0 || minY !== 0){ 1135 translateVertices(vertices, 2, -minX, -minY); 1136 super({aPos: new Attribute(2, new Float32Array(vertices))}, Math.abs(maxX - minX), Math.abs(maxY - minY)); 1137 } else { 1138 super({aPos: new Attribute(2, new Float32Array(vertices))}, maxX, maxY); 1139 } 1140 1141 this.setIndex(indices); 1142 } 1143 1144 } 1145 1146 1147 //形状 1148 class GeometryShape extends Geometry { 1149 1150 constructor(points, segments = 1) { 1151 let isu32 = false, minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; 1152 1153 points = new Shape(points).extractPoints(segments).shape; 1154 if(ShapeUtils.isClockWise(points) === false) points = points.reverse(); 1155 1156 // 1157 const indices = [], vertices = [], 1158 faces = ShapeUtils.triangulateShape(points, []); 1159 for(let i = 0, p, l = points.length; i < l; i ++){ 1160 p = points[i]; 1161 vertices.push(p.x, p.y); 1162 minX = Math.min(p.x, minX); 1163 minY = Math.min(p.y, minY); 1164 maxX = Math.max(p.x, maxX); 1165 maxY = Math.max(p.y, maxY); 1166 } 1167 1168 for(let i = 0, face, l = faces.length; i < l; i++){ 1169 face = faces[i]; 1170 indices.push(face[0], face[1], face[2]); 1171 if(isu32 === false && (face[0] >= 65535 || face[1] >= 65535 || face[2] >= 65535)) isu32 = true; 1172 } 1173 1174 // 1175 1176 if(minX !== 0 || minY !== 0){ 1177 translateVertices(vertices, 2, -minX, -minY); 1178 super({aPos: new Attribute(2, new Float32Array(vertices))}, Math.abs(maxX - minX), Math.abs(maxY - minY)); 1179 } else { 1180 super({aPos: new Attribute(2, new Float32Array(vertices))}, maxX, maxY); 1181 } 1182 1183 this.setIndex(indices, isu32); 1184 } 1185 1186 } 1187 1188 1189 //波浪矩形 1190 class GeometryRectWavy extends GeometryShape { 1191 1192 constructor(width, height, distance, divisions = 12) { 1193 const halfW = width / 2, halfH = height / 2; 1194 distance = distance === undefined ? Math.min(halfW, halfH) * 0.2 : Math.min(distance, Math.min(halfW, halfH) * 0.5); 1195 const points = [ 1196 //右上 1197 new Vector2(halfW + distance, 0), 1198 new Vector2(width, 0), 1199 new Vector2(width, halfH - distance), 1200 1201 //右下 1202 new Vector2(width, halfH + distance), 1203 new Vector2(width, height), 1204 new Vector2(halfW + distance, height), 1205 1206 //左下 1207 new Vector2(halfW - distance, height), 1208 new Vector2(0, height), 1209 new Vector2(0, halfH + distance), 1210 1211 //左上 1212 new Vector2(0, halfH - distance), 1213 new Vector2(0, 0), 1214 new Vector2(halfW - distance, 0), 1215 ]; 1216 1217 const points1 = [], curve = new SplineCurve(); 1218 for(let i = 0; i < points.length; i += 3) { 1219 curve.points = [points[i], points[i+1], points[i+2]]; 1220 const points2 = curve.getPoints(divisions); 1221 for(let i = 0; i < points2.length; i++){ 1222 points1.push(points2[i]); 1223 } 1224 } 1225 1226 super(points1, 1); 1227 } 1228 1229 } 1230 1231 1232 class ImageSource { 1233 1234 /** 1235 * ImageData 的构造器不是很友好, 这是它的替代品 1236 * @param {number} w 1237 * @param {number} h 1238 * @param {Uint8Array} d //步长为4的数组, 分别是: r, g, b, a 1239 */ 1240 constructor(w, h, d = new Uint8Array(w * h * 4)) { 1241 this.width = w; 1242 this.height = h; 1243 this.data = d; 1244 } 1245 1246 } 1247 1248 1249 class Texture { 1250 1251 static pixelStoreis = [ 1252 "PACK_ALIGNMENT", //将像素数据打包到内存中 1253 "UNPACK_ALIGNMENT", //从内存中解压缩像素数据 1254 "UNPACK_FLIP_Y_WEBGL", //翻转纹理的y轴 1255 "UNPACK_PREMULTIPLY_ALPHA_WEBGL", //预乘阿尔法通道(将alpha通道与其他颜色通道相乘) 1256 "UNPACK_COLORSPACE_CONVERSION_WEBGL", //默认颜色空间转换或不进行颜色空间转换 1257 ]; 1258 1259 static formats = [ 1260 "ALPHA", "UNSIGNED_BYTE", //14: 1,1; //阿尔法 1261 "LUMINANCE", "UNSIGNED_BYTE", //12: 1,1; //不透明灰度图 1262 "LUMINANCE_ALPHA", "UNSIGNED_BYTE", //10: 2,2; //透明灰度图 1263 "RGB", "UNSIGNED_SHORT_5_6_5", //8: 3,2 1264 "RGBA", "UNSIGNED_SHORT_5_5_5_1", //6: 4,2 1265 "RGBA", "UNSIGNED_SHORT_4_4_4_4", //4: 4,3 1266 "RGB", "UNSIGNED_BYTE", //2: 3,3 //不透明 1267 "RGBA", "UNSIGNED_BYTE", //0: 4,4 //透明 1268 ]; 1269 1270 #f_t = 0; 1271 get format() {return Texture.formats[this.#f_t];} 1272 get type() {return Texture.formats[this.#f_t + 1];} 1273 1274 #needupdate = false; //如果材质属性发生改变将此值设为true,渲染器会重绘材质的纹理(纹理不适合频繁的修改, 用着色器实现动态纹理) 1275 get needupdate() { 1276 if(this.#needupdate === false) return false; 1277 this.#needupdate = false; 1278 return true; 1279 } 1280 1281 #source = null; 1282 get source() {return this.#source;} 1283 set source(v) { 1284 this.#source = v; 1285 this.#needupdate = true; 1286 } 1287 1288 #pixelStorei = null; 1289 get pixelStorei() {return this.#pixelStorei;} 1290 get isPremultiplyAlpht() { 1291 return this.#pixelStorei === null ? false : this.#pixelStorei.includes(PixelStoreiPremultiplyAlpht); 1292 } 1293 1294 #mipmap = false; 1295 get mipmap() {return this.#mipmap;} 1296 set mipmap(v) { 1297 if(typeof v !== "boolean" || v === this.#mipmap) return; 1298 this.#mipmap = v; 1299 this.#needupdate = true; 1300 } 1301 1302 constructor(source, format = FormatRGBA, pixelStorei = [PixelStoreiPremultiplyAlpht], mipmap = false) { 1303 this.#source = source; 1304 this.#f_t = format; 1305 this.#pixelStorei = pixelStorei; 1306 this.#mipmap = mipmap; 1307 } 1308 1309 setFormatAndType(v = FormatRGBA) { 1310 this.#f_t = v; 1311 this.#needupdate = true; 1312 } 1313 1314 setPixelStorei(key = PixelStoreiPremultiplyAlpht, enable = false) { 1315 if(key >= Texture.pixelStoreis.length || key < 0) return; 1316 if(enable === true){ 1317 if(this.#pixelStorei === null) this.#pixelStorei = []; 1318 this.#pixelStorei.push(key); 1319 this.#needupdate = true; 1320 } else if(this.#pixelStorei !== null){ 1321 const i = this.#pixelStorei.indexOf(key); 1322 if(i === -1) return; 1323 this.#pixelStorei.splice(i, 1); 1324 this.#needupdate = true; 1325 } 1326 } 1327 1328 } 1329 1330 1331 class MUS { 1332 1333 static blendESs = [ 1334 "FUNC_ADD", //source + destination (default value) 1335 "FUNC_SUBTRACT", //source - destination 1336 "FUNC_REVERSE_SUBTRACT", //destination - source 1337 "MIN", //Minimum of source and destination 1338 "MAX", //Maximum of source and destination 1339 ]; 1340 1341 static blendFSs = [ 1342 "ZERO", //所有颜色乘 0 1343 "ONE", //所有颜色乘 1 1344 "SRC_COLOR", //将所有颜色乘上源颜色 1345 "ONE_MINUS_SRC_COLOR", //每个源颜色所有颜色乘 1 1346 "DST_COLOR", //将所有颜色与目标颜色相乘 1347 "ONE_MINUS_DST_COLOR", //将所有颜色乘以 1 减去每个目标颜色, 1348 "SRC_ALPHA", //将所有颜色乘以源 alpha 值 1349 "ONE_MINUS_SRC_ALPHA", //将所有颜色乘以 1 减去源 alpha 值 1350 "DST_ALPHA", //将所有颜色与目标 alpha 值相乘 1351 "ONE_MINUS_DST_ALPHA", //将所有颜色乘以 1 减去目标 alpha 值 1352 "CONSTANT_COLOR", //将所有颜色乘以一个常数颜色 1353 "ONE_MINUS_CONSTANT_COLOR", //所有颜色乘以 1 减去一个常数颜色 1354 "CONSTANT_ALPHA", //将所有颜色乘以一个常数 1355 "ONE_MINUS_CONSTANT_ALPHA", //所有颜色乘以 1 减去一个常数 1356 "SRC_ALPHA_SATURATE", //将 RGB 颜色乘以源 alpha 值或 1 减去目标 alpha 值中的较小值。alpha 值乘以 1 1357 ]; 1358 1359 #blendEnable = false; 1360 get blendEnable() {return this.#blendEnable;} 1361 set blendEnable(v) { 1362 this.#blendEnable = typeof v === "boolean" ? v : false; 1363 } 1364 1365 #blendC = {r: 0, g: 0, b: 0, a: 0}; 1366 get blendC(){return this.#blendC;} 1367 1368 #blendES = [BlendEquationAdd[0], BlendEquationAdd[1]]; 1369 get blendES(){return this.#blendES;} //mode || modeRGB, modeAlpha; 值为: MUS.blendESs 的索引 1370 1371 #blendFS = [BlendDefault[0], BlendDefault[1], BlendDefault[2], BlendDefault[3]]; 1372 get blendFS(){return this.#blendFS;} //sfactor, dfactor || srcRGB, dstRGB, srcAlpha, dstAlpha; 值为: MUS.blendFSs 的索引 1373 1374 //如果纹理属性发生改变将此值设为true,渲染器会重绘材质的纹理(纹理不适合频繁的修改, 用着色器实现动态纹理) 1375 //注意还要设置对应材质的.needupdate = true 才有效 1376 #needupdate = false; 1377 get needupdate() { 1378 if(this.#needupdate === false) return false; 1379 this.#needupdate = false; 1380 return true; 1381 } 1382 set needupdate(v) { 1383 this.#needupdate = v; 1384 } 1385 1386 /** 1387 * 设置内置的混合组合 1388 * @param {Array} v //值为带前缀 Blend* 的常量 1389 */ 1390 setBlend(v){ 1391 switch(v){ 1392 default: return false; 1393 case BlendDefault: 1394 case BlendAdd: 1395 case BlendSub: 1396 case BlendMultiply: 1397 break; 1398 } 1399 Object.assign(this.#blendFS, v); 1400 return true; 1401 } 1402 1403 /** 1404 * gl.blendFunc(sfactor, dfactor) 1405 * @param {number} sfactor //值为: MUS.blendFSs 的索引 1406 * @param {number} dfactor //值为: MUS.blendFSs 的索引 1407 */ 1408 blendFunc(sfactor, dfactor) { 1409 this.#blendFS[0] = sfactor; 1410 this.#blendFS[1] = dfactor; 1411 this.#blendFS[2] = -1; 1412 this.#blendFS[3] = -1; 1413 } 1414 1415 /** 1416 * //gl.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); 值为: MUS.blendFSs 的索引 1417 * @param {number} srcRGB 1418 * @param {number} dstRGB 1419 * @param {number} srcAlpha 1420 * @param {number} dstAlpha 1421 */ 1422 blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha) { 1423 this.#blendFS[0] = srcRGB; 1424 this.#blendFS[1] = dstRGB; 1425 this.#blendFS[2] = srcAlpha; 1426 this.#blendFS[3] = dstAlpha; 1427 } 1428 1429 } 1430 1431 1432 class Material extends MUS { 1433 1434 #texture = null; 1435 get texture() {return this.#texture;} 1436 1437 /** 1438 * @param {Texture} texture 1439 * @param {boolean} blendEnable 1440 */ 1441 constructor(texture, blendEnable) { 1442 super(); 1443 this.#texture = texture; 1444 this.blendEnable = blendEnable; 1445 } 1446 1447 } 1448 1449 1450 /** MaterialShader 1451 demo: 1452 const width = 256, height = 256; 1453 const geometry = new Geometry({ 1454 aPosition: new Attribute(2, new Float32Array([ 1455 width,0, 0,0, 0,height, 1456 0,height, width,height, width,0, 1457 ])), 1458 }, width, height); 1459 1460 const material = new MaterialShader({ 1461 vertexCode: `#version 300 es 1462 in vec2 aPosition; 1463 uniform mat3 projectionMatrix; 1464 uniform mat3 modelMatrix; 1465 void main() { 1466 gl_Position.xyz = projectionMatrix * modelMatrix * vec3(aPosition, 1.0); 1467 gl_Position.w = 1.0; 1468 } 1469 `, 1470 fragmentCode: `#version 300 es 1471 precision mediump float; //highp, mediump, lowp 1472 uniform vec4 uColor; 1473 out vec4 outColor; 1474 void main() { 1475 outColor = uColor; 1476 } 1477 `, 1478 uniforms: { 1479 projectionMatrix: renderer.projectionMatrix, 1480 modelMatrix: null, //这里够不到模型矩阵,先占个位 1481 uColor: [1, 0, 0, 1], 1482 }, 1483 }); 1484 1485 const shader = new Object2D(geometry, material).translate(100, 300); 1486 material.uniforms.modelMatrix = shader.modelMatrix; 1487 renderer.append(shader).redraw(); 1488 1489 1490 //这么做太麻烦了, 看下面这个: 1491 1492 const geometry1 = new GeometryRect(256, 256); 1493 const material1 = new MaterialShader({ 1494 vertexCode: `#version 300 es 1495 in vec2 aPos; //aPosition -> aPos 顶点属性 1496 uniform mat3 uPMat; //projectionMatrix -> uPMat 投影矩阵 1497 uniform mat3 uMat; //modelMatrix -> uMat 模型矩阵 1498 void main() { 1499 gl_Position.xyz = uPMat * uMat * vec3(aPos, 1.0); 1500 gl_Position.w = 1.0; 1501 } 1502 `, 1503 fragmentCode: `#version 300 es 1504 precision mediump float; //highp, mediump, lowp 1505 uniform vec4 uColor; 1506 out vec4 outColor; 1507 void main() { 1508 outColor = uColor; 1509 } 1510 `, 1511 uniforms: { 1512 uColor: [1, 0, 0, 1], 1513 }, 1514 }); 1515 1516 const shader1 = new Object2D(geometry1, material1).translate(100+256+10, 300); 1517 renderer.append(shader1).redraw(); 1518 1519 //每个模型的内置变量不一样(参考: defaultShaderCode), 这里只针对 Object2D; 1520 //Object2D 内置了1个属性, Geometry.attributes: {aPos: Attribute} 1521 //Object2D 内置了4个全局属性, .uniforms: {uPMat: [3x3], uMat: [3x3], uSize: [0, 0], uImage: Texture} 1522 //如果定义的着色器代码没有使用这些内置属性,渲染器在初始化它们时将自动丢弃掉 1523 1524 1525 //水波纹涟漪特效例子: 1526 1527 const materialShader = new MaterialShader({ 1528 blending: BlendDefault, 1529 vertexCode: defaultShaderCode.texture1.vertex, 1530 fragmentCode: `#version 300 es 1531 precision mediump float; //highp, mediump, lowp 1532 uniform vec2 uSize; 1533 uniform sampler2D uImage; 1534 uniform vec2 uOrigin; 1535 uniform vec2 uRange; 1536 uniform float uScale; 1537 uniform float uLife; 1538 uniform float uTime; 1539 in vec2 vPos; 1540 1541 out vec4 outColor; 1542 const float PI = 3.141592653589793; 1543 1544 float atan2(float y, float x) { 1545 if(x > 0.0){return atan(y / x);} 1546 if(x < 0.0){ 1547 if(y >= 0.0){return atan(y / x) + PI;} 1548 return atan(y / x) - PI; 1549 } 1550 if(y > 0.0){return PI;} 1551 if(y < 0.0){return -PI;} 1552 return 0.0; 1553 } 1554 1555 void main() { 1556 vec2 newPos = vPos - uOrigin; 1557 float _d = newPos.x * newPos.x + newPos.y * newPos.y; 1558 if(_d < 0.001 || _d < uRange.x * uRange.x || _d > uRange.y * uRange.y){ 1559 outColor = texture(uImage, vPos / uSize); 1560 } else { 1561 float d = sqrt((1.0 - uScale) * _d); 1562 float r = atan2(vPos.y, vPos.x); 1563 outColor = texture(uImage, (vPos + vec2(cos(r) * sin(d - uTime) / d, sin(r) * sin(d - uTime) / d) * uLife) / uSize); 1564 } 1565 } 1566 `, 1567 uniforms: { 1568 uImage: new Texture(images[0], FormatRGBA), 1569 uOrigin: [innerWidth / 2, innerHeight / 2], //扩散原点 1570 uRange: [0, innerWidth], //0: 扩散最小半径, 1: 扩散最大半径; 1571 uScale: 0.993, //值越大波就越宽 1572 uLife: innerWidth, //值越大起伏就越大 1573 uTime: 0, 1574 }, 1575 }); 1576 */ 1577 class MaterialShader extends MUS { 1578 1579 /** 1580 * @param {{vertexCode: string, fragmentCode: string, uniforms: object, blending: Array}} option 1581 */ 1582 constructor(option) { 1583 super(); 1584 this.vertexCode = option.vertexCode; 1585 this.fragmentCode = option.fragmentCode; 1586 this.uniforms = option.uniforms; 1587 this.blendEnable = this.setBlend(option.blending); 1588 } 1589 1590 } 1591 1592 1593 /** Object2D 1594 demo: 1595 const geometry = new GeometryRect(renderer.domElement.width, renderer.domElement.height); 1596 const texture = new Texture(images[0], FormatRGB); 1597 const material = new Material(texture, false); 1598 const background = new Object2D(geometry, material); 1599 renderer.append(background).redraw(); 1600 */ 1601 class Object2D { 1602 1603 #geometry = null; 1604 get geometry() { 1605 return this.#geometry; 1606 } 1607 1608 #material = null; 1609 get material() { 1610 return this.#material; 1611 } 1612 1613 #mat3A = []; 1614 get modelMatrix() {return this.#mat3A;} 1615 1616 #mat3 = null; 1617 #bbox = new Box(); 1618 get x() {return this.#bbox.x;} 1619 get y() {return this.#bbox.y;} 1620 1621 /** 1622 * 渲染器的常规成员 (复用它们: Geometry, Material, Texture, 如果这么做那么它们大部分东西都是共享的包括GPU上的缓存) 1623 * @param {Geometry} geometry 1624 * @param {Material} material 1625 */ 1626 constructor(geometry, material) { 1627 this.#geometry = geometry || null; 1628 this.#material = material || null; 1629 1630 this.#bbox.size(geometry.width, geometry.height); 1631 this.#mat3 = new Matrix3(this.#mat3A).makeTranslation(0, 0); 1632 this.visible = true; 1633 } 1634 1635 translate(x, y) { 1636 this.#bbox.x += x; 1637 this.#bbox.y += y; 1638 this.#mat3.translate(x, y); 1639 return this; 1640 } 1641 1642 rotate(r, ox = this.#bbox.w / 2, oy = this.#bbox.h / 2) { 1643 const cx = this.#bbox.x + ox, 1644 cy = this.#bbox.y + oy; 1645 this.#mat3.translate(-cx, -cy) 1646 .rotate(r).translate(cx, cy); 1647 return this; 1648 } 1649 1650 scale(x, y, ox = this.#bbox.w / 2, oy = this.#bbox.h / 2) { 1651 const cx = this.#bbox.x + ox, 1652 cy = this.#bbox.y + oy; 1653 this.#mat3.translate(-cx, -cy) 1654 .scale(x, y).translate(cx, cy); 1655 return this; 1656 } 1657 1658 setPosition(x, y) { 1659 this.#mat3.translate(x - this.#bbox.x, y - this.#bbox.y); 1660 this.#bbox.x = x; 1661 this.#bbox.y = y; 1662 return this; 1663 } 1664 1665 containsPoint(x, y) { 1666 return this.#bbox.containsPoint(x, y); 1667 } 1668 1669 } 1670 1671 1672 /** Sprite 1673 demo: 1674 const geometry = new GeometryRect(renderer.domElement.width, renderer.domElement.height); 1675 const texture = new Texture(images[3], FormatRGB); 1676 const material = new Material(texture, false); 1677 const sprite = new Sprite(geometry, material, 8, 0); 1678 renderer.append(sprite).redraw(); 1679 setInterval(() => { 1680 sprite.offset += 1; //sprite.offset += 0.1; 1681 renderer.redraw(); 1682 }, 600); 1683 */ 1684 class Sprite extends Object2D { 1685 1686 #len = 1; 1687 get len() {return this.#len;} 1688 1689 #offset = 0; 1690 get offset() {return this.#offset;} 1691 set offset(v) {this.#offset = v % this.#len;} 1692 1693 /** 1694 * 雪碧图, 精灵 (暂只支持 x * 1 的雪碧图), 设置它 .offset 实时生效! 1695 * @param {Geometry} geometry 1696 * @param {Material} material 1697 * @param {number} len //雪碧图x轴长度(图片的宽 / 每一格的宽) 1698 * @param {number} offset //雪碧图x轴位置, 浮点值, 0.0 至 len - 1 个为一个循环(offset % len) 1699 */ 1700 constructor(geometry, material, len, offset = 0.0) { 1701 super(geometry, material); 1702 this.#len = Math.floor(Math.max(this.#len, len)); 1703 this.offset = offset; 1704 } 1705 1706 } 1707 1708 1709 /** Instanced 1710 demo: 1711 const instanced = new Instanced(geos[2], mats[2], 5).translate(100, 100); 1712 for(let i = 0; i < instanced.len; i++){ //设置每一个实例的旋转 1713 instanced.rotateI(i, i / instanced.len); 1714 } 1715 1716 renderer.append(instanced).redraw(); 1717 */ 1718 class Instanced extends Object2D { 1719 1720 #frequentUpdate = false; 1721 get frequentUpdate() {return this.#frequentUpdate;} 1722 1723 #needupdate = null; 1724 #needupdateI = []; 1725 get needupdateI() {return this.#needupdateI;} 1726 get needupdate() {return this.#needupdate;} 1727 1728 #len = 0; 1729 get len() {return this.#len;} 1730 1731 #matrixData = null; 1732 get matrixData() {return this.#matrixData;} 1733 1734 #matrices = null; 1735 #matricesA = null; 1736 get matricesA() {return this.#matricesA;} 1737 1738 #bboxs = null; 1739 1740 /** 1741 * Object2D 的实例化版本 1742 * @param {Geometry} geometry 1743 * @param {Material} material 1744 * @param {number} len //实例的长度 1745 * @param {boolean} frequentUpdate //是否经常更新变换矩阵, 默认 false; (决定了变换矩阵数据在着色器中的缓存类型) 1746 */ 1747 constructor(geometry, material, len, frequentUpdate) { 1748 super(geometry, material); 1749 1750 len = Math.max(1, Math.floor(len)); 1751 1752 const matrixLen = 3 * 3, sizeByte = matrixLen * 4; 1753 this.#matrixData = new Float32Array(len * matrixLen); 1754 this.#matrices = new Array(len); 1755 this.#matricesA = new Array(len); 1756 1757 this.#needupdate = new Array(len); 1758 this.#bboxs = new Array(len); 1759 const cx = geometry.width / 2, cy = geometry.height / 2; 1760 1761 for(let i = 0, val; i < len; i++){ 1762 val = new Float32Array(this.#matrixData.buffer, i * sizeByte, matrixLen); 1763 this.#matricesA[i] = val; 1764 this.#matrices[i] = new Matrix3(val).makeTranslation(0, 0); 1765 this.#needupdate[i] = false; 1766 this.#bboxs[i] = new Box(0, 0, cx, cy); 1767 } 1768 1769 this.#len = len; 1770 this.#frequentUpdate = typeof frequentUpdate === "boolean" ? frequentUpdate : false; 1771 } 1772 1773 translateI(i, x, y) { 1774 const bboxs = this.#bboxs[i]; 1775 bboxs.x += x; 1776 bboxs.y += y; 1777 bboxs.w = this.x + bboxs.x + this.geometry.width / 2; 1778 bboxs.h = this.y + bboxs.y + this.geometry.height / 2; 1779 this.#matrices[i].translate(x, y); 1780 if(this.#needupdate[i] === false){ 1781 this.#needupdate[i] = true; 1782 this.#needupdateI.push(i); 1783 } 1784 return this; 1785 } 1786 1787 rotateI(i, x) { 1788 const bboxs = this.#bboxs[i]; 1789 this.#matrices[i].translate(-bboxs.w, -bboxs.h) 1790 .rotate(x).translate(bboxs.w, bboxs.h); 1791 if(this.#needupdate[i] === false){ 1792 this.#needupdate[i] = true; 1793 this.#needupdateI.push(i); 1794 } 1795 return this; 1796 } 1797 1798 scaleI(i, x, y) { 1799 const bboxs = this.#bboxs[i]; 1800 this.#matrices[i].translate(-bboxs.w, -bboxs.h) 1801 .scale(x, y)(bboxs.w, bboxs.h); 1802 if(this.#needupdate[i] === false){ 1803 this.#needupdate[i] = true; 1804 this.#needupdateI.push(i); 1805 } 1806 return this; 1807 } 1808 1809 containsPointI(x, y) { 1810 for(let i = this.#len; i <= 0; i++){ 1811 if(this.#bboxs[i].containsPoint(x, y) === true) return i; 1812 } 1813 return -1; 1814 } 1815 1816 } 1817 1818 1819 /** InstancedPoints 1820 demo: 1821 const points = new InstancedPoints(geos[1], mats[1], 50000, false, 10); 1822 for(let i = 0; i < points.len; i++){ //每一个实例设置一个随机位置 1823 points.translateI(i, UTILS.random(0, innerWidth - points.geometry.width), UTILS.random(0, innerHeight - points.geometry.height)); 1824 } 1825 1826 renderer.append(points).redraw(); 1827 */ 1828 class InstancedPoints extends Instanced { 1829 1830 /** 1831 * 几乎与 Instanced 一样, 就多了一个.pointSize 属性, 修改此属性实时生效! 1832 * @param {Geometry} geometry 1833 * @param {Material} material 1834 * @param {number} len 1835 * @param {boolean} frequentUpdate 1836 * @param {number} pointSize //每一个点的大小(可以是浮点数) 1837 */ 1838 constructor(geometry, material, len, frequentUpdate, pointSize) { 1839 super(geometry, material, len, frequentUpdate); 1840 this.pointSize = pointSize; 1841 } 1842 1843 } 1844 1845 1846 /** InstancedSprite 1847 demo: 1848 const geometry = new GeometryRect(renderer.domElement.width, renderer.domElement.height); 1849 const texture = new Texture(images[3], FormatRGB); 1850 const material = new Material(texture, false); 1851 const sprite = new InstancedSprite(geometry, material, 5, false, 8); 1852 for(let i = 0; i < sprite.len; i++){ //每一个实例设置一个随机位置 1853 sprite.translateI(i, UTILS.random(0, innerWidth - sprite.geometry.width), UTILS.random(0, innerHeight - sprite.geometry.height)); 1854 } 1855 renderer.append(sprite).redraw(); 1856 setInterval(() => { 1857 sprite.offset += 1; //sprite.offset += 0.1; 1858 renderer.redraw(); 1859 }, 600); 1860 */ 1861 class InstancedSprite extends Instanced { 1862 1863 #len1 = 1; 1864 get len1() {return this.#len1;} 1865 1866 #offset = 0; 1867 get offset() {return this.#offset;} 1868 set offset(v) {this.#offset = v % this.#len1;} 1869 1870 /** 1871 * Sprite 雪碧图的实例化版本, 设置它 .offset 实时生效! 1872 * @param {Geometry} geometry 1873 * @param {Material} material 1874 * @param {number} len 1875 * @param {boolean} frequentUpdate 1876 * @param {number} len1 //雪碧图x轴长度(图片的宽 / 每一格的宽) 1877 * @param {number} offset //雪碧图x轴位置, 浮点值, 0.0 至 len1 - 1 个为一个循环(offset % len1) 1878 */ 1879 constructor(geometry, material, len, frequentUpdate, len1, offset = 0.0) { 1880 super(geometry, material, len, frequentUpdate); 1881 this.#len1 = Math.floor(Math.max(this.#len1, len1)); 1882 this.offset = offset; 1883 } 1884 1885 } 1886 1887 1888 1889 //此类对外部是完全隐藏, 保密的, 只由渲染器直接调用; 1890 class Cache { 1891 1892 constructor(gl, proName, pro, obj2d, mode) { 1893 this.gl = gl; 1894 this.proName = proName; 1895 this.pro = pro; 1896 this.obj2d = obj2d; 1897 this.mode = mode; 1898 this.geo = null; //CacheGeometry 1899 this.mat = null; //CacheMaterial 1900 this.texLocs = []; 1901 this.uniforms = []; 1902 } 1903 1904 initUniforms(uniforms, matHad = false, texMap = new Map()) { 1905 const gl = this.gl; 1906 for(let n in uniforms){ 1907 const loc = gl.getUniformLocation(this.pro.program, n); 1908 if(loc === null) continue; 1909 1910 if(Texture.prototype.isPrototypeOf(uniforms[n]) === false){ 1911 this.uniforms.push(compileUniform(gl, loc, n, uniforms)); 1912 continue; 1913 } 1914 1915 if(matHad === false){ 1916 let tex = texMap.get(uniforms[n]); 1917 if(tex === undefined){ 1918 tex = new CacheTexture(gl, this.mat.textures.length, n, uniforms); 1919 gl.activeTexture(tex.index); 1920 gl.bindTexture(gl.TEXTURE_2D, tex._texture); 1921 if(tex.texture.needupdate !== undefined) updateTexture(gl, tex.texture); 1922 texMap.set(uniforms[n], tex); 1923 } 1924 tex.len++; 1925 this.mat.textures.push(tex); 1926 //this.uniforms.push(() => gl.uniform1i(loc, i)); 1927 } 1928 } 1929 1930 if(matHad === false) this.mat.lenT = this.mat.textures.length; 1931 for(let i = 0; i < this.mat.lenT; i++){ 1932 this.texLocs[i] = gl.getUniformLocation(this.pro.program, this.mat.textures[i].name); 1933 } 1934 } 1935 1936 dispose() { 1937 this.gl.deleteShader(this.pro.vertexShader); 1938 this.gl.deleteShader(this.pro.fragmentShader); 1939 this.gl.deleteProgram(this.pro.program); 1940 } 1941 1942 draw() { 1943 if(this.geo.lenI === 0){ 1944 this.gl.drawArrays(this.mode, 0, this.geo.lenV); 1945 } else { 1946 this.gl.drawElements(this.mode, this.geo.lenI, this.gl[this.geo.value.type], 0); 1947 } 1948 } 1949 1950 } 1951 1952 1953 class CacheInstanced extends Cache { 1954 1955 constructor(gl, proName, pro, instanced, mode) { 1956 super(gl, proName, pro, instanced, mode); 1957 1958 this.matrixLoc = gl.getAttribLocation(pro.program, "uIMat"); 1959 this.matrixBuffer = gl.createBuffer(); 1960 gl.bindBuffer(gl.ARRAY_BUFFER, this.matrixBuffer); 1961 gl.bufferData(gl.ARRAY_BUFFER, instanced.matrixData, gl[instanced.frequentUpdate === false ? "STATIC_DRAW" : "DYNAMIC_DRAW"]); 1962 1963 instanced.needupdate.fill(false); 1964 instanced.needupdateI.length = 0; 1965 1966 this.sizeByte = 3 * 3 * 4; 1967 this.instanced = instanced; 1968 } 1969 1970 dispose() { 1971 this.gl.deleteBuffer(this.matrixBuffer); 1972 return super.dispose(); 1973 } 1974 1975 draw() { 1976 this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.matrixBuffer); 1977 1978 const instanced = this.instanced; 1979 var n, v = instanced.needupdateI.length; 1980 1981 if(v !== 0){ //需要上传矩阵 1982 if(v !== instanced.len){ //个别矩阵更新了 1983 let i = 0; 1984 for(n = 0; n < v; n++){ 1985 i = instanced.needupdateI[n]; 1986 instanced.needupdate[i] = false; 1987 this.gl.bufferSubData(this.gl.ARRAY_BUFFER, i * this.sizeByte, instanced.matricesA[i], 0, 9); //9 = 3 * 3 = instanced.matricesA[i].length; 1988 } 1989 } else { //所有矩阵都更新了 1990 instanced.needupdate.fill(false); 1991 this.gl.bufferSubData(this.gl.ARRAY_BUFFER, 0, instanced.matrixData); 1992 } 1993 instanced.needupdateI.length = 0; 1994 } 1995 1996 for(n = 0; n < 3; n++){ 1997 v = this.matrixLoc + n; 1998 this.gl.enableVertexAttribArray(v); 1999 this.gl.vertexAttribPointer(v, 3, this.gl.FLOAT, false, this.sizeByte, n * 12); //12 = 3 mat3 * 4 byte 2000 this.gl.vertexAttribDivisor(v, 1); 2001 } 2002 2003 if(this.geo.lenI === 0){ 2004 this.gl.drawArraysInstanced(this.mode, 0, this.geo.lenV, instanced.len); 2005 } else { 2006 this.gl.drawElementsInstanced(this.mode, this.geo.lenI, this.gl[this.geo.value.type], 0, instanced.len); 2007 } 2008 } 2009 2010 } 2011 2012 2013 class CacheGeometry { 2014 2015 constructor(gl, pro, geo) { 2016 this.lenV = 0; 2017 this.attributes = {}; 2018 for(let n in geo.attributes){ 2019 const loc = gl.getAttribLocation(pro.program, n); 2020 if(loc === -1) continue; 2021 const obj = compileBuffer(gl, loc, geo.attributes[n]); 2022 this.attributes[n] = obj; 2023 if(this.lenV === 0) this.lenV = obj.value.length / obj.size; 2024 } 2025 2026 this.lenI = 0; 2027 this.indexBuffer = null; 2028 if(geo.indices !== null) { 2029 this.indexBuffer = gl.createBuffer(); 2030 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); 2031 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, geo.indices, gl.STATIC_DRAW); 2032 this.lenI = geo.indices.length; 2033 } 2034 2035 this.len = 0; 2036 this.value = geo; 2037 } 2038 2039 dispose(gl) { 2040 if(this.indexBuffer !== null){ 2041 gl.deleteBuffer(this.indexBuffer); 2042 } 2043 for(let n in this.attributes){ 2044 gl.deleteVertexArray(this.attributes[n].vao); 2045 gl.deleteBuffer(this.attributes[n].buffer); 2046 } 2047 } 2048 2049 } 2050 2051 2052 class CacheMaterial { 2053 2054 constructor(mat, texs = []) { 2055 this.textures = texs; 2056 this.lenT = texs.length; 2057 this.len = 0; 2058 this.value = mat; 2059 } 2060 2061 dispose(gl) { 2062 2063 } 2064 2065 } 2066 2067 2068 class CacheTexture { 2069 2070 constructor(gl, i, n, v) { 2071 this._texture = gl.createTexture(); 2072 this.texture = v[n]; 2073 this.name = n; 2074 this.index = gl["TEXTURE"+i]; 2075 this.len = 0; 2076 } 2077 2078 dispose(gl) { 2079 gl.deleteTexture(this._texture); 2080 } 2081 2082 } 2083 2084 2085 /* Renderer WebGL2 2D渲染器 2086 未完的功能: 2087 1 后期处理 2088 2 阴影 2089 3 渐变 2090 2091 constructor: 2092 空; 初始化选项都在 Renderer.contextOption .glOption 中自行修改 2093 2094 attribute: 2095 domElement: HTMLCanvasElement; //只读 2096 projectionMatrix: Array; //只读, 返回默认的3x3投影矩阵 2097 2098 method: 2099 append(object2d: Structure|InstancedPoints|Object2D...): this; //添加到渲染队列并创建缓存 2100 delete(object2d: Structure|InstancedPoints|Object2D...): this; //从渲染队列删除并释放缓存 2101 dispose(): undefined; //销毁 WebGL2RenderingContext, 销毁后此类无法在继续使用 2102 setSize(width, height): undefined; //设置了: 画布宽高, gl的视口, 投影矩阵; 2103 select(x, y: number): Object2D|null; //根据一个点来获取 Object2D 2104 redraw(): undefined; //重绘画布 2105 readPixels(box: Box, result: ImageSource): ImageSource; //截取像素; box.x,box.y: 距画布左上角的偏移量; result: 如果未定义则会创建一个新的 ImageSource; 2106 2107 demo: 2108 const renderer = new Renderer(); 2109 renderer.setSize(innerWidth, innerHeight); 2110 document.body.appendChild(renderer.domElement); 2111 2112 const geos = [ 2113 new GeometryRect(256, 256), 2114 new GeometryCircle(125), 2115 new GeometryRectWavy(256, 256), 2116 ]; 2117 2118 const mats = [ 2119 new Material(new Texture(images[0], FormatRGB), false), 2120 new Material(new Texture(images[1], FormatRGBA), true), 2121 new Material(new Texture(images[2], FormatRGB), false), 2122 ]; 2123 2124 renderer.domElement.addEventListener("click", e => { 2125 const geo = geos[Math.floor(UTILS.random(0, geos.length))]; //随机复用几何体 2126 const mat = mats[Math.floor(UTILS.random(0, mats.length))]; //随机复用材质 2127 const obj2d = new Object2D(geo, mat).translate(e.offsetX, e.offsetY); 2128 2129 renderer.append(obj2d).redraw(); 2130 setTimeout(() => renderer.delete(obj2d).redraw(), UTILS.random(5000, 15000)); 2131 }); 2132 2133 2134 //截取像素示例.readPixels(): 2135 //Renderer.contextOption.preserveDrawingBuffer 必须为 true, 默认为false(开启可能会影响绘制性能), 否则结果会使一个黑图 2136 renderer.domElement.addEventListener("click", e => { 2137 const geo = new GeometryRect(256, 256); 2138 geo.translate(e.offsetX, e.offsetY); 2139 2140 const source = renderer.readPixels(new Box(e.offsetX, e.offsetY, 256, 256)); 2141 const mat = new Material(source); 2142 mat.setPixelStorei(PixelStoreiFlipY, true); //设置纹理预处理: 翻转像素y; 2143 2144 renderer.append(new Object2D(geo, mat)).redraw(); 2145 }); 2146 2147 2148 //画布截屏 2149 //renderer.domElement.toBlob(ElementUtils.downloadFile, "image/png"); 2150 2151 2152 //添加后期处理(会直接影响渲染性能) 2153 const geo = new GeometryRect(innerWidth, innerHeight); 2154 const materialShader = new MaterialShader({ 2155 blending: BlendDefault, 2156 vertexCode: defaultShaderCode.texture1.vertex, 2157 fragmentCode: `#version 300 es 2158 precision mediump float; //highp, mediump, lowp 2159 uniform sampler2D uImage; 2160 uniform vec2 uSize; 2161 in vec2 vPos; 2162 out vec4 outColor; 2163 void main() { 2164 vec2 uv = vPos / uSize; 2165 uv.y = 1.0 - uv.y; //翻转y 2166 outColor = texture(uImage, uv); 2167 } 2168 `, 2169 uniforms: { 2170 //必须是 ImageSource, 并且第三个参数必须是null, 否则会创建失败 2171 uImage: new Texture(new ImageSource(geo.width, geo.height, null)), 2172 }, 2173 }); 2174 renderer.createRenderTarget(new Object2D(geo, materialShader)); 2175 renderer.redrawRenderTarget(); 2176 */ 2177 class Renderer { 2178 2179 static contextOption = { 2180 alpha: false, //画布css的背景启用阿尔法 默认 true 2181 antialias: true, //抗锯齿 默认 true 2182 depth: false, //深度缓冲 默认 true 2183 desynchronized: true, //从事件循环中取消画布绘制周期的同步来减少延迟 2184 stencil: false, //模板缓冲 默认 false 2185 premultipliedAlpha: true, //预乘阿尔法通道 默认 true 2186 preserveDrawingBuffer: false, //true: 保留绘图缓冲区 默认 false 2187 failIfMajorPerformanceCaveat: true, //指示在系统性能较低时是否创建上下文 2188 2189 powerPreference: "default", //指示哪种GPU配置适合于WebGL上下文。 2190 //可能的值是: 2191 //"default" 让用户代理决定哪个GPU配置最适合。这是默认值。 2192 //"high-performance" 将渲染性能优先于功耗。 2193 //"low-power" 将节能优先于渲染性能。 2194 2195 xrCompatible: false, 2196 } 2197 2198 static glOption = { 2199 clearColor: {r: 0.45, g: 0.45, b: 0.45, a: 1}, //gl的背景颜色(在画布css颜色之上) 2200 } 2201 2202 #contextAttributes = {}; 2203 #gl = createWebGL2(); 2204 #pro = null; 2205 2206 #states = { 2207 pro: null, 2208 blendE: false, 2209 blendC: {r: -1, g: 0, b: 0, a: 0}, 2210 blendES: [-1, 0], 2211 blendFS: [-1, 0, 0, 0], 2212 } 2213 2214 #geometries = new Map(); 2215 #materials = new Map(); 2216 #textures = new Map(); 2217 #objects = []; 2218 #caches = []; 2219 2220 #frameBuffer = null; 2221 #renderBuffer = null; 2222 #objectsRT = []; 2223 #cachesRT = []; 2224 2225 #projectionMatrix = new Matrix3(); 2226 #projectionMatrixA = []; 2227 get projectionMatrix() { 2228 return this.#projectionMatrixA; //#projectionMatrix.toArray(); 2229 } 2230 2231 get lengthObject() {return this.#objects.length;} 2232 get lengthGeometry() {return this.#geometries.size;} 2233 get lengthMaterial() {return this.#materials.size;} 2234 get lengthTexture() {return this.#textures.size;} 2235 2236 get domElement() {return this.#gl.canvas;} 2237 2238 constructor() { 2239 Object.assign(this.#contextAttributes, this.#gl.getContextAttributes()); 2240 this.#pro = { 2241 texture1: createProgram(this.#gl, defaultShaderCode.texture1.vertex, defaultShaderCode.texture1.fragment), 2242 texture1_sprite: createProgram(this.#gl, defaultShaderCode.texture1_sprite.vertex, defaultShaderCode.texture1_sprite.fragment), 2243 texture1_Instanced: createProgram(this.#gl, defaultShaderCode.texture1_Instanced.vertex, defaultShaderCode.texture1_Instanced.fragment), 2244 texture1_Instanced_points: createProgram(this.#gl, defaultShaderCode.texture1_Instanced_points.vertex, defaultShaderCode.texture1_Instanced_points.fragment), 2245 texture1_Instanced_sprite: createProgram(this.#gl, defaultShaderCode.texture1_Instanced_sprite.vertex, defaultShaderCode.texture1_Instanced_sprite.fragment), 2246 } 2247 initExtensions(this.#gl); 2248 2249 } 2250 2251 /** 2252 * @param {Object2D|Sprite|Instanced|InstancedPoints|InstancedSprite} object2d 2253 * @returns {this} 2254 */ 2255 append(object2d) { 2256 if(arguments.length === 1){ 2257 if(this.#objects.includes(object2d) === true) return this; 2258 2259 const obj = proHandler(this.#gl, this.#pro, this, object2d), 2260 cache = obj.cache; 2261 if(obj === null) return this; 2262 2263 // 2264 cache.geo = this.#geometries.get(object2d.geometry); 2265 if(cache.geo === undefined){ 2266 cache.geo = new CacheGeometry(this.#gl, cache.pro, object2d.geometry); 2267 this.#geometries.set(object2d.geometry, cache.geo); 2268 } 2269 cache.geo.len++; 2270 2271 // 2272 cache.mat = this.#materials.get(object2d.material); 2273 const matHad = cache.mat !== undefined; 2274 if(matHad === false){ 2275 cache.mat = new CacheMaterial(object2d.material); 2276 if(object2d.material.needupdate !== undefined) this.#materials.set(object2d.material, cache.mat); 2277 } else { 2278 for(let i = 0; i < cache.mat.textures.length; i++) cache.mat.textures[i].len++; 2279 } 2280 cache.mat.len++; 2281 2282 // 2283 cache.initUniforms(obj.uniforms, matHad, this.#textures); 2284 this.#caches.push(cache); 2285 this.#objects.push(object2d); 2286 return this; 2287 } 2288 2289 for(let i = 0, arg = arguments; i < arg.length; i++) this.append(arg[i]); 2290 2291 return this; 2292 } 2293 2294 /** 2295 * @param {Object2D|Sprite|Instanced|InstancedPoints|InstancedSprite} object2d 2296 * @returns {this} 2297 */ 2298 delete(object2d) { 2299 if(arguments.length === 1){ 2300 const i = this.#objects.indexOf(object2d); 2301 if(i === -1) return this; 2302 2303 const gl = this.#gl, cache = this.#caches[i]; 2304 2305 this.#objects.splice(i, 1); 2306 this.#caches.splice(i, 1); 2307 2308 if(!cache.proName || this.#pro[cache.proName] !== cache.pro){ 2309 cache.dispose(); //是自定义的着色器 2310 } 2311 2312 cache.geo.len--; 2313 if(cache.geo.len === 0){ 2314 cache.geo.dispose(gl); 2315 this.#geometries.delete(object2d.geometry); 2316 } 2317 2318 cache.mat.len--; 2319 if(cache.mat.len === 0){ 2320 cache.mat.dispose(gl); 2321 this.#materials.delete(object2d.material); 2322 } 2323 2324 for(let i = 0, tex; i < cache.mat.textures.length; i++){ 2325 tex = cache.mat.textures[i]; 2326 tex.len--; 2327 if(tex.len === 0){ 2328 tex.dispose(gl); 2329 this.#textures.delete(tex.texture); 2330 } 2331 } 2332 2333 return this; 2334 } 2335 2336 for(let i = 0, arg = arguments; i < arg.length; i++) this.delete(arg[i]); 2337 2338 return this; 2339 } 2340 2341 redraw() { 2342 const len = this.#caches.length; 2343 if(len === 0) return; 2344 2345 const gl = this.#gl, states = this.#states; 2346 //gl.clear(gl.COLOR_BUFFER_BIT); 2347 2348 for(let i = 0, v, n, t, g, m; i < len; i++){ 2349 v = this.#caches[i]; 2350 if(v.obj2d.visible !== true) continue; 2351 2352 if(states.pro !== v.pro){ 2353 states.pro = v.pro; 2354 gl.useProgram(states.pro.program); 2355 } 2356 2357 if(g !== v.geo){ 2358 g = v.geo; 2359 for(n in g.attributes) gl.bindVertexArray(g.attributes[n].vao); 2360 if(g.lenI !== 0) gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, g.indexBuffer); 2361 } 2362 2363 if(m !== v.mat || m.value.needupdate === true){ 2364 m = v.mat; 2365 2366 if(states.blendE !== m.value.blendEnable){ 2367 states.blendE = m.value.blendEnable; 2368 gl[states.blendE === true ? "enable" : "disable"](gl.BLEND); 2369 } 2370 2371 if(states.blendE === true){ 2372 if(states.blendC.r !== m.value.blendC.r || 2373 states.blendC.g !== m.value.blendC.g || 2374 states.blendC.b !== m.value.blendC.b || 2375 states.blendC.a !== m.value.blendC.a){ 2376 Object.assign(states.blendC, m.value.blendC); 2377 gl.blendColor(states.blendC.r, states.blendC.g, states.blendC.b, states.blendC.a); 2378 } 2379 2380 if(states.blendES[0] !== m.value.blendES[0] || 2381 states.blendES[1] !== m.value.blendES[1]){ 2382 Object.assign(states.blendES, m.value.blendES); 2383 if(states.blendES[0] !== -1){ 2384 if(states.blendES[1] === -1){ 2385 gl.blendEquation(gl[MUS.blendESs[states.blendES[0]]]); 2386 } else { 2387 gl.blendEquationSeparate(gl[MUS.blendESs[states.blendES[0]]], gl[MUS.blendESs[states.blendES[1]]]); 2388 } 2389 } 2390 } 2391 2392 if(states.blendFS[0] !== m.value.blendFS[0] || 2393 states.blendFS[1] !== m.value.blendFS[1] || 2394 states.blendFS[2] !== m.value.blendFS[2] || 2395 states.blendFS[3] !== m.value.blendFS[3]){ 2396 Object.assign(states.blendFS, m.value.blendFS); 2397 if(states.blendFS[0] !== -1){ 2398 if(states.blendFS[2] === -1){ 2399 gl.blendFunc(gl[MUS.blendFSs[states.blendFS[0]]], gl[MUS.blendFSs[states.blendFS[1]]]); 2400 } else { 2401 gl.blendFuncSeparate(gl[MUS.blendFSs[states.blendFS[0]]], gl[MUS.blendFSs[states.blendFS[1]]], gl[MUS.blendFSs[states.blendFS[2]]], gl[MUS.blendFSs[states.blendFS[3]]]); 2402 } 2403 } 2404 } 2405 } 2406 2407 for(n = 0; n < m.lenT; n++){ 2408 t = m.textures[n]; 2409 gl.bindTexture(gl.TEXTURE_2D, t._texture); 2410 gl.activeTexture(t.index); 2411 if(t.texture.needupdate === true) updateTexture(gl, t.texture); 2412 gl.uniform1i(v.texLocs[n], n); 2413 } 2414 } //else { 2415 2416 //for(n = 0; n < m.lenT; n++){ 2417 //gl.uniform1i(v.texLocs[n], n); //这玩意每个对象都会创建一个新的(即使材质或纹理都一样,因为它指向的是自己所用的 program) 2418 //} 2419 2420 //} 2421 2422 t = v.uniforms.length; 2423 for(n = 0; n < t; n++) v.uniforms[n](); 2424 2425 v.draw(); 2426 //resetBuffers(gl); 2427 } 2428 } 2429 2430 dispose() { 2431 this.#caches.length = 0; 2432 this.#geometries.clear(); 2433 this.#materials.clear(); 2434 this.#textures.clear(); 2435 if(this.#gl.isContextLost() === false){ 2436 this.#gl.loseContext(); 2437 } 2438 this.#gl = null; 2439 } 2440 2441 setSize(width = innerWidth, height = innerHeight) { 2442 width *= window.devicePixelRatio; 2443 height *= window.devicePixelRatio; 2444 this.domElement.width = width; 2445 this.domElement.height = height; 2446 this.#gl.viewport(0, 0, width, height); 2447 this.#projectionMatrix.projection(width, height); 2448 this.#projectionMatrix.toArray(this.#projectionMatrixA); 2449 } 2450 2451 select(x = 0, y = 0, targets = this.#objects) { 2452 for(let i = targets.length - 1, obj2d; i >= 0; i--){ 2453 obj2d = targets[i]; 2454 if(obj2d.visible === true && obj2d.containsPoint(x, y) === true) return obj2d; 2455 } 2456 return null; 2457 } 2458 2459 readPixels(box = new Box(0, 0, 100, 100), result = new ImageSource(box.w, box.h)) { 2460 const y = (1 - box.y / this.domElement.height) * this.domElement.height - box.h; 2461 this.#gl.readPixels(box.x, y, box.w, box.h, this.#gl.RGBA, this.#gl.UNSIGNED_BYTE, result.data); 2462 return result; 2463 } 2464 2465 /** 2466 * @param {Object2D|Sprite|Instanced|InstancedPoints|InstancedSprite} object2d 2467 */ 2468 createRenderTarget(object2d) { 2469 if(this.#cachesRT.length > 0) return console.warn("Renderer.createRenderTarget(): 创建失败! 已存在"); 2470 2471 const objects = this.#objects, caches = this.#caches; 2472 this.#objects = this.#objectsRT; 2473 this.#caches = this.#cachesRT; 2474 2475 this.append(object2d); 2476 const cache = this.#caches[0]; 2477 2478 if(cache === undefined || 2479 cache.mat.textures.length === 0 || 2480 ImageSource.prototype.isPrototypeOf(cache.mat.textures[0].texture.source) === false || 2481 cache.mat.textures[0].texture.source.data !== null){ 2482 this.delete(object2d); 2483 console.warn("Renderer.createRenderTarget(): 创建失败! 参数错误"); 2484 } else { 2485 const gl = this.#gl; 2486 const frameBuffer = gl.createFramebuffer(); 2487 gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer); 2488 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, cache.mat.textures[0]._texture, 0); 2489 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 2490 this.#frameBuffer = frameBuffer; 2491 } 2492 2493 this.#objects = objects; 2494 this.#caches = caches; 2495 } 2496 2497 redrawRenderTarget() { 2498 this.#gl.bindFramebuffer(this.#gl.FRAMEBUFFER, this.#frameBuffer); 2499 this.redraw(); 2500 this.#gl.bindFramebuffer(this.#gl.FRAMEBUFFER, null); 2501 2502 const objects = this.#objects, caches = this.#caches; 2503 this.#objects = this.#objectsRT; 2504 this.#caches = this.#cachesRT; 2505 this.redraw(); 2506 this.#objects = objects; 2507 this.#caches = caches; 2508 } 2509 2510 } 2511 2512 2513 export { 2514 defaultShaderCode, 2515 2516 BlendEquationAdd, 2517 2518 BlendDefault, 2519 BlendAdd, 2520 BlendSub, 2521 BlendMultiply, 2522 2523 FormatAlpha, 2524 FormatLuminance, 2525 FormatLuminanceAlpha, 2526 FormatRGB, 2527 FormatRGBA, 2528 2529 PixelStoreiFlipY, 2530 PixelStoreiPremultiplyAlpht, 2531 2532 Attribute, 2533 Geometry, 2534 GeometryRect, 2535 GeometryCircle, 2536 GeometryShape, 2537 GeometryRectWavy, 2538 2539 ImageSource, 2540 Texture, 2541 Material, 2542 MaterialShader, 2543 2544 Object2D, 2545 Sprite, 2546 Instanced, 2547 InstancedPoints, 2548 InstancedSprite, 2549 2550 Renderer, 2551 }