据我了解VAO / VBO,VAO保留了自绑定以来已设置的所有属性信息,例如。 VBO中给定顶点属性的偏移量,步幅,组件数等。
我似乎不清楚VAO和VBO是如何协同工作的。我见过的很多例子都指定了相对于当前绑定的VBO的顶点属性,当绑定VAO时,VBO中的数据变得可访问。我可以看到以这种方式使用VAO的一种方法是每个对象有一个(每个对象使用自己的VBO),但我已经读过,由于不必要地在许多VAO之间切换,这在性能上是差的。我还希望避免将所有对象数据存储在一个单片VBO中,因为我需要随时在场景中添加和删除对象 - 作为3D编辑器,我觉得应用程序更适合拥有每个几何对象都拥有自己的缓冲区,而不是一些大的,预分配的VBO。 (这是正确的假设吗?)
因此,我的问题是,一个VAO是否可以独立于VBO存储顶点属性配置?我是否能够配置VAO以期望某种格式的数据(例如位置,正常,UV)然后"交换"不同的VBO,因为我绘制不同的几何对象,或者格式信息基本上只绑定到VBO本身?如果是后者,是否值得我使用VAO?
答案 0 :(得分:2)
ARB_vertex_attrib_binding 允许您分离Vao属性格式和缓冲区绑定。
https://www.opengl.org/wiki/Vertex_Specification#Separate_attribute_format
在内部,配置Vao时,Vertex缓冲区会自动与属性索引关联。使用 ARB_vertex_attrib_binding ,您可以使用新的gl函数独立于绑定缓冲区定义属性格式,可以使用VertexBuffer函数进行切换。
这里是c#中使用openTK的一段代码:(完整的:https://github.com/jpbruyere/GGL/tree/ottd/Tetra)
这里的解决方案是构建一个VAO,并将所有网格连接起来,仅为每个网格保留
IndicesCount =和模型的总指数
protected void CreateVAOs()
{
//normal vao binding
vaoHandle = GL.GenVertexArray();
GL.BindVertexArray(vaoHandle);
GL.EnableVertexAttribArray(0);
GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0);
... other attrib bindings come here
//ARB vertex attrib binding use for fast instance buffers switching
//note that I use 4 attrib indices to bind a matrix
GL.VertexBindingDivisor (instanceBufferIndex, 1);
for (int i = 0; i < 4; i++) {
GL.EnableVertexAttribArray (instanceBufferIndex + i);
GL.VertexAttribBinding (instanceBufferIndex+i, instanceBufferIndex);
GL.VertexAttribFormat(instanceBufferIndex+i, 4, VertexAttribType.Float, false, Vector4.SizeInBytes * i);
}
if (indices != null)
GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle);
GL.BindVertexArray(0);
}
然后,我使用每个矩阵数组定义网格实例,这是一个正常的缓冲区创建,但不是静态绑定到vao。
instancesVboId = GL.GenBuffer ();
GL.BindBuffer (BufferTarget.ArrayBuffer, instancesVboId);
GL.BufferData<Matrix4> (BufferTarget.ArrayBuffer,
new IntPtr (modelMats.Length * Vector4.SizeInBytes * 4),
modelMats, BufferUsageHint.DynamicDraw);
GL.BindBuffer (BufferTarget.ArrayBuffer, 0);
为了渲染这样的vao,我在我的实例数组中循环:
public void Bind(){
GL.BindVertexArray(vaoHandle);
}
public void Render(PrimitiveType _primitiveType){
foreach (VAOItem item in Meshes) {
GL.ActiveTexture (TextureUnit.Texture1);
GL.BindTexture (TextureTarget.Texture2D, item.NormalMapTexture);
GL.ActiveTexture (TextureUnit.Texture0);
GL.BindTexture (TextureTarget.Texture2D, item.DiffuseTexture);
//Here I bind the Instance buffer with my matrices
//that's a fast switch without changing vao confing
GL.BindVertexBuffer (instanceBufferIndex, item.instancesVboId, IntPtr.Zero,Vector4.SizeInBytes * 4);
//here I draw instanced with base vertex
GL.DrawElementsInstancedBaseVertex(_primitiveType, item.IndicesCount,
DrawElementsType.UnsignedShort, new IntPtr(item.IndicesOffset*sizeof(ushort)),
item.modelMats.Length, item.BaseVertex);
}
}
最终的VAO只绑定一次。