Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. iOS SDK
Code

iOS 8: Приступаем к работе с Metal

by
Difficulty:IntermediateLength:LongLanguages:

Russian (Pусский) translation by Masha Kolesnikova (you can also view the original English article)

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

1. Но сначала

В этом руководстве предполагается, что вы знакомы с языком Objective-C и имеете некоторый опыт работы с OpenGL, OpenCL или сопоставимым графическим API.

Он также требует физического устройства с процессором Apple A7 или A8. Это означает, что вам понадобятся iPhone 5S, 6 или 6 Plus или iPad Air или mini (2-го поколения). IOS Simulator даст вам ошибки компиляции.

Этот учебник ориентирован только на Metal, и он не будет охватывать Metal Shading Language. Мы создадим шейдер, но мы рассмотрим только основные операции для взаимодействия с ним.

Если вы используете Xcode в первый раз, убедитесь, что вы добавили свой Apple ID в раздел Accounts в Preferences Xcode. Это обеспечит отсутствие проблем при развертывании приложения на вашем устройстве.

Xcode 6 включает в себя шаблон проекта для Metal, но чтобы помочь вам лучше понять Metal, мы собираемся создать проект с нуля.

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

2. Введение

Для тех из вас, кто знаком с OpenGL или OpenGL ES, Metal - это низкоуровневая трехмерная графическая среда, но с более низкими накладными расходами. В отличие от комплектов Apple Sprite Kit или Scene Kit, с которыми вы по умолчанию не можете взаимодействовать с конвейером рендеринга, у Metal есть вся необходимая сила для создания, управления и изменения этого конвейера.

Metal имеет следующие функции:

  • Фреймворк обеспечивает чрезвычайно низкий уровень доступа к графическим процессорам A7 и A8, что обеспечивает невероятно высокую производительность для сложных графических решений и вычислительных задач.
  • Metal устраняет многие узкие места производительности, такие как дорогостоящая проверка состояния, которая встречается в традиционных графических API.
  • Он явно предназначен для переноса всех дорогостоящих операций трансляции и компиляции состояний из среды выполнения и среды рендеринга.
  • Он обеспечивает предварительно скомпилированные шейдеры, объекты состояния и явное планирование команд, чтобы обеспечить максимально возможную производительность и эффективность выполнения графических решений и вычислительных задач.
  • Фреймворк был разработан для использования современных архитектурных соображений, таких как многопроцессорная и разделяемая память.
  • Он глубоко интегрирован с iOS 8, чипсетами A7 и A8 и аппаратным обеспечением Apple, создавая единый и независимый фреймворк.

Достаточно с теорией, пришло время понять, как создается Metal приложение.

3. Создание Metal приложения

Metal приложение характеризуется набором необходимых шагов для корректного представления данных на экране. Эти шаги обычно создаются по порядку, и некоторые ссылки передаются от одного к другому. Эти шаги:

  • получить устройство
  • создать командную очередь
  • создавать ресурсы, такие как буферы, текстуры и шейдеры
  • создать конвейер рендеринга
  • создать представление

Шаг 1: Получить устройство

Этот шаг включает создание объекта MTLDevice, являющегося основой приложения Metal. Класс MTLDevice обеспечивает прямой способ связи с драйвером и оборудованием GPU. Чтобы получить ссылку на экземпляр MTLDevice, вам нужно вызвать System Default Device, как показано ниже. С этой ссылкой у вас есть прямой доступ к аппаратным средствам устройства.

Шаг 2. Создание очереди команд

Класс MTLCommandQueue предоставляет способ отправки команд или инструкций на GPU. Чтобы инициализировать экземпляр класса MTLCommandQueue, вам нужно использовать ранее созданный объект MTLDevice и вызвать на нем метод newCommandQueue.

Шаг 3: Создание ресурсов

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

Например, если вам нужно передать данные для двумерной вершинной позиции, вы должны объявить одну структуру данных, содержащую объект для этой 2D-позиции. Затем вы должны объявить его как на клиенте, в приложении iOS, так и на стороне сервера, Metal шейдере. Взгляните на следующий пример для пояснения.

Обратите внимание, что вам нужно импортировать библиотеку GLKMath из фреймворка GLKit, как показано ниже.

Затем вы объявляете объект с правильными координатами.

Шаг 4. Создание пайплайна рендеринга

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

RenderingPipeline

Конвейер рендеринга настраивается с использованием двух классов:

  • MTLRenderPipelineDescriptor: предоставляет все состояния конвейера отображения, такие как позиции вершин, цвета, глубины и буферов трафарета, среди прочих
  • MTLRenderPipelineState: скомпилированная версия MTLRenderPipelineDescriptor и которая будет развернута на устройстве

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

В следующем фрагменте кода показано, как создать объект MTLRenderPipelineDescriptor.

На данный момент вы создали дескриптор, но вам все равно нужно настроить его, по крайней мере, в формате пикселей. Это то, что мы делаем в следующем блоке кода.

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

Метод newFunctionWithName ищет исходный файл в Metal, ища метод SomeVertexMethodName. Имя самого шейдера не важно, так как поиск выполняется непосредственно через имена методов. Это означает, что вы должны определить уникальные методы для уникальных операций шейдера. Позднее мы посмотрим глубже в Metal shaders.

С созданным и настроенным объектом MTLRenderPipelineDescriptor следующим шагом будет создание и определение MTLRenderPipelineState путем передачи во вновь созданном объекте MTLRenderPipelineDescriptor.

Шаг 5: Создайте представление

Чтобы создать представление Metal, вам необходимо отнаследоваться от UIView и переопределить метод layerClass, как показано ниже.

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

4. Отрисовка Metal приложения

Теперь, когда мы инициализировали необходимые объекты, нам нужно начать рисовать что-то на экране. Как и при инициализации, вам нужно выполнить несколько шагов:

  • получить буфер команд
  • установить проход рендеринга
  • отрисовать
  • передать в буфер команд

Шаг 1: Получить буфер команд

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

Шаг 2: Запустите прохождение Render Pass

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

Для тех, кто знаком с OpenGL и OpenGL ES, этот шаг аналогичен, так как фреймбуфер имеет те же свойства, что и настройки Color Attachment (от 0 до 3), Depth и Stencil. Вы можете увидеть визуальное представление этого шага на диаграмме ниже.

RenderingPass

Сначала вам нужно создать текстуру для рендеринга. Текстура создается из класса CAMetalDrawable и использует метод nextDrawable для извлечения следующей текстуры для рисования в списке.

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

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

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

Шаг 3: Рисуем

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

Шаг 4: Заблокируйте буфер команд

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

На этом этапе у вас должно быть общее представление о том, как структурировано приложение Metal. Однако, чтобы правильно понять все это, вам нужно сделать это самостоятельно. Пришло время запрограммировать ваше первое приложение Metal.

5. Создание приложения Metal

Запустите Xcode 6 и выберите New > Project... в меню File. Выберите Single View Application из списка шаблонов и выберите имя продукта. Установите Objective-C в качестве языка и выберите iPhone в меню Devices.

Откройте ViewController.m и добавьте следующие операторы импорта вверху.

Вам также необходимо добавить фреймворки Metal и QuartzCore в разделе Linked Frameworks and Libraries в Build Phases. Отныне ваше внимание должно быть нацелено на файл реализации класса ViewController.

6. Создание структуры Metal

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

В методе viewDidLoad контроллера view мы инициализируем экземпляры MTLDevice и CommandQueue.

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

Если у вас возникла проблема с настройкой объекта CAMetalLayer, следующий фрагмент кода поможет вам.

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

Единственный шаг - отобразить что-то на экране. Инициализируйте CADisplayLink, передавая self как цель и @selector(renderScene) в качестве селектора. Наконец, добавьте объект CADisplayLink в текущую итерацию цикла.

Вот как должен выглядеть законченный метод viewDidLoad.

Если вы собирете проект, вы заметите, что Xcode дает нам одно предупреждение. Нам еще нужно реализовать метод renderScene.

Метод renderScene выполняется каждый кадр. Для каждого нового фрейма необходимо инициализировать несколько объектов, таких как объекты MTLCommandBuffer и MTLRenderCommandEncoder.

Шаги, которые нам нужно предпринять для рендеринга кадра:

  • создать объект MTLCommandBuffer
  • инициализировать объект CAMetalDrawable
  • инициализировать объект MTLRenderPassDescriptor
  • настроить свойства texture, loadAction, clearColor и storeAction объекта MTLRenderPassDescriptor
  • создать новый объект MTLRenderCommandEncoder
  • передаем в командный буфер

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

Нам также необходимо реализовать метод dealloc контроллера view, в котором мы аннулируем объект displayLink. Мы устанавливаем объекты mtlDevice и mtlCommandQueue равными nil.

7. Рисование треугольника

Теперь у вас есть очень базовое приложение Metal. Пришло время добавить свой первый графический примитив, треугольник. Первый шаг - создать структуру для треугольника.

Не забудьте добавить оператор import для библиотеки GLKMath в верхней части ViewController.m.

Чтобы отобразить треугольник, вам нужно создать объект MTLRenderPipelineDescriptor и объект MTLRenderPipelineState. Кроме того, каждый объект, который нарисован на экране, принадлежит классу MTLBuffer.

С объявлением этих переменных экземпляра вы должны теперь инициализировать их в методе viewDidLoad, как я объяснил ранее.

Чтобы затенять треугольник, нам понадобятся Metal шейдеры. Metal шейдеры должны быть назначены объекту MTLRenderPipelineDescriptor и инкапсулированы через протокол MTLLibrary. Это может показаться сложным, но вам нужно использовать только следующие строки кода:

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

В Metal вы можете определить координаты системы, но в этом уроке вы будете использовать систему координат по умолчанию, то есть координаты центра экрана (0,0).

В следующем блоке кода мы создаем треугольный объект с тремя координатами (-.5f, 0.0f), (0.5f, 0.0f), (0.0f, 0.5f).

Затем мы добавляем треугольник к объекту <MTLBuffer>, который создает буфер для треугольника.

Вот как должен выглядеть законченный метод viewDidLoad.

Метод viewDidLoad завершен, но нет последнего шага, создающего шейдеры.

8. Создание шейдеров

Чтобы создать металлический шейдер, выберите New > File... в меню File, выберите Source > Metal File в разделе iOS и назовите его MyShader. Затем Xcode создаст для вас новый файл MyShader.metal.

В верхней части вы должны увидеть следующие две строки кода. Первая включает в себя Metal Standard Library, а вторая - пространство имен metal.

Первый шаг - скопировать структуру треугольника в шейдер. Шейдеры обычно делятся на две разные операции: вершину и пиксель (фрагменты). Первое связано с положением вершины, а второе связано с окончательным цветом этой вершины и всеми положениями пикселей внутри многоугольника. Вы можете рассматривать его таким образом, первый растеризует многоугольник, пиксели многоугольника, а второй будет затенять эти же пиксели.

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

Теперь давайте создадим методы вершин и фрагментов. Помните, когда вы запрограммировали объект RenderPipelineDescriptor как для вершины, так и для фрагмента? Вы использовали метод newFunctionWithName, передавая объект NSString. Эта строка - это имя метода, который вы вызываете внутри шейдера. Это означает, что вам нужно объявить два метода с этими именами: VertexColor и FragmentColor.

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

Внутри шейдеров добавьте следующий блок кода.

Метод VertexColor получит данные, сохраненные в позиции 0 буфера (выделенная память) и vertex_id вершины. Поскольку мы объявили трехвершинный треугольник, vertex_id будет 0, 1 и 2. Он выводит объект TriangleOutput, который автоматически получает FragmentColor. Наконец, он будет затенять каждый пиксель внутри этих трех вершин, используя красный цвет.

Вот и все. Создавайте и запускайте приложение и наслаждайтесь своим первым, новым 60-секундным Metal приложением.

9. Внешние ресурсы

Если вы хотите узнать больше о фреймворке Metal и как он работает, вы можете проверить несколько других ресурсов:

Заключение

Это завершает наш вводный учебник по новому фреймворку Metal. Если у вас есть какие-либо вопросы или комментарии, не стесняйтесь оставлять их в комментариях ниже.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.