Рисование другим местам назначения рендеринга

Объекты кадрового буфера являются местом назначения для рендеринга команд. При создании объекта кадрового буфера Вы имеете точный контроль над его хранением для цвета, глубины, и получаете данные с помощью шаблона. Вы обеспечиваете это хранение путем присоединения изображений к кадровому буферу, как показано на рисунке 4-1. Наиболее распространенное присоединение изображения является объектом renderbuffer. Можно также присоединить OpenGL текстура ES к цветной точке подключения кадрового буфера, что означает, что любые команды рисования представляются в текстуре. Позже, текстура может действовать как ввод к будущим командам рендеринга. Можно также создать многократные объекты кадрового буфера в единственном контексте рендеринга. Вы могли бы сделать это так, чтобы можно было совместно использовать тот же конвейер рендеринга и OpenGL ресурсы ES между многократными кадровыми буферами.

  Кадровый буфер рисунка 4-1 с цветом и глубиной renderbuffers
Framebuffer with attachments.

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

Создание объекта кадрового буфера

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

Создание внеэкранных объектов кадрового буфера

Кадровый буфер, предназначенный для внеэкранного рендеринга, выделяет все свои присоединения как OpenGL ES renderbuffers. Следующий код выделяет объект кадрового буфера с присоединениями глубины и цветом.

  1. Создайте кадровый буфер и свяжите его.

    GLuint framebuffer;
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
  2. Создайте цвет renderbuffer, выделите хранение для него и присоедините его к цветной точке подключения кадрового буфера.

    GLuint colorRenderbuffer;
    glGenRenderbuffers(1, &colorRenderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);
  3. Создайте глубину или глубину/шаблон renderbuffer, выделите хранение для него и присоедините его к точке подключения глубины кадрового буфера.

    GLuint depthRenderbuffer;
    glGenRenderbuffers(1, &depthRenderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
  4. Протестируйте кадровый буфер на полноту. Этот тест только должен быть выполнен когда изменения конфигурации кадрового буфера.

    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;
    if(status != GL_FRAMEBUFFER_COMPLETE) {
        NSLog(@"failed to make complete framebuffer object %x", status);
    }

После рисования к внеэкранному renderbuffer можно возвратить его содержание CPU для последующей обработки с помощью glReadPixels функция.

Используя кадровый буфер возражает для рендеринга к текстуре

Код для создания этого кадрового буфера почти идентичен внеэкранному примеру, но теперь текстура выделяется и присоединяется к цветной точке подключения.

  1. Создайте объект кадрового буфера (использование той же процедуры как в Создании Внеэкранных Объектов Кадрового буфера).

  2. Создайте целевую текстуру и присоедините ее к цветной точке подключения кадрового буфера.

    // create the texture
    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
  3. Выделите и присоедините буфер глубины (как прежде).

  4. Протестируйте кадровый буфер на полноту (как прежде).

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

Рендеринг к базовому слою анимации

Базовая Анимация является центральной инфраструктурой для графического рендеринга и анимации на iOS. Можно составить пользовательский интерфейс приложения или другие уровни использования дисплеев, размещающие содержание, представленное с помощью различных подсистем iOS, таких как UIKit, 2D Кварц, и OpenGL ES. OpenGL ES соединяется с Базовой Анимацией через CAEAGLLayer класс, специальный тип Базового Слоя анимации, содержание которого прибывает из OpenGL ES renderbuffer. Базовая Анимация составляет содержание renderbuffer с другими уровнями и выводит на экран получающееся изображение на экране.

  Анимация Ядра рисунка 4-2 совместно использует renderbuffer с OpenGL ES
Core Animation-based renderbuffer

CAEAGLLayer предоставляет эту поддержку OpenGL ES путем обеспечения двух основных частей функциональности. Во-первых, это выделяет совместно используемую память для renderbuffer. Во-вторых, это представляет renderbuffer Базовой Анимации, заменяя предыдущее содержание уровня данными от renderbuffer. Преимущество этой модели состоит в том, что содержание Базового Слоя анимации не должно быть нарисовано в каждом кадре, только когда представленные изменения образа.

Использовать Базовый Слой анимации для OpenGL рендеринг ES:

  1. Создайте a CAEAGLLayer возразите и сконфигурируйте его свойства.

    Для оптимальной производительности, набор значение уровня opaque свойство к YES. Посмотрите знать, что базовая анимация составляет производительность.

    Дополнительно, сконфигурируйте поверхностные свойства поверхности рендеринга путем присвоения нового словаря значений к drawableProperties свойство CAEAGLLayer объект. Можно указать формат пикселя для renderbuffer и указать, отбрасывается ли содержание renderbuffer после того, как они отправляются в Базовую Анимацию. Для списка разрешенных ключей см. Ссылку на протокол EAGLDrawable.

  2. Выделите OpenGL контекст ES и сделайте его текущим контекстом. Посмотрите Конфигурирование OpenGL Контексты ES.

  3. Создайте объект кадрового буфера (как в Создании Внеэкранных Объектов Кадрового буфера выше).

  4. Создайте цвет renderbuffer, выделив его хранение путем вызова контекста renderbufferStorage:fromDrawable: метод и передача расположенного на слое объекта как параметр. Ширина, высота и формат пикселя берутся от уровня и используются для выделения хранения для renderbuffer.

    GLuint colorRenderbuffer;
    glGenRenderbuffers(1, &colorRenderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
    [myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:myEAGLLayer];
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);
  5. Получите высоту и ширину цвета renderbuffer.

    GLint width;
    GLint height;
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);

    В более ранних примерах ширина и высота renderbuffers были явно предоставлены для выделения хранения для буфера. Здесь, код получает ширину и высоту от цвета renderbuffer после того, как будет выделено его хранение. Ваше приложение делает это, потому что фактические размерности цвета renderbuffer вычисляются на основе границ уровня и масштабного коэффициента. Другой renderbuffers, присоединенный к кадровому буферу, должен иметь те же размерности. В дополнение к использованию высоты и ширины для выделения буфера глубины используйте их, чтобы присвоить OpenGL область просмотра ES и помочь определить уровень детализации, требуемый в текстурах и моделях приложения. Посмотрите Поддерживающие Дисплеи С высокой разрешающей способностью.

  6. Выделите и присоедините буфер глубины (как прежде).

  7. Протестируйте кадровый буфер на полноту (как прежде).

  8. Добавьте CAEAGLLayer возразите против своей Базовой иерархии Слоя анимации путем передачи его addSublayer: метод видимого слоя.

Рисование к объекту кадрового буфера

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

Рендеринг по требованию или с циклом анимации

Когда нарисовать OpenGL содержание ES при рендеринге к Базовому Слою анимации, так же, как при рисовании с представлениями GLKit и контроллерами представления, необходимо выбрать. При рендеринге к внеэкранному кадровому буферу или текстуре, нарисуйте каждый раз, когда является надлежащим ситуациям, где Вы используете те типы кадровых буферов.

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

Для рисования с циклом анимации используйте a CADisplayLink объект. Ссылка дисплея является своего рода таймером, предоставленным Базовой Анимацией, позволяющей Вам синхронизировать получение с частотой обновления экрана. Перечисление 4-1 показывает, как можно получить экран, показывающий представление, используйте тот экран, чтобы создать новый объект ссылки дисплея и добавить объект ссылки дисплея к циклу выполнения.

  Создание перечисления 4-1 и запуск ссылки дисплея

displayLink = [myView.window.screen displayLinkWithTarget:self selector:@selector(drawFrame)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

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

Обычно, объект ссылки дисплея запущен каждый раз экранные обновления; то значение обычно - 60 Гц, но может варьироваться на различных устройствах. Большинство приложений не должно обновлять экранные 60 времена в секунду. Можно установить ссылку дисплея frameInterval свойство к числу фактических кадров, проходящих перед Вашим методом, вызывают. Например, если интервал кадра был установлен в 3, Ваше приложение вызывают каждым третьим кадром или примерно 20 кадрами в секунду.

Рендеринг кадра

Рисунок 4-3 показывает шагам OpenGL , приложение ES должно взять iOS, чтобы представить и представить кадр. Эти шаги включают много подсказок для улучшения производительности в приложении.

Рисунок 4-3  iOS Шаги Рендеринга OpenGL

Ясные буферы

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

Перечисление 4-2  Ясные присоединения кадрового буфера

glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

Используя glClear «подсказки» к OpenGL ES, что существующее содержание renderbuffer или текстуры может быть отброшено, избежав дорогостоящих операций для загрузки предыдущего содержания в память.

Подготовьте ресурсы и выполните команды рисования

Эти два шага охватывают большинство ключевых решений, которые Вы принимаете в разработке архитектуры Вашего приложения. Во-первых, Вы решаете то, что Вы хотите вывести на экран пользователю и сконфигурировать соответствующий OpenGL объекты ES — такие как буферные объекты вершины, текстуры, программы программы построения теней и их входные переменные — для загрузки на GPU. Затем, Вы представляете комментарии получения, говорящие GPU, как использовать те ресурсы для рендеринга кадра.

Проект средства рендеринга покрыт более подробно в OpenGL Руководство по проектированию ES. На данный момент самая важная оптимизация производительности для замечания состоит в том, что выполнение приложения быстрее, если это изменяет OpenGL ES, возражает только в начале рендеринга нового кадра. Несмотря на то, что Ваше приложение может чередоваться между изменением объектов и представлением команд рисования (как показано пунктирной линией на рисунке 4-3), это работает быстрее, если это выполняет каждый шаг только один раз на кадр.

Выполните команды рисования

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

Мультивыборка решения

Если Ваша мультивыборка использования приложения для улучшения качества изображения приложение должно разрешить пиксели, прежде чем они будут представлены пользователю. Мультивыборка покрыта подробно в Использовании Мультивыборки для Улучшения Качества изображения.

Отбросьте ненужный Renderbuffers

Работа отбрасывания является подсказкой производительности, говорящей OpenGL ES, что больше не необходимо содержание одного или более renderbuffers. Путем вывода подсказок OpenGL может быть отброшен ES, что Вам не нужно содержание renderbuffer, данных в буферах, и можно избежать дорогих задач сохранить содержание тех буферов обновленным.

На данном этапе в цикле рендеринга, Ваше приложение представило все свои команды рисования для кадра. В то время как для Вашего приложения нужен цвет renderbuffer для отображения на экран, этому, вероятно, не нужно содержание буфера глубины. Перечисление 4-3 отбрасывает содержание буфера глубины.

Перечисление 4-3  , Отбрасывающее кадровый буфер глубины

const GLenum discards[]  = {GL_DEPTH_ATTACHMENT};
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glDiscardFramebufferEXT(GL_FRAMEBUFFER,1,discards);

Представьте результаты удалить сердцевину анимации

На этом шаге цвет renderbuffer содержит завершенный кадр, таким образом, все, что необходимо сделать, присутствует он пользователю. Перечисление 4-4 связывает renderbuffer с контекстом и представляет его. Это заставляет завершенный кадр быть врученным Базовой Анимации.

Перечисление 4-4  , Представляющее законченный кадр

glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER];

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

Если Ваше приложение хочет сохранить содержание цвета renderbuffer между кадрами, добавьте kEAGLDrawablePropertyRetainedBacking ключ к словарю, сохраненному в drawableProperties свойство CAEAGLLayer объект, и удаляет GL_COLOR_BUFFER_BIT постоянный от ранее glClear вызов функции. Сохраненная поддержка может потребовать, чтобы iOS выделил дополнительную память для сохранения содержания буфера, которое может сократить производительность приложения.

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

Мультивыборка является формой сглаживания, сглаживающего зубчатые края и улучшающего качество изображения в большинстве 3D приложений. OpenGL ES 3.0 включает мультивыборку как часть базовой спецификации, и iOS обеспечивает его в OpenGL ES 1.1 и 2.0 через APPLE_framebuffer_multisample расширение. Мультивыборка использует больше памяти и время обработки фрагмента для рендеринга изображения, но это может улучшить качество изображения по более низкой стоимости производительности, чем использование других подходов.

Рисунок 4-4 показывает, как работает мультивыборка. Вместо того, чтобы создать один объект кадрового буфера, Ваше приложение создает два. Буфер мультивыборки содержит все присоединения, необходимые для рендеринга содержания (обычно цветные и буферы глубины). Буфер решения содержит только присоединения, необходимые для отображения представленного изображения пользователю (обычно цвет renderbuffer, но возможно текстура), создаваемое использование соответствующей процедуры от Создания Объекта Кадрового буфера. Мультивыборка renderbuffers выделяется с помощью тех же размерностей в качестве кадрового буфера решения, но каждый включает дополнительный параметр, указывающий число выборок для хранения для каждого пикселя. Ваше приложение выполняет весь свой рендеринг к буферу мультивыборки и затем генерирует сглаженное изображение финала путем разрешения тех выборок в буфер решения.

Рисунок 4-4  , Как работает мультивыборка

Перечисление 4-5 показывает код для создания буфера мультивыборки. Этот код использует ширину и высоту ранее создаваемого буфера. Это вызывает glRenderbufferStorageMultisampleAPPLE функция для создания мультивыбранного хранения для renderbuffer.

Перечисление 4-5  , Создающее мультидемонстрационный буфер

glGenFramebuffers(1, &sampleFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, sampleFramebuffer);
 
glGenRenderbuffers(1, &sampleColorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, sampleColorRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_RGBA8_OES, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, sampleColorRenderbuffer);
 
glGenRenderbuffers(1, &sampleDepthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, sampleDepthRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, sampleDepthRenderbuffer);
 
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));

Вот шаги для изменения кода рендеринга для поддержки мультивыборки:

  1. Во время Ясного Буферного шага Вы очищаете содержание кадрового буфера мультивыборки.

    glBindFramebuffer(GL_FRAMEBUFFER, sampleFramebuffer);
    glViewport(0, 0, framebufferWidth, framebufferHeight);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  2. После представления Ваших команд рисования Вы разрешаете содержание от буфера мультивыборки в буфер решения. Выборки, сохраненные для каждого пикселя, объединены в единственную выборку в буфере решения.

    glBindFramebuffer(GL_DRAW_FRAMEBUFFER_APPLE, resolveFrameBuffer);
    glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, sampleFramebuffer);
    glResolveMultisampleFramebufferAPPLE();
  3. На шаге Отбрасывания можно отбросить обоих renderbuffers, присоединенный к мультидемонстрационному кадровому буферу. Это вызвано тем, что содержание, которое Вы планируете представить, сохранено в кадровом буфере решения.

    const GLenum discards[]  = {GL_COLOR_ATTACHMENT0,GL_DEPTH_ATTACHMENT};
    glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE,2,discards);
  4. На Существующем шаге Результатов Вы представляете цвет renderbuffer присоединенный к кадровому буферу решения.

    glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER];

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