webgl 实现三角形

83 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第24天,点击查看活动详情

目的

通过 webgl 实现一个三角形,掌握实现webgl程序的最简流程,先熟练这一段,再学习后面的内容

分析

先分析如果绘制一个三角形,我们需要做什么

  1. 创建canvas元素
  2. 获取canvas元素,创建webgl上下文
  3. 创建着色器的 shader 实例,获取内容,并注册顶点着色器/片段着色器
  4. 创建 Program 实例、加载 shader 内容
  5. 获取顶点着色器的变量的地址,创建buffer并且赋值
  6. 绘制

创建上下文

我们直接先实现 1 和 2;

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Demo</title>
  </head>
  <body>
    <canvas id="webgl"></canvas>
  </body>
</html>
<script>
    // 创建上下文
  function createWebglContext(id, opts) {
    const webglCanvas = document.querySelector(id);

    webglCanvas.width = opts.width;
    webglCanvas.height = opts.height;

    const context = webglCanvas.getContext("webgl");

    return context;
  }
  const context  = createWebglContext("#webgl",{width:800,height:400});
</script>

创建着色器的 shader 实例,获取内容,并注册顶点着色器/片段着色器

利用 createShader 创建 shader 实例,将着色器代码通过 shaderSource 传入,再进行编译

  function createShader(gl, type, source) {
    const shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);

    const isSuccess = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
    if (isSuccess) {
      return shader;
    }
    gl.deleteShader(shader);
  }

可能会存在编译错误,所以用 getShaderParameter 判断一下是否成功,否则的话销毁掉 shader

到时候就是这样使用

const vertexShaderSource = document.querySelector("#vertex").text;
const fragmentShaderSource = document.querySelector("#fragment").text;

const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(
  gl,
  gl.FRAGMENT_SHADER,
  fragmentShaderSource
);

我们再补充一下 我们想要做的着色器代码

<script id="vertex" type="notjs">
  attribute vec4 a_position;
  void main() {
    gl_Position = a_position;
  }
</script>

<script id="fragment" type="notjs">
  precision mediump float;
  void main() {
    gl_FragColor = vec4(1, 0, 0.5, 1);
  }
</script>

创建 Program 实例、加载 shader 内容

我们写一个创建 Program 的函数,加载顶点、片段着色器,然后连接进上下文

  function createProgram(gl, vertexShader, fragmentShader) {
    var program = gl.createProgram();
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);
    var isSuccess = gl.getProgramParameter(program, gl.LINK_STATUS);
    if (isSuccess) {
      return program;
    }
    gl.deleteProgram(program);
  }

获取顶点着色器的变量的地址,创建 buffer 并且赋值

const positionAttributeLocation = gl.getAttribLocation(program,"a_position");

const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

const positions = [0, 0, 0, 0.5, 0.7, 0];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(
  positionAttributeLocation,
  2,
  gl.FLOAT,
  false,
  0,
  0
);

绘制

调用 drawArrays 使用gl.TRIANGLES绘制,顶点着色器每运行三次WebGL将会根据三个gl_Position值绘制一个三角形

  gl.drawArrays(gl.TRIANGLES, 0, 3);

成果

image.png