WebGL

重要通知

webGL基本概况

WebGL(Web 图形库)是一个 JavaScript API,可在任何兼容的 Web 浏览器中渲染高性能的交互式 3D 和 2D 图形,而无需使用插件。

const canvas = document.createElement('canvas');
const width = document.body.clientWidth;
const height = document.body.clientHeight;
canvas.setAttribute('width', width);
canvas.setAttribute('height', height);
document.body.append(canvas);

const gl = canvas.getContext("webgl");

webGL实现原理

着色器 shader

着色器是一个绘制东西到屏幕上的函数。

  • 顶点着色器

用来描述顶点特性(位置、颜色等)的程序。

const VSHADER_SOURCE = ``;
  • 片元着色器

进行逐片元处理的程序,其中,片元指图像的单元。

const FSHADER_SOURCE = ``;
  • 初始化着色器
Eshen.initShaderProgram = function(vsSource, fsSource) {
  const vertexShader = Eshen.loadShader(gl.VERTEX_SHADER, vsSource);
  const fragmentShader = Eshen.loadShader(gl.FRAGMENT_SHADER, fsSource);

  if (!vertexShader || !fragmentShader) {
    throw new Error(`vertexShader or fragmentShader is null or undefined.`);
  }

  // 创建着色器程序
  const program = gl.createProgram();

  if (!program || !gl.isProgram(program)) {
    gl.deleteProgram(program);
    return null;
  }
  // 添加预先存在的着色器
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);

  gl.linkProgram(program);
  gl.validateProgram(program);

  // 是否编译成功
  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
    console.log('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
    gl.deleteProgram(program);
    gl.deleteShader(fragmentShader);
    gl.deleteShader(vertexShader);
    return null;
  }

  return program;
}
  • 加载着色器程序
Eshen.loadShader = function(type, source) {
  // 创建一个新的着色器
  const shader = gl.createShader(type); 

  if (!shader || !gl.isShader(shader)) {
    return null;
  }

  gl.shaderSource(shader, source); // 将源代码发送到着色器
  gl.compileShader(shader); // 编译一个GLSL着色器,使其成为为二进制数据

  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    // 异常时删除着色器代码,释放连接着色器程序的内存
    var error = gl.getShaderInfoLog(shader);
    console.log('Failed to compile shader: ' + error);
    gl.deleteShader(shader);
    return null;
  }
  return shader;
}
  • 初始化Buffer缓冲区
Eshen.initBuffer = function(vertices = new Float32Array([]), n, program) {
  const vertexBuffer = gl.createBuffer();
  if (!vertexBuffer) {
    console.log('Failed to create the buffer object');
    return false;
  }

  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); // 绑定缓冲区对象
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); // 将数据写入缓冲区对象

  // attribute变量
  const attributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
  const attrArray = new Array(attributes);

  for (let i = 0; i < attributes; ++i) {
    const info = gl.getActiveAttrib(program, i);
    attrArray[i] = gl.getAttribLocation(program, info.name);

    if (attrArray[i] < 0) {
      console.log(`Failed to get the storage location of ${info.name}`);
      continue;
    } 
    gl.vertexAttribPointer(attrArray[i], n, gl.FLOAT, false, 0, 0); 
    gl.enableVertexAttribArray(attrArray[i]);
  }

  // uniform变量
  const uniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
  const uniformArray = new Array(uniforms);

  for (let i = 0; i < uniforms; ++i) {
    const info = gl.getActiveUniform(program, i);
    uniformArray[i] = gl.getUniformLocation(program, info.name);

    if (uniformArray[i] < 0) {
      console.log(`Failed to get the storage location of ${info.name}`);
    }
  }

  return true;
}

Last Updated:
Contributors: 709992523