这已经在其他地方进行了解释,但是您可以考虑WebGL1和WebGL2都具有顶点数组。默认情况下,这只是WebGL1,只有WebGL1可以在其中创建多个顶点数组(尽管所有WebGL1实现的99.9%都将其支持为扩展)
顶点数组是所有属性状态加上ELEMENT_ARRAY_BUFFER绑定的集合。
您可以想到这样的WebGL状态
function WebGLRenderingContext() {
// internal WebGL state
this.lastError: gl.NONE,
this.arrayBuffer = null;
this.vertexArray = {
elementArrayBuffer: null,
attributes: [
{ enabled: false, type: gl.FLOAT, size: 3, normalized: false,
stride: 0, offset: 0, value: [0, 0, 0, 1], buffer: null },
{ enabled: false, type: gl.FLOAT, size: 3, normalized: false,
stride: 0, offset: 0, value: [0, 0, 0, 1], buffer: null },
{ enabled: false, type: gl.FLOAT, size: 3, normalized: false,
stride: 0, offset: 0, value: [0, 0, 0, 1], buffer: null },
{ enabled: false, type: gl.FLOAT, size: 3, normalized: false,
stride: 0, offset: 0, value: [0, 0, 0, 1], buffer: null },
{ enabled: false, type: gl.FLOAT, size: 3, normalized: false,
stride: 0, offset: 0, value: [0, 0, 0, 1], buffer: null },
...
],
}
...
Run Code Online (Sandbox Code Playgroud)
而且您可以想到gl.bindBuffer这样实现
// 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;
this.arrayBuffer = buffer;
break;
case gl.ELEMENT_ARRAY_BUFFER;
this.vertexArray.elementArrayBuffer = buffer;
break;
default:
this.lastError = gl.INVALID_ENUM;
break;
}
};
Run Code Online (Sandbox Code Playgroud)
因此,您可以在上面看到,gl.bindBuffer用gl.ELEMENT_ARRAY_BUFFERset 调用elementArray当前部分vertexArray
您还可以看到vertexArray具有许多属性。它们定义了如何从缓冲区中提取数据以提供给顶点着色器。调用gl.getAttribLocation(someProgram, "nameOfAttribute")告诉您顶点着色器将查看哪个属性以从缓冲区中获取数据。
您可以使用4个函数来配置属性如何从缓冲区中获取数据。gl.enableVertexAttribArray,gl.disableVertexAttribArray,gl.vertexAttribPointer,和gl.vertexAttrib??。
他们已经有效地实施了这样的事情
this.enableVertexAttribArray = function(location) {
const attribute = this.vertexArray.attributes[location];
attribute.enabled = true; // true means get data from attribute.buffer
};
this.disableVertexAttribArray = function(location) {
const attribute = this.vertexArray.attributes[location];
attribute.enabled = false; // false means get data from attribute.value
};
this.vertexAttribPointer = function(location, size, type, normalized, stride, offset) {
const attribute = this.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 = this.arrayBuffer;
};
this.vertexAttrib4f = function(location, x, y, z, w) {
const attribute = this.vertexArray.attributes[location];
attribute.value[0] = x;
attribute.value[1] = y;
attribute.value[2] = z;
attribute.value[3] = w;
};
Run Code Online (Sandbox Code Playgroud)
现在,当您调用gl.drawArrays或gl.drawElements系统知道要如何从为提供顶点着色器而制作的缓冲区中提取数据时。看到这里如何工作。
然后有3个函数将管理与相连的所有状态this.vertexArray。他们是gl.createVertexArray,gl.bindVertexArray和gl.deleteVertexArray。在WebGL1中,可以在OES_vertex_array_object稍微重命名的扩展上使用它们 。在WebGL2上,它们仅在默认情况下可用,这也是WebGL 2.0的功能。
调用将gl.createVertexArray创建新的顶点数组。调用gl.bindVertexArrayset this.vertexArray指向您传递的set 。您可以想象它是这样实现的
this.bindVertexArray = function(vao) {
this.vertexArray = vao ? vao : defaultVertexArray;
}
Run Code Online (Sandbox Code Playgroud)
好处应该是显而易见的。在绘制每件事之前,需要设置所有属性。设置每个属性至少需要为每个使用的属性调用一次。通常,每个属性3个调用。一个调用gl.bindBuffer将一个缓冲区绑定到ARRAY_BUFFER一个对象gl.vertexAttribPointer,然后调用一次将那个缓冲区绑定到一个特定的属性,并设置如何提取数据,一个调用gl.enableVertexAttribArray打开一个属性从缓冲区中获取数据。
对于具有9个调用的位置,法线和纹理坐标的典型模型,如果您使用索引并且需要将缓冲区绑定到,则需要再+1 ELEMENT_ARRAY_BUFFER。
对于顶点数组,所有这些调用都在初始化时发生。您为要绘制的每个对象创建一个顶点数组,然后为该对象设置属性。在绘制时,只需调用一次gl.bindVertexArray即可设置所有属性和ELEMENT_ARRAY_BUFFER。
如果您只想始终使用顶点数组,则可以在WebGL1中使用此 polyfill。如果扩展存在或模仿它,它将使用内置的。当然,仿真速度较慢,但是任何需要仿真的GPU可能已经太慢了。
请注意,如果您正在寻找样品,可以将https://webglfundamentals.org和https://webgl2fundamentals.org上的相应示例进行比较。WebGL2站点到处都使用顶点数组。您将在绘制之前的WebGL1示例中注意到,对于每一个顶点数据,都将绑定该数据的缓冲区,然后设置该数据的属性。在WebGL2示例中,它发生在初始化时间而不是绘制时间。在抽奖时间,所有发生的事情都在呼唤gl.bindVertexArray
关于顶点数组要注意的一件事是它们通常需要更多的组织。如果要使用不同的着色器程序多次绘制同一对象,则一个着色器程序可能会对同一数据使用不同的属性。换句话说,在没有额外组织的情况下,shaderprogram1可以将属性3用于位置,而将shaderprogram2可以将属性2用于位置。在那种情况下,相同的顶点数组将不适用于两个程序以获取相同的数据。
解决方案是手动分配位置。您可以在WebGL2的着色器中自己执行此操作。您也可以通过gl.bindAttribLocation在链接WebGL1和WebGL2中的每个着色器程序的着色器之前进行调用来实现。我倾向于认为使用gl.bindAttribLocation它比在GLSL中做得更好,因为它更干燥
| 归档时间: |
|
| 查看次数: |
587 次 |
| 最近记录: |