Что такое пиксельные шейдеры
Ше́йдер (англ. Shader) — это программа для одной из ступеней графического конвейера, используемая в трёхмерной графике для определения окончательных параметров объекта или изображения. Она может включать в себя произвольной сложности описание поглощения и рассеяния света, наложения текстуры, отражение и преломление, затенение, смещение поверхности и эффекты пост-обработки.
нужны шейдеры чтобы игра красивее была тени, отблески, отражения.
шейдеры идут в игре, а в видеокарте стоит обработчик шейдеров, например симс 3 требует от видеокарты поддержки шейдеров версии 2.0, если видеокарта не поддерживает 2.0 (старая видеокарта) то игра просто не запустится, надо менять видяху
В программных графических движках вся цепочка рендеринга — от определения видимых частей сцены до наложения текстуры — писалась разработчиком игры. В эту цепочку можно было включать собственные нестандартные видеоэффекты. Но с появлением видеоакселераторов разработчик оказался ограничен тем набором эффектов, который заложен в аппаратное обеспечение. Вот два примера.
* Попробуйте нырнуть под воду в Quake 2 на программном и на OpenGL-рендеринге. При всём качестве аппаратно ускоренной картинки, вода там — просто синий светофильтр, в то время как в программном есть эффект плеска воды.
* В Counter-Strike эффект ослепления от светошумовой гранаты на аппаратном рендеринге — белая вспышка, на программном — белая вспышка и пикселизированный экран.
Для того, чтобы составлять сложные видеоэффекты из атомарных операций, и были изобретены шейдеры. Предшественниками шейдеров были процедурная генерация текстур (широко применявшаяся в Unreal для создания анимированных текстур воды и огня) и мультитекстурирование (на нём был основан язык шейдеров, применявшийся в Quake 3). Но и эти эффекты не обеспечивают такой гибкости, как шейдеры.
это программа для одной из ступеней графического конвейера, используемая в трёхмерной графике для определения окончательных параметров объекта или изображения. Она может включать в себя произвольной сложности описание поглощения и рассеяния света, наложения текстуры, отражение и преломление, затенение, смещение поверхности и эффекты пост-обработки.
Программируемые шейдеры гибки и эффективны. Сложные с виду поверхности могут быть визуализированы при помощи простых геометрических форм. Например, шейдеры могут быть использованы для рисования поверхности из трёхмерной керамической плитки на абсолютно плоской поверхности.
В программных графических движках вся цепочка рендеринга — от определения видимых частей сцены до наложения текстуры — писалась разработчиком игры. В эту цепочку можно было включать собственные нестандартные видеоэффекты. Но с появлением видеоакселераторов разработчик оказался ограничен тем набором эффектов, который заложен в аппаратное обеспечение. Вот два примера.
* Попробуйте нырнуть под воду в Quake 2 на программном и на OpenGL-рендеринге. При всём качестве аппаратно ускоренной картинки, вода там — просто синий светофильтр, в то время как в программном есть эффект плеска воды.
* В Counter-Strike эффект ослепления от светошумовой гранаты на аппаратном рендеринге — белая вспышка, на программном — белая вспышка и пикселизированный экран.
Для того, чтобы составлять сложные видеоэффекты из атомарных операций, и были изобретены шейдеры. Предшественниками шейдеров были процедурная генерация текстур (широко применявшаяся в Unreal для создания анимированных текстур воды и огня) и мультитекстурирование (на нём был основан язык шейдеров, применявшийся в Quake 3). Но и эти эффекты не обеспечивают такой гибкости, как шейдеры.
Высокоуровневый шейдерный язык DirectX (HLSL — High Level Shader Language)
Является надстройкой над DirectX ASM. По синтаксису сходен с C, позволяет использовать структуры, процедуры и функции.
Это специализированные процессоры, входящие в обработку в видеокарте! Ни скачать, ни взять их нельзя! Против закона о правах потребителя, их отгружают только в нагрузку к видеокарте!
шейдер это микропрограмка.
пиксельные шейдеры это микропрограмки отвечающие за пиксели.
нужны для построения картинки в процессоре
В этой статье я хочу сделать небольшое обозрение текущей ситуации с пиксельными шейдерами второй версии, представленными в DirectX9. Сначала немного истории.
Аппаратные средства
Чтобы понять, откуда появились вычислительные шейдеры, мы должны взглянуть на эволюцию аппаратных средств. Еще в старые времена, перед шейдерами, обработка геометрии и текстурирование разделились. Например, карта Voodoo² имела один растеризатор и два блока текстурирования, разделяя рабочую нагрузку между ними. Эта тема продолжалась долгое время, даже после введения шейдеров. До GeForce 7 и Radeon X1950 у графических процессоров были отдельные вершинные и пиксельные шейдеры. Шейдеры обычно имели сходные возможности с точки зрения того, что они могли вычислить (в конце концов, сложение и умножение составляют основную часть работы на графическом процессоре), но доступ к памяти сильно различался. Например, в течение длительного времени вершинные шейдеры не могли иметь доступ к текстурам. В то время разделение имело смысл. Сцены состояли из нескольких полигонов, охватывающих множество пикселей, поэтому наличие меньшей мощности вершинного шейдера обычно не приводило к узкому месту. Уменьшение функциональности вершинных шейдеров позволяло лучше их оптимизировать и делать быстрее.
Основной конвейер GPU с отдельными вершинными и пиксельными блоками. Блоки вершин записывают обработанные вершины в буфер атрибутов, пиксельные блоки потребляют его, а также получают доступ к памяти через текстурные блоки.
Однако фиксированное распределение также не дает сбалансированную нагрузку на ресурсы. По мере развития игр иногда требовалась больше мощности для обработки вершин, например, при рендеринге плотной геометрии деревьев, в то время как в других играх использовались новые модели программирования шейдеров для более сложных пиксельных. Это было также время, когда началось программирование GPGPU. То есть программисты пытались решать на графических процессорах численные задачи. В конце концов стало ясно, что фиксированное разделение недостаточно хорошо работает.
В конце 2006 — начале 2007 года, с выпуском GeForce 8800 GTX и Radeon HD 2800 началась эра «унифицированных шейдеров» (технически говоря, первым был XBox 360). Прошли времена отдельных блоков, вместо этого ядро могло обрабатывать любую рабочую нагрузку.
Унифицированный конвейер пикселей и вершин. Все устройства могут разговаривать с памятью через текстурные блоки и передавать данные между ними через буфер атрибутов.
Так что же тогда произошло? ALU — устройства, выполняющие математические инструкции, были уже похожи. Изменилось то, что различие между блоками было полностью устранено. Вершинные шейдеры теперь выполнялись в тех же блоках, что и пиксельные. Это позволяет сбалансировать рабочую нагрузку между работой вершинного и пиксельного шейдеров. Вы должны заметить здесь, что вершинные и пиксельные шейдеры должны каким-то образом общаться. Для хранения атрибутов для интерполяции необходим, например, цвет вершин. Вершинный шейдер будет вычислять атрибуты каждой вершины последовательно, но пиксельный шейдер может зависеть от этой информации некоторое время, пока все пиксели не будут обработаны. Мы вернемся к этому моменту позже, давайте сейчас просто запомним.
Унифицированный конвейер, показанный как вычислительный конвейер. Буфер атрибута становится локальной или разделяемой памятью, текстурные блоки становятся шлюзом в глобальную память, а пиксельные и вершинные блоки теперь являются общими вычислительными единицами.
Эта модель (несколько соединенных вместе ALU с дополнительной памятью, позволяющей обмениваться данными между множествами из них) была введена одновременно с «вычислительным шейдером». На самом деле есть еще несколько деталей. Например, вычислительный блок обычно обрабатывает не один элемент, а несколько, и есть еще немало кэшей, чтобы сделать все это эффективным. Ниже приведена диаграмма для одного вычислительного блока в архитектуре AMD GCN. Обратите внимание: то, что я ранее называл «вычислительный блок», теперь является «SIMD», это более важно в данный момент.
Вычислительный блок класса AMD GCN, состоящий из четырех 16-разрядных блоков SIMD, локальной памяти и различных кэшей. Выделенные пунктиром устройства разделяются между несколькими вычислительными блоками.
Надо знать, что другие графические процессоры очень похожи на этот. Я использую GCN здесь просто потому, что больше всего с ним знаком. На оборудовании NVIDIA вычислительный блок GCN отображен как «потоковый мультипроцессор» или SM. SIMD имеют разную ширину, и кэши будут выглядеть несколько иначе, но основная вычислительная модель все равно будет одинаковой.
Вернемся к блоку SIMD. Графические процессоры всегда оптимизированы для одновременной обработки многих вещей. Где у вас один пиксель, там их еще несколько, так были спроектированы аппаратные средства. В случае GCN инженеры сделали четыре 16-разрядных SIMD в каждый вычислительный блок. SIMD (сокращение для “одиночный поток команд, множественный поток данных”) может выполнять одну операцию по 16 элементам одновременно. Не за один такт — есть некоторое время ожидания. Но для GCN эта задержка составляет четыре цикла. Поэтому имея 4 SIMD и притворяясь, что SIMD не 16, а 64 в ширину, машина ведет себя как если бы она выполняла 64 инструкции за цикл. Смущены? Не волнуйтесь, это всего лишь особенность реализации, так как каждый графический процессор выполняет несколько команд вместе, будь то 64 в случае GCN или 32 на существующих архитектурах NVIDIA.
В результате мы получили графический процессор, состоящий из множества вычислительных блоков, и каждый вычислительный блок, содержащий:
- Множество SIMD-процессоров, которые выполняют инструкции.
- Некоторую локальную память внутри каждого вычислительного блока, которая может использоваться для связи между этапами шейдера.
- Каждый блок SIMD, который выполняет одну команду для многих элементов.
С этими предпосылками давайте посмотрим, как они могут обнаружить себя, если не выполняют работу пиксельных и вершинных шейдеров. Идем дальше!
Цель состоит в том, чтобы написать систему программирования, которая позволяет использовать подручные аппаратные средства. Очевидно, первое, что мы замечаем, это то, что мы хотим избежать. Все вычислительные блоки являются клиентами кэша L2. Но, очевидно, кэши L1 могут выйти из синхронизации. Поэтому, если мы распределяем работу, мы должны притворяться, что не можем говорить о вычислительных блоках. Это означает, что мы как-то должны разделить работу на более мелкие части. Мы могли бы просто притворяться, что нет вычислительных блоков и отправки отдельных элементов, но тогда мы теряем местную память. Поэтому кажется, что нужен еще один уровень ниже «вся работа тут».
Мы могли бы перейти непосредственно на уровень SIMD. Но это не оптимально, так как есть возможность, которую мы еще не обсуждали про вычислительные блоки. Поскольку у нас есть какая-то локальная память, естественно предположить, что мы можем использовать ее для синхронизации блоков SIMD (учитывая, что мы могли бы просто написать что-то в локальную память и дождаться его появления). Это также означает, что мы можем синхронизировать только в одном вычислительном блоке. Поэтому давайте использовать его в качестве следующего уровня группировки. Мы будем называть работу, которая ставится на единый вычислительный блок, рабочей группой. Таким образом, мы начинаем с рабочего домена, который затем разбивается на рабочие группы. Каждая рабочая группа работает независимо от других. Учитывая, что разработчик может не знать, сколько групп может работать одновременно, мы обеспечиваем, чтобы рабочие группы не зависели от того, что:
- Обрабатывается другая рабочая группа из того же домена.
- Рабочие группы внутри домена выполнялись в любом конкретном порядке.
Это позволяет нам запускать одну рабочую группу за другой на одном устройстве или все сразу. Теперь внутри рабочей группы нам все еще нужно много самостоятельных элементов работы, поэтому мы можем заполнить все SIMD-модули. Давайте назовем отдельный элемент работы рабочим элементом, и наша модель программирования запустит рабочие группы, содержащие множество рабочих элементов. По крайней мере, достаточно, чтобы заполнить один вычислительный блок (мы, вероятно, хотим больше, чем просто заполнить, но об этом позже).
Давайте объединим все это: наш домен состоит из рабочих групп, каждая рабочая группа отображается на один вычислительный блок, а модули SIMD обрабатывают рабочие элементы.
Вот как наша модель программирования теперь отображается на аппаратные средства. Домен состоит из рабочих групп, которые присваиваются вычислительным блокам. Каждая рабочая группа состоит из нескольких рабочих элементов.
Мы забыли, что по-видимому, есть еще один уровень, который мы не покрывали. Я упомянул, что SIMD-модуль обрабатывает несколько рабочих элементов вместе. Но мы не раскрыли это в модели программирования, у нас есть только «независимые» рабочие элементы. Давайте дадим работающим элементам вместе имя. Мы назовем их подгруппой (у AMD они обычно называются «wavefront», в то время NVIDIA называет «warp».) Теперь мы можем предоставить другой набор инструкций, которые выполняют операции во всех элементах SIMD. Например, мы могли бы вычислить минимум всех значений не проходя через локальную память.
Я уже упоминал, что ограничений на порядок накладывается очень мало. Например, графический процессор может захотеть выполнить весь домен на одном вычислительном блоке. Одной из причин этого является латентность памяти. Эти широкие SIMD-устройства великолепно щелкают числа, но также это значит, что доступ к памяти относительно сильно замедлен. На самом деле, он ужасно медленный. GCN CU может обрабатывать 64 инструкции умножения-сложения с плавающей запятой за цикл, что составляет 64 × 3 × 4 байта входных данных и 64 × 4 байта на выходе. Через большой чип, такой как Vega10, это 48 кб чтения за один цикл. На 1,5 ГГц, это 67 Тб данных, которые нужно прочитать. Системы памяти GPU были оптимизированы для большой пропускной способности ценой латентности, и это влияет на то, как мы их программируем.
Прежде чем мы рассмотрим последствия данной модели программирования, давайте подведем итог тому, как выглядят вычислительные шейдеры:
- Работа определяется с помощью трехуровневой иерархии:
- Домен определяет всю работу.
- Домен подразделяется на рабочие группы, которые выполняются независимо, но допускают связь внутри группы.
- Рабочие элементы — это отдельные элементы для обработки.
- Некоторые API также выставляют промежуточный уровень — подгруппу, которая допускает некоторые оптимизации ниже рабочей группы, но выше уровня рабочего элемента.
- Рабочие группы могут синхронизироваться внутренне и обмениваться данными через локальную память.
Эта модель программирования универсальна во всех API-интерфейсах для вычислительных шейдеров GPU. Различия в предоставляемых гарантиях. Например, API может ограничить количество рабочих групп в полете, чтобы вы могли синхронизировать их между собой. Или какое-то оборудование может гарантировать порядок выполнения, чтобы вы могли передавать информацию из одной рабочей группы в другую.
Теперь взглянем подробнее на стандарт PS 2.0 и современные видеочипы
Изначально при представлении PS 2.0 и далее, при выпуске первой бета версии DirectX9 Microsoft представила единые требования по минимально допустимой точности чисел с плавающей точкой, с идеалом, стремящемся к полноценным числам одинарной точности (32 бит single). Позже, очевидно из-за лоббирования NVIDIA, в стандарт было введено понятие ограниченной точности (partial precision) при выполнении команд шейдера. Заметим, что флаг ограниченной точности для шейдерной команды это только намек на то, что операция не требует максимальной точности, и этот флаг может быть спокойно проигнорирован драйверами/видеочипом, соответственно операция будет выполнена в обычном режиме.
Ниже приведен текст текущей спецификации по отношению к точности операций с плавающей точкой:
Итак, мы достигли центрального места статьи определения точности операций с плавающей точкой в новейших видеочипах. Для этого нами была написана специальная тестовая утилита. Результаты ее работы записываются в лог-файл в следующем виде:
Device: RADEON 9500 SERIES
Driver: ati2dvag.dll
Driver version: 6.14.1.6292
Registers precision:
Rxx = s16e7 (temporary registers)
Cxx = s16e7 (constant registers)
Txx = s16e7 (texture coordinates)
Registers precision in partial precision mode:
Rxx = s16e7 (temporary registers)
Cxx = s16e7 (constant registers)
Txx = s16e7 (texture coordinates)
Итого, после прогона программы мы получаем шесть значений, отражающих точность реализации чисел с плавающей точкой в видеочипе, по одной для каждого типа регистров в двух различных режимах выполнения операций. Саму программу Вы можете загрузить по адресу, указанному в конце статьи. Вместе с программой желающие могут посмотреть код шейдеров, использованных при определении точности вычислений.
Итак посмотрим на результаты, полученые нами при тестировании видеокарт на базе чипов от ATI и NVIDIA.
Если бы не результаты, полученные недавно на NV35, то значения в таблице были бы не очень разнообразны, не правда ли? Давайте разберемся в полученных цифрах. Широко известно, что чипы ATI используют 24 битные FP числа всегда, вне зависимости от флага ограниченной точности. Гораздо интереснее ситуация с чипами NVIDIA — все чипы, кроме NV35, всегда использует 16 битные FP числа, вне зависимости от указанной точности! И это несмотря на то, что само понятие ограниченное точности было введено именно по настоянию NVIDIA, чипы прекрасно поддерживают 32 битную точность при использовании OpenGL расширения NV_fragment_program, и именно NVIDIA везде рекламировала свои новые чипы, как чипы с истинной 32 битной точностью при выполнении пиксельных операций!
Наиболее разнообразно и корректно [среди чипов NVIDIA] поведение NV35. Видно, что в стандартном режиме в соответствии со спецификациями Microsoft вычисления производятся с 32 битной точностью, при указании возможности вычислений с пониженной точностью временные и константные регистры используют 16 битную точность, а текстурные регистры используют 32 битную точность вычислений. Хотя по спецификации Microsoft текстурные регистры в режиме с частичной точностью также могут быть 16 битной точности.
Обращаю Ваше внимание на то, что все результаты для NV3x получены уже на сертифицированных WHQL драйверах, так можно только сожалеть, что Microsoft не контролирует выполнение собственных спецификаций. Также стоит обратить внимание, что формат 16 битных FP чисел, используемых NVIDIA, в точности совпадает с тем, что предложил Кармак в 2000 году.
Проанализируем полученные результаты. Ниже приведены характеристики 16 и 24 битных FP чисел, и 32 битных FP чисел, как эталона.
Отставание s10e5 формата от остальных форматов хранения чисел с плавающей точкой по большинству параметров бросается в глаза. Как ни парадоксально, но s10e5 числа корректней сравнивать с числами с фиксированной точкой, используемыми в PS 1.x. Точность чисел в PS1.x даже в NV3x равна 12 бит, что эквивалентно точности чисел в формате s10e5 (учитывая 10 бит мантиссы, знаковый и подразумеваемый ведущий биты). И именно в сравнении с числами с фиксированной точкой видны преимущества формата s10e5 намного большие абсолютные значения: 1 (или 2 или 4 или 8 в зависимости от чипа) в сравнении с 65536 и одновременно намного меньшие абсолютные значения.
Здесь опять можно вспомнить письмо Джона Кармака, где он четко сформулировал области, в которых он хотел бы использовать числа s10e5 это освещение. Именно расширенный диапазон позволяет использовать overbright lighting, когда нужно имитировать очень яркие источники света, ослепляющие человека, а также не позволит потерять детали в тени.
Но точность s10e5 чисел именно та область, где нужно очень осторожно оперировать. Очевидно, что они не позволят корректно реализовать raytracer, как это было продемонстрировано ATi, но даже вычисление текстурных координат в пиксельном шейдере может привести к нежелательным последствиям. Ведь точность s10e5 чисел даже не позволит корректно адресовать текстуры размером 1024 пикселей по одной из осей при билинейной фильтрации. В NVIDIA хорошо это понимают и уже начали активно вести работу с разработчиками, обучая как обнаружить те области, где недостаточная точность чисел формата s10e5 приводит к неверным результатам. NVIDIA также усиленно пропагандирует проведение всех высокоточных вычислений в вершинных шейдерах.
Виды шейдеров
В зависимости от стадии конвейера шейдеры делятся на несколько типов: вершинный, фрагментный (пиксельный) и геометрический. А в новейших типах конвейеров есть еще шейдеры тесселяции. Подробно обсуждать графический конвейер мы не будем, я все думаю не написать ли об этом отдельную статью, для тех кто решит заняться изучением шейдеров и программирования графики. Напишите в комментариях если Вам интересно, я буду знать, стоит ли тратить время.
Microsoft
В феврале 2001 Microsoft уже представляла свое видение архитектуры DirectX9 (очень кстати похожей на то, что мы получили в итоге в лице ATi R300). На той презентации, в том числе было объявлено, что следующая версия пиксельных шейдеров в DirectX9, известная под аббревиатурой «PS 2.0» будет оперировать с FP числами одинарной точности (single precision), и будет близка по функциональности к вершинным шейдерам.
Что было с успехом реализовано в финальной версии DirectX9, вышедшей в декабре 2002 года.
Если остались вопросы
Как обычно, если у Вас остались какие-то вопросы, задавайте их в комментариях, я всегда отвечу. За любое доброе слово или правку ошибок я буду очень признателен.
Пишет статьи о разработке игр. Не инди, — работает рендеринг-программистом в крупной ААА студии в Санкт-Петербурге. Большой поклонник игр Naughty Dog.
Пару месяцев назад я отправился в Мюнхенский GameCamp. Это баркемп, где каждый может предложить тему для обсуждения, а затем в ходе быстрого голосования решают, какую тему принять. Я предлагал то одно, то другое. Потом один разработчик сказал, что я, вероятно, хотел бы дать материал о вычислительных шейдерах. Итак, я вошел, не надеясь привлечь много сторонников. В итоге оказался в переполненной комнате, где четверть участников примерно час болтала про вычислительные шейдеры. Основным из вопросов оказался: «Где я могу почитать об этом?». И я не мог дать однозначно хороший вводный материал (есть «Путешествие по графическому конвейеру», но он уже довольно старый.)
Intel и стандарт чисел с плавающей точкой
Сегодня стандарт IEEE-754, описывающий числа с плавающей точкой является наиболее распространенным для представления действительных чисел на компьютерах, включая x86, IA64, PowerPC и большинство Unix совместимых платформ. Как же он образовался?
В 1976 году корпорация Intel начала разработку сопроцессоров для вычисления с числами с плавающей точкой для ее i8086/8 and i432 микропроцессоров. Десять лет спустя доктор Джон Палмер (Dr. John Palmer) менеджер Intel по направлению FP сопроцессоров в университете Стэнфорд (Stanford) нанял Вильяма Кэхэна (William Kahan) в качестве консультанта по готовящемуся i8087 сопроцессору к процессорам i8086/8. В последствии по Силиконовой долине распространились слухи о i8087, и это настолько озаботило фирм-разработчиков процессоров, что в итого был сформирован комитет по определению стандарта FP арифметики для микропроцессоров. В 1977 году, после нескольких встреч комитета Кэхэна (Kahan), студент Джером Конен (Jerome Coonen) из U.C. Berkeley и профессор Гарольд Стоун (Harold Stone) подготовили черновик спецификации в виде IEEE стандарта и представили его на обсуждение в качестве стандарта IEEE p754 этот черновик был назван «K-C-S». К 1985 году, когда IEEE-754 стандарт был принял, он уже стал стандартом де-факто.
Современные x86 совместимые микропроцессоры используют 32, 64 и 80 битное представление FP чисел.
Заключение
Я надеюсь, что этот пост даст вам представление о том, как мы пришли к вычислительным шейдерам. Действительно интересно, что концепции минимального общения, доступа к локальной памяти и расхождения стоимости абсолютно универсальны. Современные многоядерные процессоры также вводят новые уровни затрат на общение с памятью, для моделирования затрат уже давно используется NUMA и т.д. Понимая, что не вся память равна, и что на лежащих в основе аппаратных средствах ваш код выполняется каким-то определенным образом, вы сможете выжать больше производительности везде!
Переводит для Вас самые интересные статьи про разработку игр. По образованию физик-программист. Техническими переводами начала подрабатывать еще на старших курсах и постепенно это переросло в основное занятие. Интересуется гуманитарными технологиями, пробует себя в журналистике.
Привет! Это небольшое введение в тему шейдеров, что это такое и как они используются при рендере графики в Unity.
Супер-реалистичная графика в Sand piper
Например, посмотрите, на вот этот милый мультфильм, песчинки, перышки птички, волны, все выглядит невероятно реальным.
*Видео могут забанить на Youtube, если оно не открывается, погуглите pixar sandpiper – короткометражный мультфильм про храброго песочника очень милый и пушистый. Умилит и продемонстрирует насколько крутой может быть компьютерная графика.
Так вот это RenderMan от фирмы Pixar. Он стал первым языком программирования шейдеров. API RenderMan является фактическим стандартом для профессионального рендеринга, используется во всех работах студии Pixar и не только их.
Пиксельный шейдер
Пиксельными шейдерами выполняют наложение текстур, освещение, и разные текстурные эффекты, такие как отражение, преломление, туман, Bump Mapping и пр. Пиксельные шейдеры также используются для пост-эффектов.
Пиксельный шейдер работает с фрагментами растрового изображения и с текстурами — обрабатывает данные, связанные с пикселями (например, цвет, глубина, текстурные координаты). Пиксельный шейдер используется на последней стадии графического конвейера для формирования фрагмента изображения.
RenderMan
Все что мы обсудили выше относится к realtime графике. Но существуют non-realtime графика. В чем разница – realtime – реальное время, тоесть здесь и сейчас – давать 60 кадров в секунду в игре, это процесс реального времени. А вот рендерить комплексный кадр для ультрасовременной анимации по несколько минут это non-realtime. Суть во времени.
Например, графику такого качества как в последних мультипликационных фильмах студии Pixar получить в реальном времени мы сейчас получить не можем. Очень большие рендер-фермы обсчитывают симуляции света по совсем другим алгоритмам, очень затратным, но дающим почти фотореалистичные картинки.
Что же дальше?
В статье я рассмотрел что такое числа с плавающей точкой, текущие форматы таких чисел в мире микропроцессоров, а также какую поддержку таких чисел обеспечивают производители видеочипов сегодня. Хочется подчеркнуть, что 16 битные числа с плавающей точкой в формате s10e5 не могут считаться подходящими для выполнения общих математических вычислений. Будем надеяться, что NVIDIA позволит разработчикам игр выбирать самим: когда использовать 32 битные числа с плавающей точкой, а когда 16 битную версию с ограниченной точностью. Причем такой выбор должен быть не только у флагмана NV35, но и у всех представителей семейства GeForce FX.
Вероятно все видеочипы следующего поколения, которые будут поддерживать пиксельные шейдеры версии 3.0, также будут поддерживать и вычисления с полноценными 32 битными числами с плавающей точкой. Но программисты, которые часто сталкиваются с вычислениями с плавающей точкой знают, что даже при работе с 32 битными числами с плавающей точкой или, как их еще называют числа с одинарной точностью (single precision), нужно быть очень осторожными и ситуации с переполнением диапазона и потерей точности довольно часты. Так что же: будем ждать следующего шага чисел с двойной точностью (double precision 64 бит)? Видимо этого не стоит ожидать в скором будущем. В подтверждение приведу следующую цитату, относящуюся к использованию чисел с плавающей точкой в пакетах рендеринга для RenderMan API:
In article , wrote:
>I noticed that the binary RIB file specification does not support double
>precision arrays only double precision values. Is there anywhere in
>PRMan or BMRT where values are stored as double precision? Should I
>ever output double precision values in my binary RIB?
The Ri routines are all single precision (so all input is parsed and
put into floats), and thus both BMRT and PRMan are almost completely
float on the inside. Of course, both use doubles occasionally as
temporaries for intermediate calculations in certain parts of the
renderers where that last little bit of precision is vital. But it's
almost correct to say that both renderers are just single precision
throughout.
Что это значит для нас? Не стоит ожидать большой пользы от применения чисел с двойной точностью. Когда они будут введены, то не как базовый тип данных, а как дополнительный, который разработчики должны явно затребовать для использования, а базовым типом чисел с плавающей точкой еще долго будут 32 битовые числа одинарной точности.
Двигателем прогресса в сторону фотореалистичности картинки в компьютерной графике я считаю именно компьютерные игры, поэтому давайте именно в разрезе видео-игр и поговорим о том, что такое “шейдеры”.
До того, как появились первые графические ускорители, всю работу по отрисовке кадров видеоигры выполнял бедняга центральный процессор.
Отрисовка кадра, довольно рутинная работа на самом деле: нужно взять “геометрию” – полигональные модели (мир, персонаж, оружие и т.д.) и растеризовать. Что такое растеризовать? Вся 3d модель состоит из мельчайших треугольников, которые растеризатор превращает в пиксели (то есть “растеризовать” значит превратить в пиксели). После растеризации взять текстурные данные, параметры освещенности, тумана и тп и рассчитать каждый результирующий пиксель игрового кадра, который будет выведен на экран игроку.
Так вот, центральный процессор (CPU – Central Processing Unit) слишком умный парень, чтобы заставлять его заниматься такой рутиной. Вместо этого логично выделить какой-то аппаратный модуль, который разгрузит CPU, чтобы тот смог заниматься более важным интеллектуальным трудом.
Таким аппаратным модулем стал – графический ускоритель или видеокарта (GPU – Graphics Processing Unit). Теперь CPU подготавливает данные и загружает рутинной работой коллегу. Учитывая, что GPU сейчас это не просто один коллега, это толпа миньонов-ядер, то он с такой работой справляется на раз.
Но мы пока не получили ответа на главный вопрос: Что такое шейдеры? Подождите, я подвожу к этому.
Хорошая, интересная и близкая к фото-реализму графика, требовала от разработчиков видеокарт реализовывать многие алгоритмы на аппаратном уровне. Тени, свет, блики и так далее. Такой подход – с реализацией алгоритмов аппаратно называется “Фиксированный пайплайн или конвейер” и там где требуется качественная графика он теперь не встречается. Его место занял “Программируемый пайплайн”.
Запросы игроков “давайте, завозите хороший графоний! удивляйте!”, толкали разработчиков игр (и производителей видеокарт соответственно) все к более и более сложным алгоритмам. Пока в какой-то момент зашитых аппаратных алгоритмов им стало слишком мало.
Наступило время видеокартам стать более интеллектуальными. Было принято решение позволить разработчикам программировать блоки графического процессора в произвольные конвейеры, реализующие разные алгоритмы. То есть разработчики игр, графические программисты отныне смогли писать программы для видеокарточек.
И вот, наконец, мы дошли до ответа на наш главный вопрос.
Джон Кармак
Еще в 2000 году Джон Кармак (John Carmaсk) упомянул о необходимости использования чисел с плавающей точкой в пиксельном конвейере, в дополнение к числам с плавающей точкой в геометрическом конвейере видеокарт. Ниже приведен перевод некоторых выдержек из его «плана»:
4/29/00
-------
Нам необходимо больше бит на цвет в наших 3Д-ускорителях.
Я уже в течение нескольких лет настаивал на необходимости парочки дополнительных бит для расширения диапазона, но сейчас я хотел бы увеличить это пожелание до полных 16 битных чисел с плавающей точкой для представления цвета на протяжении всего графического конвейера. Знаковый бит, десять бит мантиссы и пять бит экспоненты (обменяв, возможно, один или два бита между мантиссой и экспонентой). Даже это не все что бы хотелось, но это разумный шаг.
………………
Есть еще несколько тонких моментов [из-за ограниченной точности прим. ред.], таких как потеря возможного результата из-за повторяющегося возведения в квадрат исходных значений и последствий ограничений суммирования несколько источников света до модуляции их «вниз» цветом материала. Необходимость расширенного диапазона еще более очевидна. Некоторые значения имеют присущий им диапазон значений от 0 до 1, например, коэффициенты отражений и прохождений. Нормализованные вектора имеют диапазон от -1 до 1. Однако, основное числовое значение в рендеринге свет ничем не ограничено. Нам необходимо НАМНОГО больший диапазон, чем от 0 до 1. Q3 подстраивает таблицы гамма коррекции, жертвуя битом точности ради получения диапазона от 0 до 2, но мне необходимо больше чем это для даже примитивных техник рендеринга. Для точного моделирования полного светового диапазона воспринимаемого человеком нам необходимо больше пяти бит экспоненты.
……………………
64 бит пиксели. Это «The Right Thing to do». Поставщики оборудования: не будьте последней компанией, которая сделает этот переход.
Полный оригинальный текст можно найти по адресу.
Главная идея вышеприведенного текста необходимость применения чисел с плавающей точкой при пиксельных операциях (вместо словосочетания «плавающая точка» местами будет использоваться аббревиатура FP). Позже в статье я еще раз обращусь к высказыванию Кармака, а пока следуем дальше.
Код шейдера
Шейдеры в Unity написаны на HLSL (High Level Shading Language), хотя обычно вы увидите, что его называют CG. Особенно, если имеете дело со встроенным конвейером (Built-in Render Pipeline).
Вы всегда увидите этот шейдерный код между тегами CGPROGRAM / HLSLPROGRAM и ENDCG / ENDHLSL. (А еще можете увидеть CGINCLUDE / HLSLINCLUDE, который включает код в каждый проход шейдера).
Шейдеры для URP / HDRP всегда должны использовать HLSL-версии этих тегов, так как CG-теги включают некоторые дополнительные файлы, которые не нужны этим конвейерам. В противном случае это приведет к ошибке из-за переопределения в библиотеках шейдеров.
Остальная часть файла .shader написана с использованием специфичного для Unity синтаксиса, известного как ShaderLab, и включает такие блоки, как «Shader», «Properties», «SubShader» и «Pass». Документацию по синтаксису Shaderlab вы можете найти здесь.
Технически Shaderlab имеет несколько устаревших способов создания шейдеров с фиксированными функциями, что означает отсутствие в надобности CG/HLSL PROGRAM, но я бы не стал беспокоиться об их изучении, поскольку программирование шейдеров намного полезнее.
В качестве альтернативы существуют редакторы шейдеров на основе нодов, такие как Shader Graph (официальный, доступен для URP или HDRP), Amplify Shader Editor (работает во всех конвейерах, но не бесплатный) и Shader Forge (больше не поддерживается, работает только в старых версиях Unity).
Что такое шейдер?
Вершинный шейдер запускается для каждой вершины в меше и отвечает за преобразование трехмерных положений вершин (в пространстве объектов) в положения пространства отсечения (Геометрия отсекает невидимые камерой части объектов. Есть несколько дополнительных шагов, чтобы превратить это в положение на 2D экране. Надеюсь, я восполню пробелы в одном из следующих постов). Также он должен передавать из меша данные, которые потребуются для вычислений на этапе фрагментного шейдера (UV, нормали и т.д.).
В таких инструментах, как Shader Graph, все это обычно делается за нас, но важно понимать, что здесь происходит два отдельных этапа. В новых версиях есть Master Stack, чтобы четче разделить эти этапы. Он предоставляет нам порт Vertex Position, чтобы переопределить положение в пространстве объектов, прежде чем оно будет преобразовано в пространство отсечения, например, для Vertex Displacement. Мы также можем переопределить нормали и касательные, которые передаются на этап фрагментного шейдера, но Shader Graph обработает порты автоматически, если оставить поля пустыми.
Для каждого треугольника и вершины в этом треугольнике положения пространства отсечения, переданные из стадии вершин, используются для создания фрагментов — потенциальных пикселей на 2D-экране. Все данные для каждой вершины, переданные во фрагментный шейдер, также интерполируются по треугольнику. Вот почему у каждой вершины может быть указан один цвет, но треугольник получится градиентно окрашенным. (То же самое происходит с UV, что позволяет правильно наложить текстуру, а не просто брать цвет как один пиксель для каждой вершины)
Далее для этих фрагментов (потенциальных пикселей) запускается фрагментный шейдер. Он определяет цвет, который будет нарисован на экране (и в некоторых случаях выводит значение глубины). В результате может выводиться сплошной цвет с использованием цветов вершин, сэмплирование текстур и/или более сложный шейдинг с вычислениями освещения (название «шейдер» пошло от слова shade – тень).
В некоторых случаях бывает нужно отменить/отбросить пиксель из рендера (например, по alpha).
Вершинный шейдер
Вершинными шейдерами делают анимации персонажей, травы, деревьев, создают волны на воде и многие другие штуки. В вершинном шейдере программисту доступны данные, связанные с вершинами например: координаты вершины в пространстве, её текстурные координатами, её цвет и вектор нормали.
Что такое меш?
Прежде чем перейти конкретно к шейдерам, важно сначала получить базовое представление о том, что такое меш.
Меш содержит данные для 3D-модели, состоящие из вершин и того, как те соединяются в треугольники. Каждый треугольник состоит из 3 вершин, но каждая вершина может быть общей для нескольких треугольников (поэтому количество вершин не всегда будет втрое больше, чем треугольников).
Пример кубического меша, состоящего из 12 треугольников. В Blender (ПО для 3D-моделирования) это 8 вершин, однако при импорте в Unity цифра может измениться в зависимости от того, являются ли данные для каждой вершины одинаковыми у общих вершин.
Термины «меш» и «модель» обычно используются как взаимозаменяемые. Но если углубиться в детали, «меш» всегда относится к геометрии (вершины/треугольники), а «модель» может относиться к импортированному файлу, в котором иногда содержатся несколько объектов меша, сабмеши, а также материалы, анимация и т.д.
Когда мы говорим «вершина», мы обычно имеем в виду ее положение в трехмерном пространстве, но каждая вершина в меше может содержать множество фрагментов данных. Сюда входят такие данные, как:
- Положение в 3D пространстве (пространстве объектов, поэтому (0,0,0) стоит в начале меша).
- UV, также известные как Текстурные Координаты, поскольку они чаще всего используются для наложения текстуры на модель. Обычно бывают координаты Vector2 (два значения с плавающей точкой, каждая ось помечена как xy или uv), но настоящие UV каналы могут быть Vector4 и содержать для передачи данных до 4 чисел с плавающей точкой. Смотрите Mesh.SetUVs.
- Нормали (Направления, используемые для шейдинга. Некоторые программы моделирования (например, Blender) могут дополнительно использовать для определения порядка поворота вершин, который показывает в какую сторону смотрит грань. Во время рендеринга в шейдере можно отбросить переднюю или заднюю сторону грани).
- Касательные (Направления перпендикулярные нормалям, которые огибают поверхность сетки вдоль горизонтальных координат текстуры (uv.x). Используются для построения Пространства Касательных, которое необходимо в таких разновидностях шейдинга как Normal/Bump Mapping)
- Цвета вершин (Цвет, который задан каждой вершине).
Две вершины могут занимать одинаковое положение в 3D пространстве, но если не совпадают другие относящиеся к ним данные, в вершинных данных для них будет две отдельных записи.
Пример кубических мешей. Оба имеют по 12 треугольников, но у левого 24 вершины, а у правого 8.
Достаточно распространено, когда модель имеет равномерное затенение (flat shading), а не плавное (smooth shading) как на изображении выше. Равномерное затенение увеличит количество вершин, потому что нормали вершин у разных граней должны указывать в разных направлениях. (Этого может не случиться в самой программе моделирования, но произойдет при экспорте в Unity). Для плавного затенения используется среднее значение направлений, поэтому вершины можно использовать как общие, при условии, что остальные данные также совпадают!
Формат хранения FP чисел
Числа с плавающей точкой формата IEEE-754 включают в себя три основные компоненты: знак, экспоненту и мантиссу. Мантисса состоит из дробной части и подразумеваемой «ведущей» цифры. Экспонента всегда считается по основанию 2.
Одним из представлений разбиения чисел с плавающей точкой является «sXXeYY» форма, где XX обозначает количество бит в мантиссе, а YY количество бит в экспоненте. В этом представлении числа различной точности описываются следующим образом: одинарной (single) s23e8, двойной (double) s52e11, расширенной (extended) s64e15 и четверной (quadruple) s112e15.
Визуально расположение бит в памяти выглядит так:
Рассмотрим, что же хранится в данных полях.
Знаковый бит
Всего возможно два значения: 0 обозначает положительное число; 1 отрицательное.
Экспонента
Поле экспоненты должно представлять как отрицательные, так и положительные значения. Для этого, к искомому значению экспоненты прибавляется некое число bias (сдвиг), и полученное в итоге число храниться в качестве экспоненты. Например, для чисел одинарной точности значение сдвига равно 127. Таким образом, экспонента равная 0 означает, что в поле экспоненты будет храниться 127. А значение поля, равное 200 означает экспоненту равную (200-127), или 73.
Мантисса
Мантисса представляет точность числа. Она состоит из подразумеваемого лидирующего бита и «дробных» битов.
- 5.00 x 10 0
- 0.05 x 10 2
- 5000 x 10 -3
Для максимизации количества представимых чисел, числа с плавающей точкой хранятся в нормализованной форме. В нормализованной форме «десятичная» (двоичная, шестнадцетиричная) точка всегда должна располагаться после первой ненулевой цифры. В нормализованной форме пять представляется как 5.00 x 10 0 .
Небольшое, но приятное усовершенствование доступно для нас в двоичном представлении чисел, когда единственной ненулевой цифрой является 1. Таким образом, мы можем просто предположить, что ведущая цифра всегда равна 1.
Джон Кармак
Еще в 2000 году Джон Кармак (John Carmaсk) упомянул о необходимости использования чисел с плавающей точкой в пиксельном конвейере, в дополнение к числам с плавающей точкой в геометрическом конвейере видеокарт. Ниже приведен перевод некоторых выдержек из его «плана»:
4/29/00
-------
Нам необходимо больше бит на цвет в наших 3Д-ускорителях.
Я уже в течение нескольких лет настаивал на необходимости парочки дополнительных бит для расширения диапазона, но сейчас я хотел бы увеличить это пожелание до полных 16 битных чисел с плавающей точкой для представления цвета на протяжении всего графического конвейера. Знаковый бит, десять бит мантиссы и пять бит экспоненты (обменяв, возможно, один или два бита между мантиссой и экспонентой). Даже это не все что бы хотелось, но это разумный шаг.
………………
Есть еще несколько тонких моментов [из-за ограниченной точности прим. ред.], таких как потеря возможного результата из-за повторяющегося возведения в квадрат исходных значений и последствий ограничений суммирования несколько источников света до модуляции их «вниз» цветом материала. Необходимость расширенного диапазона еще более очевидна. Некоторые значения имеют присущий им диапазон значений от 0 до 1, например, коэффициенты отражений и прохождений. Нормализованные вектора имеют диапазон от -1 до 1. Однако, основное числовое значение в рендеринге свет ничем не ограничено. Нам необходимо НАМНОГО больший диапазон, чем от 0 до 1. Q3 подстраивает таблицы гамма коррекции, жертвуя битом точности ради получения диапазона от 0 до 2, но мне необходимо больше чем это для даже примитивных техник рендеринга. Для точного моделирования полного светового диапазона воспринимаемого человеком нам необходимо больше пяти бит экспоненты.
……………………
64 бит пиксели. Это «The Right Thing to do». Поставщики оборудования: не будьте последней компанией, которая сделает этот переход.
Полный оригинальный текст можно найти по адресу.
Главная идея вышеприведенного текста необходимость применения чисел с плавающей точкой при пиксельных операциях (вместо словосочетания «плавающая точка» местами будет использоваться аббревиатура FP). Позже в статье я еще раз обращусь к высказыванию Кармака, а пока следуем дальше.
“Что такое шейдеры?”
Ше́йдер (англ. shader — затеняющая программа) — это программа для видеокарточки, которая используется в трёхмерной графике для определения окончательных параметров объекта или изображения, может включать в себя описание поглощения и рассеяния света, наложения текстуры, отражения и преломление, затенение, смещение поверхности и множество других параметров.
Что такое шейдеры? Например, вот такой эффект можно получить, это шейдер воды примененный к сфере.
Проходы шейдера
Обычно шейдеры включают основной этап, который либо не имеет тега LightMode, либо использует один из таких тегов как UniversalForward (URP), ForwardBase (Built-in Pipeline) или Forward (HDRP), если шейдер предназначен для использования в прямом, а не в отложенном рендеринге (я немного объясню это в следующем разделе).
Полезная информация
Теперь Вы знаете что такое шейдеры, но помимо шейдеров, есть другие очень интересные темы в разработке игр и компьютерной графике, которые наверняка Вас заинтересуют:
-
,- техника создания потрясающих эффектов в современных видео-играх. Обзорная статья и видео с уроками создания эффектов в Unity3d ,- если Вы задумываетесь о разработке видеоигр, в качестве профессиональной карьеры или хобби, эта статья содержит отличный набор рекомендаций “с чего начать”, “какие книги читать” и т.д.
На чем пишут шейдеры?
Изначально шейдеры можно было писать на assembler-like языке, но позже появились шейдерные языки высокого уровня, похожие на язык С, такие как: Cg, GLSL и HLSL.
Такие языки намного проще чем C, ведь задачи решаемые с их помощью, гораздо проще. Система типов в таких языках отражает нужды программистов графики. Поэтому они предоставляют программисту специальные типы данных: матрицы, семплеры, векторы и тп.
Диапазоны и точность чисел с плавающей точкой
В таблице ниже представлены (сверху-вниз): точность в десятичных цифрах, максимальное и минимальное значение экспоненты, максимальное и минимальное абсолютные значения.
Сокрытие латентности и как писать код
Теперь, когда мы понимаем, как выглядят аппаратное обеспечение и модель программирования, как реально программировать это? До сих пор, похоже, мы писали обычный код. Мы обрабатываем в нем рабочий элемент, потенциально обмениваясь информацией между соседями на одном SIMD, с другими через локальную память и, наконец, читаем и пишем через глобальную память. Проблема в том, что «нормальный» код не очень хорош, так как нам нужно скрыть латентность.
Способ, которым GPU скрывает латентность тем, что у него больше работы в полете. Намного больше работы, например, у той же GCN каждый вычислительный блок может иметь в полете до 40 подгрупп. Каждый раз, когда подгруппа обращается к памяти, другая получает назначение в планировщике. Учитывая, что только четыре могут выполняться одновременно, это означает, что мы можем переключиться до 10 раз, прежде чем вернемся в подгруппу, которая начала исходный запрос.
Первая подгруппа попадает в инструкцию памяти и приостанавливается. Вычислительный блок немедленно планирует следующую подгруппу, которая также приостанавливается. После того, как четвертая подгруппа выдала инструкцию, подсистема памяти вернется, и обработка первой подгруппы может возобновиться. Таким образом, вычислительный блок выполняет работу в каждом цикле.
Однако здесь есть проблема. Переключение подгрупп должно быть мгновенным, чтобы сделать подобное возможным. Это означает, что вы не можете записать состояние программы в память и прочитать его обратно. Вместо этого все состояния всех программ постоянно хранятся в регистрах. Для этого требуется огромное количество регистров. Единичный вычислительный блок GCN имеет 256 кб регистров. При этом мы можем использовать до (256 кб/40/4/64 б) = 24 регистра для одного элемента, прежде чем потребуется уменьшить их занятость. Для нашего стиля программирования это означает, что мы должны попытаться свести к минимуму количество состояний, которых приходится поддерживать как можно больше хотя бы пока есть доступ к памяти. Если мы не получаем доступ к памяти, один вейвфронт может держать SIMD на 100% занятым. Мы также должны быть уверены, что используем эту локальную память и кэш-память L1 насколько это возможно, поскольку они имеют пропускную способность больше и задержку меньше, чем внешняя память.
Один SIMD может обрабатывать несколько рабочих элементов за один такт, на этом рисунке он имеет ширину 8. Если ветка короткая, мы не тратим много усилий. Длинные ветки, которые отключают большинство SIMD-полос, могут значительно снизить пропускную способность.
Другая проблема, с которой мы столкнемся: как обрабатываются ветви. SIMD обрабатывают все вместе, поэтому они не могут выполнять переходы. Вместо этого отдельные полосы маскируются, т.е. не участвуют в работе. Это также подразумевает, что если все рабочие элементы не занимают одну и ту же ветвь. GPU, как правило, выполняет обе стороны ветки.
Что мы узнали? Нам нужно:
- Большая область задач — чем больше самостоятельных рабочих элементов, тем лучше.
- Код с интенсивным использованием памяти должен минимизировать количество состояний, чтобы обеспечить высокую загрузку.
- Мы должны избегать ветвей, которые выводят из работы большую часть подгруппы.
Эти рекомендации будут применяться повсеместно ко всем графическим процессорам. В конце концов, все они были спроектированы для решения широкомасштабных параллельных графических задач, поэтому у них мало ветвлений, не слишком много состояний в полете, и тысячи тысяч самостоятельных рабочих элементов.
Итак: представление с плавающей точкой
В научном написании действительные числа пишутся в виде двух чисел: мантиссы и экспоненты. Например: 123.456 может быть написано как 1.23456 x 10 2 . В шестнадцатиричной системе счисления число 123.abc будет эквивалентно 1.23abc x 16 2 .
Представление с плавающей точкой решает несколько проблем. Числа с фиксированной точкой имеют жестко очерченный диапазон, который ограничивает их от представления очень больших или очень маленьких чисел. Также числа с фиксированной точкой имеют склонность к потере точности при делении и умножении.
Числа с плавающей точкой с другой стороны используют что-то подобное «плавающему окну» точности в зависимости от масштаба числа. Это позволяет с легкостью представлять числа от 1,000,000,000,000 до 0.0000000000000001.
В статье я не буду рассматривать тонкости стандарта в отношении операций с плавающей точкой, а коснусь только главного иного представления FP чисел по сравнению с целыми числами и сравню диапазоны и точность FP чисел, поддерживаемых центральными процессорами и GPU видео-чипами.
Но сначала еще немного истории.
Графический пайплайн
Преимущество программируемого конвейера перед его предшественником в том, что теперь программистам можно создавать свои алгоритмы самостоятельно, а не пользоваться зашитым аппаратно набором опций.
Сначала видеокарты оснастили несколькими специализированными процессорами, поддерживающими разные наборы инструкций. Шейдеры делили на три типа в зависимости от того, какой процессор будет их исполнять. Но затем видеокарты стали оснащать универсальными процессорами, поддерживающими наборы инструкций всех трёх типов шейдеров. Деление шейдеров на типы сохранилось для описания назначения шейдера.
Помимо графических задач с такими интеллектуальными видеокартами появилась возможность выполнения на GPU вычислений общего назначения (не связанных с компьютерной графикой).
Впервые полноценная поддержка шейдеров появилась в видеокартах серии GeForce 3, но зачатки были реализованы ещё в GeForce256 (в виде Register Combiners).
Что-же такое числа с плавающей точкой?
Существуют несколько способов представить действительные числа на компьютерах.
1) Представление с фиксированной точкой устанавливает точку-разделитель в произвольном месте целого числа. Такое представление сопоставляет целые числа части чего-либо. Например, считая для 1/100 метра эквивалентно единице и предположив, что мы можем хранить в памяти 5 десятичных чисел, мы сможем представлять как 999.00 м. так и 000.99 м.
2) Представление в виде дробных чисел представляет число как отношение двух целых чисел.
3) Представление с плавающей точкой наиболее используемое решение. Это представление хранит числа в «научном» написании 1,45*10 19 . Далее мы будем рассматривать именно это представление.
Геометрический шейдер
Геометрические шейдеры способны создавать новую геометрию, и могут использоваться для создания частиц, изменения детализации модели «на лету», создание силуэтов и т.п. В отличие от предыдущего вершинного, способны обработать не только одну вершину, но и целый примитив. Примитивом может быть отрезок (две вершины) и треугольник (три вершины), а при наличии информации о смежных вершинах (англ. adjacency) для треугольного примитива может быть обработано до шести вершин.
Читайте также: