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 源码



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。