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

javascript js WebGL WebGL2 后期处理特效之点击水波纹涟漪例子

3

主题

3

帖子

9

积分

新手上路

Rank: 1

积分
9
先来看结果图(转.gif掉帧了): 

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

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

本帖子中包含更多资源

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

x

举报 回复 使用道具