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