我应该使用哪个OpenGL Primitive来绘制三角测量?

问题描述 投票:2回答:1

我有以下图片:

enter image description here

我能够像以下一样进行三角测量:enter image description here

我使用python的triangle库做到了。我的三角测量结果存储在一个dict对象中,如下所示:

>>> 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 ...

现在,我想使用OpenGL将此纹理分割为网格。我想知道我应该使用哪种原语?我认为TRIANGLE_STRIP是正确的解决方案,但它是一个复杂的三角测量,很明显只有一个TRIANGLE_STRIP是不够的。

python opengl triangulation
1个回答
4
投票

你有2个阵列。第一个数组包含2维顶点坐标,第二个数组包含索引。 你必须使用glDrawElements来绘制第二个数组中包含的三角形基元。索引指的是第一个数组的相应顶点坐标。

首先,您要为顶点坐标创建浮点缓冲区,并为索引创建一个积分缓冲区。最简单的方法是使用NumPy将嵌套列表或数组转换为数组缓冲区。

假设你有[[x0,y0],[x1,y1],[x2,y2],......]形式的vertices数组和[[a0,b0,c0]形式的indices数组],[a1,b1,c1],[a2,b2,c2],...],然后可以像这样创建缓冲区:

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)

使用ctypes而不是NumPy可以做到同样的事情。但是这些列表必须分别以[x0,y0,x1,y1,x2,y2,...]的形式展平[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)

创建顶点数组对象。见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)

如果要绘制三角形图元,则绑定顶点数组对象并调用glDrawElements就足够了:

glBindVertexArray(vao)
glDrawElements(GL_TRIANGLES, no_of_indices, GL_UNSIGNED_INT, None)

关于评论:

[...]我已经知道如何使用glTexCoord2f然后使用glVertex3f对飞机进行纹理处理,但是没有弄清楚如何用vao来做到这一点。

最简单的方法是创建一个单独的纹理坐标数组。假设你有[[u0,v0],[u1,v1],[u2,v2],......]形式的纹理坐标texAttr。生成缓冲区很简单:

texAttr_array = np.array(texAttr, dtype=np.float32)

如果你有一个着色器程序,那么你要添加纹理坐标属性:

EG

layout (location = 0) in vec2 vertex;
layout (location = 1) in vec2 texAttr;

并定义通用顶点属性数据的数组。

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)

如果使用兼容性配置文件和固定功能属性,则需要指定glTexCoordPointer并启用客户端状态GL_TEXTURE_COORD_ARRAY。 注意,客户端状态GL_VERTEX_ARRAYglVertexPointer被映射到顶点属性0.请参阅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)

请注意,如果您不使用着色器,则必须启用二维纹理

glEnable(GL_TEXTURE_2D)

关于评论:

我喜欢逐个取代顶点[...]

单个顶点坐标可以通过glBufferSubData更改,其中第二个参数是到顶点坐标的字节偏移量。坐标i的偏移量为4*2*i(4是浮点数的大小,以字节为单位,每个坐标由2个分量x和y组成)。

© www.soinside.com 2019 - 2024. All rights reserved.