Не самый простой вопрос, но я в любом случае постараюсь.
Важным свойством 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.Таким образом, привязка также будет действовать в течение каждого цикла рендеринга.
Надеюсь, это поможет вам при начале работы.Хотя я бы порекомендовал некоторый учебник, который мог бы иметь немного больше контекста.