webgl实现canvas三维多彩方形碎片粒子飞舞动画效果代码
代码语言:html
所属分类:粒子
代码描述:webgl实现canvas三维多彩方形碎片粒子飞舞动画效果代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<html lang="en"> <head> <meta charset="UTF-8"> <style> body { background: #66f; margin: 0; overflow: hidden; } canvas { height: 100vh; width: 100vw; touch-action: none; } .osc { left: 0px; position: fixed; top: 0px; } .button { position: fixed; z-index: 10; right: 0; bottom: 0; } .controls { position: fixed; z-index: 10; left: 0; bottom: 0; } .playpause { background: #AAB; padding: 10px; } .playpause label { display: block; box-sizing: border-box; width: 0; height: 20px; cursor: pointer; border-color: transparent transparent transparent #202020; transition: 100ms all ease; will-change: border-width; border-style: double; border-width: 0px 0 0px 20px; } .playpause input[type='checkbox'] { visibility: hidden; } .playpause.checked label { border-style: double; border-width: 0px 0 0px 20px; } .playpause label { border-style: solid; border-width: 10px 0 10px 20px; } /* } */ </style> </head> <body> <script id="vertexShader_particle" type="x-shader/x-vertex"> attribute vec3 a_position; attribute vec3 a_particle; attribute vec2 a_reference; uniform float u_time; uniform mat4 u_m_model; uniform mat4 u_m_view; uniform mat4 u_m_MVP; uniform mat4 u_m_proj; uniform sampler2D b_position; uniform sampler2D b_velocity; varying vec3 v_colour; varying float v_fogDepth; varying float v_opacity; float random(vec2 st) { return fract(sin(dot(st, vec2(12.9898, 78.233)))* 43758.5453123); } vec3 hsv2rgb(vec3 c) { vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); } float hash21(vec2 p) { p = fract(p * vec2(233.34, 851.74)); p += dot(p, p + 23.45); return fract(p.x * p.y); } mat3 fromQuat(vec4 q) { float x = q.x; float y = q.y; float z = q.z; float w = q.w; float x2 = q.x*2.; float y2 = q.y*2.; float z2 = q.z*2.; float xx = x * x2; float yx = y * x2; float yy = y * y2; float zx = z * x2; float zy = z * y2; float zz = z * z2; float wx = w * x2; float wy = w * y2; float wz = w * z2; return mat3( 1. - yy -zz, yx -wz, zx + wy, yx + wz, 1. - xx - zz, zy - wx, zx - wy, zy + wx, 1. - xx - yy ); } /** * Generates a look-at matrix with the given eye position, focal point, and up axis. * If you want a matrix that actually makes an object look at another object, you should use targetTo instead. * * @param {mat4} out mat4 frustum matrix will be written into * @param {vec3} eye Position of the viewer * @param {vec3} center Point the viewer is looking at * @param {vec3} up vec3 pointing up * @returns {mat4} out */ mat4 lookAt(vec3 e, vec3 c, vec3 u) { // if (Math.abs(e.x - c.x) < EPSILON && // Math.abs(e.y - c.y) < EPSILON && // Math.abs(e.z - c.z) < EPSILON) { // return new Mat4(); // } vec3 off = normalize(e - c); vec3 or = vec3( u.y * off.z - u.z * off.y, u.z * off.x - u.x * off.z, u.x * off.y - u.y * off.x ); or = normalize(or); vec3 tn = vec3( off.y * or.z - off.z * or.y, off.z * or.x - off.x * or.z, off.x * or.y - off.y * or.x ); tn = normalize(tn); return mat4( or.x, tn.x, off.x, 0, or.y, tn.y, off.y, 0, or.z, tn.z, off.z, 0, -(or.x * e.x + or.y * e.y + or.z * e.z), -(tn.x * e.x + tn.y * e.y + tn.z * e.z), -(off.x * e.x + off.y * e.y + off.z * e.z), 1 ); } vec3 palette(in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d) { return a + b*cos(6.28318*(c*t+d)); } void main() { // vec4 pos = vec4(a_particle, 1.); // vec4 mvPos = u_m_view * u_m_model * pos; // gl_Position = u_m_proj * mvPos; // float isq = ( 1. / -mvPos.z ); // gl_PointSize = (100.) * isq; vec3 position = texture2D(b_position, a_reference).xyz; vec3 velocity = texture2D(b_velocity, a_reference).xyz; // vec4 quat = vec4(normalize(velocity), 0.); // mat3 mat = fromQuat(quat); // vec3 particle = a_particle * vec3(1, 1.+length(velocity*velocity*.05), 1) * .1 * mat; float vl = min(length(velocity*velocity)*.01, 5.); vec3 p = a_particle * vec3(1.-vl*.2, 1, 1.+vl); float vl1 = smoothstep(0., 20., length(velocity)); p *= (.3 + vl1); mat4 look = lookAt( normalize(position), normalize(position+velocity), normalize(position) ); vec3 particle = (vec4(p * .2, 1) * look).xyz; // vec3 particle = (vec4(a_particle.yzx*vec3(1,1,1.+length(velocity*velocity)*.01), 1) * .2 * look).xyz; position += particle; vec4 pos = vec4(position, 1.); float l = length(pos); vec4 mvPos = u_m_view * u_m_model * pos; v_fogDepth = mvPos.z; float isq = (1. / -mvPos.z); float b = smoothstep(0., 80., l); float s = clamp(b*6., 0.1, 1.); v_opacity = b; gl_Position = u_m_proj * mvPos; float hash = hash21(a_reference); v_colour = palette( hash*.5+.3, vec3(0.5, 0.5, 0.5), vec3(0.5, 0.5, 0.5), vec3(1.0, 1.0, 1.0), vec3(0.5, 0.3, 0.2) ); // v_colour = hsv2rgb(vec3(.6 + hash * .3 + vl1 * .1, 1., hash * .5 + .3)); // if(length(a_reference) == 0.) v_colour = vec3(1,0,0); } </script> <script id="vertexShader_buffer" type="x-shader/x-vertex"> attribute vec4 a_position; uniform mat4 u_modelViewMatrix; uniform mat4 u_projectionMatrix; void main() { gl_Position = a_position; } </script> <script id="fragmentShader_velocity" type="x-shader/x-fragment"> #extension GL_OES_standard_derivatives: enable precision highp float; uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; uniform sampler2D s_noise; uniform int u_frame; uniform float u_nsize; uniform float u_seed; uniform sampler2D b_velocity; uniform sampler2D b_position; #define PI 3.141592653589793 #define HPI 1.5707963267948966 #define TAU 6.283185307179586 #define G 0.67408 mat4 rotationMatrix(vec3 axis, float angle) { axis = normalize(axis); float s = sin(angle); float c = cos(angle); float oc = 1.0 - c; return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0, oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0, oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0, 0.0, 0.0, 0.0, 1.0); } vec3 hash33(vec3 p) { return fract(vec3( sin(p.x) * 43543.454354, sin(p.y) * 7531.154354, sin(p.z) * 10053.75315 )); } void main() { vec2 uv = gl_FragCoord.xy / u_resolution.xy; vec3 position = texture2D(b_position, uv).xyz; vec3 velocity = texture2D(b_velocity, uv).xyz; vec3 acceleration = vec3(position); vec3 f = position; float tm = u_time; float l = length(position); position = (vec4(position, 1.) * rotationMatrix(vec3(sin(tm * 25.), cos(tm * 10.), sin(tm) * cos(tm * 5.)), .5 + 10. / l)).xyz; vec3 spherical = vec3(1./max(l, .1), atan(position.y, position.x), acos(position.z / l)); float a = sin(length(spherical.yz) * 5. + tm) * 5.; acceleration.x = spherical.x * sin(spherical.z) * cos(spherical.y) * a; acceleration.y = spherical.x * sin(spherical.z) * sin(spherical.y) * a; acceleration.z = spherical.x * cos(spherical.z) * a; f = normalize(f - acceleration) * -1.; f *= smoothstep(10., 40., l) * 2.; vec3 vel = velocity * .99 + (acceleration + f) * .5; gl_FragColor = vec4(vel, 1.0); } </script> <script id="fragmentShader_position" type="x-shader/x-fragment"> #extension GL_OES_standard_derivatives: enable precision highp float; uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; uniform float u_delta; uniform sampler2D s_noise; uniform bool u_nreset; uniform sampler2D b_prime; uniform sampler2D b_velocity; uniform sampler2D b_position; uniform sampler2D b_origin; vec2 getScreenSpace() { vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution.xy) / min(u_resolution.y, u_resolution.x); return uv; } vec3 hash33(vec3 p) { return fract(vec3( sin(p.x) * 43543.454354, sin(p.y) * 7531.154354, sin(p.z) * 10053.75315 )); } void main() { vec2 uv = getScreenSpace(); vec2 s = gl_FragCoord.xy / u_resolution.xy; vec3 position = texture2D(b_position, s).xyz; vec3 velocity = texture2D(b_velocity, s).xyz; vec3 pos = position + velocity * u_delta * .5; if (length(pos) > 100.) { pos = pos / length(pos) * 2.; } gl_FragColor = vec4(pos, 1.0); } </script> <script id="fragmentShader_particle" type="x-shader/x-fragment"> #extension GL_OES_standard_derivatives: enable precision highp float; uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; uniform sampler2D s_noise; uniform bool u_transition; uniform float u_transition_val; uniform sampler2D b_prime; uniform sampler2D b_position; varying vec3 v_colour; varying float v_fogDepth; varying float v_opacity; vec2 getScreenSpace() { vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution.xy) / min(u_resolution.y, u_resolution.x); return uv; } void main() { float fade = smoothstep(1., 0., u_transition_val); gl_FragColor = vec4(mix(vec3(1), v_colour, fade), 1.); // vec2 uv = gl_PointCoord.xy - .5; // vec2 s = gl_FragCoord.xy / u_resolution.xy; // float l = length(uv); // float c = smoothstep(.5, 0., l); // float fog = smoothstep(-200., -1., v_fogDepth); // float opacity = c*fog; // if(c < .1) discard; // float fade = smoothstep(1., 0., u_transition_val); // gl_FragColor = vec4( // mix( // vec4(1.), // mix( // vec4(1), // vec4(v_colour, opacity), // c), // fade // ) // ); } </script> <script id="fragmentShader_blur" type="x-shader/x-fragment"> #extension GL_OES_standard_derivatives: enable precision highp float; uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; uniform sampler2D s_noise; uniform sampler2D b_prime; uniform sampler2D b_blur; varying vec3 v_colour; vec2 getScreenSpace() { vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution.xy) / min(u_resolution.y, u_resolution.x); return uv; } void main() { vec2 uv = getScreenSpace(); vec2 s = gl_FragCoord.xy / u_resolution.xy; vec4 n1 = texture2D(b_blur, s); vec4 n = clamp(texture2D(b_prime, s), 0., 1.); vec4 c = n1*.5 + n*.5; gl_FragColor = clamp(c, 0., 1.); } </script> <script id="fragmentShader_bloom" type="x-shader/x-fragment"> #extension GL_OES_standard_derivatives: enable precision highp float; uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; uniform sampler2D s_noise; uniform int u_bloomstep; uniform sampler2D b_prime; uniform sampler2D b_blur; uniform sampler2D b_bloom; varying vec3 v_colour; vec2 getScreenSpace() { vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution.xy) / min(u_resolution.y, u_resolution.x); return uv; } vec4 tex(sampler2D tex, vec2 co) { return clamp(texture2D(tex, co), 0., 1.); } void main() { vec2 uv = getScreenSpace(); vec2 s = gl_FragCoord.xy / u_resolution.xy; vec2 p = 1./u_resolution.xy; // vec4 n1 = texture2D(b_blur, s); // vec4 n = texture2D(b_prime, s); vec4 n1; vec4 c; vec4 n = texture2D(b_prime, s); vec4 n2 = n; if (u_bloomstep == 0) { n1 = tex(b_blur, s); n1 += tex(b_blur, s + vec2(0, p.y)); n1 += tex(b_blur, s + vec2(0, p.y*2.)); n1 += tex(b_blur, s + vec2(0, p.y*3.)); n1 += tex(b_blur, s + vec2(0, p.y*-1.)); n1 += tex(b_blur, s + vec2(0, p.y*-2.)); n1 += tex(b_blur, s + vec2(0, p.y*-3.)); n1 /= 7.; c = n1; } else if (u_bloomstep == 1) { n1 = tex(b_bloom, s); n1 += tex(b_bloom, s + vec2(p.x, 0.)); n1 += tex(b_bloom, s + vec2(p.x*2., 0)); n1 += tex(b_bloom, s + vec2(p.x*3., 0)); n1 += tex(b_bloom, s + vec2(p.x*-1., 0)); n1 += tex(b_bloom, s + vec2(p.x*-2., 0)); n1 += tex(b_bloom, s + vec2(p.x*-3., 0)); n1 /= 7.; c = pow(n1, vec4(2.)); } gl_FragColor = clamp(n1, 0., 1.); } </script> <script id="fragmentShader_buffer" type="x-shader/x-fragment"> #extension GL_OES_standard_derivatives: enable precision highp float; uniform vec2 u_resolution; uniform vec2 u_mouse; uniform float u_time; uniform sampler2D s_noise; uniform bool u_transition; uniform float u_transition_val; uniform sampler2D b_prime; uniform sampler2D b_blur; uniform sampler2D b_bloom; varying vec3 v_colour; vec2 getScreenSpace() { vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution.xy) / min(u_resolution.y, u_resolution.x); return uv; } void main() { vec2 uv = getScreenSpace(); vec2 s = gl_FragCoord.xy / u_resolution.xy; vec2 p = .5/u_resolution.xy; // vec4 bloom = texture2D(b_bloom, s); vec4 n = texture2D(b_blur, s); float fade = smoothstep(1., 0., u_transition_val); gl_FragColor = vec4( mix( vec3(1), n.rgb, fade) * (1. + (1.-fade)), 1.); } </script> <div class="controls"> <div class="playpause checked"> <label> <input checked="checked" type="checkbox" value="None" id="playpause" name="check"> </label> </div> </div> <script type="module"> import { Vec2, Vec3, Mat2, Mat3, Mat4, Quat } from 'https://cdn.skypack.dev/wtc-math'; import gifJs from 'https://cdn.skypack.dev/gif.js'; console.clear(); // Determine whether a number is a power of 2 function powerOf2(v) { return v && !(v & (v - 1)); } // Return the next greatest power of 2 function nextPow2( v ) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } // Update a provided image to the nearest power of 2 in size. const pow2Image = (c) => { const newWidth = powerOf2(c.width) ? c.width : nextPow2(c.width); const newHeight = powerOf2(c.height) ? c.height : nextPow2(c.height); const _c = document.createElement('canvas'); const ctx = _c.getContext('2d'); _c.width = newWidth; _c.height = newHeight; ctx.drawImage(c, 0, 0, newWidth, newHeight); return _c; } const asyncImageLoad = function(img, src) { return new Promise((resolve, reject) => { img.onload = () => resolve(img); img.onerror = reject; img.src = src; }) } const glEnumToString = (function() { const haveEnumsForType = {}; const enums = {}; function addEnums(gl) { const type = gl.constructor.name; if (!haveEnumsForType[type]) { for (const key in gl) { if (typeof gl[key] === 'number') { const existing = enums[gl[key]]; enums[gl[key]] = existing ? `${existing} | ${key}` : key; } } haveEnumsForType[type] = true; } } return function glEnumToString(gl, value) { addEnums(gl); return enums[value] || (typeof value === 'number' ? `0x${value.toString(16)}` : value); }; }()); const addExtensions = (ctx) => { // Set up the extensions ctx.getExtension('OES_standard_derivatives'); ctx.getExtension('EXT_shader_texture_lod'); ctx.getExtension('OES_texture_float'); ctx.getExtension('WEBGL_color_buffer_float'); ctx.getExtension('OES_texture_float_linear'); ctx.getExtension('EXT_color_buffer_float'); } function createContext(c, opt_attribs, params) { const ctx = c.getContext("webgl", params) || this._el.getContext("experimental-webgl", params); addExtensions(ctx); return ctx; } const quatToMat4 = (q) => { if(q.array) q = q.array; // This just transforms a provided vector into to an array. if(q instanceof Array && q.length >= 4) { const [x, y, z, w] = q; const [x2, y2, z2] = q.map(x => x * 2.); const xx = x * x2, yx = y * x2, yy = y * y2, zx = z * x2, zy = z * y2, zz = z * z2, wx = w * x2, wy = w * y2, wz = w * z2; return new Mat4( 1 - yy -zz, yx -wz, zx + wy, 0, yx + wz, 1 - xx - zz, zy - wx, 0, zx - wy, zy + wx, 1 - xx - yy, 0, 0, 0, 0, 1 ); } } class Renderer { static #defaultOptions = { width: 512, height: 512, pxRatio: Math.min(window.devicePixelRatio, 2), clearing: true, depthTesting: true, premultipliedAlpha: true } static BLENDING_DEBUG = -1; static BLENDING_NORMAL = 1; static BLENDING_ADDITIVE = 2; static BLENDING_SUBTRACTIVE = 4; static BLENDING_MULTIPLY = 8; static BLENDING_OFF = 16; isWebgl2 = false; #blending; #blendingEnabled = false; #buffers = []; constructor(canvas, options) { options = Object.assign({}, Renderer.#defaultOptions, options); this.width = options.width; this.height = options.height; this.pxRatio = options.pxRatio; this.clearing = options.clearing; this.depthTesting = options.depthTesting; this.canvas = canvas || document.createElement('canvas'); this.canvas.width = this.width * this.pxRatio; this.canvas.height = this.height * this.pxRatio; this.premultipliedAlpha = options.premultipliedAlpha; this.ctx = this.canvas.getContext("webgl", options) || this.canvas.getContext("experimental-webgl", options); this.ctx.viewportWidth = this.canvas.width; this.ctx.viewportHeight = this.canvas.height; this.uniformResolution = new Uniform(this.ctx, 'resolution', Uniform.TYPE_V2, [this.canvas.width, this.canvas.height]); this.addExtensions(); } resize(w, h, ratio) { this.width = w; this.height = h; this.pxRatio = ratio || this.pxRatio; this.canvas.width = this.width * this.pxRatio; this.canvas.height = this.height * this.pxRatio; this.ctx.viewportWidth = this.canvas.width; this.ctx.viewportHeight = this.canvas.height; this.uniformResolution = new Uniform(this.ctx, 'resolution', Uniform.TYPE_V2, [this.canvas.width, this.canvas.height]); } setViewport(dimensions) { let w = this.width*this.pxRatio; let h = this.height*this.pxRatio; if(dimensions) { w = dimensions[0]; h = dimensions[1]; } this.ctx.viewport(0, 0, w, h); this.uniformResolution = new Uniform(this.ctx, 'resolution', Uniform.TYPE_V2, [w, h]); } addExtensions() { this.ctx.getExtension('OES_standard_derivatives'); this.ctx.getExtension('EXT_shader_texture_lod'); this.ctx.getExtension('OES_texture_float'); this.ctx.getExtension('WEBGL_color_buffer_float'); this.ctx.getExtension('OES_texture_float_linear'); this.ctx.getExtension('EXT_color_buffer_float'); } linkBuffer(buffer) { let hasBuffer = false; this.#buffers.forEach((b) => { if(buffer === b) hasBuffer = true; }); if(!hasBuffer) { this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, buffer.buffer); this.ctx.bufferData( this.ctx.ARRAY_BUFFER, buffer.data, buffer.drawType); } buffer.link(this.currentProgram.program); } setupProgram(program, buffers, attributes, uniforms) { this.currentProgram = program; this.ctx.useProgram(program.program); this.premultiplied = program.premultiplied; this.depthTesting = program.depthTesting; if(program.blending === Program.BLENDING_NORMAL && program.transparent === false ) { this.blending = Program.BLENDING_OFF; } else { this.blending = program.blending; } this.clearColour = program.clearColour; const a = this.clearColour[3]; // console.log('prem', this.premultipliedAlpha) if(this.premultipliedAlpha) this.clearColour = this.clearColour.map((c, i) => c * a ); this.ctx.clearColor(...this.clearColour); // TODO: Unlink unused buffers during this setup phase as well. buffers.forEach(buffer => { this.linkBuffer(buffer); }); // this.ctx.enable(ctx.DEPTH_TEST); if(this.depthTesting) this.ctx.enable(ctx.DEPTH_TEST); else this.ctx.disable(ctx.DEPTH_TEST); uniforms.forEach(uniform => { uniform.bind(program.program); }); this.uniformResolution.bind(program.program); } render(points, buffer) { this.ctx.bindFramebuffer(this.ctx.FRAMEBUFFER, buffer?.fb || null); if(this.clearing) { this.ctx.clear( this.ctx.COLOR_BUFFER_BIT ); if(this.depthTesting) this.ctx.clear( this.ctx.DEPTH_BUFFER_BIT ); } switch(this.currentProgram.renderType) { case Program.RENDER_TRIANGLES: this.ctx.drawArrays(this.ctx.TRIANGLES, 0, points); break; case Program.RENDER_STRIP: this.ctx.drawArrays(this.ctx.TRIANGLE_STRIP, 0, points); break; case Program.RENDER_LINES: this.ctx.drawArrays(this.ctx.LINE_STRIP, 0, points); break; case Program.RENDER_LINELOOP: this.ctx.drawArrays(this.ctx.LINE_LOOP, 0, points); break; case Program.RENDER_POINTS: this.ctx.drawArrays(this.ctx.POINTS, 0, points); break; } } /* SETTERS AND GETTERS */ get blending() { return this.#blending || Program.BLENDING_NORMAL; } set blending(blending) { if(blending === Renderer.BLENDING_DEBUG) { if(!this.breakLog) { console.log(blending, Renderer.BLENDING_OFF, this.premultiplied) this.breakLog = true; } this.#blending = blending; this.ctx.enable(this.ctx.BLEND); this.ctx.blendFuncSeparate( this.ctx.ONE, this.ctx.ONE_MINUS_SRC_ALPHA, this.ctx.ONE, this.ctx.ONE_MINUS_SRC_ALPHA ); return; } this.#blending = blending; if(blending === Renderer.BLENDING_OFF) { this.ctx.disable(this.ctx.BLEND); this.#blendingEnabled = false; return; } if ( this.#blendingEnabled === false ) { this.ctx.enable(this.ctx.BLEND); // this.ctx.alphaFunc(this.ctx.GL_GREATER, 0.5); // this.ctx.enable(this.ctx.GL_ALPHA_TEST); this.#blendingEnabled = true; } if( this.premultiplied ) { switch (this.blending) { case Renderer.BLENDING_NORMAL: this.ctx.blendFuncSeparate( this.ctx.ONE, this.ctx.ONE_MINUS_SRC_ALPHA, this.ctx.ONE, this.ctx.ONE_MINUS_SRC_ALPHA ); break; case Renderer.BLENDING_ADDITIVE: this.ctx.blendFunc( this.ctx.ONE, this.ctx.ONE ); break; case Renderer.BLENDING_SUBTRACTIVE: this.ctx.blendFuncSeparate( this.ctx.ZERO, this.ctx.ZERO, this.ctx.ONE_MINUS_SRC_COLOR, this.ctx.ONE_MINUS_SRC_ALPHA ); break; case Renderer.BLENDING_MULTIPLY: this.ctx.blendFuncSeparate( this.ctx.ZERO, this.ctx.SRC_COLOR, this.ctx.ZERO, this.ctx.SRC_ALPHA ); break; } } else { switch (this.blending) { case Renderer.BLENDING_NORMAL: this.ctx.blendFuncSeparate( this.ctx.SRC_ALPHA, this.ctx.ONE_MINUS_SRC_ALPHA, this.ctx.ONE, this.ctx.ONE_MINUS_SRC_ALPHA ); break; case Renderer.BLENDING_ADDITIVE: this.ctx.blendFunc( this.ctx.SRC_ALPHA, this.ctx.ONE ); break; case Renderer.BLENDING_SUBTRACTIVE: this.ctx.blendFunc( this.ctx.ZERO, this.ctx.ONE_MINUS_SRC_COLOR ); break; case Renderer.BLENDING_MULTIPLY: this.ctx.blendFunc( this.ctx.ZERO, this.ctx.SRC_COLOR ); break; } } } } class Buffer { static #defaultAttribute = { numComponents: 2, offset: 0, stride: 0 }; static #defaults = { attributes: [{ name: 'position' } ], normalized: false, drawType: window.WebGLRenderingContext.STATIC_DRAW, type: window.WebGLRenderingContext.FLOAT } constructor(ctx, data, options) { this.ctx = ctx; this.name = name; options = Object.assign({}, Buffer.#defaults, options); this.attributes = options.attributes.map(a => Object.assign({}, Buffer.#defaultAttribute, a)); this.normalized = options.normalized; this.drawType = options.drawType; this.type = options.type; if(data instanceof Array) data = new Float32Array(data); this.data = data; this.buffer = ctx.createBuffer(); } link(program, hasBuffer = false) { let location = this.ctx.getAttribLocation(program, `a_${this.name}`); this.attributes.forEach(attribute => { const location = this.ctx.getAttribLocation(program, `a_${attribute.name}`); this.ctx.vertexAttribPointer(location, attribute.numComponents, this.type, this.normalized, attribute.stride, attribute.offset); this.ctx.enableVertexAttribArray(location); }); } get length() { return this.data.length; } } class Program { static RENDER_TRIANGLES = 0; static RENDER_STRIP = 1; static RENDER_LINES = 2; static RENDER_LINELOOP = 4; static RENDER_POINTS = 8; static #defaultOptions = { renderType: Program.RENDER_TRIANGLES, clearColour: [1.0, 1.0, 1.0, 1.0], blending: Renderer.BLENDING_OFF, premultiplied: true, transparent: false, depthTesting: true } #vShader #fShader #p #renderType constructor(ctx, vertexShaderSource, fragmentShaderSource, options = {}) { options = Object.assign({}, Program.#defaultOptions, options); this.ctx = ctx; this.renderType = options.renderType; this.clearColour = options.clearColour; this.blending = options.blending; this.premultiplied = options.premultiplied; this.transparent = options.transparent; this.depthTesting = options.depthTesting; // Create the shaders this.vShader = Program.createShaderOfType(this.ctx, this.ctx.VERTEX_SHADER, vertexShaderSource); this.fShader = Program.createShaderOfType(this.ctx, this.ctx.FRAGMENT_SHADER, fragmentShaderSource); // Create the program and link the shaders this.#p = this.ctx.createProgram(); this.ctx.attachShader(this.#p, this.vShader); this.ctx.attachShader(this.#p, this.fShader); this.ctx.linkProgram(this.#p); // Check the result of linking var linked = this.ctx.getProgramParameter(this.#p, this.ctx.LINK_STATUS); if (!linked) { var error = this.ctx.getProgramInfoLog(this.#p); console.log('Failed to link program: ' + error); this.ctx.deleteProgram(this.#p); this.ctx.deleteShader(this.fShader); this.ctx.deleteShader(this.vShader); } } get program() { return this.#p; } /* SETTERS AND GETTERS */ set renderType(value) { if([ Program.RENDER_TRIANGLES, Program.RENDER_STRIP, Program.RENDER_LINES, Program.RENDER_LINELOOP, Program.RENDER_POINTS ].indexOf(value) > -1) this.#renderType = value; } get renderType() { return this.#renderType; } /** * Static Methods */ /** * Create a shader of a given type given a context, type and source. * * @static * @param {WebGLContext} ctx The context under which to create the shader * @param {WebGLShaderType} type The shader type, vertex or fragment * @param {string} source The shader source. * @return {WebGLShader} The created shader */ static createShaderOfType(ctx, type, source) { const shader = ctx.createShader(type); ctx.shaderSource(shader, source); ctx.compileShader(shader); // Check the compile status const compil.........完整代码请登录后点击上方下载按钮下载查看
网友评论0