Как реализовать VBO для больших сеток и получить плавную анимацию?

Я создаю анимацию в Maya продолжительностью в минуту и ​​собираюсь визуализировать ее в OpenGL. Я делаю это как проект в колледже.

Сцена состоит только из человеческого лица с искаженными выражениями. Сетка имеет около 2200 четырехугольных граней.

Я нашел perl-скрипт, который конвертирует объектные файлы Wavefront в массивы вершин и нормалей. Я намереваюсь анимировать в Maya со скоростью 24 кадра в секунду, затем экспортировать сетку в каждом кадре в объектный файл Wavefront, а затем запускать все это через сценарий perl, который даст мне массивы вершин и нормалей.

Итак, чтобы проверить возможность, я преобразовал два кадра анимации в Maya в объектные файлы и прогнал их через сценарий (после его настройки), что дало мне тысячи вызовов glVertex и glNormal. Я скопировал все это в свою программу на C++ и скомпилировал. Он работает гладко.

Учитывая, насколько большой будет программа, когда я скопирую в нее операторы glVertex и glNormal длительностью 60 секунд*24 кадра, я хочу попробовать использовать VBO. Итак, я читал об этом, но я не совсем понимаю реализацию.

Итак, мой первый вопрос: как лучше всего реализовать VBO в этом случае?

Я думаю о 2D-массивах как для вершин, так и для нормалей, по одному для каждого кадра; и GL_STATIC_DRAW_ARB для параметра "использование" файла glBufferDataARB().

Скажем, если моя анимация длится 5 кадров, моя сетка лица состоит из 2200 вершин и нормалей, то я создам:

GLfloat face_vertices[5][2200] = {.....};
GLfloat face_normals[5][2200] = {.....};

Мой второй вопрос: будет ли приведенный выше код работать или работать «хорошо» с VBO?

Кроме того, я не уверен, важна ли эта информация, но мой компьютер работает на графической карте Intel 82945G, и я почти уверен, что компьютеры в моем колледже также работают на Intel. Просто подумал, что упомяну об этом.

ОБНОВИТЬ

Производительность также вызывает беспокойство.


person adi    schedule 18.04.2012    source источник
comment
Как ты сделал свою оснастку? Сопоставляются ли вершины с соединениями линейно? Если да, вы можете легко экспортировать сетку с костями и анимацией в файл Wavefront и прочитать его одним из множества игровых движков. Некоторые из них способны воспроизводить анимацию на аппаратных шейдерах, но я не уверен, есть ли Intel в списке поддерживаемых.   -  person Rekin    schedule 19.04.2012
comment
О, я совершил настоящий мысленный прыжок. Что касается ваших оптимизаций VBO - они работают только для статических сеток со старым (фиксированным, например, без шейдеров) конвейером. Итак, если Intel не очень эффективен, все, что вы можете сделать, это использовать несколько VBO - каждый для одного кадра.   -  person Rekin    schedule 19.04.2012
comment
@Rekin они работают только для статических сеток со старым конвейером - А? Теперь, что вы имеете в виду с этим? Кстати, он не использует никакого риггинга, а использует простую анимацию морфинга.   -  person Christian Rau    schedule 22.04.2012


Ответы (2)


Я думаю о 2D-массивах как для вершин, так и для нормалей, по одному для каждого кадра; и

Я думаю, что это неправильное решение. С таким объемом данных имеет смысл его стримить. Например, держать в памяти 1 секунду анимации, остальное подгружать по требованию. Я считаю, что для этого сценария есть GL_STREAM_**** флагов.

Лучшим решением будет экспорт костей из майя и их анимация. (В этом случае вам понадобится один меш, который никогда не изменится)

Единственная ситуация, в которой вам пришлось бы экспортировать покадровую анимацию для каждой вершины, — это когда вы экспортируете что-то безумно дорогое в вычислительном отношении. Единственный реалистичный сценарий, о котором я могу думать, - это 3D-жидкостные сетки (топология меняется в самом кадре и т. д.) - все остальное можно вычислить либо на ЦП, либо на графическом процессоре. Однако в вашем сообщении не указано, что это ваш сценарий. Итак, по закону Мерфи я должен предположить, что вы используете неэффективное решение проблемы, которую можно решить по-другому.

: Будет ли приведенный выше код работать или работать «хорошо» с VBO?

Невозможно ответить, потому что вы не сказали, как вы собираетесь рисовать данные. Можно поставить любую машину на колени даже с простой геометрией, злоупотребляя шейдерами, альфа-смешиванием или рендерингом одного и того же МНОЖЕСТВО раз.

person SigTerm    schedule 22.04.2012

Если бы вы могли плавно запустить два кадра своей анимации, вы могли бы плавно запустить 60 * 24 кадра, «стоящих операторов glVertex и glNormal», если бы вы могли автоматически генерировать вызовы GL из своей анимации Maya. Единственная проблема этого подхода заключается в том, что ваш исходный код и двоичный исполняемый файл будут безумно огромными. Это проблема, которая делает ваш подход «плохим».

Итак, во-первых, вместо одного вызова glVertex для данных каждой вершины вы вполне можете хранить свои данные в массиве (или std::vector, если уж на то пошло) и перебирать их с помощью простого цикла:

std::vector<int> idx;
std::vector<vertex> frame_data;
...
glBegin(GL_QUADS);
for(int i = 0; i < idx.size(); ++i) {
  glVertex3f(frame_data[idx].x, frame_data[idx].y, frame_data[idx].z);
  glNormal3f(frame_data[idx].nx, frame_data[idx].ny, frame_data[idx].nz);
}
glEnd();

Idx представляет грани, каждые 4 элемента в idx образуют четырехугольник. Frame_data — это конкретные данные вершин для этого кадра, у вас должен быть один такой массив для каждого кадра, и эти данные индексируются idx. Таким образом, единственная проблема, которую вам нужно решить, — это как считывать эти данные в ваше приложение. Если вы можете сгенерировать вызовы glVertex из вашего файла сетки, вы могли бы вместо этого сгенерировать файл, который вы можете легко загрузить в свое приложение с помощью C++ fstream, и создать массивы данных, а затем просто перебрать их и выполнить вызовы рисования.

Вы не увидите разницы в производительности между использованием glBegin()/glEnd() и VBO в этом случае, потому что 2200 quads — это слишком мало, чтобы иметь какое-либо значение, но это было бы интересным упражнением для вас. Организация данных в массивах, о которых я вам говорил (idx и vertex_data), — ​​это первый шаг к использованию VBO. Вы должны упаковать все данные относительно одной вершины внутри одной структуры:

struct vertex {
  float x, y, z; // Position
  float nx, ny, nz; // Normal
};
...
vertex frame_data[v_count];
uint16_t idx[2200 * 4]; // 4 vertices makes one face

Обратите внимание, что v_count не 2200. Это количество ваших четырехугольников, поэтому это число относится к размеру idx, а не к frame_data, т. е. одна и та же вершина может использоваться в нескольких гранях четырехугольников.

Вам понадобятся два буфера, один статический для хранения idx (GL_ELEMENT_ARRAY_BUFFER с GL_STATIC_DRAW), потому что он не изменится во время выполнения, и другой «потоковый» буфер для хранения данных вершин (GL_ARRAY_BUFFER с GL_STREAM_DRAW). Последний использует «GL_STREAM_DRAW», потому что вам нужно будет переписывать его содержимое каждый кадр для анимации. См. glBufferData.

person lvella    schedule 22.04.2012
comment
спасибо за все ваши ответы, я посмотрю на них.....сейчас немного завален. см. ОБНОВЛЕНИЕ @SigTerm, я собираюсь нарисовать его с помощью glDrawElements(). - person adi; 25.04.2012