gpt4 book ai didi

javascript - webgl中绑定(bind)缓冲区的逻辑是什么?

转载 作者:数据小太阳 更新时间:2023-10-29 04:23:30 25 4
gpt4 key购买 nike

我有时会发现自己在以不同的顺序声明缓冲区(使用 createBuffer/bindBuffer/bufferdata)和在代码的其他部分(通常在绘图循环中)重新绑定(bind)它们之间挣扎。

如果我在绘制数组之前没有重新绑定(bind)顶点缓冲区,控制台会提示试图访问超出范围的顶点。我的怀疑是最后一个绑定(bind)对象在指针处传递,然后传递给 drawarrays 但是当我在代码开头更改顺序时,没有任何变化。有效的方法是在绘制循环中重新绑定(bind)缓冲区。所以,我无法真正理解这背后的逻辑。什么时候需要重新绑定(bind)?为什么需要重新绑定(bind)?属性0指的是什么?

最佳答案

我不知道这是否会有所帮助。正如一些人所说,GL/WebGL 内部有一堆 状态 .您调用的所有函数都会设置状态。设置完成后,您可以调用 drawArraysdrawElements所有这些状态都用于绘制事物
这已在 SO 的其他地方进行了解释,但绑定(bind)缓冲区只是在 WebGL 中设置 2 个全局变量中的 1 个。之后,您通过其绑定(bind)点引用缓冲区。
你可以这样想

gl = function() {
// internal WebGL state
let lastError;
let arrayBuffer = null;
let vertexArray = {
elementArrayBuffer: null,
attributes: [
{ enabled: false, type: gl.FLOAT, size: 3, normalized: false,
stride: 0, offset: 0, buffer: null },
{ enabled: false, type: gl.FLOAT, size: 3, normalized: false,
stride: 0, offset: 0, buffer: null },
{ enabled: false, type: gl.FLOAT, size: 3, normalized: false,
stride: 0, offset: 0, buffer: null },
{ enabled: false, type: gl.FLOAT, size: 3, normalized: false,
stride: 0, offset: 0, buffer: null },
{ enabled: false, type: gl.FLOAT, size: 3, normalized: false,
stride: 0, offset: 0, buffer: null },
...
],
}
// these values are used when a vertex attrib is disabled
let attribValues = [
[0, 0, 0, 1],
[0, 0, 0, 1],
[0, 0, 0, 1],
[0, 0, 0, 1],
[0, 0, 0, 1],
...
];
...

// Implementation of gl.bindBuffer.
// note this function is doing nothing but setting 2 internal variables.
this.bindBuffer = function(bindPoint, buffer) {
switch(bindPoint) {
case gl.ARRAY_BUFFER;
arrayBuffer = buffer;
break;
case gl.ELEMENT_ARRAY_BUFFER;
vertexArray.elementArrayBuffer = buffer;
break;
default:
lastError = gl.INVALID_ENUM;
break;
}
};
...
}();
之后,其他 WebGL 函数引用这些函数。例如 gl.bufferData可能会做类似的事情
   // implementation of gl.bufferData
// Notice you don't pass in a buffer. You pass in a bindPoint.
// The function gets the buffer one of its internal variable you set by
// previously calling gl.bindBuffer

this.bufferData = function(bindPoint, data, usage) {

// lookup the buffer from the bindPoint
var buffer;
switch (bindPoint) {
case gl.ARRAY_BUFFER;
buffer = arrayBuffer;
break;
case gl.ELEMENT_ARRAY_BUFFER;
buffer = vertexArray.elemenArrayBuffer;
break;
default:
lastError = gl.INVALID_ENUM;
break;
}

// copy data into buffer
buffer.copyData(data); // just making this up
buffer.setUsage(usage); // just making this up
};
除了这些绑定(bind)点之外,还有许多属性。默认情况下,这些属性也是全局状态。它们定义了如何从缓冲区中提取数据以提供给顶点着色器。调用 gl.getAttribLocation(someProgram, "nameOfAttribute")告诉您顶点着色器将查看哪个属性以从缓冲区中获取数据。
因此,您可以使用 4 个函数来配置属性如何从缓冲区获取数据。 gl.enableVertexAttribArray , gl.disableVertexAttribArray , gl.vertexAttribPointer , 和 gl.vertexAttrib?? .
他们有效地实现了这样的事情
this.enableVertexAttribArray = function(location) {
const attribute = vertexArray.attributes[location];
attribute.enabled = true; // true means get data from attribute.buffer
};

this.disableVertexAttribArray = function(location) {
const attribute = vertexArray.attributes[location];
attribute.enabled = false; // false means get data from attribValues[location]
};

this.vertexAttribPointer = function(location, size, type, normalized, stride, offset) {
const attribute = vertexArray.attributes[location];
attribute.size = size; // num values to pull from buffer per vertex shader iteration
attribute.type = type; // type of values to pull from buffer
attribute.normalized = normalized; // whether or not to normalize
attribute.stride = stride; // number of bytes to advance for each iteration of the vertex shader. 0 = compute from type, size
attribute.offset = offset; // where to start in buffer.

// IMPORTANT!!! Associates whatever buffer is currently *bound* to
// "arrayBuffer" to this attribute
attribute.buffer = arrayBuffer;
};

this.vertexAttrib4f = function(location, x, y, z, w) {
const attrivValue = attribValues[location];
attribValue[0] = x;
attribValue[1] = y;
attribValue[2] = z;
attribValue[3] = w;
};
现在,当您调用 gl.drawArraysgl.drawElements系统知道您想如何从缓冲区中提取数据以提供顶点着色器。 See here for how that works .
由于属性是 全局状态这意味着每次您调用 drawElementsdrawArrays您如何设置属性就是如何使用它们。如果您将属性 #1 和 #2 设置到每个具有 3 个顶点的缓冲区,但您要求使用 gl.drawArrays 绘制 6 个顶点你会得到一个错误。同样,如果您创建一个绑定(bind)到 gl.ELEMENT_ARRAY_BUFFER 的索引缓冲区, bindpoint 并且该缓冲区的索引大于 2,您将得到 index out of range错误。如果您的缓冲区只有 3 个顶点,那么唯一有效的索引是 0 , 1 , 和 2 .
通常,每次绘制不同的东西时,都会重新绑定(bind)绘制该东西所需的所有属性。绘制一个有位置和法线的立方体?将缓冲区与位置数据绑定(bind),设置用于位置的属性,将缓冲区与法线数据绑定(bind),设置用于法线的属性,现在进行绘制。接下来绘制一个带有位置、顶点颜色和纹理坐标的球体。绑定(bind)包含位置数据的缓冲区,设置用于位置的属性。绑定(bind)包含顶点颜色数据的缓冲区,设置用于顶点颜色的属性。绑定(bind)包含纹理坐标的缓冲区,设置用于纹理坐标的属性。
唯一不重新绑定(bind)缓冲区的情况是,如果您不止一次地绘制相同的东西。例如绘制 10 个立方体。您将重新绑定(bind)缓冲区,然后为一个立方体设置制服,绘制它,为下一个立方体设置制服,绘制它,重复。
我还应该补充一点,有一个扩展名 [ OES_vertex_array_object ] 这也是 WebGL 2.0 的一个特性。顶点数组对象是上面称为 vertexArray 的全局状态。其中包括 elementArrayBuffer和所有的属性。
调用 gl.createVertexArray使新的其中之一。调用 gl.bindVertexArray设置全局 attributes指向绑定(bind)顶点数组中的那个。
调用 gl.bindVertexArray那么将是
 this.bindVertexArray = function(vao) {
vertexArray = vao ? vao : defaultVertexArray;
}
这样做的好处是让您在初始化时设置所有属性和缓冲区,然后在绘制时只需 1 个 WebGL 调用将设置所有缓冲区和属性。
这是 webgl state diagram这可能有助于更好地可视化这一点。

关于javascript - webgl中绑定(bind)缓冲区的逻辑是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27148273/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com