我应该何时在WebGL/OOpenGL中启用/禁用顶点位置属性
When should I enable/disable vertex position attributes in WebGL/OpenGL?
我正在编写一些WebGL代码,其中包含多个按顺序运行的着色器程序。
以前,我在gl上下文和着色器的初始化过程中根据需要使用gl.enableVertexAttribArray(...)
。我可能错误地认为,调用此函数是为gl.useProgram(...)
选择的程序设置特定状态
现在,我的第一个着色器程序有两个已启用的属性数组,第二个程序有一个已启用。当第二个程序运行时,我得到一个错误:
Error: WebGL: drawArrays: no VBO bound to enabled vertex attrib index 1!
这让我想到,在第一个程序中使用顶点属性1后,我可能需要禁用它,但我想验证这是我应该做的,并希望得到为什么这是正确的或不正确的解释。
每次使用前后,每个阵列位置的enableVertexAttribArray(...)
和disableVertexAttribArray
的最佳实践是什么?
我一生中从未调用过disableVertexAttribArray
,我已经编写了100个WebGL程序。调用它可能有也可能没有任何性能优势,但不调用它没有兼容性问题
规范指出,只有当属性被当前程序使用并且访问超出范围,或者没有绑定到已启用属性的缓冲区时,才会出现错误。
我们可以测试一下,看看它能正常工作。
var vsThatUses2Attributes = `
attribute vec4 position;
attribute vec2 texcoord;
varying vec2 v_texcoord;
void main() {
v_texcoord = texcoord;
gl_Position = position;
}
`;
var vsThatUses1Attribute = `
attribute vec4 position;
varying vec2 v_texcoord;
void main() {
v_texcoord = position.xy * 0.5 + 0.5;
gl_Position = position + vec4(1, 0, 0, 0);
}
`;
var fs = `
precision mediump float;
varying vec2 v_texcoord;
void main () {
gl_FragColor = vec4(v_texcoord, v_texcoord.x * v_texcoord.y, 1);
}
`;
var gl = document.querySelector("canvas").getContext("webgl");
document.body.appendChild(gl.canvas);
var programThatUses2Attributes = twgl.createProgramFromSources(gl, [vsThatUses2Attributes, fs]);
var programThatUses1Attribute = twgl.createProgramFromSources(gl, [vsThatUses1Attribute, fs]);
var positionLocation2AttribProg = gl.getAttribLocation(programThatUses2Attributes, "position");
var texcoordLocation2AttribProg = gl.getAttribLocation(programThatUses2Attributes, "texcoord");
var positionLocation1AttribProg = gl.getAttribLocation(programThatUses1Attribute, "position");
var positionBufferFor2AttribPrg = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBufferFor2AttribPrg);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
-1, -1,
-.5, 1,
0, -1,
]), gl.STATIC_DRAW);
var texcoordBufferFor2AttribPrg = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBufferFor2AttribPrg);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0, 0,
0.5, 1,
1, 0,
]), gl.STATIC_DRAW);
var positionBufferFor1AttribPrg = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBufferFor1AttribPrg);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
-1, -1,
0, -1,
-1, 1,
-1, 1,
0, -1,
0, 1,
]), gl.STATIC_DRAW);
// turn on 2 attributes
gl.enableVertexAttribArray(positionLocation2AttribProg);
gl.enableVertexAttribArray(texcoordLocation2AttribProg);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBufferFor2AttribPrg);
gl.vertexAttribPointer(positionLocation2AttribProg, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBufferFor2AttribPrg);
gl.vertexAttribPointer(texcoordLocation2AttribProg, 2, gl.FLOAT, false, 0, 0);
// draw with 2 attributes enabled
gl.useProgram(programThatUses2Attributes);
gl.drawArrays(gl.TRIANGLES, 0, 3);
// setup for second program that uses only 1 attribute
gl.bindBuffer(gl.ARRAY_BUFFER, positionBufferFor1AttribPrg);
gl.vertexAttribPointer(positionLocation1AttribProg, 2, gl.FLOAT, false, 0, 0);
// NOTICE WE HAVE !NOT turned off other attribute
gl.useProgram(programThatUses1Attribute);
gl.drawArrays(gl.TRIANGLES, 0, 6);
log("glError:", gl.getError());
function log() {
var pre = document.createElement("pre");
pre.appendChild(document.createTextNode(Array.prototype.join.call(arguments, " ")));
document.body.appendChild(pre);
}
canvas { border: 1px solid black; }
<script src="https://twgljs.org/dist/twgl.min.js"></script>
<pre>
This example draws a triangle with 3 vertices using 2 attributes.
It then draws a quad using 6 vertices and 1 attribute
<b>WITHOUT TURNING OFF THE NOW 2nd UNUSED ATTRIBUTE</b>.
That means not only is that attribute left on but it only has 3 vertices even
though the draw will use 6 vertices. Because that attribute is not 'comsumed' by
the current program it's ok according to the spec.
</pre>
<canvas width="150" height="30"></canvas>
所以,你的错误很可能是其他原因。
注意,删除缓冲区会将其从属性中解除绑定,此时它将是一个没有缓冲区的已启用属性,除非禁用它,否则会导致错误
属性状态与您发现的程序状态是分开的。
你的错误正是它所说的。您试图绘制,该程序需要属性#1上的数据。您在某个时刻使用gl.enableVertexAttribArray
启用了它,但没有使用gl.vertexAttribPointer
为它提供任何数据。所以你犯了一个错误。
注意,gl.vertexAttribPointer
将当前绑定到gl.ARRAY_BUFFER
的缓冲区绑定到指定的属性。
你可能会发现这个答案很有用
https://stackoverflow.com/a/27164577/128511
这个问答帮助我回答了我的问题:
使用两个或多个属性数不同的着色器时发生冲突
为了使其正常工作,在使用不使用属性的着色器程序绘制之前,我需要禁用未使用的属性。我无法解释为什么有些人说这不必要,但这样做解决了我的问题。
您永远不需要在WebGL中调用disableVertexAttribArray()
。我会注意到为什么这个方法一开始确实存在。
正如您所知,WebGL只是从OpenGLES2移植的库,而OpenGLES1是OpenGL的一个子集
在OpenGL的API列表中,有一些其他方法可以将顶点缓冲区传递给GPU,而不将顶点缓冲区时指定为指针。例如,在OpenGL环境中,可以通过调用gl.begin()
、gl.Vertex()
、gl.end()
等来发送顶点缓冲区数据。
这样,您就不需要调用gl.enableVertexAttribArray()
。
但是,如果不在WebGL中调用enableVertexAttribArray()
,就无法指定缓冲区。因此,您永远不需要调用方法,这只是历史原因。
并且您不需要在每帧中调用enableVertexAttribArray()
。这是一个非常繁重的操作,因为你不应该称之为每一帧。您只需要在初始化缓冲区之后立即调用enableVertexAttribArray()
。
- RegEx删除空属性?例如,如果(class=“”||class=“”)移除;否则就下课
- 全局变量和全局对象的属性之间有什么区别吗
- 如果使用 lodash 将属性存在于另一个对象中,则向对象添加属性
- 如何在Bootstrap Modal中为动态点击生成的变量设置jade属性
- 序列化数据属性中对象的最可靠方法
- 分析高度属性时出现意外值{{specs.height}}.index.html
- TypeError:无法读取属性'推'未定义的JavaScript
- 同样,同样的错误'ahorcado.js:26未捕获类型错误:无法读取属性'beginPath'
- AngularJS-使用'true'属性
- 可以't使用JavaScript获取width属性
- 未捕获的TypeError无法读取未定义的属性socialsharing
- 如何使用javascript获取嵌套对象中所有子对象的单个属性
- JavaScript Pub/Sub属性访问问题
- 从JavaScript访问struts操作中的属性
- 是否可以从父类访问子类的属性
- webGL,javascript:尝试访问属性1中超出范围的顶点
- 我应该何时在WebGL/OOpenGL中启用/禁用顶点位置属性
- “没有VBO绑定到启用的顶点属性索引0”试图在WebGL中绘制一个简单的纹理
- 材质贴图错误:glDrawElements:试图访问属性2中超出范围的顶点
- 导出的场景/网格中没有顶点属性(Blender到Babylon.js导出器)