I've the following image :
That I was able to triangulate like the following :
I did it using the triangle library of python. My triangulation result is stored into a dict
object which look like that:
>>> triangulation["vertices"]
array([[ 23. , 282. ],
[ 24. , 254. ],
[ 30. , 239. ],
[ 43. , 219. ],
[ 60. , 204. ], ... And so on ...
>>> triangulation["triangles"]
array([[ 89, 106, 105],
[ 99, 35, 86],
[110, 68, 87],
[ 47, 66, 83],
[ 72, 82, 74], ... And so on ...
Now, I want to distord and draw this texture as a mesh using OpenGL. I was wondering which primitive should I use? I think that TRIANGLE_STRIP
is the right solution but it's a complex triangulation and it seems obvious that only one TRIANGLE_STRIP will not be enough.
You've 2 arrays. The first array contains the 2 dimensional vertex coordinates and the second array contains the indices.
You have to use glDrawElements
tor draw the triangle primitives which are contained in the 2nd array. The indices refer to the corresponding vertex coordinates of the 1st array.
First you've to create a floating point buffer for the vertex coordinates and an integral buffer for the indices. The easiest way is to use NumPy, to transform nested list or arrays to array buffers.
Assuming that you've an array of vertices
in the form [[x0, y0], [x1, y1], [x2, y2],...] and an array of indices
in the form [[a0, b0, c0], [a1, b1, c1], [a2, b2, c2],...], then the buffers can be created like this:
import numpy as np
vertex_array = np.array(vertices, dtype=np.float32)
no_of_indices = len(indices) * 3
index_array = np.array(indices, dtype=np.uint32)
The same can be done by using ctypes
, instead of NumPy. But then the lists have to be flattened in the form [x0, y0, x1, y1, x2, y2,...] respectively [a0, b0, c0, a1, b1, c1, a2, b2, c2,...]:
vertex_array = (ctypes.c_float * len(flat_vertices))(*flat_vertices)
no_of_indices = len(flat_indices) * 3
index_array = (ctypes.c_uint32 * no_of_indices)(*flat_indices)
Create a vertex array object. See Vertex Specification:
vao = glGenVertexArrays(1)
glBindVertexArray(vao)
ibo = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_array, GL_STATIC_DRAW)
vbo = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferData(GL_ARRAY_BUFFER, vertex_array, GL_STATIC_DRAW)
glVertexAttribPointer(0, 2, GL_FLOAT, False, 0, None)
glEnableVertexAttribArray(0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
If you want to draw the triangle primitives it is sufficient to bind the vertex array object and to call glDrawElements
:
glBindVertexArray(vao)
glDrawElements(GL_TRIANGLES, no_of_indices, GL_UNSIGNED_INT, None)
Regarding to the comment:
[...] I already know how to texture a plane by using
glTexCoord2f
thenglVertex3f
but didn't figure out how I can do it with a vao.
The easiest way is to create a separate array of texture coordinates. Assuming you've the texture coordinates texAttr
in the form [[u0, v0], [u1, v1], [u2, v2],...].
Generating the buffer is straight forward:
texAttr_array = np.array(texAttr, dtype=np.float32)
If you have a shader program, then you've to add the texture coordinate attribute:
e.g.
layout (location = 0) in vec2 vertex;
layout (location = 1) in vec2 texAttr;
and to define an array of generic vertex attribute data.
vao = glGenVertexArrays(1)
glBindVertexArray(vao)
# [...] index buffer
vbo = glGenBuffers(2)
glBindBuffer(GL_ARRAY_BUFFER, vbo[0])
glBufferData(GL_ARRAY_BUFFER, vertex_array, GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, vbo[1])
glBufferData(GL_ARRAY_BUFFER, texAttr_array, GL_STATIC_DRAW)
glVertexAttribPointer(0, 2, GL_FLOAT, False, 0, None)
glEnableVertexAttribArray(0)
glVertexAttribPointer(1, 2, GL_FLOAT, False, 0, None)
glEnableVertexAttribArray(1)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
If you use compatibility profile and the fixed function attributes, then you've to specify the glTexCoordPointer
and enable the client state GL_TEXTURE_COORD_ARRAY
.
Note, the client state GL_VERTEX_ARRAY
and glVertexPointer
is mapped to the vertex attribute 0. See What are the Attribute locations for fixed function pipeline in OpenGL 4.0++ core profile?:
vao = glGenVertexArrays(1)
glBindVertexArray(vao)
# [...] index buffer
vbo = glGenBuffers(2)
glBindBuffer(GL_ARRAY_BUFFER, vbo[0])
glBufferData(GL_ARRAY_BUFFER, vertex_array, GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, vbo[1])
glBufferData(GL_ARRAY_BUFFER, texAttr_array, GL_STATIC_DRAW)
glVertexPointer(2, GL_FLOAT, 0, None)
glEnableClientState(GL_VERTEX_ARRAY)
glTexCoordPointer(2, GL_FLOAT, 0, None)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
Note, if you don't use a shader, then 2 dimensional texturing has to be enabled by
glEnable(GL_TEXTURE_2D)
Regarding to the comment:
I d'like to displace vertex one by one [...]
A single vertex coordinate can be changed by glBufferSubData
, where the 2nd parameter is a byte offset to the vertex coordinate. The offset for the coordinate i
would be 4*2*i
(4 is the size of float in bytes, and each coordinate consist of 2 components x and y).