From a06021531d94705269598238ddfbdd677606660a Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Mon, 28 Aug 2023 13:06:53 +0800 Subject: [PATCH] =?UTF-8?q?=E7=9D=80=E8=89=B2=E5=99=A8=E7=89=B9=E6=95=88?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=8A=A8=E7=94=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/fx/shader.ts | 127 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 109 insertions(+), 18 deletions(-) diff --git a/src/core/fx/shader.ts b/src/core/fx/shader.ts index 0e7ffce..269efec 100644 --- a/src/core/fx/shader.ts +++ b/src/core/fx/shader.ts @@ -1,6 +1,6 @@ -import { Ticker } from 'mutate-animate'; +import { Animation, Ticker, hyper } from 'mutate-animate'; import { EmitableEvent, EventEmitter } from '../common/eventEmitter'; -import { loading } from '../loader/load'; +import { ensureArray } from '../../plugin/utils'; interface ShaderEvent extends EmitableEvent {} @@ -33,6 +33,32 @@ interface MixedImage { update(): void; } +type UniformBinderNum = 1 | 2 | 3 | 4; +type UniformBinderType = 'f' | 'i'; +type UniformFunc< + N extends UniformBinderNum, + T extends UniformBinderType, + V extends 'v' | '' +> = `uniform${N}${T}${V}`; + +type UniformBinderValue = N extends 1 + ? number + : N extends 2 + ? [number, number] + : N extends 3 + ? [number, number, number] + : [number, number, number, number]; + +interface UniformBinder< + N extends UniformBinderNum, + T extends UniformBinderType, + V extends 'v' | '' +> { + value: UniformBinderValue; + set(value: UniformBinderValue): void; + get(): UniformBinderValue; +} + const builtinVs = ` #ifdef GL_ES precision highp float; @@ -106,25 +132,31 @@ export class ShaderEffect extends EventEmitter { * @param compile 是否重新编译着色器脚本,并重新创建纹理 */ update(compile: boolean = false) { - const gl = this.gl; - if (compile) { - gl.deleteProgram(this.program); - gl.deleteTexture(this.texture); - gl.deleteBuffer(this.buffer?.position ?? null); - gl.deleteBuffer(this.buffer?.texture ?? null); - gl.deleteShader(this.shader?.vertex ?? null); - gl.deleteShader(this.shader?.fragment ?? null); - - this.program = this.createProgram(); - this.programInfo = this.getProgramInfo(); - this.buffer = this.initBuffers(); - this.texture = this.createTexture(); - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); - } + if (compile) this.compile(); this.textureCanvas?.update(); this.drawScene(); } + /** + * 仅重新编译着色器,不进行纹理创建和特效渲染 + */ + compile() { + const gl = this.gl; + gl.deleteProgram(this.program); + gl.deleteTexture(this.texture); + gl.deleteBuffer(this.buffer?.position ?? null); + gl.deleteBuffer(this.buffer?.texture ?? null); + gl.deleteShader(this.shader?.vertex ?? null); + gl.deleteShader(this.shader?.fragment ?? null); + + this.program = this.createProgram(); + this.programInfo = this.getProgramInfo(); + this.buffer = this.initBuffers(); + this.texture = this.createTexture(); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); + gl.useProgram(this.program); + } + /** * 设置顶点着色器,使用 glsl 编写,插件提供了一些新的 api * 着色器中必须包含 main 函数,同时为 gl_Position 赋值 @@ -182,6 +214,64 @@ export class ShaderEffect extends EventEmitter { gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); } + /** + * 创建一个全局变量绑定器,用于操作全局变量 + * @param uniform 全局变量的变量名 + * @param num 变量的元素数量,float和int视为1,vec2 vec3 vec4分别视为 2 3 4 + * @param type 数据类型,可以填'f',表示浮点型,或者填'i',表示整型 + * @param vector 是否为向量,可以填'v',表示是向量,或者填'',表示不是向量 + * @returns 一个uniform绑定器,用于操作全局变量uniform + */ + createUniformBinder< + N extends UniformBinderNum, + T extends UniformBinderType, + V extends 'v' | '' + >(uniform: string, num: N, type: T, vector: V): UniformBinder { + if (!this.program) { + throw new Error( + `Uniform binder should be use when the program initialized.` + ); + } + + const suffix = `${num}${type}${vector ? 'v' : ''}`; + const func = `uniform${suffix}` as UniformFunc; + const value = ( + num === 1 ? 0 : Array(num).fill(0) + ) as UniformBinderValue; + + const loc = this.gl.getUniformLocation(this.program, uniform); + const gl = this.gl; + + return { + value, + set(value) { + this.value = value; + let v; + if (vector === 'v') { + let _v = ensureArray(value); + if (type === 'f') { + v = new Float32Array(_v); + } else { + v = new Int32Array(_v); + } + } else { + v = ensureArray(value); + } + // 对uniform赋值 + if (vector === 'v') { + // @ts-ignore + gl[func](loc, v); + } else { + // @ts-ignore + gl[func](loc, ...v); + } + }, + get() { + return this.value; + } + }; + } + private createProgram() { const gl = this.gl; const vs = this.loadShader(gl.VERTEX_SHADER, this.vsSource); @@ -398,7 +488,8 @@ export function replaceGameCanvas(effect: ShaderEffect, canvas: string[]) { let zIndex = 0; canvas.forEach(v => { const canvas = core.canvas[v].canvas; - const z = parseInt(canvas.style.zIndex); + const style = getComputedStyle(canvas); + const z = parseInt(style.zIndex); if (z > zIndex) zIndex = z; canvas.style.display = 'none'; });