|
- 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.REPEAT); //REPEAT(重复), CLAMP_TO_EDGE(夹到边缘), MIRRORED_REPEAT(像镜子一样的重复?)
- 764 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
- 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: null,
- 785 },
- 786 }
- 787
- 788 let proName = "", pro = null;
- 789
- 790 switch(object2d.constructor.name){
- 791 case "Object2D":
- 792 proName = "texture1";
- 793
- 794 if(isMS === false){
- 795 pro = pros[proName];
- 796 } else {
- 797 pro = createProgram(gl, object2d.material.vertexCode, object2d.material.fragmentCode);
- 798 proName = "";
- 799 }
- 800
- 801 result.uniforms.uImage = object2d.material.texture;
- 802 result.uniforms.uSize = [object2d.geometry.width, object2d.geometry.height];
- 803 result.cache = new Cache(proName, pro, gl[ModeTriangles]);
- 804 break;
- 805
- 806 case "Sprite":
- 807 proName = "texture1_sprite";
- 808
- 809 if(isMS === false){
- 810 pro = pros[proName];
- 811 } else {
- 812 pro = createProgram(gl, object2d.material.vertexCode, object2d.material.fragmentCode);
- 813 proName = "";
- 814 }
- 815
- 816 result.uniforms.uImage = object2d.material.texture;
- 817 result.uniforms.uSize = [object2d.geometry.width, object2d.geometry.height];
- 818 result.uniforms.uLen = object2d.len;
- 819 Object.defineProperty(result.uniforms, "uOffset", {
- 820 enumerable: true, //编译时需要遍历 uniforms
- 821 get: () => {return object2d.offset;},
- 822 });
- 823 result.cache = new Cache(proName, pro, gl[ModeTriangles]);
- 824 break;
- 825
- 826 case "Instanced":
- 827 proName = "texture1_Instanced";
- 828
- 829 if(isMS === false){
- 830 pro = pros[proName];
- 831 } else {
- 832 pro = createProgram(gl, object2d.material.vertexCode, object2d.material.fragmentCode);
- 833 proName = "";
- 834 }
- 835
- 836 result.uniforms.uImage = object2d.material.texture;
- 837 result.uniforms.uSize = [object2d.geometry.width, object2d.geometry.height];
- 838 result.cache = new CacheInstanced(proName, pro, gl[ModeTriangles], gl, object2d);
- 839 break;
- 840
- 841 case "InstancedPoints":
- 842 proName = "texture1_Instanced_points";
- 843
- 844 if(isMS === false){
- 845 pro = pros[proName];
- 846 } else {
- 847 pro = createProgram(gl, object2d.material.vertexCode, object2d.material.fragmentCode);
- 848 proName = "";
- 849 }
- 850
- 851 result.uniforms.uImage = object2d.material.texture;
- 852 Object.defineProperty(result.uniforms, "uSize", {
- 853 enumerable: true, //编译时需要遍历 uniforms
- 854 get: () => {return object2d.pointSize;},
- 855 });
- 856 result.cache = new CacheInstanced(proName, pro, gl[ModePoints], gl, object2d);
- 857 break;
- 858
- 859 case "InstancedSprite":
- 860 proName = "texture1_Instanced_sprite";
- 861
- 862 if(isMS === false){
- 863 pro = pros[proName];
- 864 } else {
- 865 pro = createProgram(gl, object2d.material.vertexCode, object2d.material.fragmentCode);
- 866 proName = "";
- 867 }
- 868
- 869 result.uniforms.uImage = object2d.material.texture;
- 870 result.uniforms.uSize = [object2d.geometry.width, object2d.geometry.height];
- 871 result.uniforms.uLen = object2d.len1;
- 872 Object.defineProperty(result.uniforms, "uOffset", {
- 873 enumerable: true, //编译时需要遍历 uniforms
- 874 get: () => {return object2d.offset;},
- 875 });
- 876 result.cache = new CacheInstanced(proName, pro, gl[ModeTriangles], gl, object2d);
- 877 break;
- 878 }
- 879
- 880 if(isMS) Object.assign(result.uniforms, object2d.material.uniforms);
- 881
- 882 return result;
- 883 }
- 884
- 885
- 886 /* glsl 一些内置函数:
- 887 abs 返回一个数的绝对值。
- 888 acos 返回一个数的反余弦。
- 889 asin 返回一个数的反正弦。
- 890 atan 返回一个数的反正切。
- 891 atan2 返回从X轴到点(y,x)的角度(以弧度为单位)。
- 892 cos 返回一个数的余弦。
- 893 sin 返回一个数的正弦。
- 894 sqrt 返回一个数的平方根。
- 895 tan 返回一个数的正切。
- 896 round 将一个指定的数值表达式舍入到最近的整数并将其返回。
- 897 random 返回一个0和1之间的伪随机数。
- 898 parseFloat 返回从字符串转换而来的浮点数。
- 899 parseInt 返回从字符串转换而来的整数。
- 900 pow 返回一个指定幂次的底表达式的值。
- 901 step(float a, float x): a < x ? x : a;
- 902 clamp(float x, float min, float max): min > x ? min : min < x && max > x ? x : max; 返回三个值中的中间值
- 903 mix(vac4 color1, vec4 color2, float weight) 返回两种颜色的混合, color2 为 weight, color1 为 1 - weight
- 904 mod(float x, float y): x % y
- 905
- 906 exp 返回e的x次幂。
- 907 log 返回x的自然对数,
- 908 exp2 返回2的x次幂。
- 909 log2 返回x的2为底的对数,
- 910
- 911 inversesqrt 回1/xxx,
- 912 sign 返回数值的符号值。
- 913
- 914 texture2D(uSampler, gl_PointCoord.xy) gl_PointCoord 特殊变量能自动获取 points 的纹理坐标
- 915 */
- 916
- 917
- 918 class Attribute {
- 919
- 920 /**
- 921 * @param {number} size
- 922 * @param {Array|TypeBufferArray} value
- 923 */
- 924 constructor(size, value) {
- 925 this.size = size;
- 926 this.value = value;
- 927 }
- 928
- 929 }
- 930
- 931
- 932 /** Geometry
- 933 demo:
- 934 const width = 256, height = 256;
- 935
- 936 const geometry = new Geometry({
- 937 aPosition: new Attribute(2, new Float32Array([
- 938 width,0, 0,0, 0,height,
- 939 0,height, width,height, width,0,
- 940 ])),
- 941 }, width, height);
- 942
- 943
- 944 //顶点索引版本:
- 945 const geometry = new Geometry({
- 946 aPosition: new Attribute(2, new Float32Array([
- 947 0,0, width,0, width,height, 0,height,
- 948 ]))
- 949 }, width, height);
- 950
- 951 geometry.setIndex([1,0,3, 3,2,1]);
- 952 */
- 953 class Geometry {
- 954
- 955 #type = "UNSIGNED_SHORT"; //索引面的类型(初始化时自动选择设置); 可能的值有: UNSIGNED_SHORT|UNSIGNED_INT
- 956 get type() {return this.#type;}
- 957
- 958 #offset = 0; //绘制几何体的偏移
- 959 get offset() {return this.#offset;}
- 960
- 961 #indices = null;
- 962 get indices() {return this.#indices;}
- 963
- 964 #w = 0;
- 965 #h = 0;
- 966 get width() {return this.#w;}
- 967 get height() {return this.#h;}
- 968
- 969 /**
- 970 * @param {{aPos: Attribute}} attributes 必须定义(面索用.setIndex()方法设置)
- 971 * @param {Box} bbox 可选(如果未定义则在构造器中自动计算一次)
- 972 */
- 973 constructor(attributes, w = 0, h = 0) {
- 974 this.attributes = attributes;
- 975 this.#w = w;
- 976 this.#h = h;
- 977 }
- 978
- 979 /**
- 980 * 根据 this.attributes[attributeName] 的顶点设置边界大小
- 981 * @param {string} attributeName
- 982 */
- 983 computeSize(attributeName) {
- 984 const att = this.attributes[attributeName];
- 985 if(Attribute.prototype.isPrototypeOf(att) === false) return;
- 986 const obj = computeBBox(att.value, att.size);
- 987 if(obj.x !== 0 || obj.y !== 0){
- 988 translateVertices(att.value, att.size, -obj.x, -obj.y);
- 989 this.#w = Math.abs(obj.x1 - obj.x);
- 990 this.#h = Math.abs(obj.y1 - obj.y);
- 991 } else {
- 992 this.#w = obj.x1;
- 993 this.#h = obj.y1;
- 994 }
- 995 }
- 996
- 997 /**
- 998 * 设置顶点索引
- 999 * @param {[]|Uint16Array|Uint32Array} indices
- 1000 * @param {undefined|boolean} isu32 //如果 indices 已是类型数组可以忽略此参数
- 1001 * @returns
- 1002 */
- 1003 setIndex(indices, isu32) {
- 1004 if(this.#indices !== null) return console.warn("不支持更改索引面");
- 1005
- 1006 switch(indices.constructor.name){
- 1007 case "Array":
- 1008 break;
- 1009
- 1010 case "Uint32Array":
- 1011 this.#type = "UNSIGNED_INT";
- 1012 this.#indices = indices;
- 1013 return;
- 1014
- 1015 default:
- 1016 case "Uint16Array":
- 1017 this.#type = "UNSIGNED_SHORT";
- 1018 this.#indices = indices;
- 1019 return;
- 1020 }
- 1021
- 1022 if(typeof isu32 !== "boolean"){
- 1023 isu32 = false;
- 1024 for(let i = 0; i < indices.length; i++){
- 1025 if(indices[i] < 65535) continue;
- 1026 isu32 = true;
- 1027 break;
- 1028 }
- 1029 }
- 1030
- 1031 if(isu32 === false) {
- 1032 this.#type = "UNSIGNED_SHORT";
- 1033 this.#indices = new Uint16Array(indices);
- 1034 } else {
- 1035 this.#type = "UNSIGNED_INT";
- 1036 this.#indices = new Uint32Array(indices);
- 1037 }
- 1038 }
- 1039
- 1040 }
- 1041
- 1042
- 1043 //矩形
- 1044 class GeometryRect extends Geometry {
- 1045
- 1046 constructor(width, height) {
- 1047 super({aPos: new Attribute(2, new Float32Array([0,0, width,0, width,height, 0,height]))}, width, height);
- 1048 this.setIndex([1, 0, 3, 3, 2, 1], false);
- 1049 }
- 1050
- 1051 }
- 1052
- 1053
- 1054 //圆形
- 1055 class GeometryCircle extends Geometry {
- 1056
- 1057 constructor(radius = 1, segments = 32, thetaStart = 0, thetaLength = Math.PI * 2) {
- 1058 segments = Math.max(3, segments);
- 1059
- 1060 let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
- 1061
- 1062 const vertices = [0, 0];
- 1063 for ( let s = 0, i = 3, segment; s <= segments; s ++, i += 3 ) {
- 1064 segment = thetaStart + s / segments * thetaLength;
- 1065 const x = radius * Math.cos( segment ),
- 1066 y = radius * Math.sin( segment );
- 1067 vertices.push(x, y);
- 1068 minX = Math.min(x, minX);
- 1069 minY = Math.min(y, minY);
- 1070 maxX = Math.max(x, maxX);
- 1071 maxY = Math.max(y, maxY);
- 1072 }
- 1073
- 1074 const indices = [];
- 1075 for ( let i = 1; i <= segments; i ++ ) {
- 1076 indices.push( i, i + 1, 0 );
- 1077 }
- 1078
- 1079 if(minX !== 0 || minY !== 0){
- 1080 translateVertices(vertices, 2, -minX, -minY);
- 1081 super({aPos: new Attribute(2, new Float32Array(vertices))}, Math.abs(maxX - minX), Math.abs(maxY - minY));
- 1082 } else {
- 1083 super({aPos: new Attribute(2, new Float32Array(vertices))}, maxX, maxY);
- 1084 }
- 1085
- 1086 this.setIndex(indices);
- 1087 }
- 1088
- 1089 }
- 1090
- 1091
- 1092 //形状
- 1093 class GeometryShape extends Geometry {
- 1094
- 1095 constructor(points, segments = 1) {
- 1096 let isu32 = false, minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
- 1097
- 1098 points = new Shape(points).extractPoints(segments).shape;
- 1099 if(ShapeUtils.isClockWise(points) === false) points = points.reverse();
- 1100
- 1101 //
- 1102 const indices = [], vertices = [],
- 1103 faces = ShapeUtils.triangulateShape(points, []);
- 1104 for(let i = 0, p, l = points.length; i < l; i ++){
- 1105 p = points[i];
- 1106 vertices.push(p.x, p.y);
- 1107 minX = Math.min(p.x, minX);
- 1108 minY = Math.min(p.y, minY);
- 1109 maxX = Math.max(p.x, maxX);
- 1110 maxY = Math.max(p.y, maxY);
- 1111 }
- 1112
- 1113 for(let i = 0, face, l = faces.length; i < l; i++){
- 1114 face = faces[i];
- 1115 indices.push(face[0], face[1], face[2]);
- 1116 if(isu32 === false && (face[0] >= 65535 || face[1] >= 65535 || face[2] >= 65535)) isu32 = true;
- 1117 }
- 1118
- 1119 //
- 1120
- 1121 if(minX !== 0 || minY !== 0){
- 1122 translateVertices(vertices, 2, -minX, -minY);
- 1123 super({aPos: new Attribute(2, new Float32Array(vertices))}, Math.abs(maxX - minX), Math.abs(maxY - minY));
- 1124 } else {
- 1125 super({aPos: new Attribute(2, new Float32Array(vertices))}, maxX, maxY);
- 1126 }
- 1127
- 1128 this.setIndex(indices, isu32);
- 1129 }
- 1130
- 1131 }
- 1132
- 1133
- 1134 //波浪矩形
- 1135 class GeometryRectWavy extends GeometryShape {
- 1136
- 1137 constructor(width, height, distance, divisions = 12) {
- 1138 const halfW = width / 2, halfH = height / 2;
- 1139 distance = distance === undefined ? Math.min(halfW, halfH) * 0.2 : Math.min(distance, Math.min(halfW, halfH) * 0.5);
- 1140 const points = [
- 1141 //右上
- 1142 new Vector2(halfW + distance, 0),
- 1143 new Vector2(width, 0),
- 1144 new Vector2(width, halfH - distance),
- 1145
- 1146 //右下
- 1147 new Vector2(width, halfH + distance),
- 1148 new Vector2(width, height),
- 1149 new Vector2(halfW + distance, height),
- 1150
- 1151 //左下
- 1152 new Vector2(halfW - distance, height),
- 1153 new Vector2(0, height),
- 1154 new Vector2(0, halfH + distance),
- 1155
- 1156 //左上
- 1157 new Vector2(0, halfH - distance),
- 1158 new Vector2(0, 0),
- 1159 new Vector2(halfW - distance, 0),
- 1160 ];
- 1161
- 1162 const points1 = [], curve = new SplineCurve();
- 1163 for(let i = 0; i < points.length; i += 3) {
- 1164 curve.points = [points[i], points[i+1], points[i+2]];
- 1165 const points2 = curve.getPoints(divisions);
- 1166 for(let i = 0; i < points2.length; i++){
- 1167 points1.push(points2[i]);
- 1168 }
- 1169 }
- 1170
- 1171 super(points1, 1);
- 1172 }
- 1173
- 1174 }
- 1175
- 1176
- 1177 class ImageSource {
- 1178
- 1179 /**
- 1180 * ImageData 的构造器不是很友好, 这是它的替代品
- 1181 * @param {number} w
- 1182 * @param {number} h
- 1183 * @param {Uint8Array} d //步长为4的数组, 分别是: r, g, b, a
- 1184 */
- 1185 constructor(w, h, d = new Uint8Array(w * h * 4)) {
- 1186 this.width = w;
- 1187 this.height = h;
- 1188 this.data = d;
- 1189 }
- 1190
- 1191 }
- 1192
- 1193
- 1194 class Texture {
- 1195
- 1196 static pixelStoreis = [
- 1197 "PACK_ALIGNMENT", //将像素数据打包到内存中
- 1198 "UNPACK_ALIGNMENT", //从内存中解压缩像素数据
- 1199 "UNPACK_FLIP_Y_WEBGL", //翻转纹理的y轴
- 1200 "UNPACK_PREMULTIPLY_ALPHA_WEBGL", //预乘阿尔法通道(将alpha通道与其他颜色通道相乘)
- 1201 "UNPACK_COLORSPACE_CONVERSION_WEBGL", //默认颜色空间转换或不进行颜色空间转换
- 1202 ];
- 1203
- 1204 static formats = [
- 1205 "ALPHA", "UNSIGNED_BYTE", //14: 1,1; //阿尔法
- 1206 "LUMINANCE", "UNSIGNED_BYTE", //12: 1,1; //不透明灰度图
- 1207 "LUMINANCE_ALPHA", "UNSIGNED_BYTE", //10: 2,2; //透明灰度图
- 1208 "RGB", "UNSIGNED_SHORT_5_6_5", //8: 3,2
- 1209 "RGBA", "UNSIGNED_SHORT_5_5_5_1", //6: 4,2
- 1210 "RGBA", "UNSIGNED_SHORT_4_4_4_4", //4: 4,3
- 1211 "RGB", "UNSIGNED_BYTE", //2: 3,3 //不透明
- 1212 "RGBA", "UNSIGNED_BYTE", //0: 4,4 //透明
- 1213 ];
- 1214
- 1215 #f_t = 0;
- 1216 get format() {return Texture.formats[this.#f_t];}
- 1217 get type() {return Texture.formats[this.#f_t + 1];}
- 1218
- 1219 #needupdate = false; //如果材质属性发生改变将此值设为true,渲染器会重绘材质的纹理(纹理不适合频繁的修改, 用着色器实现动态纹理)
- 1220 get needupdate() {
- 1221 if(this.#needupdate === false) return false;
- 1222 this.#needupdate = false;
- 1223 return true;
- 1224 }
- 1225
- 1226 #source = null;
- 1227 get source() {return this.#source;}
- 1228 set source(v) {
- 1229 this.#source = v;
- 1230 this.#needupdate = true;
- 1231 }
- 1232
- 1233 #pixelStorei = null;
- 1234 get pixelStorei() {return this.#pixelStorei;}
- 1235 get isPremultiplyAlpht() {
- 1236 return this.#pixelStorei === null ? false : this.#pixelStorei.includes(PixelStoreiPremultiplyAlpht);
- 1237 }
- 1238
- 1239 #mipmap = false;
- 1240 get mipmap() {return this.#mipmap;}
- 1241 set mipmap(v) {
- 1242 if(typeof v !== "boolean" || v === this.#mipmap) return;
- 1243 this.#mipmap = v;
- 1244 this.#needupdate = true;
- 1245 }
- 1246
- 1247 constructor(source, format = FormatRGBA, pixelStorei = [PixelStoreiPremultiplyAlpht], mipmap = false) {
- 1248 this.#source = source;
- 1249 this.#f_t = format;
- 1250 this.#pixelStorei = pixelStorei;
- 1251 this.#mipmap = mipmap;
- 1252 }
- 1253
- 1254 setFormatAndType(v = FormatRGBA) {
- 1255 this.#f_t = v;
- 1256 this.#needupdate = true;
- 1257 }
- 1258
- 1259 setPixelStorei(key = PixelStoreiPremultiplyAlpht, enable = false) {
- 1260 if(key >= Texture.pixelStoreis.length || key < 0) return;
- 1261 if(enable === true){
- 1262 if(this.#pixelStorei === null) this.#pixelStorei = [];
- 1263 this.#pixelStorei.push(key);
- 1264 this.#needupdate = true;
- 1265 } else if(this.#pixelStorei !== null){
- 1266 const i = this.#pixelStorei.indexOf(key);
- 1267 if(i === -1) return;
- 1268 this.#pixelStorei.splice(i, 1);
- 1269 this.#needupdate = true;
- 1270 }
- 1271 }
- 1272
- 1273 }
- 1274
- 1275
- 1276 class MUS {
- 1277
- 1278 static blendESs = [
- 1279 "FUNC_ADD", //source + destination (default value)
- 1280 "FUNC_SUBTRACT", //source - destination
- 1281 "FUNC_REVERSE_SUBTRACT", //destination - source
- 1282 "MIN", //Minimum of source and destination
- 1283 "MAX", //Maximum of source and destination
- 1284 ];
- 1285
- 1286 static blendFSs = [
- 1287 "ZERO", //所有颜色乘 0
- 1288 "ONE", //所有颜色乘 1
- 1289 "SRC_COLOR", //将所有颜色乘上源颜色
- 1290 "ONE_MINUS_SRC_COLOR", //每个源颜色所有颜色乘 1
- 1291 "DST_COLOR", //将所有颜色与目标颜色相乘
- 1292 "ONE_MINUS_DST_COLOR", //将所有颜色乘以 1 减去每个目标颜色,
- 1293 "SRC_ALPHA", //将所有颜色乘以源 alpha 值
- 1294 "ONE_MINUS_SRC_ALPHA", //将所有颜色乘以 1 减去源 alpha 值
- 1295 "DST_ALPHA", //将所有颜色与目标 alpha 值相乘
- 1296 "ONE_MINUS_DST_ALPHA", //将所有颜色乘以 1 减去目标 alpha 值
- 1297 "CONSTANT_COLOR", //将所有颜色乘以一个常数颜色
- 1298 "ONE_MINUS_CONSTANT_COLOR", //所有颜色乘以 1 减去一个常数颜色
- 1299 "CONSTANT_ALPHA", //将所有颜色乘以一个常数
- 1300 "ONE_MINUS_CONSTANT_ALPHA", //所有颜色乘以 1 减去一个常数
- 1301 "SRC_ALPHA_SATURATE", //将 RGB 颜色乘以源 alpha 值或 1 减去目标 alpha 值中的较小值。alpha 值乘以 1
- 1302 ];
- 1303
- 1304 #blendEnable = false;
- 1305 get blendEnable() {return this.#blendEnable;}
- 1306 set blendEnable(v) {
- 1307 this.#blendEnable = typeof v === "boolean" ? v : false;
- 1308 }
- 1309
- 1310 #blendC = {r: 0, g: 0, b: 0, a: 0};
- 1311 get blendC(){return this.#blendC;}
- 1312
- 1313 #blendES = [BlendEquationAdd[0], BlendEquationAdd[1]];
- 1314 get blendES(){return this.#blendES;} //mode || modeRGB, modeAlpha; 值为: MUS.blendESs 的索引
- 1315
- 1316 #blendFS = [BlendDefault[0], BlendDefault[1], BlendDefault[2], BlendDefault[3]];
- 1317 get blendFS(){return this.#blendFS;} //sfactor, dfactor || srcRGB, dstRGB, srcAlpha, dstAlpha; 值为: MUS.blendFSs 的索引
- 1318
- 1319 //如果纹理属性发生改变将此值设为true,渲染器会重绘材质的纹理(纹理不适合频繁的修改, 用着色器实现动态纹理)
- 1320 //注意还要设置对应材质的.needupdate = true 才有效
- 1321 #needupdate = false;
- 1322 get needupdate() {
- 1323 if(this.#needupdate === false) return false;
- 1324 this.#needupdate = false;
- 1325 return true;
- 1326 }
- 1327 set needupdate(v) {
- 1328 this.#needupdate = v;
- 1329 }
- 1330
- 1331 /**
- 1332 * 设置内置的混合组合
- 1333 * @param {Array} v //值为带前缀 Blend* 的常量
- 1334 */
- 1335 setBlend(v){
- 1336 switch(v){
- 1337 default: return;
- 1338 case BlendDefault:
- 1339 case BlendAdd:
- 1340 case BlendSub:
- 1341 case BlendMultiply:
- 1342 break;
- 1343 }
- 1344 Object.assign(this.#blendFS, v);
- 1345 }
- 1346
- 1347 /**
- 1348 * gl.blendFunc(sfactor, dfactor)
- 1349 * @param {number} sfactor //值为: MUS.blendFSs 的索引
- 1350 * @param {number} dfactor //值为: MUS.blendFSs 的索引
- 1351 */
- 1352 blendFunc(sfactor, dfactor) {
- 1353 this.#blendFS[0] = sfactor;
- 1354 this.#blendFS[1] = dfactor;
- 1355 this.#blendFS[2] = -1;
- 1356 this.#blendFS[3] = -1;
- 1357 }
- 1358
- 1359 /**
- 1360 * //gl.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); 值为: MUS.blendFSs 的索引
- 1361 * @param {number} srcRGB
- 1362 * @param {number} dstRGB
- 1363 * @param {number} srcAlpha
- 1364 * @param {number} dstAlpha
- 1365 */
- 1366 blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha) {
- 1367 this.#blendFS[0] = srcRGB;
- 1368 this.#blendFS[1] = dstRGB;
- 1369 this.#blendFS[2] = srcAlpha;
- 1370 this.#blendFS[3] = dstAlpha;
- 1371 }
- 1372
- 1373 }
- 1374
- 1375
- 1376 class Material extends MUS {
- 1377
- 1378 #texture = null;
- 1379 get texture() {return this.#texture;}
- 1380
- 1381 /**
- 1382 * @param {Texture} texture
- 1383 * @param {boolean} blendEnable
- 1384 */
- 1385 constructor(texture, blendEnable = true) {
- 1386 super();
- 1387 this.#texture = texture;
- 1388 this.blendEnable = blendEnable;
- 1389 }
- 1390
- 1391 }
- 1392
- 1393
- 1394 /** MaterialShader
- 1395 demo:
- 1396 const width = 256, height = 256;
- 1397 const geometry = new Geometry({
- 1398 aPosition: new Attribute(2, new Float32Array([
- 1399 width,0, 0,0, 0,height,
- 1400 0,height, width,height, width,0,
- 1401 ])),
- 1402 }, width, height);
- 1403
- 1404 const material = new MaterialShader({
- 1405 vertexCode: `#version 300 es
- 1406 in vec2 aPosition;
- 1407 uniform mat3 projectionMatrix;
- 1408 uniform mat3 modelMatrix;
- 1409 void main() {
- 1410 gl_Position.xyz = projectionMatrix * modelMatrix * vec3(aPosition, 1.0);
- 1411 gl_Position.w = 1.0;
- 1412 }
- 1413 `,
- 1414 fragmentCode: `#version 300 es
- 1415 precision mediump float; //highp, mediump, lowp
- 1416 uniform vec4 uColor;
- 1417 out vec4 outColor;
- 1418 void main() {
- 1419 outColor = uColor;
- 1420 }
- 1421 `,
- 1422 uniforms: {
- 1423 projectionMatrix: renderer.projectionMatrix,
- 1424 modelMatrix: null, //这里够不到模型矩阵,先占个位
- 1425 uColor: [1, 0, 0, 1],
- 1426 },
- 1427 });
- 1428
- 1429 const shader = new Object2D(geometry, material).translate(100, 300);
- 1430 material.uniforms.modelMatrix = shader.modelMatrix;
- 1431 renderer.append(shader).redraw();
- 1432
- 1433
- 1434 //这么做太麻烦了, 看下面这个:
- 1435
- 1436 const geometry1 = new GeometryRect(256, 256);
- 1437 const material1 = new MaterialShader({
- 1438 vertexCode: `#version 300 es
- 1439 in vec2 aPos; //aPosition -> aPos 顶点属性
- 1440 uniform mat3 uPMat; //projectionMatrix -> uPMat 投影矩阵
- 1441 uniform mat3 uMat; //modelMatrix -> uMat 模型矩阵
- 1442 void main() {
- 1443 gl_Position.xyz = uPMat * uMat * vec3(aPos, 1.0);
- 1444 gl_Position.w = 1.0;
- 1445 }
- 1446 `,
- 1447 fragmentCode: `#version 300 es
- 1448 precision mediump float; //highp, mediump, lowp
- 1449 uniform vec4 uColor;
- 1450 out vec4 outColor;
- 1451 void main() {
- 1452 outColor = uColor;
- 1453 }
- 1454 `,
- 1455 uniforms: {
- 1456 uColor: [1, 0, 0, 1],
- 1457 },
- 1458 });
- 1459
- 1460 const shader1 = new Object2D(geometry1, material1).translate(100+256+10, 300);
- 1461 renderer.append(shader1).redraw();
- 1462
- 1463 //每个模型的内置变量不一样(参考: defaultShaderCode), 这里只针对 Object2D;
- 1464 //Object2D 内置了1个属性, Geometry.attributes: {aPos: Attribute}
- 1465 //Object2D 内置了4个全局属性, .uniforms: {uPMat: [3x3], uMat: [3x3], uSize: [0, 0], uImage: Texture}
- 1466 //如果定义的着色器代码没有使用这些内置属性,渲染器在初始化它们时将自动丢弃掉
- 1467 */
- 1468 class MaterialShader extends MUS {
- 1469
- 1470 constructor(option = {vertexCode: "", fragmentCode: "", uniforms: {uTime: 0}}) {
- 1471 super();
- 1472 this.vertexCode = option.vertexCode;
- 1473 this.fragmentCode = option.fragmentCode;
- 1474 this.uniforms = option.uniforms;
- 1475 }
- 1476
- 1477 }
- 1478
- 1479
- 1480 /** Object2D
- 1481 demo:
- 1482 const geometry = new GeometryRect(renderer.domElement.width, renderer.domElement.height);
- 1483 const texture = new Texture(images[0], FormatRGB);
- 1484 const material = new Material(texture, false);
- 1485 const background = new Object2D(geometry, material);
- 1486 renderer.append(background).redraw();
- 1487 */
- 1488 class Object2D {
- 1489
- 1490 #geometry = null;
- 1491 get geometry() {
- 1492 return this.#geometry;
- 1493 }
- 1494
- 1495 #material = null;
- 1496 get material() {
- 1497 return this.#material;
- 1498 }
- 1499
- 1500 #mat3A = [];
- 1501 get modelMatrix() {return this.#mat3A;}
- 1502
- 1503 #mat3 = null;
- 1504 #bbox = new Box();
- 1505 #cx = 0;
- 1506 #cy = 0;
- 1507 get x() {return this.#bbox.x;}
- 1508 get y() {return this.#bbox.y;}
- 1509
- 1510 /**
- 1511 * 渲染器的常规成员 (复用它们: Geometry, Material, Texture, 如果这么做那么它们大部分东西都是共享的包括GPU上的缓存)
- 1512 * @param {Geometry} geometry
- 1513 * @param {Material} material
- 1514 */
- 1515 constructor(geometry, material) {
- 1516 this.#geometry = geometry || null;
- 1517 this.#material = material || null;
- 1518
- 1519 this.#bbox.size(geometry.width, geometry.height);
- 1520 this.#mat3 = new Matrix3(this.#mat3A).makeTranslation(0, 0);
- 1521 this.#cx = this.#bbox.w / 2;
- 1522 this.#cy = this.#bbox.h / 2;
- 1523 }
- 1524
- 1525 translate(x, y) {
- 1526 this.#bbox.x += x;
- 1527 this.#bbox.y += y;
- 1528 this.#cx = this.#bbox.x + this.#bbox.w / 2;
- 1529 this.#cy = this.#bbox.y + this.#bbox.h / 2;
- 1530 this.#mat3.translate(x, y);
- 1531 return this;
- 1532 }
- 1533
- 1534 rotate(x) {
- 1535 this.#mat3.translate(-this.#cx, -this.#cy)
- 1536 .rotate(x).translate(this.#cx, this.#cy);
- 1537 return this;
- 1538 }
- 1539
- 1540 scale(x, y) {
- 1541 this.#mat3.translate(-this.#cx, -this.#cy)
- 1542 .scale(x, y).translate(this.#cx, this.#cy);
- 1543 return this;
- 1544 }
- 1545
- 1546 containsPoint(x, y) {
- 1547 return this.#bbox.containsPoint(x, y);
- 1548 }
- 1549
- 1550 }
- 1551
- 1552
- 1553 /** Sprite
- 1554 demo:
- 1555 const geometry = new GeometryRect(renderer.domElement.width, renderer.domElement.height);
- 1556 const texture = new Texture(images[3], FormatRGB);
- 1557 const material = new Material(texture, false);
- 1558 const sprite = new Sprite(geometry, material, 8, 0);
- 1559 renderer.append(sprite).redraw();
- 1560 setInterval(() => {
- 1561 sprite.offset += 1; //sprite.offset += 0.1;
- 1562 renderer.redraw();
- 1563 }, 600);
- 1564 */
- 1565 class Sprite extends Object2D {
- 1566
- 1567 #len = 1;
- 1568 get len() {return this.#len;}
- 1569
- 1570 #offset = 0;
- 1571 get offset() {return this.#offset;}
- 1572 set offset(v) {this.#offset = v % this.#len;}
- 1573
- 1574 /**
- 1575 * 雪碧图, 精灵 (暂只支持 x * 1 的雪碧图), 设置它 .offset 实时生效!
- 1576 * @param {Geometry} geometry
- 1577 * @param {Material} material
- 1578 * @param {number} len //雪碧图x轴长度(图片的宽 / 每一格的宽)
- 1579 * @param {number} offset //雪碧图x轴位置, 浮点值, 0.0 至 len - 1 个为一个循环(offset % len)
- 1580 */
- 1581 constructor(geometry, material, len, offset = 0.0) {
- 1582 super(geometry, material);
- 1583 this.#len = Math.floor(Math.max(this.#len, len));
- 1584 this.offset = offset;
- 1585 }
- 1586
- 1587 }
- 1588
- 1589
- 1590 /** Instanced
- 1591 demo:
- 1592 const instanced = new Instanced(geos[2], mats[2], 5).translate(100, 100);
- 1593 for(let i = 0; i < instanced.len; i++){ //设置每一个实例的旋转
- 1594 instanced.rotateI(i, i / instanced.len);
- 1595 }
- 1596
- 1597 renderer.append(instanced).redraw();
- 1598 */
- 1599 class Instanced extends Object2D {
- 1600
- 1601 #frequentUpdate = false;
- 1602 get frequentUpdate() {return this.#frequentUpdate;}
- 1603
- 1604 #needupdate = null;
- 1605 #needupdateI = [];
- 1606 get needupdateI() {return this.#needupdateI;}
- 1607 get needupdate() {return this.#needupdate;}
- 1608
- 1609 #len = 0;
- 1610 get len() {return this.#len;}
- 1611
- 1612 #matrixData = null;
- 1613 get matrixData() {return this.#matrixData;}
- 1614
- 1615 #matrices = null;
- 1616 #matricesA = null;
- 1617 get matricesA() {return this.#matricesA;}
- 1618
- 1619 #bboxs = null;
- 1620
- 1621 /**
- 1622 * Object2D 的实例化版本
- 1623 * @param {Geometry} geometry
- 1624 * @param {Material} material
- 1625 * @param {number} len //实例的长度
- 1626 * @param {boolean} frequentUpdate //是否经常更新变换矩阵, 默认 false; (决定了变换矩阵数据在着色器中的缓存类型)
- 1627 */
- 1628 constructor(geometry, material, len, frequentUpdate) {
- 1629 super(geometry, material);
- 1630
- 1631 len = Math.max(1, Math.floor(len));
- 1632
- 1633 const matrixLen = 3 * 3, sizeByte = matrixLen * 4;
- 1634 this.#matrixData = new Float32Array(len * matrixLen);
- 1635 this.#matrices = new Array(len);
- 1636 this.#matricesA = new Array(len);
- 1637
- 1638 this.#needupdate = new Array(len);
- 1639 this.#bboxs = new Array(len);
- 1640 const cx = geometry.width / 2, cy = geometry.height / 2;
- 1641
- 1642 for(let i = 0, val; i < len; i++){
- 1643 val = new Float32Array(this.#matrixData.buffer, i * sizeByte, matrixLen);
- 1644 this.#matricesA[i] = val;
- 1645 this.#matrices[i] = new Matrix3(val).makeTranslation(0, 0);
- 1646 this.#needupdate[i] = false;
- 1647 this.#bboxs[i] = new Box(0, 0, cx, cy);
- 1648 }
- 1649
- 1650 this.#len = len;
- 1651 this.#frequentUpdate = typeof frequentUpdate === "boolean" ? frequentUpdate : false;
- 1652 }
- 1653
- 1654 translateI(i, x, y) {
- 1655 const bboxs = this.#bboxs[i];
- 1656 bboxs.x += x;
- 1657 bboxs.y += y;
- 1658 bboxs.w = this.x + bboxs.x + this.geometry.width / 2;
- 1659 bboxs.h = this.y + bboxs.y + this.geometry.height / 2;
- 1660 this.#matrices[i].translate(x, y);
- 1661 if(this.#needupdate[i] === false){
- 1662 this.#needupdate[i] = true;
- 1663 this.#needupdateI.push(i);
- 1664 }
- 1665 return this;
- 1666 }
- 1667
- 1668 rotateI(i, x) {
- 1669 const bboxs = this.#bboxs[i];
- 1670 this.#matrices[i].translate(-bboxs.w, -bboxs.h)
- 1671 .rotate(x).translate(bboxs.w, bboxs.h);
- 1672 if(this.#needupdate[i] === false){
- 1673 this.#needupdate[i] = true;
- 1674 this.#needupdateI.push(i);
- 1675 }
- 1676 return this;
- 1677 }
- 1678
- 1679 scaleI(i, x, y) {
- 1680 const bboxs = this.#bboxs[i];
- 1681 this.#matrices[i].translate(-bboxs.w, -bboxs.h)
- 1682 .scale(x, y)(bboxs.w, bboxs.h);
- 1683 if(this.#needupdate[i] === false){
- 1684 this.#needupdate[i] = true;
- 1685 this.#needupdateI.push(i);
- 1686 }
- 1687 return this;
- 1688 }
- 1689
- 1690 containsPointI(x, y) {
- 1691 for(let i = this.#len; i <= 0; i++){
- 1692 if(this.#bboxs[i].containsPoint(x, y) === true) return i;
- 1693 }
- 1694 return -1;
- 1695 }
- 1696
- 1697 }
- 1698
- 1699
- 1700 /** InstancedPoints
- 1701 demo:
- 1702 const points = new InstancedPoints(geos[1], mats[1], 50000, false, 10);
- 1703 for(let i = 0; i < points.len; i++){ //每一个实例设置一个随机位置
- 1704 points.translateI(i, UTILS.random(0, innerWidth - points.geometry.width), UTILS.random(0, innerHeight - points.geometry.height));
- 1705 }
- 1706
- 1707 renderer.append(points).redraw();
- 1708 */
- 1709 class InstancedPoints extends Instanced {
- 1710
- 1711 /**
- 1712 * 几乎与 Instanced 一样, 就多了一个.pointSize 属性, 修改此属性实时生效!
- 1713 * @param {Geometry} geometry
- 1714 * @param {Material} material
- 1715 * @param {number} len
- 1716 * @param {boolean} frequentUpdate
- 1717 * @param {number} pointSize //每一个点的大小(可以是浮点数)
- 1718 */
- 1719 constructor(geometry, material, len, frequentUpdate, pointSize) {
- 1720 super(geometry, material, len, frequentUpdate);
- 1721 this.pointSize = pointSize;
- 1722 }
- 1723
- 1724 }
- 1725
- 1726
- 1727 /** InstancedSprite
- 1728 demo:
- 1729 const geometry = new GeometryRect(renderer.domElement.width, renderer.domElement.height);
- 1730 const texture = new Texture(images[3], FormatRGB);
- 1731 const material = new Material(texture, false);
- 1732 const sprite = new InstancedSprite(geometry, material, 5, false, 8);
- 1733 for(let i = 0; i < sprite.len; i++){ //每一个实例设置一个随机位置
- 1734 sprite.translateI(i, UTILS.random(0, innerWidth - sprite.geometry.width), UTILS.random(0, innerHeight - sprite.geometry.height));
- 1735 }
- 1736 renderer.append(sprite).redraw();
- 1737 setInterval(() => {
- 1738 sprite.offset += 1; //sprite.offset += 0.1;
- 1739 renderer.redraw();
- 1740 }, 600);
- 1741 */
- 1742 class InstancedSprite extends Instanced {
- 1743
- 1744 #len1 = 1;
- 1745 get len1() {return this.#len1;}
- 1746
- 1747 #offset = 0;
- 1748 get offset() {return this.#offset;}
- 1749 set offset(v) {this.#offset = v % this.#len1;}
- 1750
- 1751 /**
- 1752 * Sprite 雪碧图的实例化版本, 设置它 .offset 实时生效!
- 1753 * @param {Geometry} geometry
- 1754 * @param {Material} material
- 1755 * @param {number} len
- 1756 * @param {boolean} frequentUpdate
- 1757 * @param {number} len1 //雪碧图x轴长度(图片的宽 / 每一格的宽)
- 1758 * @param {number} offset //雪碧图x轴位置, 浮点值, 0.0 至 len1 - 1 个为一个循环(offset % len1)
- 1759 */
- 1760 constructor(geometry, material, len, frequentUpdate, len1, offset = 0.0) {
- 1761 super(geometry, material, len, frequentUpdate);
- 1762 this.#len1 = Math.floor(Math.max(this.#len1, len1));
- 1763 this.offset = offset;
- 1764 }
- 1765
- 1766 }
- 1767
- 1768
- 1769
- 1770 //此类对外部是完全隐藏, 保密的, 只由渲染器直接调用;
- 1771 class Cache {
- 1772
- 1773 constructor(proName, pro, mode) {
- 1774 this.proName = proName;
- 1775 this.pro = pro;
- 1776 this.mode = mode;
- 1777 this.geo = null;
- 1778 this.mat = null;
- 1779 this.texLocs = [];
- 1780 this.uniforms = [];
- 1781 this.isselect = false;
- 1782 }
- 1783
- 1784 initUniforms(gl, uniforms, matHad = false, texMap = new Map()) {
- 1785 for(let n in uniforms){
- 1786 const loc = gl.getUniformLocation(this.pro.program, n);
- 1787 if(loc === null) continue;
- 1788
- 1789 if(Texture.prototype.isPrototypeOf(uniforms[n]) === false){
- 1790 this.uniforms.push(compileUniform(gl, loc, n, uniforms));
- 1791 continue;
- 1792 }
- 1793
- 1794 if(matHad === false){
- 1795 let tex = texMap.get(uniforms[n]);
- 1796 if(tex === undefined){
- 1797 tex = new CacheTexture(gl, this.mat.textures.length, n, uniforms);
- 1798 gl.activeTexture(tex.index);
- 1799 gl.bindTexture(gl.TEXTURE_2D, tex._texture);
- 1800 if(tex.texture.needupdate !== undefined) updateTexture(gl, tex.texture);
- 1801 texMap.set(uniforms[n], tex);
- 1802 }
- 1803 tex.len++;
- 1804 this.mat.textures.push(tex);
- 1805 //this.uniforms.push(() => gl.uniform1i(loc, i));
- 1806 }
- 1807 }
- 1808
- 1809 if(matHad === false) this.mat.lenT = this.mat.textures.length;
- 1810 for(let i = 0; i < this.mat.lenT; i++){
- 1811 this.texLocs[i] = gl.getUniformLocation(this.pro.program, this.mat.textures[i].name);
- 1812 }
- 1813 }
- 1814
- 1815 dispose(gl) {
- 1816 gl.deleteShader(this.pro.vertexShader);
- 1817 gl.deleteShader(this.pro.fragmentShader);
- 1818 gl.deleteProgram(this.pro.program);
- 1819 }
- 1820
- 1821 draw(gl) {
- 1822 if(this.geo.lenI === 0){
- 1823 gl.drawArrays(this.mode, 0, this.geo.lenV);
- 1824 } else {
- 1825 gl.drawElements(this.mode, this.geo.lenI, gl[this.geo.value.type], 0);
- 1826 }
- 1827 }
- 1828
- 1829 }
- 1830
- 1831
- 1832 class CacheInstanced extends Cache {
- 1833
- 1834 constructor(proName, pro, mode, gl, instanced) {
- 1835 super(proName, pro, mode);
- 1836
- 1837 this.matrixLoc = gl.getAttribLocation(pro.program, "uIMat");
- 1838 this.matrixBuffer = gl.createBuffer();
- 1839 gl.bindBuffer(gl.ARRAY_BUFFER, this.matrixBuffer);
- 1840 gl.bufferData(gl.ARRAY_BUFFER, instanced.matrixData, gl[instanced.frequentUpdate === false ? "STATIC_DRAW" : "DYNAMIC_DRAW"]);
- 1841
- 1842 instanced.needupdate.fill(false);
- 1843 instanced.needupdateI.length = 0;
- 1844
- 1845 this.sizeByte = 3 * 3 * 4;
- 1846 this.instanced = instanced;
- 1847 }
- 1848
- 1849 dispose(gl) {
- 1850 gl.deleteBuffer(this.matrixBuffer);
- 1851 return super.dispose(gl);
- 1852 }
- 1853
- 1854 draw(gl) {
- 1855 gl.bindBuffer(gl.ARRAY_BUFFER, this.matrixBuffer);
- 1856
- 1857 const instanced = this.instanced;
- 1858 var n, v = instanced.needupdateI.length;
- 1859
- 1860 if(v !== 0){ //需要上传矩阵
- 1861 if(v !== instanced.len){ //个别矩阵更新了
- 1862 let i = 0;
- 1863 for(n = 0; n < v; n++){
- 1864 i = instanced.needupdateI[n];
- 1865 instanced.needupdate[i] = false;
- 1866 gl.bufferSubData(gl.ARRAY_BUFFER, i * this.sizeByte, instanced.matricesA[i], 0, 9); //9 = 3 * 3 = instanced.matricesA[i].length;
- 1867 }
- 1868 } else { //所有矩阵都更新了
- 1869 instanced.needupdate.fill(false);
- 1870 gl.bufferSubData(gl.ARRAY_BUFFER, 0, instanced.matrixData);
- 1871 }
- 1872 instanced.needupdateI.length = 0;
- 1873 }
- 1874
- 1875 for(n = 0; n < 3; n++){
- 1876 v = this.matrixLoc + n;
- 1877 gl.enableVertexAttribArray(v);
- 1878 gl.vertexAttribPointer(v, 3, gl.FLOAT, false, this.sizeByte, n * 12); //12 = 3 mat3 * 4 byte
- 1879 gl.vertexAttribDivisor(v, 1);
- 1880 }
- 1881
- 1882 if(this.geo.lenI === 0){
- 1883 gl.drawArraysInstanced(this.mode, 0, this.geo.lenV, instanced.len);
- 1884 } else {
- 1885 gl.drawElementsInstanced(this.mode, this.geo.lenI, gl[this.geo.value.type], 0, instanced.len);
- 1886 }
- 1887 }
- 1888
- 1889 }
- 1890
- 1891
- 1892 class CacheGeometry {
- 1893
- 1894 constructor(gl, pro, geo) {
- 1895 this.lenV = 0;
- 1896 this.attributes = {};
- 1897 for(let n in geo.attributes){
- 1898 const loc = gl.getAttribLocation(pro.program, n);
- 1899 if(loc === -1) continue;
- 1900 const obj = compileBuffer(gl, loc, geo.attributes[n]);
- 1901 this.attributes[n] = obj;
- 1902 if(this.lenV === 0) this.lenV = obj.value.length / obj.size;
- 1903 }
- 1904
- 1905 this.lenI = 0;
- 1906 this.indexBuffer = null;
- 1907 if(geo.indices !== null) {
- 1908 this.indexBuffer = gl.createBuffer();
- 1909 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
- 1910 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, geo.indices, gl.STATIC_DRAW);
- 1911 this.lenI = geo.indices.length;
- 1912 }
- 1913
- 1914 this.len = 0;
- 1915 this.value = geo;
- 1916 }
- 1917
- 1918 dispose(gl) {
- 1919 if(this.indexBuffer !== null){
- 1920 gl.deleteBuffer(this.indexBuffer);
- 1921 }
- 1922 for(let n in this.attributes){
- 1923 gl.deleteVertexArray(this.attributes[n].vao);
- 1924 gl.deleteBuffer(this.attributes[n].buffer);
- 1925 }
- 1926 }
- 1927
- 1928 }
- 1929
- 1930
- 1931 class CacheMaterial {
- 1932
- 1933 constructor(mat, texs = []) {
- 1934 this.textures = texs;
- 1935 this.lenT = texs.length;
- 1936 this.len = 0;
- 1937 this.value = mat;
- 1938 }
- 1939
- 1940 dispose(gl) {
- 1941
- 1942 }
- 1943
- 1944 }
- 1945
- 1946
- 1947 class CacheTexture {
- 1948
- 1949 constructor(gl, i, n, v) {
- 1950 this._texture = gl.createTexture();
- 1951 this.texture = v[n];
- 1952 this.name = n;
- 1953 this.index = gl["TEXTURE"+i];
- 1954 this.len = 0;
- 1955 }
- 1956
- 1957 dispose(gl) {
- 1958 gl.deleteTexture(this._texture);
- 1959 }
- 1960
- 1961 }
- 1962
- 1963
- 1964 /* Renderer WebGL2 2D渲染器
- 1965 constructor:
- 1966 空; 初始化选项都在 Renderer.contextOption .glOption 中自行修改
- 1967
- 1968 attribute:
- 1969 domElement: HTMLCanvasElement; //只读
- 1970 projectionMatrix: Array; //只读, 返回默认的3x3投影矩阵
- 1971
- 1972 method:
- 1973 append(object2d: Structure|InstancedPoints|Object2D...): this; //添加到渲染队列并创建缓存
- 1974 delete(object2d: Structure|InstancedPoints|Object2D...): this; //从渲染队列删除并释放缓存
- 1975 dispose(): undefined; //销毁 WebGL2RenderingContext, 销毁后此类无法在继续使用
- 1976 setSize(width, height): undefined; //设置了: 画布宽高, gl的视口, 投影矩阵;
- 1977 select(x, y: number): Object2D|null; //根据一个点来获取 Object2D
- 1978 redraw(): undefined; //重绘画布
- 1979 readPixels(box: Box, result: ImageSource): ImageSource; //截取像素; box.x,box.y: 距画布左上角的偏移量; result: 如果未定义则会创建一个新的 ImageSource;
- 1980
- 1981 demo:
- 1982 const renderer = new Renderer();
- 1983 renderer.setSize(innerWidth, innerHeight);
- 1984 document.body.appendChild(renderer.domElement);
- 1985
- 1986 const geos = [
- 1987 new GeometryRect(256, 256),
- 1988 new GeometryCircle(125),
- 1989 new GeometryRectWavy(256, 256),
- 1990 ];
- 1991
- 1992 const mats = [
- 1993 new Material(new Texture(images[0], FormatRGB), false),
- 1994 new Material(new Texture(images[1], FormatRGBA), true),
- 1995 new Material(new Texture(images[2], FormatRGB), false),
- 1996 ];
- 1997
- 1998 renderer.domElement.addEventListener("click", e => {
- 1999 const geo = geos[Math.floor(UTILS.random(0, geos.length))]; //随机复用几何体
- 2000 const mat = mats[Math.floor(UTILS.random(0, mats.length))]; //随机复用材质
- 2001 const obj2d = new Object2D(geo, mat).translate(e.offsetX, e.offsetY);
- 2002
- 2003 renderer.append(obj2d).redraw();
- 2004 setTimeout(() => renderer.delete(obj2d).redraw(), UTILS.random(5000, 15000));
- 2005 });
- 2006
- 2007
- 2008 //截取像素示例.readPixels():
- 2009 //Renderer.contextOption.preserveDrawingBuffer 必须为 true, 默认为false(开启可能会影响绘制性能), 否则结果会使一个黑图
- 2010 renderer.domElement.addEventListener("click", e => {
- 2011 const geo = new GeometryRect(256, 256);
- 2012 geo.translate(e.offsetX, e.offsetY);
- 2013
- 2014 const source = renderer.readPixels(new Box(e.offsetX, e.offsetY, 256, 256));
- 2015 const mat = new Material(source);
- 2016 mat.setPixelStorei(PixelStoreiFlipY, true); //设置纹理预处理: 翻转像素y;
- 2017
- 2018 renderer.append(new Object2D(geo, mat)).redraw();
- 2019 });
- 2020
- 2021
- 2022 //画布截屏
- 2023 //renderer.domElement.toBlob(ElementUtils.downloadFile, "image/png");
- 2024 */
- 2025 class Renderer {
- 2026
- 2027 static contextOption = {
- 2028 alpha: false, //画布css的背景启用阿尔法 默认 true
- 2029 antialias: true, //抗锯齿 默认 true
- 2030 depth: false, //深度缓冲 默认 true
- 2031 desynchronized: true, //从事件循环中取消画布绘制周期的同步来减少延迟
- 2032 stencil: false, //模板缓冲 默认 false
- 2033 premultipliedAlpha: true, //预乘阿尔法通道 默认 true
- 2034 preserveDrawingBuffer: false, //true: 保留绘图缓冲区 默认 false
- 2035 failIfMajorPerformanceCaveat: true, //指示在系统性能较低时是否创建上下文
- 2036
- 2037 powerPreference: "default", //指示哪种GPU配置适合于WebGL上下文。
- 2038 //可能的值是:
- 2039 //"default" 让用户代理决定哪个GPU配置最适合。这是默认值。
- 2040 //"high-performance" 将渲染性能优先于功耗。
- 2041 //"low-power" 将节能优先于渲染性能。
- 2042
- 2043 xrCompatible: false,
- 2044 }
- 2045
- 2046 static glOption = {
- 2047 clearColor: {r: 0.45, g: 0.45, b: 0.45, a: 1}, //gl的背景颜色(在画布css颜色之上)
- 2048 }
- 2049
- 2050 #contextAttributes = {};
- 2051 #gl = createWebGL2();
- 2052 #pro = null;
- 2053
- 2054 #states = {
- 2055 pro: null,
- 2056 blendE: false,
- 2057 blendC: {r: -1, g: 0, b: 0, a: 0},
- 2058 blendES: [-1, 0],
- 2059 blendFS: [-1, 0, 0, 0],
- 2060 }
- 2061
- 2062 #geometries = new Map();
- 2063 #materials = new Map();
- 2064 #textures = new Map();
- 2065 #objects = [];
- 2066 #caches = [];
- 2067
- 2068 #projectionMatrix = new Matrix3();
- 2069 #projectionMatrixA = [];
- 2070 get projectionMatrix() {
- 2071 return this.#projectionMatrixA; //#projectionMatrix.toArray();
- 2072 }
- 2073
- 2074 get lengthObject() {return this.#objects.length;}
- 2075 get lengthGeometry() {return this.#geometries.size;}
- 2076 get lengthMaterial() {return this.#materials.size;}
- 2077 get lengthTexture() {return this.#textures.size;}
- 2078
- 2079 get domElement() {return this.#gl.canvas;}
- 2080
- 2081 constructor() {
- 2082 Object.assign(this.#contextAttributes, this.#gl.getContextAttributes());
- 2083 this.#pro = {
- 2084 texture1: createProgram(this.#gl, defaultShaderCode.texture1.vertex, defaultShaderCode.texture1.fragment),
- 2085 texture1_sprite: createProgram(this.#gl, defaultShaderCode.texture1_sprite.vertex, defaultShaderCode.texture1_sprite.fragment),
- 2086 texture1_Instanced: createProgram(this.#gl, defaultShaderCode.texture1_Instanced.vertex, defaultShaderCode.texture1_Instanced.fragment),
- 2087 texture1_Instanced_points: createProgram(this.#gl, defaultShaderCode.texture1_Instanced_points.vertex, defaultShaderCode.texture1_Instanced_points.fragment),
- 2088 texture1_Instanced_sprite: createProgram(this.#gl, defaultShaderCode.texture1_Instanced_sprite.vertex, defaultShaderCode.texture1_Instanced_sprite.fragment),
- 2089 }
- 2090 initExtensions(this.#gl);
- 2091 }
- 2092
- 2093 /**
- 2094 * @param {Object2D|Sprite|Instanced|InstancedPoints|InstancedSprite} object2d
- 2095 * @returns {this}
- 2096 */
- 2097 append(object2d) {
- 2098 if(arguments.length === 1){
- 2099 if(this.#objects.includes(object2d) === true) return this;
- 2100
- 2101 const obj = proHandler(this.#gl, this.#pro, this, object2d),
- 2102 cache = obj.cache;
- 2103 if(obj === null) return this;
- 2104
- 2105 //
- 2106 cache.geo = this.#geometries.get(object2d.geometry);
- 2107 if(cache.geo === undefined){
- 2108 cache.geo = new CacheGeometry(this.#gl, cache.pro, object2d.geometry);
- 2109 this.#geometries.set(object2d.geometry, cache.geo);
- 2110 }
- 2111 cache.geo.len++;
- 2112
- 2113 //
- 2114 cache.mat = this.#materials.get(object2d.material);
- 2115 const matHad = cache.mat !== undefined;
- 2116 if(matHad === false){
- 2117 cache.mat = new CacheMaterial(object2d.material);
- 2118 if(object2d.material.needupdate !== undefined) this.#materials.set(object2d.material, cache.mat);
- 2119 } else {
- 2120 for(let i = 0; i < cache.mat.textures.length; i++) cache.mat.textures[i].len++;
- 2121 }
- 2122 cache.mat.len++;
- 2123
- 2124 //
- 2125 cache.initUniforms(this.#gl, obj.uniforms, matHad, this.#textures);
- 2126 this.#caches.push(cache);
- 2127 this.#objects.push(object2d);
- 2128 return this;
- 2129 }
- 2130
- 2131 for(let i = 0, arg = arguments; i < arg.length; i++) this.append(arg[i]);
- 2132
- 2133 return this;
- 2134 }
- 2135
- 2136 /**
- 2137 * @param {Object2D|Sprite|Instanced|InstancedPoints|InstancedSprite} object2d
- 2138 * @returns {this}
- 2139 */
- 2140 delete(object2d) {
- 2141 if(arguments.length === 1){
- 2142 const i = this.#objects.indexOf(object2d);
- 2143 if(i === -1) return this;
- 2144
- 2145 const gl = this.#gl, cache = this.#caches[i];
- 2146
- 2147 this.#objects.splice(i, 1);
- 2148 this.#caches.splice(i, 1);
- 2149
- 2150 if(!cache.proName || this.#pro[cache.proName] !== cache.pro){
- 2151 cache.dispose(gl); //是自定义的着色器
- 2152 }
- 2153
- 2154 cache.geo.len--;
- 2155 if(cache.geo.len === 0){
- 2156 cache.geo.dispose(gl);
- 2157 this.#geometries.delete(object2d.geometry);
- 2158 }
- 2159
- 2160 cache.mat.len--;
- 2161 if(cache.mat.len === 0){
- 2162 cache.mat.dispose(gl);
- 2163 this.#materials.delete(object2d.material);
- 2164 }
- 2165
- 2166 for(let i = 0, tex; i < cache.mat.textures.length; i++){
- 2167 tex = cache.mat.textures[i];
- 2168 tex.len--;
- 2169 if(tex.len === 0){
- 2170 tex.dispose(gl);
- 2171 this.#textures.delete(tex.texture);
- 2172 }
- 2173 }
- 2174
- 2175 return this;
- 2176 }
- 2177
- 2178 for(let i = 0, arg = arguments; i < arg.length; i++) this.delete(arg[i]);
- 2179
- 2180 return this;
- 2181 }
- 2182
- 2183 redraw() {
- 2184 const len = this.#caches.length;
- 2185 if(len === 0) return;
- 2186
- 2187 const gl = this.#gl, states = this.#states;
- 2188 //gl.clear(gl.COLOR_BUFFER_BIT);
- 2189
- 2190 for(let i = 0, n, t, v, g, m; i < len; i++){
- 2191 v = this.#caches[i];
- 2192
- 2193 if(states.pro !== v.pro){
- 2194 states.pro = v.pro;
- 2195 gl.useProgram(states.pro.program);
- 2196 }
- 2197
- 2198 if(g !== v.geo){
- 2199 g = v.geo;
- 2200 for(n in g.attributes) gl.bindVertexArray(g.attributes[n].vao);
- 2201 if(g.lenI !== 0) gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, g.indexBuffer);
- 2202 }
- 2203
- 2204 if(m !== v.mat || m.value.needupdate === true){
- 2205 m = v.mat;
- 2206
- 2207 if(states.blendE !== m.value.blendEnable){
- 2208 states.blendE = m.value.blendEnable;
- 2209 gl[states.blendE === true ? "enable" : "disable"](gl.BLEND);
- 2210 }
- 2211
- 2212 if(states.blendE === true){
- 2213 if(states.blendC.r !== m.value.blendC.r ||
- 2214 states.blendC.g !== m.value.blendC.g ||
- 2215 states.blendC.b !== m.value.blendC.b ||
- 2216 states.blendC.a !== m.value.blendC.a){
- 2217 Object.assign(states.blendC, m.value.blendC);
- 2218 gl.blendColor(states.blendC.r, states.blendC.g, states.blendC.b, states.blendC.a);
- 2219 }
- 2220
- 2221 if(states.blendES[0] !== m.value.blendES[0] ||
- 2222 states.blendES[1] !== m.value.blendES[1]){
- 2223 Object.assign(states.blendES, m.value.blendES);
- 2224 if(states.blendES[0] !== -1){
- 2225 if(states.blendES[1] === -1){
- 2226 gl.blendEquation(gl[MUS.blendESs[states.blendES[0]]]);
- 2227 } else {
- 2228 gl.blendEquationSeparate(gl[MUS.blendESs[states.blendES[0]]], gl[MUS.blendESs[states.blendES[1]]]);
- 2229 }
- 2230 }
- 2231 }
- 2232
- 2233 if(states.blendFS[0] !== m.value.blendFS[0] ||
- 2234 states.blendFS[1] !== m.value.blendFS[1] ||
- 2235 states.blendFS[2] !== m.value.blendFS[2] ||
- 2236 states.blendFS[3] !== m.value.blendFS[3]){
- 2237 Object.assign(states.blendFS, m.value.blendFS);
- 2238 if(states.blendFS[0] !== -1){
- 2239 if(states.blendFS[2] === -1){
- 2240 gl.blendFunc(gl[MUS.blendFSs[states.blendFS[0]]], gl[MUS.blendFSs[states.blendFS[1]]]);
- 2241 } else {
- 2242 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]]]);
- 2243 }
- 2244 }
- 2245 }
- 2246 }
- 2247
- 2248 for(n = 0; n < m.lenT; n++){
- 2249 t = m.textures[n];
- 2250 gl.activeTexture(t.index);
- 2251 gl.bindTexture(gl.TEXTURE_2D, t._texture);
- 2252 if(t.texture.needupdate === true) updateTexture(gl, t.texture);
- 2253 gl.uniform1i(v.texLocs[n], n);
- 2254 }
- 2255 } else {
- 2256
- 2257 for(n = 0; n < m.lenT; n++){
- 2258 gl.uniform1i(v.texLocs[n], n); //这玩意每个对象都会创建一个新的(即使材质或纹理都一样,因为它指向的是自己所用的 program)
- 2259 }
- 2260
- 2261 }
- 2262
- 2263 t = v.uniforms.length;
- 2264 for(n = 0; n < t; n++) v.uniforms[n]();
- 2265
- 2266 v.draw(gl);
- 2267 //resetBuffers(gl);
- 2268 }
- 2269 }
- 2270
- 2271 dispose() {
- 2272 this.#geometries.clear();
- 2273 this.#materials.clear();
- 2274 this.#textures.clear();
- 2275 if(this.#gl.isContextLost() === false){
- 2276 this.#gl.loseContext();
- 2277 }
- 2278 this.#gl = null;
- 2279 }
- 2280
- 2281 setSize(width = innerWidth, height = innerHeight) {
- 2282 width *= window.devicePixelRatio;
- 2283 height *= window.devicePixelRatio;
- 2284 this.domElement.width = width;
- 2285 this.domElement.height = height;
- 2286 this.#gl.viewport(0, 0, width, height);
- 2287 this.#projectionMatrix.projection(width, height);
- 2288 this.#projectionMatrix.toArray(this.#projectionMatrixA);
- 2289 }
- 2290
- 2291 select(x = 0, y = 0, targets = this.#objects) {
- 2292 const len = targets.length;
- 2293 for(let i = len, obj2d; i >= 0; i--){
- 2294 obj2d = targets[i];
- 2295 if(this.#caches[i].isselect === true && obj2d.geometry.containsPoint(x, y) === true) return obj2d;
- 2296 }
- 2297 return null;
- 2298 }
- 2299
- 2300 readPixels(box = new Box(0, 0, 100, 100), result = new ImageSource(box.w, box.h)) {
- 2301 const y = (1 - box.y / this.domElement.height) * this.domElement.height - box.h;
- 2302 this.#gl.readPixels(box.x, y, box.w, box.h, this.#gl.RGBA, this.#gl.UNSIGNED_BYTE, result.data);
- 2303 return result;
- 2304 }
- 2305
- 2306 }
- 2307
- 2308
- 2309 export {
- 2310 defaultShaderCode,
- 2311
- 2312 BlendEquationAdd,
- 2313
- 2314 BlendDefault,
- 2315 BlendAdd,
- 2316 BlendSub,
- 2317 BlendMultiply,
- 2318
- 2319 FormatAlpha,
- 2320 FormatLuminance,
- 2321 FormatLuminanceAlpha,
- 2322 FormatRGB,
- 2323 FormatRGBA,
- 2324
- 2325 PixelStoreiFlipY,
- 2326 PixelStoreiPremultiplyAlpht,
- 2327
- 2328 Attribute,
- 2329 Geometry,
- 2330 GeometryRect,
- 2331 GeometryCircle,
- 2332 GeometryShape,
- 2333 GeometryRectWavy,
- 2334
- 2335 ImageSource,
- 2336 Texture,
- 2337 Material,
- 2338 MaterialShader,
- 2339
- 2340 Object2D,
- 2341 Sprite,
- 2342 Instanced,
- 2343 InstancedPoints,
- 2344 InstancedSprite,
- 2345
- 2346 Renderer,
- 2347 }
复制代码 Renderer Code
使用栗子: - 1 import { UTILS, AnimateLoop, TweenCache } from './lib/Utils.js';
- 2 import { CanvasImageText } from './lib/ElementUtils.js';
- 3 import {
- 4 FormatRGB,
- 5 FormatRGBA,
- 6
- 7 Attribute,
- 8 Geometry,
- 9 GeometryRect,
- 10 GeometryCircle,
- 11 GeometryShape,
- 12 GeometryRectWavy,
- 13
- 14 ImageSource,
- 15 Texture,
- 16 Material,
- 17 MaterialShader,
- 18
- 19 Object2D,
- 20 Sprite,
- 21 Instanced,
- 22 InstancedPoints,
- 23 InstancedSprite,
- 24
- 25 Renderer,
- 26 } from './lib/Two.js';
- 27
- 28
- 29 //完整源代码分享网址: https://share.weiyun.com/84cLfjst
- 30
- 31
- 32 const images = [
- 33 "./img/girls.jpg",
- 34 "./img/ball.png",
- 35 "./img/water.jpg",
- 36 "./img/spriteX8.png",
- 37 ]
- 38
- 39 { //init images
- 40 let len = 0;
- 41 for(let i = 0; i < images.length; i++) {
- 42 const image = new Image();
- 43 image.onload = () => {
- 44 if(len++ === images.length - 1) main();
- 45 }
- 46 image.src = images[i];
- 47 images[i] = image;
- 48 }
- 49 }
- 50
- 51 function main() {
- 52 //初始化渲染器
- 53 const renderer = new Renderer();
- 54 renderer.setSize();
- 55 document.body.appendChild(renderer.domElement);
- 56 console.log(renderer);
- 57
- 58
- 59 //共享的组件
- 60 const geos = [
- 61 new GeometryRect(256, 256),
- 62 new GeometryCircle(125),
- 63 new GeometryRectWavy(256, 256),
- 64 ];
- 65 const texs = [
- 66 new Texture(images[0], FormatRGB),
- 67 new Texture(images[1], FormatRGBA),
- 68 new Texture(images[2], FormatRGB),
- 69 ];
- 70 const mats = [
- 71 new Material(texs[0], false),
- 72 new Material(texs[1], true),
- 73 new Material(texs[2], false),
- 74 ];
- 75
- 76
- 77 const rotates = [];
- 78 renderer.domElement.addEventListener("click", e => {
- 79 const geo = geos[Math.floor(UTILS.random(0, geos.length))];
- 80 const mat = mats[Math.floor(UTILS.random(0, mats.length))];
- 81
- 82 const obj2d = new Object2D(geo, mat).translate(e.offsetX, e.offsetY);
- 83 renderer.append(obj2d);
- 84 rotates.push(obj2d);
- 85
- 86 setTimeout(() => {
- 87 renderer.delete(obj2d);
- 88 rotates.splice(rotates.indexOf(obj2d), 1);
- 89 }, UTILS.random(5000, 15000));
- 90 });
- 91
- 92
- 93 //创建背景和标题
- 94 const background = new Object2D(new GeometryRect(innerWidth, innerHeight), new Material(new Texture(images[0], FormatRGB), false));
- 95 const imageTitle = new CanvasImageText().setFont(40).size(innerWidth, 50).fillText("点击画布随机生成 Object2D !", "green").image;
- 96 const title = new Object2D(new GeometryRect(imageTitle.width, imageTitle.height), new Material(new Texture(imageTitle, FormatRGBA), true));
- 97 title.translate(0, 10);
- 98
- 99
- 100 //Object2D 的实例化版本
- 101 const instanced = new Instanced(geos[2], mats[2], 5).translate(100, 100);
- 102 for(let i = 0; i < instanced.len; i++){
- 103 instanced.rotateI(i, i / instanced.len);
- 104 }
- 105
- 106
- 107 //实例粒子
- 108 const points = new InstancedPoints(geos[1], mats[1], 100, false, 10);
- 109 for(let i = 0; i < points.len; i++){
- 110 points.translateI(i, UTILS.random(0, innerWidth - points.geometry.width), UTILS.random(0, innerHeight - points.geometry.height));
- 111 }
- 112
- 113
- 114 //实例雪碧图
- 115
- 116
- 117 //雪碧图
- 118 const sprite = new Sprite(geos[2], new Material(new Texture(images[3])), 8).translate(100+256+10, 100);
- 119 const tween = new TweenCache({x: 0}, {x: 1}, 300, () => { //每 300 毫秒更换一次
- 120 sprite.offset += 1;
- 121 tween.reverse();
- 122 tween.start();
- 123 }, true);
- 124
- 125
- 126 renderer.append(background, instanced, points, sprite, title);
- 127
- 128 function loop() {
- 129 for(let i = 0, len = rotates.length; i < len; i++) rotates[i].rotate(i / len);
- 130 tween.update(); //sprite.offset += 1; //sprite.offset += 0.1;
- 131 renderer.redraw();
- 132 }
- 133
- 134 new AnimateLoop(loop).play();
- 135 }
- 136
- 137
复制代码
//完整源代码分享网址: https://share.weiyun.com/84cLfjst 结果图:
未完 持续更新中...
来源:https://www.cnblogs.com/weihexinCode/p/18333260
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|