blobt
4 years ago
6 changed files with 401 additions and 2 deletions
-
3src/App.tsx
-
32src/render/common.ts
-
285src/render/webgl/WebGLHepler.ts
-
3src/render/webgl/WebGLMesh.ts
-
3src/render/webgl/WebGLProgram.ts
-
75src/render/webgl/WebGLTexture.ts
@ -1 +1,33 @@ |
|||||
export let EPSILON: number = 0.0001; |
export let EPSILON: number = 0.0001; |
||||
|
|
||||
|
export enum EShaderType { |
||||
|
VS_SHADER, |
||||
|
FS_SHADER |
||||
|
} |
||||
|
|
||||
|
export enum EGLSLESDataType { |
||||
|
FLOAT_VEC2 = 0x8B50, |
||||
|
FLOAT_VEC3, |
||||
|
FLOAT_VEC4, |
||||
|
INT_VEC2, |
||||
|
INT_VEC3, |
||||
|
INT_VEC4, |
||||
|
BOOL, |
||||
|
BOOL_VEC2, |
||||
|
BOOL_VEC3, |
||||
|
BOOL_VEC4, |
||||
|
FLOAT_MAT2, |
||||
|
FLOAT_MAT3, |
||||
|
FLOAT_MAT4, |
||||
|
SAMPLER_2D, |
||||
|
SAMPLER_CUBE, |
||||
|
|
||||
|
FLOAT = 0x1406, |
||||
|
INT = 0x1404 |
||||
|
} |
||||
|
|
||||
|
export enum EGLTexWrapType { |
||||
|
GL_REPEAT, //设置为gl对应的常量
|
||||
|
GL_MIRRORED_REPEAT, |
||||
|
GL_CLAMP_TO_EDGE |
||||
|
} |
@ -0,0 +1,285 @@ |
|||||
|
import { EShaderType, EGLSLESDataType } from "../common"; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* uniform参数 |
||||
|
*/ |
||||
|
export class GLUniformInfo { |
||||
|
public size: number; |
||||
|
public type: EGLSLESDataType; |
||||
|
public location: WebGLUniformLocation; |
||||
|
|
||||
|
public constructor(size: number, type: number, loc: WebGLUniformLocation) { |
||||
|
this.size = size; |
||||
|
this.type = type; |
||||
|
this.location = loc; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export class GLAttribInfo { |
||||
|
public size: number; |
||||
|
public type: EGLSLESDataType; |
||||
|
public location: number; |
||||
|
public constructor(size: number, type: number, loc: number) { |
||||
|
this.size = size; |
||||
|
this.type = type; |
||||
|
this.location = loc; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export type GLUinformMap = { [key: string]: GLUniformInfo }; |
||||
|
export type GLAttribMap = { [key: string]: GLAttribInfo }; |
||||
|
|
||||
|
export class GLHelper { |
||||
|
|
||||
|
/** |
||||
|
* 打印webgl上下文的各个状态 |
||||
|
* @param gl |
||||
|
*/ |
||||
|
public static printStates(gl: WebGLRenderingContext): void { |
||||
|
// 所有的boolean状态变量,共9个
|
||||
|
console.log("1. isBlendEnable = " + gl.isEnabled(gl.BLEND)); |
||||
|
console.log("2. isCullFaceEnable = " + gl.isEnabled(gl.CULL_FACE)); |
||||
|
console.log("3. isDepthTestEnable = " + gl.isEnabled(gl.DEPTH_TEST)); |
||||
|
console.log("4. isDitherEnable = " + gl.isEnabled(gl.DITHER)); |
||||
|
console.log("5. isPolygonOffsetFillEnable = " + gl.isEnabled(gl.POLYGON_OFFSET_FILL)); |
||||
|
console.log("6. isSampleAlphtToCoverageEnable = " + gl.isEnabled(gl.SAMPLE_ALPHA_TO_COVERAGE)); |
||||
|
console.log("7. isSampleCoverageEnable = " + gl.isEnabled(gl.SAMPLE_COVERAGE)); |
||||
|
console.log("8. isScissorTestEnable = " + gl.isEnabled(gl.SCISSOR_TEST)); |
||||
|
console.log("9. isStencilTestEnable = " + gl.isEnabled(gl.STENCIL_TEST)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 打印webgl信息 |
||||
|
* @param gl |
||||
|
*/ |
||||
|
public static printWebGLInfo(gl: WebGLRenderingContext): void { |
||||
|
console.log("renderer = " + gl.getParameter(gl.RENDERER)); |
||||
|
console.log("version = " + gl.getParameter(gl.VERSION)); |
||||
|
console.log("vendor = " + gl.getParameter(gl.VENDOR)); |
||||
|
console.log("glsl version = " + gl.getParameter(gl.SHADING_LANGUAGE_VERSION)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取textture信息 |
||||
|
* @param gl |
||||
|
*/ |
||||
|
public static printWebGLTextureInfo(gl: WebGLRenderingContext): void { |
||||
|
console.log("MAX_COMBINED_TEXTURE_IMAGE_UINTS = ", gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS)); |
||||
|
console.log("MAX_TEXTURE_IMAGE_UNITS = ", gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS)); |
||||
|
console.log("MAX_TEXTURE_SIZE = ", gl.getParameter(gl.MAX_TEXTURE_SIZE)); |
||||
|
console.log("MAX_CUBE_MAP_TEXTURE_SIZE", gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 触发context lose 事件 |
||||
|
* @param gl |
||||
|
*/ |
||||
|
public static triggerContextLosEvent(gl: WebGLRenderingContext): void { |
||||
|
let context: WEBGL_lose_context | null = gl.getExtension('WEBGL_lose_context'); |
||||
|
if (context !== null) { |
||||
|
context.loseContext(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取webgl错误 |
||||
|
* @param gl |
||||
|
*/ |
||||
|
public static checkGLError(gl: WebGLRenderingContext): boolean { |
||||
|
let err: number = gl.getError(); |
||||
|
if (err === 0) { |
||||
|
return false; |
||||
|
} else { |
||||
|
console.log("WebGL ERROR NO: ", err); |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置webgl的默认状态 |
||||
|
* @param gl |
||||
|
*/ |
||||
|
public static setDefaultState(gl: WebGLRenderingContext): void { |
||||
|
gl.clearColor(0.0, 0.0, 0.0, 0.0);//每次清屏时,将颜色缓冲区设置全透明 黑色
|
||||
|
gl.clearDepth(1.0);//每次清屏时,将深度缓冲区设置成1.0
|
||||
|
gl.enable(gl.DEPTH_TEST); //每次清屏时候开始深度测试
|
||||
|
gl.enable(gl.CULL_FACE);//每次清屏时候开始背面剔除
|
||||
|
gl.enable(gl.SCISSOR_TEST);//每次清屏时候开启剪切测试
|
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置webgl的视口 |
||||
|
* @param gl |
||||
|
* @param v |
||||
|
*/ |
||||
|
public static setViewport(gl: WebGLRenderingContext, v: number[]) { |
||||
|
gl.viewport(v[0], v[1], v[2], v[3]); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建着色器 |
||||
|
* @param gl |
||||
|
* @param type |
||||
|
* @returns |
||||
|
*/ |
||||
|
public static createShader(gl: WebGLRenderingContext, type: EShaderType): WebGLShader { |
||||
|
let ret: WebGLShader | null = null; |
||||
|
|
||||
|
if (type === EShaderType.VS_SHADER) { |
||||
|
ret = gl.createShader(gl.VERTEX_SHADER); |
||||
|
} else { |
||||
|
ret = gl.createShader(gl.FRAGMENT_SHADER); |
||||
|
} |
||||
|
|
||||
|
if (ret === null) { |
||||
|
throw new Error("WebGLShader create failed!"); |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 编译着色器 |
||||
|
* @param gl |
||||
|
* @param code |
||||
|
* @param shader |
||||
|
* @returns |
||||
|
*/ |
||||
|
public static compileShader(gl: WebGLRenderingContext, code: string, shader: WebGLShader): boolean { |
||||
|
gl.shaderSource(shader, code);//载入shader源码
|
||||
|
gl.compileShader(shader); |
||||
|
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS) === false) { |
||||
|
alert(gl.getShaderInfoLog(shader));//如果编译出错,弹出出错信息
|
||||
|
gl.deleteShader(shader); |
||||
|
return false; |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建链接器对象 |
||||
|
* @param gl |
||||
|
* @returns |
||||
|
*/ |
||||
|
public static createProgram(gl: WebGLRenderingContext): WebGLProgram { |
||||
|
let ret: WebGLProgram | null = gl.createProgram(); |
||||
|
if (ret === null) { |
||||
|
throw new Error("WebGLProgram create falied!"); |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* |
||||
|
* @param gl 渲染上下文对象 |
||||
|
* @param program 链接器对象 |
||||
|
* @param vsShader 顶点着色器 |
||||
|
* @param fsShader 片段着色器 |
||||
|
* @param beforeProgramLink 链接前执行函数 |
||||
|
* @param afterProgramLink 链接后执行函数 |
||||
|
*/ |
||||
|
public static linkProgram( |
||||
|
gl: WebGLRenderingContext, |
||||
|
program: WebGLProgram, |
||||
|
vsShader: WebGLShader, |
||||
|
fsShader: WebGLShader, |
||||
|
beforeProgramLink: ((gl: WebGLRenderingContext, program: WebGLProgram) => void) | null = null, |
||||
|
afterProgramLink: ((gl: WebGLRenderingContext, program: WebGLProgram) => void) | null = null |
||||
|
): boolean { |
||||
|
|
||||
|
gl.attachShader(program, vsShader); |
||||
|
gl.attachShader(program, fsShader); |
||||
|
|
||||
|
if (beforeProgramLink !== null) { |
||||
|
beforeProgramLink(gl, program); |
||||
|
} |
||||
|
|
||||
|
gl.linkProgram(program); |
||||
|
if (gl.getProgramParameter(program, gl.LINK_STATUS) === false) { |
||||
|
alert(gl.getProgramInfoLog(program)); |
||||
|
gl.deleteShader(vsShader); |
||||
|
gl.deleteShader(fsShader); |
||||
|
gl.deleteProgram(program); |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
gl.validateProgram(program); |
||||
|
if (gl.getProgramParameter(program, gl.VALIDATE_STATUS) === false) { |
||||
|
alert(gl.getProgramInfoLog(program)); |
||||
|
gl.deleteShader(vsShader); |
||||
|
gl.deleteShader(fsShader); |
||||
|
gl.deleteProgram(program); |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (afterProgramLink !== null) { |
||||
|
afterProgramLink(gl, program); |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取生效的attribute |
||||
|
* @param gl |
||||
|
* @param program |
||||
|
* @param out |
||||
|
*/ |
||||
|
public static getProgramActiveAttribs(gl: WebGLRenderingContext, program: WebGLProgram, out: GLAttribMap): void { |
||||
|
|
||||
|
let count: number = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);//获取当前active状态的attribute的数量, active_attributes/uniforms必须在link后才能获得
|
||||
|
|
||||
|
for (let i = 0; i < count; i++) { |
||||
|
let info: WebGLActiveInfo | null = gl.getActiveAttrib(program, i); |
||||
|
if (info) { |
||||
|
out[info.name] = new GLAttribInfo(info.size, info.type, gl.getAttribLocation(program, info.name)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取生效的uniform |
||||
|
* @param gl |
||||
|
* @param program |
||||
|
* @param out |
||||
|
*/ |
||||
|
public static getProgramActiveUniforms(gl: WebGLRenderingContext, program: WebGLProgram, out: GLUinformMap): void { |
||||
|
let count: number = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); |
||||
|
|
||||
|
for (let i = 0; i < count; i++) { |
||||
|
let info: WebGLActiveInfo | null = gl.getActiveUniform(program, i); |
||||
|
if (info) { |
||||
|
let loc: WebGLUniformLocation | null = gl.getUniformLocation(program, info.name); |
||||
|
if (loc !== null) { |
||||
|
out[info.name] = new GLUniformInfo(info.size, info.type, loc); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建一个webgl buffer |
||||
|
* @param gl |
||||
|
* @returns |
||||
|
*/ |
||||
|
public static createBuffer(gl: WebGLRenderingContext): WebGLBuffer { |
||||
|
let ret: WebGLBuffer | null = gl.createBuffer(); |
||||
|
if (ret === null) { |
||||
|
throw new Error("webgl create buffer failed!"); |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建color buffer |
||||
|
* @param gl |
||||
|
* @returns |
||||
|
*/ |
||||
|
public static getColorBufferData(gl: WebGLRenderingContext): Uint8Array { |
||||
|
let ret: Uint8Array = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4); |
||||
|
gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, ret); |
||||
|
return ret; |
||||
|
} |
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
export abstract class GLMeshBase { |
||||
|
|
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
export class GLProgram { |
||||
|
|
||||
|
} |
@ -0,0 +1,75 @@ |
|||||
|
import { EGLTexWrapType } from "../common"; |
||||
|
import { GLHelper } from "./WebGLHepler"; |
||||
|
|
||||
|
|
||||
|
export class GLTexture { |
||||
|
|
||||
|
public gl: WebGLRenderingContext; |
||||
|
public isMipmap: boolean; //是否使用了mipmap
|
||||
|
public width: number; |
||||
|
public height: number; |
||||
|
public format: number; //在内存或显存中的存储格式,默认是gl.RGBA
|
||||
|
public type: number; //像素的数据类型,默认是gl.UNSIGNED_BYTE
|
||||
|
public texture: WebGLTexture; |
||||
|
public target: number; //gl.TEXTURE_2D
|
||||
|
public name: string; //纹理的名称
|
||||
|
|
||||
|
public constructor(gl: WebGLRenderingContext, name: string = '') { |
||||
|
this.gl = gl; |
||||
|
this.isMipmap = false; |
||||
|
this.width = this.height = 0; |
||||
|
this.format = gl.RGBA; |
||||
|
this.type = gl.UNSIGNED_BYTE; |
||||
|
let tex: WebGLTexture | null = gl.createTexture(); |
||||
|
if (tex === null) { |
||||
|
throw new Error("WebGL texture create falied!"); |
||||
|
} |
||||
|
this.texture = tex; |
||||
|
this.target = gl.TEXTURE_2D; |
||||
|
this.name = name; |
||||
|
this.wrap(); |
||||
|
this.filter(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断是否是2的倍数 |
||||
|
* @param x |
||||
|
* @returns |
||||
|
*/ |
||||
|
public static isPowerOfTwo(x: number) { |
||||
|
return (x & (x - 1)) == 0; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 纹理包装设置 |
||||
|
* @param mode |
||||
|
*/ |
||||
|
public wrap(mode: EGLTexWrapType = EGLTexWrapType.GL_REPEAT): void { |
||||
|
this.gl.bindTexture(this.target, this.texture); |
||||
|
if (mode === EGLTexWrapType.GL_CLAMP_TO_EDGE) { |
||||
|
this.gl.texParameteri(this.target, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); |
||||
|
this.gl.texParameteri(this.target, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); |
||||
|
} else if (mode === EGLTexWrapType.GL_REPEAT) { |
||||
|
this.gl.texParameteri(this.target, this.gl.TEXTURE_WRAP_S, this.gl.REPEAT); |
||||
|
this.gl.texParameteri(this.target, this.gl.TEXTURE_WRAP_T, this.gl.REPEAT); |
||||
|
} else { |
||||
|
this.gl.texParameteri(this.target, this.gl.TEXTURE_WRAP_S, this.gl.MIRRORED_REPEAT); |
||||
|
this.gl.texParameteri(this.target, this.gl.TEXTURE_WRAP_T, this.gl.MIRRORED_REPEAT); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置纹理滤波 |
||||
|
* @param minLinear |
||||
|
* @param magLinear |
||||
|
*/ |
||||
|
public filter(minLinear: boolean = true, magLinear: boolean = true): void { |
||||
|
this.gl.bindTexture(this.target, this.texture); |
||||
|
if (this.isMipmap) { |
||||
|
this.gl.texParameteri(this.target, this.gl.TEXTURE_MIN_FILTER, minLinear ? this.gl.LINEAR_MIPMAP_LINEAR : this.gl.NEAREST_MIPMAP_NEAREST); |
||||
|
} else { |
||||
|
this.gl.texParameteri(this.target, this.gl.TEXTURE_MIN_FILTER, minLinear ? this.gl.LINEAR : this.gl.NEAREST); |
||||
|
} |
||||
|
this.gl.texParameteri(this.target, this.gl.TEXTURE_MIN_FILTER, magLinear ? this.gl.LINEAR : this.gl.NEAREST); |
||||
|
} |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue