翼度科技»论坛 编程开发 JavaScript 查看内容

test 2D渲染器 WebGL WebGL2

5

主题

5

帖子

15

积分

新手上路

Rank: 1

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

来源:https://www.cnblogs.com/weihexinCode/p/18333260
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具