OpenGL: Как спроектировать эффективную систему рендеринга, используя массивы вершин с глубиной сортировки - PullRequest
5 голосов
/ 13 декабря 2010

Люди постоянно говорят мне использовать хотя бы Vertex Arrays.Но я думаю, что это не очень хорошая идея, поскольку я использую glPushMatrix() с glTranslatef/glRotatef для позиционирования объекта в трехмерном мире.

Итак, я должен прекратить использовать glPushMatrix() и вычислить повернутый / перемещенныйпозиции вершин в мире «вручную», а затем помещают их данные вершин в массив вершин и затем визуализируют их все сразу?

Но все это станет еще более запутанным, когда я буду использовать разные текстурные поверхности для всехобъекты на экране, которые также отсортированы по глубине.

Итак:

  1. Мне бы также пришлось хранить каждый объект с идентификатором поверхности текстуры.
  2. Iотсортирует все видимые объекты по их позиции Z (игра просматривается только сверху вниз, и все объекты плоские).
  3. Я бы прошел через этот отсортированный массив:
  4. Создать новый буфери скопировать в этот буфер только вершину / texcoord / color / normal:
  5. Каждый раз, когда идентификатор поверхности текстуры изменяется с предыдущего идентификатора, я буду привязываться к правильному идентификатору текстуры:
  6. Загрузитьданные вершины я сталкиваюсьected.
  7. Освободить буфер, используемый для временного массива вершин.
  8. Повторять шаги 4-7, пока я не просмотрю все данные, которые я отсортировал на первом месте.
  9. Бесплатномои отсортированные данные массива и повторите шаги 1-9.

Правильно ли я делаю это?

Кроме того, как я должен проектировать структуру данных для объектов, которые я буду сортировать?Например, хорошо ли использовать std::vector для хранения данных вершин для каждого объекта?Или есть лучшая альтернатива?Я думал, что std::vector для хранения всех этих данных будет выглядеть так:

struct GameObject {
    int TexID;
    float z; // we will sort by this
    vector<VTCNStruct> VertexData; // store each point of the object here (including color/normal/texcoord points).
};

vector<GameObject> GameObjectBuffer; // push all sortable objects here

Кроме того, на шаге 4: возможно ли использовать уже существующий std::vector в этом случае?У меня была идея, что я должен использовать необработанные массивы, такие как new float[100] для отправки массива вершин в мой графический процессор, или я мог бы каким-то образом (эффективно) каким-то образом (эффективно) использовать здесь уже существующий отсортированный std::vector, не создавая каждый раз новый буферID текстуры меняется?

Ответы [ 2 ]

11 голосов
/ 14 декабря 2010

Просьба отказаться от glBegin / glEnd , теперь , она устарела и была удалена из OpenGL-4. Вам определенно следует использовать массивы вершин, даже лучше, если вы используете объекты буфера вершин.

Используя непосредственный режим (glBegin / glEnd), драйвер OpenGL должен создавать массив вершин из вызовов функций. Поскольку неясно, сколько вершин поступит, в конечном итоге будет перераспределяться память несколько раз (времена, в которые графические процессоры непосредственно выполняли вызовы между glBegin / glEnd, давно прошли).

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

Затем между рисованием объектов настройте матрицу вида модели.

Порядок сортировки должен быть следующим:

  1. разделить на непрозрачные и полупрозрачные объекты. Сортировать непрозрачные
  2. Сортировка opqaues по объектам GL (текстура, шейдер, материалы и т. Д.), Поскольку переключение объектов GL является наиболее дорогим.
  3. Для каждой отдельной группы объектов GL сортируйте рядом с дальним и рисуйте в этом порядке
  4. Сортировка полупрозрачных далеко и близко и рисовать в этом порядке

Вы не должны пытаться возиться с загрузкой / загрузкой буфера. Просто загрузите данные вершин один раз, а затем просто настройте индексные массивы и порядок их отправки. Не нужно беспокоиться о доступной памяти OpenGL, нет никаких ограничений. Если ваши данные не помещаются в ОЗУ GPU, драйвер отвечает за их замену в системной памяти - поэтому вам также следует сначала отсортировать объекты OpenGL, поскольку каждый раз, когда вы переключаете объекты OpenGL (glBindTexture, glBindBuffer и т. Д.), Драйвер может нужно поменять местами, так что вы хотите свести к минимуму эти операции обмена. Объем данных, отправляемых в графический процессор в виде индексных массивов, будет намного меньше, чем тот, который отправляется при вызовах в непосредственном режиме, как минимум:

  • Массив индексов: 16 бит на вершину (16-битные индексы размера наиболее эффективны).

  • Вызов немедленного режима: 4 * 32 бита на вершину

2 голосов
/ 13 декабря 2010

Вы должны хранить один массив вершин на объект. Не используйте glTranslatef / glRotatef и т. Д. Вместо этого сверните все в одну матрицу. Используйте эту матрицу для глубокой сортировки ваших объектов. Затем нарисуйте свои объекты спереди назад, нажав матрицу преобразования объектов, нарисовав массив вершин, а затем вытолкнув матрицу преобразования.

Этот подход означает, что вы не создаете и не освобождаете массивы для хранения данных вершин.

Что касается использования std :: vector, большинство реализаций использует необработанный массив C внутри, поэтому вы можете сделать & myVec [0], чтобы получить этот массив. Однако не пытайтесь сохранить этот указатель, поскольку std :: vector может изменить realloc своего массива, и тогда ваш постоянный указатель больше не будет действительным.

...