Webgl 调用glDisableVertexAttributeArray()是否重要?

Webgl 调用glDisableVertexAttributeArray()是否重要?,webgl,vertex-shader,Webgl,Vertex Shader,我不完全清楚启用顶点属性数组的范围。我有几个不同的着色器程序,具有不同数量的顶点属性。GlenableVertexAttributeArray调用是着色器程序的本地调用还是全局调用 现在,当我创建着色器程序时,我正在启用顶点属性数组,并且从未禁用它们,所有这些似乎都可以工作,但似乎我应该在draw调用之前/之后启用/禁用它们。这有影响吗 (碰巧我在WebGL中,所以我们真正讨论的是gl.enableVertexAttribArray和gl.disableVertexAttribArray。我还要

我不完全清楚启用顶点属性数组的范围。我有几个不同的着色器程序,具有不同数量的顶点属性。GlenableVertexAttributeArray调用是着色器程序的本地调用还是全局调用

现在,当我创建着色器程序时,我正在启用顶点属性数组,并且从未禁用它们,所有这些似乎都可以工作,但似乎我应该在draw调用之前/之后启用/禁用它们。这有影响吗


(碰巧我在WebGL中,所以我们真正讨论的是
gl.enableVertexAttribArray
gl.disableVertexAttribArray
。我还要注意的是,OpenGL着色语言桔子书对这些调用的信息性很差。)启用顶点属性数组的状态可以绑定到顶点数组对象(VAO),也可以是全局的

如果您使用的是VAO,则不应禁用属性数组,因为它们封装在VAO中


但是,对于全局顶点属性数组启用状态,您应该禁用它们,因为如果它们保持启用状态,OpenGL将尝试从数组中读取,该数组可能绑定到无效指针,如果指针指向客户端地址空间,则可能导致程序崩溃,或者,如果指向绑定顶点缓冲区对象的限制之外,则引发OpenGL错误。

WebGL与OpenGL不同

在WebGL中,只要有一个缓冲区附加到属性上,就明确允许启用数组,并且(a)如果使用了缓冲区,它的大小足以满足draw调用,或者(b)不使用缓冲区

与OpenGL ES 2.0不同,WebGL不允许客户端阵列

证明:

const gl=document.querySelector(“canvas”).getContext(“webgl”);
常量vsUses2Attributes=`
属性向量4位置;
属性向量4颜色;
可变的vec4 v_颜色;
void main(){
gl_位置=位置;
gl_PointSize=20.0;
v_color=颜色;
}
`;
常量vsUses1Attribute=`
属性向量4位置;
可变的vec4 v_颜色;
void main(){
gl_位置=位置;
gl_PointSize=20.0;
v_color=vec4(0,1,1,1);
}
`
常数fs=`
精密中泵浮子;
可变的vec4 v_颜色;
void main(){
gl_FragColor=v_颜色;
}
`;
const program2Attribs=twgl.createProgram(gl[vsUses2Attributes,fs]);
const program1Attrib=twgl.createProgram(gl[vsUses1Attribute,fs]);
函数createBuffer(数据){
const buf=gl.createBuffer();
gl.bindBuffer(gl.ARRAY\u BUFFER,buf);
总账缓冲数据(总账数组缓冲区、新Float32Array(数据)、总账静态绘图);
返回buf;
}
const buffer3Points=createBuffer([
-0.7, 0.5,
0.0, 0.5,
0.7, 0.5,
]);
const buffer3Colors=createBuffer([
1, 0, 0, 1,
0, 1, 0, 1,
0, 0, 1, 1,
]);
const buffer9Points=createBuffer([
-0.8, -0.5,
-0.6, -0.5,
-0.4, -0.5,
-0.2, -0.5,
0.0, -0.5,
0.2, -0.5,
0.4, -0.5,
0.6, -0.5,
0.8, -0.5,
]);
//设置2个属性
{
const posLoc=gl.getAttribLocation(program2Attribs,“位置”);
gl.EnableVertexAttributeArray(posLoc);
gl.bindBuffer(gl.ARRAY\u BUFFER,buffer3点);
gl.VertexAttribute指针(posLoc,2,gl.FLOAT,false,0,0);
const colorLoc=gl.getAttributeLocation(program2Attribs,'color');
gl.EnableVertexAttributeArray(colorLoc);
gl.bindBuffer(gl.ARRAY\u BUFFER,buffer3颜色);
gl.VertexAttributePointer(colorLoc,4,gl.FLOAT,false,0,0);
}
//画
总账使用程序(程序2附件);
总图绘制阵列(总图点,0,3);
//设置1属性(不要禁用第二个属性
{
const posLoc=gl.getAttrib位置(program1Attrib,“位置”);
gl.EnableVertexAttributeArray(posLoc);
gl.bindBuffer(gl.ARRAY_BUFFER,buffer9Points);
gl.VertexAttribute指针(posLoc,2,gl.FLOAT,false,0,0);
}
//画
总账使用程序(程序1附件);
总图绘制阵列(总图点,0,9);
const err=gl.getError();
log(err?`ERROR:${twgl.glEnumToString(gl,err)}`:'no WebGL errors');
canvas{边框:1px纯黑;}


首先,它绘制3个点(3个顶点,2个属性)
第二,它绘制9个点(9个顶点,1个属性)
它不调用gl.disableVertexAttrib,因此在第二次绘制调用时,其中一个属性仍处于启用状态。它指向的缓冲区中只有3个顶点,即使将绘制9个顶点。没有错误。


对于webGL,我将选择“是”,调用gl.disablevertexattributearray非常重要

Chrome给了我这个警告:

WebGL: INVALID_OPERATION: drawElements: attribs not setup correctly
当程序更改为使用少于最大属性数的程序时,就会发生这种情况。显然,解决方案是在绘图之前禁用未使用的属性


如果您的所有程序都使用相同数量的属性,那么在初始化时调用gl.enableVertexAttributeArray就可以了。否则,当您更改程序时,您将需要管理它们。

将其视为属性是VAO的本地属性,而不是着色器程序。VBO位于GPU内存中

认为WebGL默认存在WebGL使用的默认VAO(它也可以是程序员创建的一个VAO,同样的概念也适用)。这个VAO包含一个称为ARRAYH缓冲区的目标,在该GPU内存中任何VBO都可以绑定。这个VAO还包含属性数组固定数量的属性数组。(数量取决于实现和平台,这里假设8是Webgl规范要求的最小值)。此外,该VAO将具有元素\数组\缓冲区目标,任何索引数据缓冲区都可以绑定到该目标

现在,当您创建着色器程序时,它将具有您指定的属性。Webgl将指定一个可能的属性槽“编号”链接着色器程序时,属性将访问程序中指定的所有属性。现在,属性将使用VAO中相应的属性插槽来访问绑定到VAO中数组缓冲区或元素数组缓冲区目标的数据。现在,当使用函数gl.enableVertexAttrib时