Drawing primitives using vertex buffers

VBO was, in the past, a part of an OpenGL as an extension. With the new OpenGL specification, the VBO mechanism is included in the GLSL specification. This means that you can reuse much of the existing functionality with small changes. VBOs present an opaque storage for data; therefore, they might contain the vertex positions, texture coordinates, colors or any other data. GLSL shaders can use these buffers but they must be differentiated so the shader program knows what data is stored inside of these buffers. That's where the vertex array objects or VAO come in. The vertex array object is a structure that merges VBOs for use in the shader program. They are used in GLSL shader programs as a main source of vertex attributes. Each of the attributes can be submitted in its own VBO. It ensures efficient upload of all vertices into graphic memory and you can easily add other vertices if needed.

You may find it desirable to use interleaved data format for VBO. It's a way to store all the vertex attributes into one vertex buffer. Examples of data layout are shown in the following diagram:

Drawing primitives using vertex buffers

There are three cases of decisions on data layout:

  • Each vertex attribute has its own VBO—vertices, normal vectors, and vertex colors.
  • All the attributes are stored in one VBO. They are grouped by the attribute type.
  • All the attributes are stored in one VBO. They are grouped by the vertex.

Note that if you plan on frequent updating of vertex attributes, it's better to reserve the whole VBO for this purpose. This way OpenGL can optimize memory access to vertex attributes.

Getting ready

This recipe will use data layout where each vertex attribute will use its own VBO. You'll be using the vertex position, the texture coordinates, and the vertex color. Therefore, you'll need to create three VBOs. You can create the vertex buffer objects with the gl.GenBuffers function:

local vertex_buffer_object = gl.GenBuffers(3)

It accepts one parameter that presents the number of vertex buffer objects to be created.

You'll also be using the vertex array object that specifies the vertex data layout and references to all used VBOs. The vertex array object can be created using the gl.GenVertexArrays function. This function accepts the number of vertex array objects to be reserved:

local vertex_array_object = gl.GenVertexArrays(1)

How to do it…

You'll need one vertex buffer object for each vertex attribute. In this case, you'll be using three vertex buffer objects for the vertex position, the vertex color, and the vertex texture coordinates. Now, you can fill each one with the corresponding vertex data.

Vertex positions

We will use four vertices to draw the rectangular polygon. The following code will define the vertex positions for one rectangle:

//vertex positions are specified by X, Y pairs
local vertex_positions = {
  -1, -1,
  1, -1,
  1, 1,
     -1, 1,
}
gl.BindBuffer(gl_enum.GL_ARRAY_BUFFER, vertex_buffer_object[1])
gl.BufferData(gl_enum.GL_ARRAY_BUFFER, vertex_positions, gl_enum.GL_STATIC_DRAW)

Vertex colors

You can use this code to store the vertex colors:

//vertex colors use RGBA quadruplets
local vertex_colors = {
  1,0,0,1,
  0,1,0,1,
  0,0,1,1,
  1,1,0,1,
}
gl.BindBuffer(gl_enum.GL_ARRAY_BUFFER, vertex_buffer_object[2])
gl.BufferData(gl_enum.GL_ARRAY_BUFFER, vertex_colors, gl_enum.GL_STATIC_DRAW)

Vertex texture coordinates

The following code will define the texture coordinates for vertices:

//texture coordinates use U, V coordinate pairs
local vertex_texcoords = {
  0, 0,
  1, 0,
  1, 1,
     0, 1,
}
gl.BindBuffer(gl_enum.GL_ARRAY_BUFFER, vertex_buffer_object[3])
gl.BufferData(gl_enum.GL_ARRAY_BUFFER, vertex_texcoords, gl_enum.GL_STATIC_DRAW)

Now that you have data stored in VBOs, you'll have to bind them into VAO. The vertex array object contains data layout information. For instance, if the vertex position consists of three dimensions, each vertex will use three subsequent values from VBO that contains vertex positions.

Before using the vertex array object, you'll need to bind it with the gl.BindVertexArray function:

gl.BindVertexArray(vertex_array_object[1])

Another step is enabling and mapping vertex attributes to buffers. In this recipe, each vertex contains three vertex attributes: the vertex position, the vertex color and the texture coordinate. Each vertex attribute will use different attribute index. This index will correspond to the location value in the shader source:

layout (location = 0) in vec3 VertexPosition;

The vertex attribute is mapped by a pair of functions: gl.BindBuffer and gl.VertexAttribPointer. The first one prepares VBO to be used. The second command uses this function specification:

gl.VertexAttribPointer(location_index, vertex_elements_count, normalized, stride)

The final code will look like this:

-- vertex position
gl.BindBuffer(gl_enum.GL_ARRAY_BUFFER, vertex_buffer_object[1])
gl.VertexAttribPointer(0, 2, false, 0)

-- vertex color
gl.BindBuffer(gl_enum.GL_ARRAY_BUFFER, vertex_buffer_object[2])
gl.VertexAttribPointer(1, 4, false, 0)

-- texture coordinates
gl.BindBuffer(gl_enum.GL_ARRAY_BUFFER, vertex_buffer_object[3])
gl.VertexAttribPointer(2, 2, false, 0)

Notice that the vertex position is specified by two elements (x, y), vertex color by four elements (r, g, b, a) and texture coordinates by two elements (s, t).

The last thing you'll need to do before drawing is enabling vertex attributes with the gl.EnableVertexAttribArray function.

gl.EnableVertexAttribArray(0)
gl.EnableVertexAttribArray(1)
gl.EnableVertexAttribArray(2)

Alternatively, you can disable certain vertex attributes with the gl.DisableVertexArray function:

gl.DisableVertexAttribArray(attribute_index)

After all these steps, you are ready to use VBOs and VAO to efficiently draw vertices. Don't forget to bind the currently used vertex array object before drawing. Otherwise, OpenGL wouldn't know what data to use and you could get unpredictable results.

Vertices can be drawn by using the gl.DrawArrays function:

gl.DrawArrays(gl_enum.GL_QUADS, 0, 4)

The first parameter specifies what graphic primitive will be used. It uses the same constants as were used in the gl.Begin function. The second parameter sets the vertex offset and the last one is a number of vertices to be used.

How it works…

Vertex buffer objects can contain arbitrary data. Vertex itself can use more than one vertex attribute. Attributes usually contain more than one element. For instance, the vertex position uses two coordinates in 2D space, but in 3D space there are three coordinates. OpenGL doesn't know how many coordinates you use for vertices. Therefore, vertex array objects are used to help with this issue. Vertex array object defines how to get attributes for each vertex. Keep in mind that it contains only references to VBOs, so you'll need to keep them.

LuaGL uses the float data type for VBO elements.

How it works…

There's more…

VBO presents a common data storage. It provides limited storage depending on implementation and current machine. Some parts can be cached in system RAM and the currently used parts are in graphic memory.

Another thing is that the gl.BufferData function reserves a certain amount of memory to store data. You can use only a reserved range for data updates. There might be situations where you know exactly how much storage you'll need, but you don't want to upload data right away. For this case, you can use the gl.BufferData function, but instead of submitting data in a Lua table, you'll be using elements count:

local element_count = 12
gl.BufferData(gl_enum.GL_ARRAY_BUFFER, element_count, gl_enum.GL_STATIC_DRAW)

This will reserve memory space for 12 elements, which you can update with the gl.BufferSubData function:

local offset = 0
local data = {1,2,3,4}
gl.BufferSubData(gl_enum.GL_ARRAY_BUFFER, offset, data)

The offset parameter presents a number of elements to be skipped.

See also

  • The Using uniform variables with shaders recipe
  • The Writing a vertex shader recipe
  • The Writing a fragment (pixel) shader recipe
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.122.68