test 2D渲染器 WebGL WebGL2
1 import { Box, Matrix3, Vector2 } from './Utils.js';2 import { Shape, ShapeUtils, SplineCurve } from './TwoUtils.js';
3
4 const BlendEquationAdd = ;
5
6 const BlendDefault = ,
7 BlendAdd = ,
8 BlendSub = ,
9 BlendMultiply = ;
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, //不透明的背景图
44 uSampler1: images, //透明的圆球
45 opacity: 1,
46 ratio: 0.5,
47 uSize: ,
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,
71 uSampler1: images,
72 damp: 1,
73 uSize: ,
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, //waterColor.jpg
97 uSampler1: images, //waterNormal.jpg
98 uColor: , //绿色
99 uTime: 0,
100 uSize: ,
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: => ;
469 function reversePoints(points = ) {
470 for(let i = 0, j = points.length - 1; i < j; i += 2, j -= 2){
471 points = points;
472 points = points;
473 points = points;
474 points = points;
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 += x;
497 vertices += 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;
506 y = vertices;
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){
609 case "number":
610 return () => gl.uniform1f(loc, v);
611
612 case "object":
613 break;
614
615 default: return function(){};
616 }
617
618 //vec2, vec3, vec4, Matrix3x3, Matrix4x4
619 if(Array.isArray(v) === true){
620 switch(v.length){
621 case 2:
622 return () => gl.uniform2f(loc, v, v);
623
624 case 3:
625 return () => gl.uniform3f(loc, v, v, v);
626
627 case 4:
628 return () => gl.uniform4f(loc, v, v, v, v);
629
630 case 9:
631 return () => gl.uniformMatrix3fv(loc, false, v);
632
633 case 16:
634 return () => gl.uniformMatrix4fv(loc, false, v);
635 }
636 }
637
638 //Material
639 /* if(Material.prototype.isPrototypeOf(v) === true){
640 const i = t.length,
641 obj = {
642 texture: gl.createTexture(),
643 source: v,
644 index: gl["TEXTURE"+i],
645 needupdate: false,
646 };
647
648 t = obj;
649 gl.activeTexture(obj.index);
650 gl.bindTexture(gl.TEXTURE_2D, obj.texture);
651
652 const material = v;
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) === true){
666 switch(v.size){
667 case 1:
668 return () => gl.uniform1fv(loc, v.value);
669
670 case 2:
671 return () => gl.uniform2fv(loc, v.value);
672
673 case 3:
674 return () => gl.uniform3fv(loc, v.value);
675
676 case 4:
677 return () => gl.uniform4fv(loc, v.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) gl.deleteBuffer(buffers);
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];
751 if(v !== undefined) gl.pixelStorei(gl, true);
752 }
753 }
754
755 if(ImageSource.prototype.isPrototypeOf(tex.source) === true){
756 gl.texImage2D(gl.TEXTURE_2D, 0, gl, tex.source.width, tex.source.height, 0, gl, gl, tex.source.data);
757 } else {
758 gl.texImage2D(gl.TEXTURE_2D, 0, gl, gl, gl, 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;
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 = ;
803 result.cache = new Cache(proName, pro, gl);
804 break;
805
806 case "Sprite":
807 proName = "texture1_sprite";
808
809 if(isMS === false){
810 pro = pros;
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 = ;
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);
824 break;
825
826 case "Instanced":
827 proName = "texture1_Instanced";
828
829 if(isMS === false){
830 pro = pros;
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 = ;
838 result.cache = new CacheInstanced(proName, pro, gl, gl, object2d);
839 break;
840
841 case "InstancedPoints":
842 proName = "texture1_Instanced_points";
843
844 if(isMS === false){
845 pro = pros;
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, gl, object2d);
857 break;
858
859 case "InstancedSprite":
860 proName = "texture1_Instanced_sprite";
861
862 if(isMS === false){
863 pro = pros;
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 = ;
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, 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();
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 的顶点设置边界大小
981 * @param {string} attributeName
982 */
983 computeSize(attributeName) {
984 const att = this.attributes;
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 < 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())}, width, height);
1048 this.setIndex(, 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 = ;
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;
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;
1115 indices.push(face, face, face);
1116 if(isu32 === false && (face >= 65535 || face >= 65535 || face >= 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, points];
1165 const points2 = curve.getPoints(divisions);
1166 for(let i = 0; i < points2.length; i++){
1167 points1.push(points2);
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;}
1217 get type() {return Texture.formats;}
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 = , 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];
1314 get blendES(){return this.#blendES;} //mode || modeRGB, modeAlpha; 值为: MUS.blendESs 的索引
1315
1316 #blendFS = , BlendDefault, BlendDefault, BlendDefault];
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 = sfactor;
1354 this.#blendFS = dfactor;
1355 this.#blendFS = -1;
1356 this.#blendFS = -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 = srcRGB;
1368 this.#blendFS = dstRGB;
1369 this.#blendFS = srcAlpha;
1370 this.#blendFS = 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: ,
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: ,
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: , uMat: , uSize: , 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, 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, 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, mats, 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 = val;
1645 this.#matrices = new Matrix3(val).makeTranslation(0, 0);
1646 this.#needupdate = false;
1647 this.#bboxs = 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;
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.translate(x, y);
1661 if(this.#needupdate === false){
1662 this.#needupdate = true;
1663 this.#needupdateI.push(i);
1664 }
1665 return this;
1666 }
1667
1668 rotateI(i, x) {
1669 const bboxs = this.#bboxs;
1670 this.#matrices.translate(-bboxs.w, -bboxs.h)
1671 .rotate(x).translate(bboxs.w, bboxs.h);
1672 if(this.#needupdate === false){
1673 this.#needupdate = true;
1674 this.#needupdateI.push(i);
1675 }
1676 return this;
1677 }
1678
1679 scaleI(i, x, y) {
1680 const bboxs = this.#bboxs;
1681 this.#matrices.translate(-bboxs.w, -bboxs.h)
1682 .scale(x, y)(bboxs.w, bboxs.h);
1683 if(this.#needupdate === false){
1684 this.#needupdate = 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.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, mats, 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, 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) === false){
1790 this.uniforms.push(compileUniform(gl, loc, n, uniforms));
1791 continue;
1792 }
1793
1794 if(matHad === false){
1795 let tex = texMap.get(uniforms);
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, 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 = gl.getUniformLocation(this.pro.program, this.mat.textures.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, 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);
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;
1865 instanced.needupdate = false;
1866 gl.bufferSubData(gl.ARRAY_BUFFER, i * this.sizeByte, instanced.matricesA, 0, 9); //9 = 3 * 3 = instanced.matricesA.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, 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);
1901 this.attributes = 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.vao);
1924 gl.deleteBuffer(this.attributes.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;
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, FormatRGB), false),
1994 new Material(new Texture(images, FormatRGBA), true),
1995 new Material(new Texture(images, FormatRGB), false),
1996 ];
1997
1998 renderer.domElement.addEventListener("click", e => {
1999 const geo = geos; //随机复用几何体
2000 const mat = mats; //随机复用材质
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.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);
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;
2146
2147 this.#objects.splice(i, 1);
2148 this.#caches.splice(i, 1);
2149
2150 if(!cache.proName || this.#pro !== 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;
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);
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;
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.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(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 !== m.value.blendES ||
2222 states.blendES !== m.value.blendES){
2223 Object.assign(states.blendES, m.value.blendES);
2224 if(states.blendES !== -1){
2225 if(states.blendES === -1){
2226 gl.blendEquation(gl]]);
2227 } else {
2228 gl.blendEquationSeparate(gl]], gl]]);
2229 }
2230 }
2231 }
2232
2233 if(states.blendFS !== m.value.blendFS ||
2234 states.blendFS !== m.value.blendFS ||
2235 states.blendFS !== m.value.blendFS ||
2236 states.blendFS !== m.value.blendFS){
2237 Object.assign(states.blendFS, m.value.blendFS);
2238 if(states.blendFS !== -1){
2239 if(states.blendFS === -1){
2240 gl.blendFunc(gl]], gl]]);
2241 } else {
2242 gl.blendFuncSeparate(gl]], gl]], gl]], gl]]);
2243 }
2244 }
2245 }
2246 }
2247
2248 for(n = 0; n < m.lenT; n++){
2249 t = m.textures;
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);
2254 }
2255 } else {
2256
2257 for(n = 0; n < m.lenT; n++){
2258 gl.uniform1i(v.texLocs, n); //这玩意每个对象都会创建一个新的(即使材质或纹理都一样,因为它指向的是自己所用的 program)
2259 }
2260
2261 }
2262
2263 t = v.uniforms.length;
2264 for(n = 0; n < t; n++) v.uniforms();
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;
2295 if(this.#caches.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;
47 images = 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, FormatRGB),
67 new Texture(images, FormatRGBA),
68 new Texture(images, FormatRGB),
69 ];
70 const mats = [
71 new Material(texs, false),
72 new Material(texs, true),
73 new Material(texs, false),
74 ];
75
76
77 const rotates = [];
78 renderer.domElement.addEventListener("click", e => {
79 const geo = geos;
80 const mat = mats;
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, 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, mats, 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, mats, 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, new Material(new Texture(images)), 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.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】 我们会及时删除侵权内容,谢谢合作!
页:
[1]