webgl学习03-动态绘制点

动态绘制点

动态传递顶点坐标

绘制动态点需要进行 JavaScript 和 GLSL 之间的信息交互,即将JS代码中指定的点位传入GLSL中进行绘制。

常规顶点着色器代码如下,我们需要通过JS代码给 gl_Position 传值来动态的绘制点位。

const VertexSource = `
  void main () {
    // 顶点坐标
    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
    // 顶点渲染像素大小
    gl_PointSize = 25.0;
  }
`

此时就需要引入GLSL中的变量 attribute 。

attribute变量

GLSL 中有三种类型的变量,而 attribute 就是其中之一。详细介绍如下表:

这些变量我们都可以在 JavaScript 中获取到他们引用地址,并对他们设置值。

代码如下:

通常命名方式为 类型前缀+变量名。比如说我们的一个 attribute 变量,我们以 a_Xxx 的方式来命名,如下 a_Dnamic

const VertexSource = `
  // 定义了一个名为 a_dnamic,类型为 vec4 的 attribute 变量
  attribute vec4 a_Dnamic;

  void main () {
    // 将变量赋值给顶点坐标
    gl_Position = a_Dnamic;
    // 顶点渲染像素大小
    gl_PointSize = 25.0;
  }
`

接下来,我们只需在 JavaScript 中获取这个变量 a_Dnamic再赋值就能实现动态传递顶点坐标了。

其中 gl.getAttribLocation表示根据变量名获取 program 中的 attribute 变量。

gl.vertexAttrib[1234]f[v]表示根据获取到的 attribute 变量进行赋值。其中1234为接受的浮点数数量,未接受为默认值0.0或1.0;v为允许接受数组。

绘制动态点完整代码

const VertexSource = /* glsl */ `
    attribute vec4 a_dnamic_posi;
    void main() {
        gl_Position = a_dnamic_posi;
        gl_PointSize = 25.0;
    }
`;

const FragSource = /* glsl */ `
    void main() {
        gl_FragColor = vec4(0.0, 0.0, 0.9, 1.0);
    }
`;

const canvas = document.querySelector("#c");
const gl = canvas.getContext("webgl");

// 设置 canvas 背景色(若无需变化颜色,则只需要设置一次即可)
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// 清空 canvas
gl.clear(gl.COLOR_BUFFER_BIT);

const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, VertexSource);
gl.compileShader(vertexShader);

const fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, FragSource);
gl.compileShader(fragShader);

const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragShader);

gl.linkProgram(program);
gl.useProgram(program);

let a_dnamicPosi = gl.getAttribLocation(program, "a_dnamic_posi");
let points = [];
canvas.onmousedown = function (e) {
    let x = e.offsetX;
    let y = e.offsetY;
    let rect = e.target.getBoundingClientRect();
    x = (x - rect.left - canvas.width / 2) / (canvas.width / 2);
    y = (canvas.height / 2 - (y - rect.top)) / (canvas.height / 2);
    points.push([x, y]);
    gl.clear(gl.COLOR_BUFFER_BIT);
    points.forEach((v)=>{
        // 必须通过记录的点位来渲染是因为webgl使用的是颜色缓冲区
        // GPU是将画面颜色记录在缓冲区冲,一次性绘制在屏幕上的,每次都会清空屏幕
        gl.vertexAttrib3f(a_dnamicPosi, ...v, 0.0);
        gl.drawArrays(gl.POINTS, 0, 1);
    })
};

 

posted @ 2024-01-30 09:53  邢韬  阅读(26)  评论(0编辑  收藏  举报