I've been working with WebGL1 for some time but now that I'm learning more about WebGL2, I'm confused what Vertex Array
s actually do. For example, in the following example, I can remove all references to them (e.g. creation, binding, deletion) and the example continues to work.
相关问题
- OpenGL Shaders. Pass array of float
- debugging webgl in chrome
- Difference from eglCreatePbufferSurface and eglCre
- SecurityError for same-origin image texImage2D
- Render 3d Objects into Cameraview
相关文章
- Why is glClear blocking in OpenGLES?
- Writing to then reading from an offscreen FBO on i
- How to get OpenGL version using Javascript?
- Why do I need to define a precision value in webgl
- How to change one texture image of a 3d model(maya
- Issue in passing Egl configured surface to native
- Draw a line over UIViewController
- Why do my three.js examples not load properly?
This has been explained elsewhere but you can consider both WebGL1 and WebGL2 to have a vertex array. It's just WebGL1 by default only has one where as WebGL2 you can create multiple vertex arrays (although 99.9% of all WebGL1 implementations support them as an extension)
A Vertex Array is the collection of all attribute state plus the
ELEMENT_ARRAY_BUFFER
binding.You can think of WebGL state like this
And you can think of
gl.bindBuffer
as implemented like thisSo you can see above, calling
gl.bindBuffer
withgl.ELEMENT_ARRAY_BUFFER
sets theelementArray
part of the currentvertexArray
You can also see
vertexArray
has a number of attributes. They define how to pull data out of the buffers to supply to your vertex shader. Callinggl.getAttribLocation(someProgram, "nameOfAttribute")
tells you which attribute the vertex shader will look at to get data out of a buffer.There's 4 functions that you use to configure how an attribute will get data from a buffer.
gl.enableVertexAttribArray
,gl.disableVertexAttribArray
,gl.vertexAttribPointer
, andgl.vertexAttrib??
.They're effectively implemented something like this
Now, when you call
gl.drawArrays
orgl.drawElements
the system knows how you want to pull data out of the buffers you made to supply your vertex shader. See here for how that works.There's then 3 functions that will manage all state connected to
this.vertexArray
. They aregl.createVertexArray
,gl.bindVertexArray
andgl.deleteVertexArray
. In WebGL1 they are available on theOES_vertex_array_object
extension slightly renamed. On WebGL2 they are just available by default which is also a feature of WebGL 2.0.Calling
gl.createVertexArray
makes new vertex array. Callinggl.bindVertexArray
setsthis.vertexArray
to point to the one you pass in. You can imagine it implemented like thisThe benefit should be obvious. Before each thing you want to draw you need to set all the attributes. Setting each attribute requires a minimum of one call per used attribute. More commonly 3 calls per attribute. One call to
gl.bindBuffer
to bind a buffer toARRAY_BUFFER
and one call togl.vertexAttribPointer
to then bind that buffer to a specific attribute and set how to pull data out and one call togl.enableVertexAttribArray
to turn on getting data from a buffer for the attribute.For a typical model with positions, normals, and texture coordinates that's 9 calls, +1 more if you're using indices and need to bind a buffer to
ELEMENT_ARRAY_BUFFER
.With vertex arrays all those calls happen at init time. You make a vertex array for each thing you want to draw then setup the attributes for that thing. At draw time it then only takes one call to
gl.bindVertexArray
to setup all the attributes and theELEMENT_ARRAY_BUFFER
.If you'd like to just always use vertex arrays you can use this polyfill in WebGL1. It uses the built in one if the extension exists or else emulates it. Of course emulation is slower but any GPU that would need the emulation is probably already too slow.
note if you're looking for samples maybe compare the corresponding examples on https://webglfundamentals.org to https://webgl2fundamentals.org. The WebGL2 site uses vertex arrays everywhere. You'll notice in the WebGL1 examples just before drawing, for each piece of vertex data the buffer for that data is bound and then the attribute for that data is setup. In the WebGL2 examples that happens at init time instead of draw time. At draw time all that happens is calling
gl.bindVertexArray
One extra thing about vertex arrays to be aware of is that they generally require more organization. If you're going to draw the same object more than once with different shader programs then it's possible one shader program will use different attributes for the same data. In other words, with no extra organization shaderprogram1 might use attribute 3 for position where as shaderprogram2 might attribute 2 for position. In that case the same vertex array would not work with both programs for the same data.
The solution is to manually assign the locations. You can do this in the shaders themselves in WebGL2. You can also do it by calling
gl.bindAttribLocation
before linking the shaders for each shaderprogram in both WebGL1 and WebGL2. I tend to think usinggl.bindAttribLocation
is better than doing it in GLSL because it's more D.R.Y.