Как использовать UV координаты в OpenGL вместе с Index Buffer?
Я пытаюсь отрисовать куб с помощью Index Buffer. То есть у меня есть 8 точек и индексный буфер, который показывает в каком порядке нужно отрисовывать эти точки, чтобы из треугольников получился куб. Выглядит это примерно так:
float positions[] = {
-0.5f, 0.5f, 0.5f, //0
0.5f, 0.5f, 0.5f, //1
-0.5f,-0.5f, 0.5f, //2
0.5f,-0.5f, 0.5f, //3
-0.5f, 0.5f,-0.5f, //4
0.5f, 0.5f,-0.5f, //5
-0.5f,-0.5f,-0.5f, //6
0.5f,-0.5f,-0.5f, //7
};
unsigned int indices[] = {
0, 1, 2,
1, 2, 3,
4, 5, 6,
5, 6, 7,
1, 5, 3,
5, 3, 7,
0, 4, 2,
4, 2, 6,
4, 5, 0,
5, 0, 1,
6, 7, 2,
7, 2, 3
};
/* ... пропускаю в данном примере подготовку и передачу в OpenGL всех данных ибо это не относится к проблеме*/
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, nullptr));
И все работает. Но после я решил натянуть текстуры с использованием индексного буфера и столкнулся с тем что не получается ассоциировать каждую вершину куба с одной единственной позицией на двумерной текстуре, потому как для каждой отдельной грани (состоящей из двух треугольников) нужны разные координаты текстур и в таком случае использовать индексы для отрисовки не получается. Ибо если добавить UV координаты рядом с обычными и попробовать отрисовать куб, то получится что-то вроде этого:
float positions[] = {
//Pos //UV
-0.5f, 0.5f, 0.5f, 0.f, 1.f, //0
0.5f, 0.5f, 0.5f, 1.f, 1.f, //1
-0.5f,-0.5f, 0.5f, 0.f, 0.f, //2
0.5f,-0.5f, 0.5f, 1.f, 0.f, //3
-0.5f, 0.5f,-0.5f, 0.f, 1.f, //4
0.5f, 0.5f,-0.5f, 0.f, 1.f, //5
-0.5f,-0.5f,-0.5f, 0.f, 0.f, //6
0.5f,-0.5f,-0.5f, 0.f, 0.f //7
};
unsigned int indices[] = {
0, 1, 2,
1, 2, 3,
4, 5, 6,
5, 6, 7,
1, 5, 3,
5, 3, 7,
0, 4, 2,
4, 2, 6,
4, 5, 0,
5, 0, 1,
6, 7, 2,
7, 2, 3
};
/* ... пропускаю в данном примере подготовку и передачу в OpenGL всех данных ибо это не относится к проблеме*/
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, nullptr));
И так как в OpenGL я новичок, то не знаю как это сделать правильно. Можно конечно плюнуть и не использовать индексы и просто описать все треугольники по отдельности как-то так:
float positions[] = {
// Position UV
-0.5f, 0.5f, 0.5f, 0.f, 1.f,
-0.5f,-0.5f, 0.5f, 0.f, 0.f,
0.5f, 0.5f, 0.5f, 1.f, 1.f,
0.5f, 0.5f, 0.5f, 1.f, 1.f,
-0.5f,-0.5f, 0.5f, 0.f, 0.f,
0.5f,-0.5f, 0.5f, 1.f, 0.f,
-0.5f, 0.5f,-0.5f, 0.f, 1.f,
0.5f, 0.5f,-0.5f, 1.f, 1.f,
-0.5f,-0.5f,-0.5f, 0.f, 0.f,
-0.5f,-0.5f,-0.5f, 0.f, 0.f,
0.5f, 0.5f,-0.5f, 1.f, 1.f,
0.5f,-0.5f,-0.5f, 1.f, 0.f,
0.5f, 0.5f,-0.5f, 1.f, 1.f,
0.5f, 0.5f, 0.5f, 0.f, 1.f,
0.5f,-0.5f, 0.5f, 0.f, 0.f,
0.5f, 0.5f,-0.5f, 1.f, 1.f,
0.5f,-0.5f, 0.5f, 0.f, 0.f,
0.5f,-0.5f,-0.5f, 1.f, 0.f,
-0.5f, 0.5f, 0.5f, 0.f, 1.f,
-0.5f, 0.5f,-0.5f, 1.f, 1.f,
-0.5f,-0.5f, 0.5f, 0.f, 0.f,
-0.5f,-0.5f, 0.5f, 0.f, 0.f,
-0.5f, 0.5f,-0.5f, 1.f, 1.f,
-0.5f,-0.5f,-0.5f, 1.f, 0.f,
0.5f, 0.5f,-0.5f, 1.f, 1.f,
-0.5f, 0.5f,-0.5f, 0.f, 1.f,
-0.5f, 0.5f, 0.5f, 0.f, 0.f,
0.5f, 0.5f,-0.5f, 1.f, 1.f,
-0.5f, 0.5f, 0.5f, 0.f, 0.f,
0.5f, 0.5f, 0.5f, 1.f, 0.f,
-0.5f,-0.5f,-0.5f, 0.f, 1.f,
0.5f,-0.5f,-0.5f, 1.f, 1.f,
-0.5f,-0.5f, 0.5f, 0.f, 0.f,
-0.5f,-0.5f, 0.5f, 0.f, 0.f,
0.5f,-0.5f,-0.5f, 1.f, 1.f,
0.5f,-0.5f, 0.5f, 1.f, 0.f,
};
/* ... пропускаю в данном примере подготовку и передачу в OpenGL всех данных ибо это не относится к проблеме*/
glDrawArrays(GL_TRIANGLES, 0, 36));
И на выходе получается абсолютно правильный и ожидаемый результат:

Но к сожалению, код становится более загромаждённым и приходится хранить гораздо больше данных, чем при использовании индексного буфера. Можно ли как-то передавать разные UV координаты для отдельных граней и при этом всё ещё использовать индексный буфер?
Ответы (1 шт):
В общем случае, одна вершина - одна UV координата. Если вам нужно разбивать/дублировать UV, то и вершины придется разбить/продублировать.
Куб, это ярчайший пример необходимости дублирования вершин из-за UV развертки - (8 вершин превращаются в 24 (что всё ещё капельку лучше, чем просто треугольники, с которыми будет 36 вершин). Для других моделей и форм всё гораздо лучше. Так что не забрасывайте индексы, они вам еще пригодятся )
