Перейти к содержимому

Gpu skinning что такое

  • автор:

CPU Skinning vs. GPU Skinning

В процессе работы со скелетной анимацией возник вопрос о целесообразности скининга на GPU. Сейчас весь скиннинг у меня выполняется на CPU, шейдеры не используются, но недавно начал задумываться о том, чтобы доверить им скиннинг. Вопрос: какой из способов будет быстрее (на шейдЫрах или ЦПУ), если исп-ся попиксельное освещение и стенсильные тени. ИМХО, цпу будет пошустрее, ибо при GPU скиннинге вершины нужно преобразовывать каждый раз при рендере (в т.ч. при каждом из проходов при освещении), а на CPU можно расчитывать один раз за кадр. Правда, можно пользовать расширение EXT_pixel_buffer_object для рендернинга меша в пиксельный буффер, преобразования его шейдере и рендеринга меша из этого пиксельного буффера, но я слабо представляю себе это. Ещё одним плюсом скиннинга на CPU является испльзование одинаковых шейдеров для рендеринга статических и анимированных мешей.

Вобщем я сказал, теперь хочу увидеть ваши мнения.

#1
8:15, 4 апр 2006

Просто skinning — конечно, быстрее на шейдерах. Если есть стенсили — все становится чуть сложнее.
http://www.gamedev.ru/community/gamedev_lecture/articles/?id=19
Вот тут я пытался немного об этом рассказать. Есть вопросы — спрошай 🙂

#2
10:51, 4 апр 2006

Вот как идея, можно например теневой меш для скининга (тот который с дегенератными квадами) скинить на GPU и сразу экструзить его, так как рендерится он всего раз для источника. Остальные скинить на CPU.
Ещё лучше чтобы скининг подстраивался под GPU и CPU, т.е. часть на GPU часть на CPU в зависимости от загруженности того или иного :).

#3
11:02, 4 апр 2006

Помоему сейчас проше все на GPU делать.
Карточке не сложно, а процы чет почти и не развиваются

Right-Click Select

Right-Click Select

Got an idea for a feature that you think Blender absolutely must have? This is the place to make your proposals. Share your idea with the community. Discuss it. Revise it. Flesh it out to the point that it’s a well thought-out, actionable proposal that a Blender developer can work with.

Don’t have any ideas right now? That’s OK! Your experience counts. Help other people improve their ideas by voting and offering comments and insights.

Dev Diary — Skeletal Animation and GPU Skinning

I got bored of working on my toy renderer. So I decided to switch it up a bit and work on some other typical systems of a game engine. And then out of nowhere, skeletal animation hit my mind. “yeah… why not?! How hard can it be? You got a mesh and some bones. You accumulate bone transforms. You tick and interpolate the animation keyframes…” Before I knew it, I was 30 hours deep in the rabbit hole, about to pull my hair out staring at a deformed humanoid mesh flapping its leg around all over the place.

The Skeleton

The first couple nights of this adventure, I had some random TV shows playing in the background. Everything was still chill. Then I realize after days I still couldn’t even wrap my head around getting all the data I needed to set up the bone structure correctly. To be fair, the node graph and bone data relationship in Assimp is confusing as fuck. Anyways, here are the things we need:

  • Transform and Inverse Bind Pose(OffsetMatrix) of each bone (passed as uniform)
  • Bound bones (IDs/indices and weights) of each vertex (stored as vertex attribute)

The Math

The goal of skeletal animation system, is to animate/move the “skin” (mesh made of vertices) “along” with the bound bones and deform accordingly. What’s stored in the animation key frames, are the local transformation of the specific bone in model space. So in order get a model transform of a child bone, we need to chain/recursively multiply all the local transformation of its parent bones. So now we can get the model space transformation of any bone.

But the bones by default are all positioned in the default bind pose of the skeleton (usually a T-Pose). How do we calculate the transformation needed to transform a bone from default bind pose to animated pose?

(I remember I was asked this exact question during a interview for frostbite)

Imagine two nodes represent an arm. We want to move it from Pose 1 to Pose 2. If these were vectors, the delta would be (p2-p1). But we’re messing with matrices here. So it’s a little different. The correct way to calculate the delta is: Pose2 Transform * Inverse of Pose1 Transform

We can get the Pose2 transform from the animation frames. Inverse of Pose1, or the Inverse Bindpose, is actually conveniently provided by Assimp. It’s called OffsetMatrix.

// the model transform is calculated each animation frame
// the offsetmatrix or the inverse bind pose, can be cached at initialization
// the final transform of a bone:
boneTransforms[boneID] = bone.modelTransform * bone.offsetMatrix;

The Skinning

// vertex shaderin ivec4 boneIDs;
in vec4 boneWeights;
const int MAX_BONES = 100;
uniform mat4 gBones[MAX_BONES];
uniform mat4 u_mvp;
void main() vec4 localPos = vec4(0.0);
// each vertex can be influenced by 4 bones max
for(int i = 0; i < 4; i++) mat4 boneTransform = gBones[boneIDs[i]];
vec4 posePosition = boneTransform * vec4(pos, 1.0);
localPos += posePosition * boneWeights[i];

// todo: need to apply the bone transformation
// to normal as well
>
gl_Position = u_mvp * localPos;
>

yo when I saw this little shit walking smoothly, after a week of struggling. It felt so fucking good. And I guess this is what we live for.

All the little Gotchas:

  1. all the matrices in assimp, are row major. So if you’re using opengl or glm, either transpose everything on the go to column major, or transpose it at the end when setting the uniform
  2. The bone ID/index vertex attributes are obviously integers since these are indices to the bone transformation array. As a result glVertexAttribPointer can’t be used, since it will convert everything to floats. So either use glVertexAttribIPointer or make sure to cast to int when indexing into the bone tranformation array in vertex shader.

Thoughts for future:

  1. Optimize bone transforms uniform data flow. don’t need full 4×4 matrix for example
  2. Experiment doing the skinning on CPU. How does that perform in comparison, specially if we can offload to worker threads.
  3. Experiment with instancing
  4. Experiment with different interpolation methods. And wtf are dual quaternions the pros keep talking about

Gpu skinning что такое

Оптимизация производительности графики

Хорошая производительность критична для многих игр. Ниже даны простые советы по увлечению скорости рендеринга в вашей игре.

Какова стоимость графики

Графическая часть вашей игры нагружает в первую очередь две системы компьютера: GPU (графический процессор) и CPU (центральный процессор). Первое правило любой оптимизации: найти, где возникает проблема, так как стратегия оптимизации для GPU и CPU имеет существенные различия (иногда даже возникает ситуация, когда при оптимизации для GPU больше нагрузки ложится на CPU и наоборот).

Типичные узкие места и их проверка:

  • GPU часто ограничен филлрейтом (fillrate) или пропускной способностью памяти.
  • Запуск игры с более низким разрешением экрана увеличивает производительность? Тогда вы скорее всего ограничены филлрейтом GPU.
  • CPU часто ограничен количеством вещей, которые должны быть отрисованы, также известно, как “draw calls”.
  • Проверьте показателль “draw calls” в окне Rendering Statistics; если он составляет больше нескольких тысяч (для PC) или нескольких сотен (для мобильных устройств), то вам может потребоваться оптимизация количества объектов.
  • GPU обрабатывает слишком много вершин. Какое количество вершин является нормальным, определяется GPU и набором вертексных шейдеров. Можно посоветовать использовать не более 100 тысяч для мобильных устройств и не более нескольких миллионов для PC.
  • The CPU has too many vertices to process. This could be in skinned meshes, cloth simulation, particles, or other game objects and meshes. As above, it is generally good practice to keep this number as low as possible without compromising game quality. See the section on CPU optimization below for guidance on how to do this.
  • Рендеринг не создаёт проблем ни для GPU, ни для CPU. Проблема может быть, к примеру, в скриптах или физике. Используйте профайлер для поиска источника проблемы.

CPU optimization

В процессе визуализации любого объекта на экране CPU должен немного потрудиться: выяснить, какие источники света влияют на объект, настроить шейдер и его параметры, отправить коменды отрисовки графическому драйверу, который подготовит команды для отправки на видеокарту. Все эти операции могут быть не очень дешёвыми в своей сумме, если у вас есть много видимых объектов.

All this “per object” CPU usage is resource-intensive, so if you have lots of visible objects, it can add up. For example, if you have a thousand triangles, it is much easier on the CPU if they are all in one mesh, rather than in one mesh per triangle (adding up to 1000 meshes). The cost of both scenarios on the GPU is very similar, but the work done by the CPU to render a thousand objects (instead of one) is significantly higher.

Reduce the visible object count. To reduce the amount of work the CPU needs to do:

  • Объединяйте близко расположенные объекты: вручную или используя инструмент draw call batching в Unity.
  • Используйте меньше материалов, объединяйте текстуры в большие текстурные атласы.
  • Используйте меньше объектов, которые должны визуализироваться несколько раз (отражения, тени, попиксельные источники света и т. п., смотрите ниже).

Объединяйте объекты так, чтобы каждый меш содержал хотя бы несколько сотен треугольников и использоват только один Материал . Важно понимать, что объединение двух объектов, использующих разные материалы, не даст увеличения производительности. Основная причина, по которой два меша используют разные материалы, состоит в том, что они использують разные текстуры. Для оптимизации производительности CPU нужно убедиться, что объекты, которые вы объединяете, используют одну текстуру.

Однако, когда вы используете много пиксельных источников света при Forward rendering path, бывают ситуации, в которых не имеет смысла объединять объекты, это более подробно описано ниже.

GPU: Оптимизация геометрии моделей

There are two basic rules for optimizing the geometry of a model:

  • Не используйте треугольников больше, чем необходимо
  • Старайтесь держать количество швов на UV-карте и количество жёстких рёбер (удваивающих вершины) как можно более низким

Следует отметить, что количество вершин, которое обрабатывает видеокарта, обычно не совпадает с количеством, показываемым 3D-приложением. Приложения для моделирования обычно показывают геометрическое количество вершин, то есть, количество угловых точек, составляющих модель. Для видеокарты некоторые геометрические вершины необходимо разбить на несколько логических вершин для корректной визуализации. Вершина может быть разбита на несколько, если она имеет несколько нормалей, UV-координат или вертексных цветов. Следовательно, количество вершин в Unity неизменно выше, чем количество вершин в 3D-приложении.

В то время как количество геометрии в моделях оказывает влияние в первую очередь на GPU, некоторые функции Unity предполагают обработку моделей и на CPU, например mesh skinning.

Самое быстрое освещение — это то, которое не рассчитывается. Используйте карты освещения для запекания статичного освещения вместо расчёта освещения в каждом кадре. Процесс создания карт освещения требует много времени, чем простое размещения источников света в сцене, но:

  • Это намного быстрее работает (в 2–3 раза по сравнению с 2 пиксельными источниками света)
  • Это выглядит лучше, так как вы можете запечь глобальное освещение и с более высоким качеством

Во многих случаях можно заменить размещение источников света правильной настройков шейдеров и контента. Для примера, вместо размещения источника света прямо перед камерой для получения эффекта “подсветка краёв модели” (rim lighting), проще добавить расчёт этого эффекта прямо в шейдере.

Освещение в forward rendering

Освещение в forward rendering

Пиксельное динамическое освещение добавит затраты на визуализацию каждого пикселя и может привести к появлению объектов, визуализируемых в несколько проходов. На маломощных устройствах, таких как мобильные устройства или дешёвые PC, следует избегать использования более чем одного пиксельного источника света , освещающего каждый отдельный объект, и стараться использовать карты освещения. Вершинное динамическое освещение может добавить затраты для случаев вершинных трансформаций. Старайтесь избегать ситуаций, когда несколько источников света освещают один объект.

Если вы используете пиксельное освещение, то каждлый меш будет визуализирован столько раз, сколько пиксельных источников света его освещает. Если вы объедините два меша, находящихся далеко друг от друга, то это увеличит габариты меша. Все пиксельные источники света, освещавшие каждую часть объединённого меша, будут освещать теперь этот меш, поэтому количество проходов визуализации, необходимое для этого меша, увеличится. Как правило, число проходов для объединённого меша равно сумме проходов для составивших его частей, в результате чего нет выигрыша от объединения. По этой причине не стоит объединять меши, которые достаточно далеко друг от друга, чтобы быть освещёнными разными пиксельными источниками света.

В процессе визуализации Unity находит все источники света вокруг меша и рассчитывает их важность для данного меша. В настройках Quality Settings можно задать, сколько источников света в конце концов может использоваться для освещения каждого меша. Для каждого источника света его приоритет вычисляется на основании расстояния до меша и яркости этого источника света. Также имеет значение параметр Render Mode внутри компонента Light, который может принимать два значения: Important или Not Important . Источники света, помеченные как Not Important имеют более низкий приоритет.

Для примера рассмотрим игру, где игрок управляет автомобилем, движущимся в темноте со включёнными фарами. Скорее всего, передние фары будут наиболее важным источником света в игре и параметр Render Mode будет установлен для них в значение Important . Задние огни будут менее важны, не оказывая значительного влияния на конечное изображения, так что для них Render Mode можно установить в Not Important , сэкономив тем самым аппаратные ресурсы.

Оптимизация пиксельного освещения сохраняет ресурсы и CPU и GPU: CPU делает меньше draw calls, а GPU обрабатывает меньше вершин и растеризует меньше пикселей для каждого дополнительного объекта.

GPU: сжатие текстур и мипмапы

Использование сжатых текстур уменьшает размер ваших текстур (в результате они быстрее загружаются и занимают меньше памяти), а также может значительно повысить производительность. Сжатые текстуры используют малую часть пропускной способности памяти, в сравнении с 32-битными RGBA-текстурами.

Использование мипмап для текстур

Как правило, параметр импорта Generate Mip Maps включён для текстур, используемых в 3D-сцене. В этом случае сжатие текстур поможет ограничить количество текстурных данных, транспортируемых в GPU при визуализации. Мимпапы позволяют GPU использовать для маленьких треугольников текстуры пониженного разрешения.

Есть исключение из этого правила: когда один тексель (пиксель текстуры) соответствует одному пикселю экрана, что встречается в элементах пользовательского интерфейса и в 2D-играх.

LOD и послойное задание дистанции для сulling

Culling objects involves making objects invisible. This is an effective way to reduce both the CPU and GPU load.

В некоторых играх целесообразно обрезать мелкие объекты более агрессивно, чем крупные, чтобы снизить разницу между нагрузкой на CPU и GPU. Для примера, маленькие камни и трава могут обрезаться на меньшей дистанции, чем большие здания.

There are a number of ways you can achieve this:

  • Use the Level Of Detail system
  • Manually set per-layer culling distances on the camera

Это может быть достигнуто использованием системы Level Of Detail или ручной настройкой дистанции обрезки для камеры по слоям. Вы можете поместить мелкие объекты в отдельный слой и задать ему дистанцию обрезки, используя свойство Camera.layerCullDistances.

Тени в реальном времени

Тени в реальном времени хорошо выглядят, но они могут сильно снижать производительность, одновременно добавляя дополнительные draw calls для CPU и дополнительную обработку для GPU. Подробности даны на странице Shadows.

GPU: советы для написания высокопроизводительных шейдеров

Different platforms have vastly different performance capabilities; a high-end PC GPU can handle much more in terms of graphics and shaders than a low-end mobile GPU. The same is true even on a single platform; a fast GPU is dozens of times faster than a slow integrated GPU.

Имейте в виду, что производительность GPU на мобильных устройствах и PC начального уровня скорее всего будет намного ниже, чем на PC, который вы используете для разработки. Как правило, шейдеры нужно вручную оптимизировать, чтобы уменьшить количество расчётов и чтений текстуры для получения высокой производительности. Для примера, некоторые встроенные в Unity шейдеры имеют “мобильные” эквиваленты, которые работают намного быстрее за счёт некоторых ограничений и упрощений.

Ниже приведены рекомендации, которые важны для GPU в мобильных устройствах и PC низкого уровня:

Сложные математические операции

Transcendental mathematical functions (such as pow , exp , log , cos , sin , tan ) are quite resource-intensive, so avoid using them where possible. Consider using lookup textures as an alternative to complex math calculations if applicable.

Avoid writing your own operations (such as normalize , dot , inversesqrt ). Unity’s built-in options ensure that the driver can generate much better code. Remember that the Alpha Test ( discard ) operation often makes your fragment shader slower.

Операции с плавающей точкой

While the precision ( float vs half vs fixed ) of floating point variables is largely ignored on desktop GPUs, it is quite important to get a good performance on mobile GPUs. See the Shader Data Types and Precision page for details.

Подробности о производительности шейдеров можно прочитать на странице Shader Performance.

Список шагов для увеличения производительности вашей игры

  • Сохраняйте количество вершин между 200 000 и 3 000 000 в каждом кадре, если целевая платформа — PC
  • Если вы используете встроенные шейдеры, проверьте категории шейдеров Mobile и Unlit. Они прекрасно работают и на немобильных платформ, но являются упрощёнными версиями более сложных шейдеров.
  • Уменьшите количество различных материалов в сцене — используйте один материал для нескольких объектов, где это возможно.
  • Установите свойство Static для неподвижных объектов, чтобы использовать внутреннию оптимизацию static batching.
  • Only have a single (preferably directional) pixel light affecting your geometry, rather than multiples.
  • Bake lighting rather than using dynamic lighting.
  • Используйте сжатие текстур, когда это возможно, а также отдавайте предпочтение 16-битным текстурами перед 32-битными.
  • Avoid using fog where possible.
  • Узнайте преимущества технологии Occlusion Culling и используйте её для снижения количества видимой геометрии и количества draw calls в случаях со сложными статичными сценами с большим количеством перекрывающих друг друга объектов. Планируйте свои игровые уровни с учётом этой технологии.
  • Используйте скайбоксы для имитации далеко расположенной геометрии.
  • Используйте пиксельные шейдеры или инструменты для совмещения текстур, чтобы смешивать текстуры вместо многопроходной визуализации.
  • Use half precision variables where possible.
  • Сводите к минимуму количество сложных математических операций в пиксельных шейдерах: pow , sin , cos и т. п.
  • Используйте меньше текстур.
  • Unity Profiler Window. Производительность освещения

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *