Какой примитив OpenGL я должен использовать для рисования триангуляции? - PullRequest
2 голосов
/ 10 марта 2019

У меня есть следующее изображение:

enter image description here

То, что я смог триангулировать следующим образом: enter image description here

Я сделал это, используя библиотеку Python треугольник .Мой результат триангуляции сохраняется в объекте 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 будет недостаточно.

1 Ответ

4 голосов
/ 10 марта 2019

У вас есть 2 массива.Первый массив содержит 2-мерные координаты вершин, а второй массив содержит индексы.
Вы должны использовать glDrawElements, чтобы нарисовать примитивы треугольника, которые содержатся во втором массиве.Индексы относятся к соответствующим координатам вершин 1-го массива.

Сначала необходимо создать буфер с плавающей запятой для координат вершин и интегральный буфер для индексов.Самый простой способ - использовать NumPy для преобразования вложенного списка или массивов в буферы массивов.

Предполагая, что у вас есть массив vertices в форме [[x0, y0], [x1, y1], [x2, y2], ...] и массив indices в форме [[a0, b0, c0], [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)

Создать объект массива вершин.См. Спецификация вершин :

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.

Самый простой способ - создать отдельный массив текстурных координат.Предполагая, что у вас есть координаты текстуры texAttr в форме [[u0, v0], [u1, v1], [u2, v2], ...].Генерация буфера проста:

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

Если у вас есть шейдерная программа, вам нужно добавить атрибут координаты текстуры:

например,

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_ARRAY и glVertexPointer сопоставлено с атрибутом вершины 0. См. Каковы местоположения атрибутовдля конвейера с фиксированными функциями в профиле ядра OpenGL 4.0 ++? :

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, где 2-й параметр - это смещение в байтах относительно координаты вершины.Смещение для координаты i будет равно 4*2*i (4 - это размер с плавающей точкой в ​​байтах, и каждая координата состоит из 2 компонентов x и y ).

...