#opengl #glsl
#opengl #glsl
Вопрос:
Я разрабатываю небольшой 3D-движок, используя OpenGL и GLSL.
Я включил систему пакетной обработки данных вершин, целью которой является сбор всей геометрии (всех объектов), использующих одну и ту же программу шейдеров и одинаковые преобразования в уникальном объекте вершинного буфера (VBO), тем самым минимизируя изменения состояния (привязку) и вызовы рисования.
В настоящее время я использую функцию ‘glMultiDrawElements’ для рендеринга определенного пакета данных (таким образом, один вызов draw). Так, например, если у меня в пакете 3 сетки, у меня также есть 3 массива индексов (по одному для каждой сетки), организованных в массив ‘GLvoid **’ (двойной массив). Итак, чтобы отобразить мои 3 сетки, у меня есть уникальный вызов glMultiDrawElements, но я должен передать непосредственно функции двойной массив элементов в параметре.
Но мне интересно (по вопросу производительности), возможно ли сохранить все элементы (двойной массив элементов) в объекте индексного буфера (IBO) (как это можно сделать с помощью glDrawElements -> здесь простой массив элементов) и связать его перед вызовом glMultiDrawElements… Я так не думаю, потому что это двойной массив, а не простой массив, но, возможно (и я надеюсь на это) Я ошибаюсь.
Вот пример использования glDrawElements (псевдокод):
[...]
//Setup data
[...]
#define OFFSET_BUFFER(offset) ((char*)NULL offset)
foreach (pMeshGeometry from meshes) //iterates for each mesh of the scene
{
pMeshGeometry->GetIndexBuffer().Lock(); //Bind IBO
{
glDrawElements(pMeshGeometry->GetPrimitiveType(),
pMeshGeometry->GetIndexBufferSize(), pMeshGeometry->GetIndexBuffer().GetType(), OFFSET_BUFFER(0)); //Render a specific mesh eccording to indices
}
}
На данный момент я использую glMultiDrawElement таким образом:
glMultiDrawElements(GL_TRIANGLES, amp;this->m_CountElementArray[0], GL_UNSIGNED_INT,
(const GLvoid **)amp;this->m_IndexAttribArray[0], this->m_CountElementArray.size()); //I enter the array of pointer directly in parameter
Итак, возможно, следующий пример должен быть возможен:
#define OFFSET_BUFFER(offset) ((char**)NULL offset) //Something like this
glMultiDrawElements(GL_TRIANGLES, amp;this->m_CountElementArray[0], GL_UNSIGNED_INT,
OFFSET_BUFFER(0), this->m_CountElementArray.size()); //Something like this
Итак, если это невозможно сделать, я подумал о функции ‘glDrawRangeElements’. Для моего примера из 3 сеток в уникальном VBO мне просто нужно будет привязать IBO перед каждым вызовом glDrawRangeElements (здесь 3 вызова рисования для каждой сетки -> so цикл glDrawRangeElements). Итак, здесь явно можно использовать IBO.
Этот метод наверняка сработает, но я не думаю, что он лучший! Я думаю, что это можно сделать, используя glMultiDrawElements с IBO, но я не знаю, как это сделать.
Или, может быть, это действительно невозможно. Возможно, тот факт, что ввод directy в параметр массива индексов выполняется быстрее, чем метод, использующий glDrawRangeElements и его IBO, и поэтому использование IBO в этом случае, возможно, устарело и поэтому не адаптировано.
Что вы об этом думаете?
Комментарии:
1. Пожалуйста , используйте некоторые разрывы строк. Этот гигантский абзац практически невозможно прочитать.
2. Что именно вы здесь спрашиваете? Даже с разрывами строк я не уверен.
3. Извините, я думал, это ясно. Подводя итог, мне интересно, можно ли использовать IBO с glMultiDrawElements вместо прямого использования двойного массива индексов в параметре.
4. @user1364743: Нет «двойного массива». Существует массив указателей / смещений. Есть ARB_multi_draw_indirect . Но я не уверен, что это то, о чем вы просите.
5. Извините, я хотел сказать массив указателей, а не двойной массив. Я обновил свой вопрос, добавив пример исходного кода (псевдокода) с помощью метода ‘glDrawElements’. Как вы можете видеть перед основным циклом, я настраиваю все данные вершин в VBO, а все данные индексов — в IBO. После этого в основном цикле я использую макрос OFFSET_BUFFER. Это работает. Возможно ли использовать такой макрос для функции ‘glMultiDrawElements’ (и поэтому использовать IBO вместо прямого использования массива указателей)?
Ответ №1:
Вы, конечно, можете использовать индексные буферы с glMultiDrawElements()
. Массивы индексов на стороне клиента устарели в профиле ядра OpenGL. Итак, если glMultiDrawElements()
не удалось бы работать с индексными буферами, не было бы возможности использовать его больше.
Чтобы увидеть, как это работает, нам нужно посмотреть, что означают аргументы glMultiDrawElements()
. Вызов — это, по сути, просто ярлык для нескольких glDrawElements()
вызовов. Подпись:
void glMultiDrawElements(GLenum mode, const GLsizei* count, GLenum type,
const GLvoid** indices, GLsizei primcount);
Помимо некоторых деталей проверки ошибок, этот вызов эквивалентен:
for (int i = 0; i < primcount; i) {
glDrawElements(mode, count[i], type, indices[i]);
}
Теперь помните, что если буфер индекса привязан, последним аргументом glDrawElements()
является относительное смещение в буфер. Таким образом, соответствующий 4-й элемент glMultiDrawElements()
представляет собой массив смещений в буфер. 2-й аргумент — это соответствующий массив значений.
Люди часто используют макрос, чтобы скрыть громоздкое преобразование типа последнего аргумента glDrawElements()
. Используя это:
#define BUFFER_OFFSET(offset) (static_cast<char*>(0) (offset))
В качестве примера, допустим, у нас есть привязка к индексному буферу, и мы хотим нарисовать 3 поддиапазона индексного массива одним вызовом:
- 20 индексов, начинающихся с индекса 10 в буфере.
- 30 индексов, начиная с индекса 40 в буфере.
- 10 индексов, начинающихся с индекса 90 в буфере.
Я буду использовать unsigned shorts (GLushort) для типа индекса. Таким образом, индексный буфер был бы заполнен данными из GLushort indexA[100]
в какой-то момент в прошлом. Тогда вызов setup и draw выглядит следующим образом:
GLsizei count[3] = {20, 30, 10};
GLvoid* indices[3] = {
BUFFER_OFFSET(10 * sizeof(GLushort)),
BUFFER_OFFSET(40 * sizeof(GLushort)),
BUFFER_OFFSET(90 * sizeof(GLushort)),
};
glMultiDrawElements(GL_TRIANGLE_STRIP, count, GL_UNSIGNED_SHORT, indices, 3);
Комментарии:
1. Большое вам спасибо за этот полный ответ. Я уверен, что ваше решение является лучшим, и оно очень логично. Я собираюсь интегрировать ее в свою программу. Хорошего дня. Пока!