Единственный раз, когда вы не должны что-то делать на стороне графического процессора, это если вам нужен результат (в легко доступной форме) на стороне процессора для дальнейшего моделирования.
Взяв твой пример. Предположим, у вас есть 4 сетки по 250 КБ, которые представляют собой иерархию частей тела (как скелет). Предположим, вы используете матрицу с плавающей запятой 4x4 для преобразований (64 байта) для каждой сетки. Вы можете:
В каждом кадре выполняйте вычисления преобразования сетки на стороне приложения (ЦП), а затем загружайте четыре сетки в ГП. Это приведет к отправке около 1000 КБ данных на графический процессор за кадр.
Когда приложение запустится, загрузите данные для 4-х сеток в GPU (это будет в позе покоя/идентификации). Затем в каждом кадре при вызове рендеринга вы вычисляете только новые матрицы для каждого меша (положение/поворот/масштаб) и загружаете эти матрицы в GPU и выполняете преобразование там. Это приводит к тому, что на GPU за кадр отправляется ~256 байт.
Как видите, даже если данные в примере сфабрикованы, основное преимущество заключается в том, что вы минимизируете объем данных, передаваемых между ЦП и ГП для каждого кадра.
Единственный случай, когда вы предпочтете первый вариант, — это если вашему приложению нужны результаты преобразования для выполнения какой-либо другой работы. Графический процессор очень эффективен (особенно при параллельной обработке вершин), но получить информацию от графического процессора не так уж просто (и тогда она обычно представлена в виде текстуры, т. е. RenderTarget). Одним из конкретных примеров такой «дальнейшей работы» может быть проверка столкновений в трансформированных позициях сетки.
редактировать Вы можете сказать, основываясь на том, как вы вызываете API openGL, где в некоторой степени хранятся данные*. Вот краткое изложение:
Массивы вершин
glVertexPointer(...)
glDrawArray(...)
используя этот метод, передавая массив вершин из CPU -> GPU в каждом кадре. Вершины обрабатываются последовательно по мере их появления в массиве. Существует вариант этого метода (glDrawElements), который позволяет указывать индексы.
ВБО
glBindBuffer(...)
glBufferData(...)
glDrawElements(...)
VBO позволяют хранить данные сетки на графическом процессоре (примечание см. ниже). Таким образом, вам не нужно отправлять данные меша в GPU в каждом кадре, только данные преобразования.
*Хотя мы можем указать, где должны храниться наши данные, в спецификации OpenGL фактически не указано, как поставщики должны это реализовать. Это означает, что мы можем подсказывать, что данные наших вершин должны храниться в VRAM, но в конечном итоге это зависит от драйвера!
Хорошие справочные ссылки для этого материала:
Справочная страница OpenGL: https://www.opengl.org/sdk/docs/man/html/start.html
Объяснения OpenGL: http://www.songho.ca/opengl
Концепции Java OpenGL для рендеринга: http://www.java-gaming.org/topics/introduction-to-vertex-arrays-and-vertex-buffer-objects-opengl/24272/view.html
01.12.2015