2D игры и современные OpenGL

10

предпонятий

Хорошо, так что я собрала так:

  • не использовать фиксированный конвейер (не рекомендуется или не рекомендуется)
  • vbos хранит "объектные модели" (в основном n данных вершин)
  • vaos описывает, как данные располагаются так, чтобы вызовы отрисовки знали, какая часть каждого vbo предназначена для какой информации о вершине (один vao может ссылаться на несколько vbos, обратное довольно сложно)
  • каждый вызов отрисовки также отправляет данные вершин в шейдеры

Как я вижу 3D (опционально)

Учитывая эту информацию, я вижу, как хорошо рисовать сложные 3D-объекты в современном OpenGL. В основном вы загружаете кучу объектных моделей (возможно, из Blender или другого подобного программного обеспечения) в VBO с локальными координатами, а затем просто предоставляете для каждого экземпляра объекта свой параметр шейдера (смещение) для рисования в мировом пространстве.

Проблема / вопрос

В 2D проблемы и приоритеты совершенно иные. Вы не рисуете много сложных объектов, вам не нужны сложные проекционные матрицы, а еще много чего проще и шейдеров.

Как лучше всего рисовать часто (действительно часто, в основном, каждый кадр) изменяющуюся геометрию с помощью современного OpenGL?

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

Мои попытки (необязательно)

Итак, я начал думать, как мне поступить с рисованием базовой 2D-геометрии на экране:

  • квадрат: загрузить [(1, 0), (1, 1), (0, 1), (0, 0)]VBO для геометрии квадрата в локальном пространстве, затем предоставить шейдеру фактическую ширину квадрата, мировые координаты и информацию о цвете.

остывает, выглядит легко. Давайте перейдем к кругу:

  • круг: треугольный веер с ... эх. насколько точность (количество вершин)? для маленьких кругов точность должна быть небольшой, а для кругов с ошибками - высокой. Очевидно, что загрузка 1 VBO не может подходить для всех случаев. Что если мне нужно добавить точность, потому что размер круга увеличен, чтобы он был больше?

Менее круто. Давайте перейдем к чему-то немного более простому, прямоугольнику:

  • прямоугольник: да. нет "общей геометрии прямоугольника". У вас просто есть соотношение ширины и высоты, и все, но каждый прямоугольник, вероятно, отличается, если размер изменяется.

Как вы можете видеть, все идет вниз оттуда. Особенно со сложными полигонами и еще много чего.

Нет кода политики: P

Мне просто нужен обзор идеи, код не нужен, особенно код на C или C ++. Просто скажите что-то вроде: «создайте VBO с этими данными вершин, а затем свяжите их, ...».

башмак
источник
Я думаю, я понимаю, что вы спрашиваете, но вы можете дать этому вопросу немного больше указаний. Немного неясно, о чем спрашивают, что на самом деле является серьезной причиной.
Лизоль
@AidanMueller Я не уверен, что вы имеете в виду, но не стесняйтесь давать больше указаний, если вы чувствуете необходимость.
Чистка
Главный ответ в настоящее время начинается со слов: «Вы, кажется, главный вопрос». Это указывает на то, что неясно, что вы спрашиваете. Может быть, вы должны дать краткое изложение того, что вам не нужно знать в конце вашего вопроса. В конце концов, это Q / A, а не обсуждение.
Лизоль
@AidanMueller Не в этом контексте, я считаю. Там написано «Ваш главный вопрос, кажется…», а затем он цитирует вопрос, который я написал. Что на самом деле указывает на то, что это достаточно ясно, чтобы быть в кавычках. Также фраза указывает не на то, что мой вопрос неясен, а на то, что есть главный вопрос и еще один второстепенный вопрос (а именно: каково решение конкретных случаев, которые я представил). Я действительно не вижу проблемы с моим текущим вопросом, и, видимо, даже ответчики не сделали, поскольку я нашел оба ответа очень полезными и к сути.
Чистка
Вы можете нарисовать точный круг с фрагментным шейдером.
user253751

Ответы:

5

Ваш главный вопрос, кажется, таков:

Как лучше всего рисовать часто (действительно часто, в основном, каждый кадр) изменяющуюся геометрию с помощью современного OpenGL?

В большинстве случаев нет большой разницы между 2d и 3d OpenGL. Графический конвейер имеет одну дополнительную координату, Z, которая не будет использоваться так много в 2d, но это все.

Есть несколько способов изменить геометрию на каждом розыгрыше.

  • Вы можете выдвигать новые предоставленные процессором вершины каждый кадр. (См. Https://stackoverflow.com/questions/14155615/opengl-updating-vertex-buffer-with-glbufferdata для некоторых заметок о повторном использовании буферов.)

  • Вы можете нарисовать различные части существующего буфера, с помощью glDrawArrays(mode, first, count). Если анимация повторяется, возможно, вы можете поместить предварительно вычисленные кадры с различными списками вершин в один большой буфер и нарисовать соответствующую часть буфера каждый кадр.

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

  • Если у вас много экземпляров одной и той же геометрии (возможно, под влиянием атрибутов), тогда glDrawElementsInstanced()может быть полезно

  • Вы можете влиять на список вершин алгоритмически в вершинных, геометрических или тесселяционных шейдерах. Если анимация может быть описана математически, вы можете сохранить один и тот же список вершин и изменить только несколько шейдерных форм в каждом кадре.

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

В целом, я бы сказал: «Компьютеры быстры, сделайте так, чтобы они работали самым простым способом, каким вы можете, например, устанавливая свежие вершины, сделанные из ЦП, в каждом кадре. Затем посмотрите, достаточно ли это хорошо. Профилируйте использование батареи / ЦП во-первых, след памяти второй.

Ваш другой вопрос , перефразированный: «Какой хороший способ рисовать круги и прямоугольники?»

Круги.

  • С тесселяционными шейдерами (или геометрическими шейдерами) вы можете сделать вашу геометрию динамической.

  • Вы можете рисовать квадраты, а в вашем фрагментном шейдере только непрозрачные (альфа = 1,0) внутри радиуса и прозрачные (альфа = 0,0) вне радиуса. Тогда это идеальный пиксель каждый раз. (Сделайте ваши квадратные вершины от -1 до +1, а во фрагментном шейдере что-то вроде outColor.a = dot(coord.xy, coord.xy) < 1.0 ? 1.0 : 0.0;. Может также немного сгладить край, там бы выглядело хорошо ...)

  • Вы можете просто использовать, скажем, 120-треугольный вентилятор. Наверное, достаточно хорошо.

Прямоугольники.

  • Я думаю, что вы ответили на свой вопрос. То, что вы предлагаете, будет хорошо работать!
Дэвид ван Бринк
источник
Фрагмент-шейдер / радиус довольно аккуратный, спасибо. Что касается ответа на мой собственный вопрос, я не думаю, что понимаю, что вы имеете в виду.
Чистка
О, как и в случае с квадратом, вы упоминаете, что управляете шириной (я полагаю, с равномерным), и вы написали: «У вас просто есть соотношение ширины и высоты, и все, но каждый прямоугольник, вероятно, отличается, если размер меняется» , Итак, для прямоугольника сделайте то же самое, что и квадрат, но вам нужно 4 значения (x, y, w, h) вместо 3 (x, y, w). Или передать (xlow, xhigh, ylow, yhigh) как четыре униформы. С вашим вводом (от 0,0) до (1,1) этого достаточно, чтобы вершинный шейдер сделал то, что ему нужно.
Дэвид ван Бринк
О, я вижу, это имеет смысл.
Чистка
Есть ли в современном GL автоматический вентилятор, такой как GL_TRIANGLE_FAN из конвейера с фиксированными функциями?
Джон П
5

Я не могу сказать, что являюсь экспертом в этом вопросе, и в моем игровом проекте (ах) я сконцентрировался больше на 3D стороне, поэтому моя 2D сторона довольно проста, как правило, с использованием вещей, созданных для 3D стороны; и, очевидно, моя перспектива на стороне игры, поэтому моя 2D-графика больше ориентирована на блиц спрайтов, чем на геометрию. С этой точки зрения,

1) Квадраты и прямоугольники довольно просты. У меня есть только одна коробка 1x1 в VBO, которую я использую, чтобы уничтожить все. Я передаю матрицы MVP в шейдеры с этим «блоком единиц» и объединяю его с дополнительным масштабированием, чтобы масштабировать блок до нужных размеров - как вы знаете, у вас может быть различный масштаб x и y.

В своих целях я подумывал перейти от использования «блока юнитов» к какому-то движку частиц для бликов 2D спрайтов, но это уже другая история.

2) Я мало работаю с кругами, я просто использую фиксированные VBO с определенным количеством вершин. Но я мог предположить, что я мог бы сделать некоторые шаги, чтобы повлиять на количество вершин, нарисованных для круга.

При подключении данных VBO к атрибутам шейдера я использую glVertexAttribPointer. У него есть параметр шага, предназначенный для использования для чередующихся данных (которые я использую). Но может быть возможно использовать это так:

glVertexAttribPointer(..., n * sizeof(VERTEX_DATA), ...);

... чтобы выбрать каждую n-ю вершину из буфера, таким образом влияя на количество вершин, нарисованных для круга. Я мог бы создать несколько VAO, имеющих один и тот же VBO с разным шагом, влияющим на количество вершин, нарисованных для круга. Я не пробовал это, подумал.

В общем, да, работа с VBO и тому подобным делает настройку на стороне процессора немного более сложной, поэтому я изучал разные вещи, чтобы сделать настройку на стороне GPU (шейдеры). Тем не менее, согласно этой статье, использование VBO более эффективно на современном оборудовании, даже если вам нужно много «вмешательства» на стороне процессора:

http://www.quelsolaar.com/opengl_performance.txt

Надеюсь, что это поможет вам немного разработать и решить ваши направления.

Мако
источник
2
"настройка шага, чтобы повлиять на количество вершин, нарисованных для круга" Супер круто!
Дэвид ван Бринк