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