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); }) };