Hi guys!
I have to draw several objects (300/400 max) whose each one consists in:
- 4 vertices (coordinates)
- a 512*512 pixels texture
To display all my objects, currently, I first build 5 VBOs per object (vertices, colors, index, uv_coordinates and texture). Then, in my display function, I loop on all objects to draw them but, due to multiple calls to some functions such as bindBuffer() or glVertexAttribPointer(), I don’t believe it is the optimal approach.
I am also wondering how to cleverly store such objects in memory (VAO, VBO,…).
My shaders:
vertex_code = """
#version 440 core
uniform float scale;
uniform mat4 Model;
uniform mat4 View;
uniform mat4 Projection;
in vec2 position;
in vec4 color;
out vec4 v_color;
void main()
{
gl_Position = Projection * View * Model * vec4(scale*position, 0.0, 1.0);
v_color = color;
} """
fragment_code = """
#version 440 core
in vec4 v_color;
void main()
{
gl_FragColor = v_color;
} """
The initialization of my objects:
# Generate buffers for each tile
buffer_vertices = gl.glGenBuffers(row_grid.size)
buffer_colors = gl.glGenBuffers(row_grid.size)
buffer_index= gl.glGenBuffers(row_grid.size)
# To simplify, textures are not used here
buffer_uv_coordinates = gl.glGenBuffers(row_grid.size)
buffer_texture = gl.glGenBuffers(row_grid.size)
for iTile, (iRow, iCol) in enumerate(zip(np.nditer(row_grid), np.nditer(col_grid))):
print('iRow=%i, iCol=%i'%(iRow, iCol))
# compute current object bounding box
tileBeamStart = iRow*blockSize*2**wtfLevel
tileBeamEnd = (iRow*blockSize+511)*2**wtfLevel+1
tileSampleStart = iCol*blockSize*2**wtfLevel
tileSampleEnd = (iCol*blockSize+511)*2**wtfLevel+1
# array filled with its 4 corners
mat_vertices = np.array([[tileSampleStart, tileBeamStart],
[tileSampleStart, tileBeamEnd],
[tileSampleEnd, tileBeamStart],
[tileSampleEnd, tileBeamEnd]])
# Delaunay triangulation to generate index
delaunay_tri = Delaunay(mat_vertices)
# read current tile to further be used as texture
tile = ...
vertices = np.ascontiguousarray(mat_vertices.flatten(), dtype=np.float32)
index = np.ascontiguousarray(delaunay_tri.simplices.flatten(), dtype=np.uint32)
# generate random colors
tmp = np.random.rand(mat_vertices.shape[0],3)
#tmp = np.ones(shape=(mat_vertices.shape[0],3))
tmp2 = np.ones(shape=(mat_vertices.shape[0],1))
tmp = np.hstack((tmp, tmp2 ))
colors = np.ascontiguousarray(tmp.flatten().astype(np.float32))
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buffer_vertices[iTile])
gl.glBufferData(gl.GL_ARRAY_BUFFER, vertices.nbytes, vertices, gl.GL_DYNAMIC_DRAW)
# COLORS
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buffer_colors[iTile])
gl.glBufferData(gl.GL_ARRAY_BUFFER, colors.nbytes, colors, gl.GL_DYNAMIC_DRAW)
# INDEX ARRAY
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, buffer_index[iTile])
gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, index.nbytes, index, gl.GL_STATIC_DRAW)
And my display function:
def display():
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
#gl.glDrawArrays(gl.GL_TRIANGLES, 0, 12)
gl.glEnable(gl.GL_DEPTH_TEST)
gl.glDepthFunc(gl.GL_LESS)
# loop on all objects
for iTile in range(row_grid.size):
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, buffer_index[iTile])
loc = gl.glGetAttribLocation(program, "position")
gl.glEnableVertexAttribArray(loc)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buffer_vertices[iTile])
gl.glVertexAttribPointer(loc, 2, gl.GL_FLOAT, False, 0, ctypes.c_void_p(0))
loc = gl.glGetAttribLocation(program, "color")
gl.glEnableVertexAttribArray(loc)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buffer_colors[iTile])
gl.glVertexAttribPointer(loc, 4, gl.GL_FLOAT, False, 0, ctypes.c_void_p(0))
gl.glDrawElements(gl.GL_TRIANGLES, len(index), gl.GL_UNSIGNED_INT, ctypes.c_void_p(0))
glut.glutSwapBuffers()