From 0b0aaa5b2a6e9428b34246f99a8306e640d17e88 Mon Sep 17 00:00:00 2001 From: blobt Date: Fri, 30 Apr 2021 12:26:24 +0800 Subject: [PATCH] =?UTF-8?q?WebGLProgram=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/render/webgl/WebGLProgram.ts | 427 +++++++++++++++++++++++++++++++ 1 file changed, 427 insertions(+) diff --git a/src/render/webgl/WebGLProgram.ts b/src/render/webgl/WebGLProgram.ts index 7648b302..8dd17192 100755 --- a/src/render/webgl/WebGLProgram.ts +++ b/src/render/webgl/WebGLProgram.ts @@ -1,3 +1,430 @@ +import { GLAttribBits, GLAttribState } from "./WebGLAttribState"; +import { vec2, vec3, vec4, mat4, quat } from "../math"; +import { GLTexture } from "./WebGLTexture"; +import { GLShaderSource } from "./WebGLShaderSource"; +import { GLHelper, GLAttribMap, GLUinformMap } from "./WebGLHepler"; +import { EShaderType } from "../common"; + export class GLProgram { + public static readonly MVMatrix: string = "uMVMatrix"; + public static readonly ModelMatrix: string = "uModelMatrix"; + public static readonly ViewMatrix: string = "uViewMatrix"; + public static readonly ProjectMatrix: string = "uProjectMatrix"; + public static readonly NormalMatrix: string = "uNormalMatrix"; + public static readonly MVPMatrix: string = "uMVPMatrix"; + public static readonly Color: string = "uColor"; + + public static readonly Sampler: string = "uSampler"; //纹理采样器 + public static readonly DiffuseSampler: string = "uDiffuseSampler"; //漫反射采样器 + public static readonly NormalSampler: string = "uNormalSampler"; //法线采样器 + public static readonly SpecularSampler: string = "uSpecularSampler"; //高光采样器 + public static readonly DepthSampler: string = "uDepthSampler"; //高光采样器 + + /** + * @var WebGL上下文 + */ + public gl: WebGLRenderingContext; + + /** + * @var program name + */ + public name: string; + + /** + * @var 顶点属性的bits值 + */ + private _attribuState: GLAttribBits; + + /** + * @var 连接器 + */ + public program: WebGLProgram; + + /** + * @var vs编译器 + */ + public vsShader: WebGLShader; + + /** + * @var fs编译器 + */ + public fsShader: WebGLShader; + + + /** + * @var 存储所有attribute + */ + public attribMap: GLAttribMap; + + /** + * @var 存储所有 uniform + */ + public uniformMap: GLUinformMap; + + /** + * @function 当调用gl.useProgram(this.program)后触发bindCallback回调 + */ + public bindCallback: ((program: GLProgram) => void) | null; + + /** + * @function 当调用gl.useProgram(null)前触发unbindCallback回调函数 + */ + public unbindCallback: ((program: GLProgram) => void) | null; + + /** + * @arr + */ + private _vsShaderDefineStrings: string[] = []; + + /** + * @arr + */ + private _fsShaderDefineStrings: string[] = []; + + /** + * 获取顶点属性bits值 + */ + public get attribState(): GLAttribBits { + return this._attribuState; + } + + /** + * + */ + private programBeforeLink(gl: WebGLRenderingContext, program: WebGLProgram): void { + if (GLAttribState.hasPosition(this._attribuState)) { + gl.bindAttribLocation(program, GLAttribState.POSITION_LOCATION, GLAttribState.POSITION_NAME); + } + if (GLAttribState.hasNormal(this._attribuState)) { + gl.bindAttribLocation(program, GLAttribState.NORMAL_LOCATION, GLAttribState.NORMAL_NAME); + } + if (GLAttribState.hasTexCoord_0(this._attribuState)) { + gl.bindAttribLocation(program, GLAttribState.TEXCOORD_LOCATION, GLAttribState.TEXCOORD_NAME); + } + if (GLAttribState.hasTexCoord_1(this._attribuState)) { + gl.bindAttribLocation(program, GLAttribState.TEXCOORD1_LOCATION, GLAttribState.TEXCOORD1_NAME); + } + if (GLAttribState.hasColor(this._attribuState)) { + gl.bindAttribLocation(program, GLAttribState.COLOR_LOCATION, GLAttribState.COLOR_NAME); + } + if (GLAttribState.hasTangent(this._attribuState)) { + gl.bindAttribLocation(program, GLAttribState.TANGENT_LOCATION, GLAttribState.TANGENT_NAME); + } + } + + /** + * 把attribute 和 uniform 读入 相应map + * @param gl + * @param program + */ + private programAfterLink(gl: WebGLRenderingContext, program: WebGLProgram): void { + GLHelper.getProgramActiveAttribs(gl, program, this.attribMap); + GLHelper.getProgramActiveUniforms(gl, program, this.uniformMap); + } + + public constructor(context: WebGLRenderingContext, attribState: GLAttribBits, vsShader: string | null = null, fsShader: string | null = null, name: string = "") { + this.gl = context; + this._attribuState = attribState; + this.bindCallback = null; + this.unbindCallback = null; + + let shader: WebGLShader | null = GLHelper.createShader(this.gl, EShaderType.VS_SHADER); + if (shader === null) { + throw new Error("create vertex shader failed!"); + } + this.vsShader = shader; + + shader = null; + shader = GLHelper.createShader(this.gl, EShaderType.FS_SHADER); + if (shader === null) { + throw new Error("create fragment shader failed!"); + } + this.fsShader = shader; + + let program: WebGLProgram | null = GLHelper.createProgram(this.gl); + if (program === null) { + throw new Error("create webgl program failed!"); + } + this.program = program; + + this.attribMap = {}; + this.uniformMap = {}; + + if (vsShader !== null && fsShader !== null) { + this.loadShader(vsShader, fsShader); + } + + this.name = name; + } + + /** + * 在Vertex Shader中动态添加宏 + * @param str + */ + public addVSShaderMacro(str: string): void { + if (str.indexOf("#define ") === -1) { + str = "#define " + str; + } + this._vsShaderDefineStrings.push(str); + } + + /** + * 在fragment Shader中动态添加宏 + * @param str + */ + public addFSShaderMacro(str: string): void { + if (str.indexOf("#define ") === -1) { + str = "#define " + str; + } + this._fsShaderDefineStrings.push(str); + } + + /** + * 编译和链接shader到program + * @param vs + * @param fs + */ + public loadShader(vs: string, fs: string): void { + if (this._vsShaderDefineStrings.length > 0) { + let join: string = this._vsShaderDefineStrings.join("\n"); + vs = join + vs; + } + if (this._fsShaderDefineStrings.length > 0) { + let join: string = this._fsShaderDefineStrings.join("\n"); + fs = join + fs; + } + + if (GLHelper.compileShader(this.gl, vs, this.vsShader) === false) { + throw new Error("compiler vs shader failed!"); + } + + if (GLHelper.compileShader(this.gl, fs, this.fsShader) === false) { + throw new Error("compiler fs shader failed!"); + } + + if (GLHelper.linkProgram(this.gl, this.program, this.vsShader, this.fsShader, this.programBeforeLink.bind(this), this.programAfterLink.bind(this)) === false) { + throw new Error("link program failed!"); + } + } + + /** + * + */ + public bind(): void { + this.gl.useProgram(this.program); + if (this.bindCallback !== null) { + this.bindCallback(this); + } + } + + /** + * + */ + public unbind(): void { + if (this.unbindCallback !== null) { + this.unbindCallback(this); + } + this.gl.useProgram(null); + } + + /** + * 获取uniform 地址 + * @param name + * @returns + */ + public getUniformLocation(name: string): WebGLUniformLocation | null { + return this.gl.getUniformLocation(this.program, name); + } + + /** + * 获取attribute地址 + * @param name + * @returns + */ + public getAttributeLocation(name: string): number { + return this.gl.getAttribLocation(this.program, name); + } + + /** + * 设置attribute地址 + * @param name + * @returns + */ + public setAttributeLocation(name: string, loc: number): void { + this.gl.bindAttribLocation(this.program, loc, name); + } + + /** + * 设置整数uniform + * @param name + * @param i + * @returns + */ + public setInt(name: string, i: number): boolean { + let loc: WebGLUniformLocation | null = this.getUniformLocation(name); + if (loc !== null) { + this.gl.uniform1i(loc, i); + return true; + } + return false; + } + + /** + * 设置浮点数uniform + * @param name + * @param i + * @returns + */ + public setFloat(name: string, f: number): boolean { + let loc: WebGLUniformLocation | null = this.getUniformLocation(name); + if (loc !== null) { + this.gl.uniform1f(loc, f); + return true; + } + return false; + } + + /** + * 设置二位向量 uniform + * @param name + * @param i + * @returns + */ + public setVector2(name: string, v: vec2): boolean { + let loc: WebGLUniformLocation | null = this.getUniformLocation(name); + if (loc !== null) { + this.gl.uniform2fv(loc, v.values); + return true; + } + return false; + } + + /** + * 设置三位向量 uniform + * @param name + * @param i + * @returns + */ + public setVector3(name: string, v: vec3): boolean { + let loc: WebGLUniformLocation | null = this.getUniformLocation(name); + if (loc !== null) { + this.gl.uniform3fv(loc, v.values); + return true; + } + return false; + } + + /** + * 设置四位向量 uniform + * @param name + * @param i + * @returns + */ + public setVector4(name: string, v: vec4): boolean { + let loc: WebGLUniformLocation | null = this.getUniformLocation(name); + if (loc !== null) { + this.gl.uniform4fv(loc, v.values); + return true; + } + return false; + } + + /** + * 设置四元数 uniform + * @param name + * @param i + * @returns + */ + public setQuat(name: string, q: quat): boolean { + let loc: WebGLUniformLocation | null = this.getUniformLocation(name); + if (loc !== null) { + this.gl.uniform4fv(loc, q.values); + return true; + } + return false; + } + + /** + * 设置三维矩阵 uniform + * @param name + * @param i + * @returns + */ + public setMatrix3(name: string, m: mat4): boolean { + let loc: WebGLUniformLocation | null = this.getUniformLocation(name); + if (loc !== null) { + this.gl.uniformMatrix3fv(loc, false, m.values); + return true; + } + return false; + } + + /** + * 设置四维矩阵 uniform + * @param name + * @param i + * @returns + */ + public setMatrix4(name: string, m: mat4): boolean { + let loc: WebGLUniformLocation | null = this.getUniformLocation(name); + if (loc !== null) { + this.gl.uniformMatrix4fv(loc, false, m.values); + return true; + } + return false; + } + + /** + * 设置采样器 uniform + * @param name + * @param i + * @returns + */ + public setSampler(name: string, s: number): boolean { + let loc: WebGLUniformLocation | null = this.getUniformLocation(name); + if (loc !== null) { + this.gl.uniform1i(loc, s); + return true; + } + return false; + } + + /** + * 加载模型视图矩阵 + * @param mat + * @returns + */ + public loadModelViewMatrix(mat: mat4): boolean { + return this.setMatrix4(GLProgram.MVMatrix, mat); + } + + /** + * 载入采样器 + * @param unit + * @returns + */ + public loadSampler(unit: number = 0): boolean { + return this.setSampler(GLProgram.Sampler, unit); + } + + /** + * 创建默认材质贴图program + * @param gl + * @returns + */ + public static createDefaultTextureProgram(gl: WebGLRenderingContext): GLProgram { + let ret: GLProgram = new GLProgram(gl, GLAttribState.makeVertexAttribs(true, false, false, false, false), GLShaderSource.textureShader.vs, GLShaderSource.textureShader.fs) + return ret; + } + + /** + * 创建颜色贴图program + * @param gl + * @returns + */ + public static createDefaultColorProgram(gl: WebGLRenderingContext): GLProgram { + let ret: GLProgram = new GLProgram(gl, GLAttribState.makeVertexAttribs(false, false, false, false, true), GLShaderSource.colorShader.vs, GLShaderSource.colorShader.fs) + return ret; + } } \ No newline at end of file