Как эффективно рендерить несколько разных элементов с помощью OpenGL - PullRequest
0 голосов
/ 21 октября 2018

Я делаю простой STG движок с OpenGL (а точнее с LWJGL3). В этой игре может быть несколько разных типов предметов (называемых маркерами) в одном кадре, и каждый типможет иметь 10-20 экземпляров. Я надеюсь найти эффективный способ его рендеринга.

Я прочитал несколько книг о современном OpenGL и нашел метод под названием «Instanced Rendering», но, похоже, он работает только с тем жеinstances. Должен ли я использовать цикл for для рисования всех элементов непосредственно для моего случая?

Другой вопрос касается памяти. Должен ли я создавать VBO для каждого кадра, так как количество элементов всегда меняется?

Ответы [ 3 ]

0 голосов
/ 23 октября 2018

Я прочитал несколько книг о современном OpenGL и нашел метод, называемый «Instanced Rendering», но, похоже, он работает только с одинаковыми экземплярами. Могу ли я использовать цикл for для рисования всех элементов непосредственно для моего случая?

Еще один вопрос касается памяти. Должен ли я создать VBO для каждого кадра, поскольку количество элементов постоянно меняется?

Они оба зависят от количества пуль, которые вы планируете иметь,Если вы думаете, что у вас будет менее тысячи патронов, вы почти наверняка можете отправить их все в VBO каждый кадр и загрузить, и ваши конечные пользователи не заметят.Если вы планируете какую-то непристойную сумму, не делайте этого.

Я бы сказал, что вы должны писать все в каждом кадре, потому что это просто прямо сейчас , и если вы начнетеЗаметив проблемы с производительностью, вы должны изучить экземпляры или какой-либо другой метод.Когда вы дойдете до «позже», вам должно быть удобнее с OpenGL и найти способы оптимизировать его, который не будет у вас над головой (не говоря уже о том, что это у вас над головой, но больше опыта может только помочь сделать его менее сложным).позже).

Отбраковка пуль на экране также не должна быть на вашем радаре.

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

0 голосов
/ 26 октября 2018

20 объектов - это ничего .Ваша программа будет очень быстрой независимо от того, как вы их рисуете.

Когда у вас есть 10000 объектов, вам нужно будет запросить эффективный способ.

До этого рисуйте их в любом направлении.наиболее удобно.Это, вероятно, означает отдельный вызов отрисовки для объекта.

0 голосов
/ 22 октября 2018

Не самый простой вопрос, но я в любом случае постараюсь.

Важным свойством OpenGL является то, что контекст OpenGL всегда связан с одним потоком .Таким образом, каждый OpenGL-метод должен вызываться в этом потоке.Распространенным способом борьбы с этим является использование очереди.

Пример:
Мы используем архитектуру Model-View-Controller.
У нас есть 3 потока;Один для чтения ввода, один для обработки полученных сообщений и один для визуализации сцены.
Здесь контекст OpenGL привязан к потоку визуализации.
Первый поток получает сообщение «Добавить модель в положение x».Первый поток не успевает обработать сообщение, потому что может появиться другое сообщение, и мы не хотим его откладывать.Поэтому мы просто даем это сообщение второму потоку для обработки, добавляя его в очередь второго потока.
Второй поток читает сообщение и выполняет необходимые задачи настолько, насколько это возможно, прежде чем контекст OpenGL потребуется.Like читает файл Wavefront (.obj) из памяти и создает массивы из полученных данных.
Затем наш второй поток ставит эти данные в очередь в наш поток OpenGL для обработки.Поток OpenGL генерирует VBO и VAO и сохраняет в них данные.

Назад к вашему вопросу
Объекты, созданные OpenGL, остаются в контекстной памяти до тех пор, пока они не будут удалены вручную или контекст уничтожен.Таким образом, он работает примерно так же, как C, где вам приходится вручную выделять память и освобождать ее, когда она больше не используется.Таким образом, вы не должны создавать новые объекты для каждого кадра, но должны повторно использовать данные, которые остаются неизменными .Кроме того, если у вас есть несколько объектов, которые используют одну и ту же модель или текстуру, вы должны просто загрузить эту модель один раз и применить все специфичные для объекта различия к шейдерам .

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

bind shader
load values to shader's uniform variables that don't change between entities.
bind model and texture (as those stay the same for each rock)
for(each rock in rocks){
   load values to shader's uniform variables that do change between each rock, like the transformation.
   render
}
unbind shader

Примечание. Вам не нужно отвязывать / связывать шейдер каждого кадра, если вы используете только один шейдер.То же самое касается VAO и любого другого объекта OpenGL.Таким образом, привязка также будет действовать в течение каждого цикла рендеринга.

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

...