介绍
enableVertexAttribArray
是 WebGL 中的一个方法,用于启用指定位置的顶点属性数组。
在WebGL中,图形渲染通常涉及到顶点数据的传递和处理。enableVertexAttribArray 用于启用顶点着色器中的属性变量,使得 WebGL 能够使用这些属性的数据进行渲染。
具体用法如下:
var positionAttribLocation = gl.getAttribLocation(program, 'position');
gl.enableVertexAttribArray(positionAttribLocation);
这样,顶点着色器中的 position 属性就被启用了,表示 WebGL 应该使用缓冲区中的数据来渲染顶点。
一般而言,enableVertexAttribArray 需要和 gl.vertexAttribPointer 配合使用。gl.vertexAttribPointer 用于指定顶点属性数组的数据格式和存储方式。在启用了顶点属性后,你可以使用它们来渲染图形。
讲解
下面案例就是绘制两个三角面,第一个attribute
有position
和color
,分别使用enableVertexAttribArray
开启position
和color
后,渲染第一个彩色顶点着色三角面,然后disableVertexAttribArray(color)
,关闭color
,再渲染第二个三角面可以看到颜色值没传进去,颜色使用的默认的黑色vecr(0.0)
gl.disableVertexAttribArray(colorLoc);
注意1
enableVertexAttribArray 的状态是在 WebGL 上下文中全局的,而不是特定于单个顶点着色器程序。一旦启用了某个顶点属性,这个状态就会一直保持,直到被禁用。
所以,如果在使用一个顶点着色器程序中启用了某个顶点属性,然后切换到另一个顶点着色器程序,你通常不需要再次调用 enableVertexAttribArray。已经启用的顶点属性状态会保持有效,直到显式地调用 gl.disableVertexAttribArray(index) 关闭。
// 启用顶点属性
var positionAttribLocation = gl.getAttribLocation(program1, 'position');
gl.enableVertexAttribArray(positionAttribLocation);
// ... 在 program1 中绘制 ...
// 不需要再次启用,状态会保持有效
var positionAttribLocation2 = gl.getAttribLocation(program2, 'position');
// ... 在 program2 中绘制 ...
在这个例子中,我们在 program1 中启用了 ‘position’ 属性,然后在切换到 program2 之后,不需要再次调用 gl.enableVertexAttribArray(positionAttribLocation2)。已经启用的状态会保持有效。
需要注意的是,当你在使用不同的着色器程序时,你可能需要重新设置 gl.vertexAttribPointer,因为不同的顶点着色器程序可能对顶点属性的数据格式有不同的要求。但 enableVertexAttribArray 只需要在首次设置时启用,之后会保持有效。
注意2
注意一下啊,这个方法之前理解一直是错误的,比如有两个shader,分别是shaderA
和shaderB
shaderA
里面有两个attribute
,分别是position
和color
shaderB
里面只有一个attribute
,是position
此时当使用shaderA
绘制的时候肯定会调用gl.enableVertexAttribArray
激活position
和color
完了再使用shaderB
绘制的时候如果shaderA
之前没有调用gl.disableVertexAttribArray
关闭position
和color
的话,这里碰巧可能不会出现问题,就不需要调用gl.enableVertexAttribArray
激活自己
的position
了,但是最好是使用完就关闭掉
完整案例
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Basic Draw Rectangle</title>
</script>
</head>
<body>
<canvas id="canvas" width="400" height="400"></canvas>
<script>
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
const vsGLSL = `
attribute vec4 position;
attribute vec4 color;
uniform vec4 offset;
varying vec4 v_color;
void main() {
gl_Position = position + offset;
v_color = color;
}
`;
const fsGLSL = `
precision highp float;
varying vec4 v_color;
void main() {
gl_FragColor = v_color;
}
`;
const createShader = function (gl, type, glsl) {
const shader = gl.createShader(type)
gl.shaderSource(shader, glsl)
gl.compileShader(shader)
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
throw new Error(gl.getShaderInfoLog(shader))
}
return shader
};
const compileShadersAndLinkProgram = function (gl, prg, vsGLSL, fsGLSL) {
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vsGLSL)
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fsGLSL)
gl.attachShader(prg, vertexShader)
gl.attachShader(prg, fragmentShader)
gl.linkProgram(prg)
if (!gl.getProgramParameter(prg, gl.LINK_STATUS)) {
throw new Error(gl.getProgramInfoLog(prg))
}
// NOTE! These are only here to unclutter the diagram.
// It is safe to detach and delete shaders once
// a program is linked though it is arguably not common.
// and I usually don't do it.
gl.detachShader(prg, vertexShader)
gl.deleteShader(vertexShader)
gl.detachShader(prg, fragmentShader)
gl.deleteShader(fragmentShader)
return prg
};
const prog = gl.createProgram();
compileShadersAndLinkProgram(gl, prog, vsGLSL, fsGLSL);
const positionLoc = gl.getAttribLocation(prog, 'position');
const colorLoc = gl.getAttribLocation(prog, 'color');
const offsetLoc = gl.getUniformLocation(prog, 'offset');
// vertex positions for triangle
const vertexPositions = new Float32Array([
0.0, 0.4,
-0.4, -0.4,
0.4, -0.4,
]);
const vertexColors = new Float32Array([
1, 1, 0, 1, // yellow
0, 1, 1, 1, // cyan
1, 0, 1, 1, // magenta
]);
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertexPositions, gl.STATIC_DRAW);
const colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertexColors, gl.STATIC_DRAW);
// this is not needed. It's just here to unclutter the diagram
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// above this line is initialization code
// --------------------------------------
// below is rendering code.
// --------------------------------------
// First draw a triangle with a different color for each vertex
// set the attributes
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.enableVertexAttribArray(positionLoc);
gl.vertexAttribPointer(
positionLoc, // location
2, // size (components per iteration)
gl.FLOAT, // type of to get from buffer
false, // normalize
0, // stride (bytes to advance each iteration)
0, // offset (bytes from start of buffer)
);
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.enableVertexAttribArray(colorLoc);
gl.vertexAttribPointer(
colorLoc, // location
4, // size (components per iteration)
gl.FLOAT, // type of to get from buffer
false, // normalize
0, // stride (bytes to advance each iteration)
0, // offset (bytes from start of buffer)
);
// this is not needed. It's just here to unclutter the diagram
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.useProgram(prog);
// draw on left
gl.uniform4fv(offsetLoc, [-0.5, 0, 0, 0]);
// draw 3 vertices (1 triangle)
gl.drawArrays(gl.TRIANGLES, 0, 3);
// Now draw the triangle again in a solid color
// by turning off the color attribute and setting
// an attribute values
gl.disableVertexAttribArray(colorLoc);
// gl.vertexAttrib4fv(colorLoc, [0.3, 0.6, 0.9, 1]);
// draw on right
gl.uniform4fv(offsetLoc, [0.5, 0, 0, 0]);
// draw 3 vertices (1 triangle)
gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>
</body>
</html>