blobt
4 years ago
1 changed files with 427 additions and 0 deletions
@ -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 { |
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; |
||||
|
} |
||||
} |
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue