在绘制一个点文章中 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变量传输数据
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);