webGL入门-动态绘制一个点

189 阅读3分钟

在绘制一个点文章中 juejin.cn/post/706527… ,我们看到点的位置信息是直接写死在顶点着色器中的,虽然程序便于理解,但是缺乏可扩展性。

所以我们需要webGL程序可以将顶点的位置坐标从javascript传到着色器程序中。

<canvas id="glcanvas" width="640" height="480"></canvas>
  // 顶点着色器程序
  const VSHADER_SOURCE = `attribute vec4 a_Position; // a1.声明attribute变量
  void main() {
    gl_Position = a_Position; // a2.将attribute变量赋值给gl_Position变量
    gl_PointSize = 10.0;
  }`;

  // 片元着色器程序
  const FSHADER_SOURCE = `void main() {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  }`;

  function main() {
    // 1.获取canvas元素
    const canvas = document.getElementById("glcanvas");

    // 2.获取webgl绘图上下文
    const gl = canvas.getContext("webgl");

    if (!gl) {
      alert("不支持webgl");
      return;
    }

    // 初始化着色器(封装在另一个函数库中,具体请看 https://juejin.cn/post/7066335207510507534)
    if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
      console.log("着色器初始化失败");
      return;
    }

    // 3.设置背景色(指定清空canvas的颜色)
    gl.clearColor(0.0, 1.0, 0.0, 1.0);

    // a3.获取attribute变量的存储位置
    const a_Position = gl.getAttribLocation(gl.program, "a_Position");

    setInterval(() => {
      // 4.清空canvas
      gl.clear(gl.COLOR_BUFFER_BIT);

      const num = Math.cos(Math.PI * Math.random());
      // a4.向attribute变量传输数据
      gl.vertexAttrib3f(a_Position, num, 0.0, 0.0);

      // 使用vertexAttrib3f的同族函数
      // gl.vertexAttrib1f(a_Position, 0.5)
      // gl.vertexAttrib2f(a_Position, 0.5, 0.0)
      // gl.vertexAttrib4f(a_Position, 0.5, 0.0, 0.0, 1.0)

      // 5.绘制一个点
      gl.drawArrays(gl.POINTS, 0, 1);
    }, 100);
  }

  main();

使用attribute变量流程

  • a1.在顶点着色器中,声明attribute变量
  • a2.将attribute变量赋值给gl_Position变量
  • a3.获取attribute变量的存储位置
  • a4.向attribute变量传输数据

image.png

a1.声明 attribute 变量

attribute变量是与顶点相关的数据。attribut变量是一种GLSL变量,被用来从外部向顶点着色器内传输数据,只有顶点着色器才能使用它。

// <存储限定符><类型><变量名>
attribute vec4 a_Position;

// 关键字attribute被称为存储限定符,表示接下来的变量是一个attribute变量
// attribute变量必须声明成全局变量,数据将从着色器外部传给改变量

a3.获取 attribute 变量的存储位置

在initShaders中初始化了着色器,然后webGL系统中就建立了顶点着色器,webGL会对着色器进行解析,辨别出着色器具有attribute变量,每个变量都具有一个存储地址,以便通过存储地址向变量传输数据。

gl.getAttribLocation()

WebGLRenderingContext.getAttribLocation() 方法返回了给定 WebGLProgram 对象中某属性的下标指向位置(获取由name参数指定的attribute变量的存储地址)

  /**
   * @param program 一个包含了属性参数的 WebGLProgram 对象(指定包含顶点着色器和片元着色器的着色器程序对象)
   * @param name 需要获取下标指向位置的属性参数名(string类型)
   * 返回值: 表明属性位置的下标(attribute变量的存储地址),GLint 数字,如果找不到该属性则返回-1
   */
  GLint gl.getAttribLocation(program, name);
// a3.获取attribute变量的存储位置 
const a_Position = gl.getAttribLocation(gl.program, "a_Position");
// gl.program 获取到的是WebGLProgram对象。必须在初始化着色器后才能获取gl.program,因为初始化着色器流程才会创建WebGLProgram对象

a4.向 attribute 变量赋值

attribute变量的存储地址获取到后,将存储地址保存在js变量中,然后使用该变量来向着色器传入值。使用gl.vertexAttrib3f()来赋值

gl.vertexAttrib3f()

/**
 * 将数据(v0, v1, v2)传给由 index 参数指定的 attribute 变量
 * @param index 指定将要修改的 attribute 变量的存储位置(即gl.getAttribLocation()的返回值)
 * @param v0 指定填充 attribute 变量第一个分量的值(浮点型数值,X坐标)
 * @param v1 指定填充 attribute 变量第二个分量的值(浮点型数值,Y坐标)
 * @param v2 指定填充 attribute 变量第三个分量的值(浮点型数值,Z坐标)
 */
void gl.vertexAttrib3f(index, v0, v1, v2);

gl.vertexAttrib[1234]f[v] 同族函数

vertexAttrib3f 是同族函数里的一种。v1,v2,v3不填时,将以v1=0.0, v2=0.0, v3=1.0填充。

/**
 * @param index GLuint 类型,指定了待修改顶点attribute变量的存储位置
 * @param v0, v1, v2, v3 浮点数类型Number,用于设置顶点attibute变量的各分量值
 * @param value Float32Array 类型,用于设置顶点attibute变量的向量值
 */
void gl.vertexAttrib1f(index, v0);
void gl.vertexAttrib2f(index, v0, v1);
void gl.vertexAttrib3f(index, v0, v1, v2);
void gl.vertexAttrib4f(index, v0, v1, v2, v3);

void gl.vertexAttrib1fv(index, value);
void gl.vertexAttrib2fv(index, value);
void gl.vertexAttrib3fv(index, value);
void gl.vertexAttrib4fv(index, value);

// 示例
const a_foobar = gl.getAttribLocation(shaderProgram, "foobar");
// 分别设置每个组件:
gl.vertexAttrib3f(a_foobar, 10.0, 5.0, 2.0);
// or提供一个Float32Array:
const floatArray = new Float32Array([10.0, 5.0, 2.0]);
gl.vertexAttrib3fv(a_foobar, floatArray);