Using offsets into the buffer in PyOpenGL calls

2019-08-04 10:18发布

In OpenGL the indices parameter for glDrawElements has two different meanings, depending on if you are using GL_ELEMENT_ARRAY_BUFFER or not.

If you have a VBO bound, then it is the offset to start in that buffer, rather than the buffer itself.

When using PyOpenGL, how can you specify the offset to start at in a glDrawElements call? How can you specify multiple start offsets in a glMultiDrawElements call?

1条回答
贼婆χ
2楼-- · 2019-08-04 10:36

In the following examples a list of 6 indices is used, which may form a quad which consists of 2 triangle primitives.

indices = [0, 1, 2, 0, 2, 3]

Since the data which is passed to the OpenGL functions has to consist of fixed size units in a coherent buffer, the list of values has to be stored to an array of floats. Coherent array buffers can be created either by ctypes library or numpy.array library.
The type of the array elements has to match value type enumerator constant, which is set, at the call of glDrawElements or glMultiDrawElements:

ctypes.c_ubyte   /  numpy.uint8     <->    GL_UNSIGNED_BYTE
ctypes.c_ushort  /  numpy.uint16    <->    GL_UNSIGNED_SHORT
ctypes.c_uint    /  numpy.uint32    <->    GL_UNSIGNED_INT

Using ctypes:

import ctypes

indexArray = (ctypes.c_uint * 6)(*indices)

Using numpy:

import numpy

indexArray = numpy.array(indices, dtype=numpy.uint32)

For using an index buffer and glDrawElements there are different opportunities.

Using Legacy OpenGL (compatibility profile xontext), the buffer can be directly passed to glDrawElements. The pointer to the array data is passed to the function.

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, indexArray)

If named element array buffer object is stated in the vertex array object, then the last parameter of glDrawElements is treated as a byte offset into the buffer object's data store.

glBindVertexArray(vao)

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexArray, GL_STATIC_DRAW)

If the indices should be drawn, starting at the 1st element of the buffer, then the last parameter can be None, which is equivalent to ctypes.c_void_p(0):

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)

If the drawing should not start with the first index, then the byte offset of the start index has to be calculated. e.g. 3*4 sets the start to the 3 index, for a buffer of type GL_UNSIGNED_INT:

glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, ctypes.c_void_p(3 * 4))

The use of glMultiDrawElements is very similar.

Using a compatibility profile xontext, the buffer pointers can be directly passed to the OpenGL function.

To arrays of indices have to be generated:

Using ctypes:

indexArray1 = (ctypes.c_uint * 3)(0, 1, 2)
indexArray2 = (ctypes.c_uint * 3)(0, 2, 3)

Using numpy:

indexArray1 = numpy.array([0, 1, 2], dtype=numpy.uint32)
indexArray2 = numpy.array([0, 2, 3], dtype=numpy.uint32)

The pointers to the buffers have to be arranged to an array of pointers:

Using ctypes the pointer to the index data arrays is get by ctypes.addressof():

indexPtr = (ctypes.c_void_p * 2)(ctypes.addressof(indexArray1),ctypes.addressof(indexArray2))

Using numpy the pointer to the index data arrays is get by numpy.ndarray.ctypes:

indexPtr = numpy.array([indexArray1.ctypes.data, indexArray2.ctypes.data], dtype=numpy.intp)

This array of pointer can be passed to the OpenGL function:

counts   = [3, 3]
glMultiDrawElements(GL_TRIANGLES, counts, GL_UNSIGNED_INT, indexPtr, 2)

If a vertex array object with an named element array buffer is used,

glBindVertexArray(vao)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo)

then the index parameter is treated as a pointer to an array of byte offsets. In the following an array with 2 offset is passed to the function. 0 identifies the 1st index in the array and 3*4 the 3rd index.

Using ctypes:

indexPtr = (ctypes.c_void_p * 2)(0, 3 * 4)
counts   = [3, 3]
glMultiDrawElements(GL_TRIANGLES, counts, GL_UNSIGNED_INT, indexPtr, 2)

Using numpy:

indexPtr = np.array([0, 3*4], dtype=numpy.intp)
counts   = [3, 3]
glMultiDrawElements(GL_TRIANGLES, counts, GL_UNSIGNED_INT, indexPtr, 2)
查看更多
登录 后发表回答