Муниципальное образовательное учреждение дополнительного Методический центр «Раменский дом учителя»



  • Как научиться
  • Уроки начинающим
  • _empty_
  • Новости
  • Статьи

    мозаика

    1. Патчи
    2. Шейдер управления тесселяцией
    3. Тесселяция примитивного поколения
    4. Абстрактный патч
    5. Уровни тесселяции
    6. Расстояние между краями тесселяции
    7. Примитивный порядок генерации
    8. Тесселяция примитивов
    9. Квадроциклы
    10. Изолинии
    11. Примеры
    12. Интерфейс патча и непрерывность

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

    Примечание. Здесь описывается функция OpenGL 4.0, а не старая функция тесселяции gluTess *.

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

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

    Шейдер управления тесселяцией (TCS) определяет, сколько тесселяции нужно сделать (он также может корректировать фактические данные исправления, а также передавать дополнительные данные исправления на более поздние этапы). Следовательно, TCS несет главную ответственность за обеспечение непрерывности исправлений. Таким образом, если у вас есть два соседних патча, которые должны иметь разные уровни тесселяции, вызовы TCS для разных патчей должны использовать свои элементы управления тесселяцией, чтобы гарантировать, что общие ребра (ы) между патчами используют один и тот же уровень тесселяции. Без этой защиты могут возникать пробелы и разрывы в том, что должно быть смежными пятнами.

    TCS является необязательным; Значения тесселяции по умолчанию могут использоваться, если не предоставлено TCS.

    генератор примитивных тесселяции берет входной патч и подразделяет его на основе значений, вычисленных TCS или предоставленных по умолчанию.

    Шейдер оценки тесселяции (TES) берет мозаичный патч и вычисляет значения вершин для каждой сгенерированной вершины.

    Патчи

    Этапы тесселяции работают на патчи, примитивный тип обозначается константой GL_PATCHES. Примитив патча является примитивом общего назначения, где каждые n вершин являются новым примитивом патча. Количество вершин в патче может быть определено на уровне приложения с помощью:

    недействительным glPatchParameteri (GLenum pname, значение GLint);

    с GL_PATCH_VERTICES в качестве цели и значением, которое находится в полуоткрытом диапазоне [1, GL_MAX_PATCH_VERTICES). Максимальное количество вершин патча зависит от реализации, но никогда не будет меньше 32.

    Примитивы патчей - это всегда последовательность отдельных патчей; нет такой вещи, как «патч-полоса» или «патч-петля» или что-то подобное. Так что для заданный поток вершин каждая группа значений количества вершин будет отдельным патчем. Если вам нужно сделать что-то вроде полос треугольника, вы должны использовать Индексированный рендеринг чтобы получить подобное поведение, хотя это не уменьшит количество вершин в списке индекса. К счастью, Пост-преобразование кеша должен иметь дело с любым влиянием производительности, имеющим больше индексов

    Шейдер управления тесселяцией

    Первый шаг тесселяции - это необязательный вызов шейдера управления тесселяцией (TCS). У TCS есть две работы:

    • Определите количество тесселяции, которое должен иметь примитив.
    • Выполните любые специальные преобразования на входных данных патча.

    TCS может изменить размер патча, добавляя больше вершин для каждого патча или предоставляя меньше. Тем не менее, TCS не может отменить исправление (напрямую; оно может сделать это косвенно) и не может записать несколько исправлений. Поэтому для каждого патча, предоставленного приложением, один патч будет предоставлен на следующем этапе тесселяции.

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

    недействительным glPatchParameterfv (GLenum pname, const GLfloat * значения);

    Когда pname - GL_PATCH_DEFAULT_OUTER_LEVEL, значения - это 4-элементный массив с плавающей точкой, определяющий четыре внешних уровня тесселяции. Когда pname - GL_PATCH_DEFAULT_INNER_LEVEL, значения - это 2-элементный массив с плавающей точкой, определяющий два внутренних уровня тесселяции.

    Эти значения по умолчанию соответствуют выходным переменным TCS для каждого патча gl_TessLevelOuter [4] и gl_TessLevelInner [2].

    Тесселяция примитивного поколения

    Генерация примитивов - это этап с фиксированной функцией, отвечающий за создание набора новых примитивов из входного патча. Этот этап выполняется только если шейдер оценки тесселяции (TES) активен в текущей программе или программном конвейере. На примитивную генерацию влияют следующие факторы:

    • Уровни тесселяции, предоставляемые TCS или значениями по умолчанию, как указано выше.
    • Расстояние между мозаичными вершинами, определенное на последующем этапе TES. Это может быть equal_spacing, дробный_эвен_спейс или дробный_дд_спейсинг.
    • Тип входного примитива, определенный последующим TES, который может быть одним из треугольников, четырехугольников или изолиний. TES также может принудительно генерировать тесселяцию как серию точек, а не треугольников или линий, предоставляя примитив point_mode.
    • Порядок генерации примитива, определенный последующим TES, который может быть cw или ccw. Это, в сочетании с положением сгенерированных примитивов, используется для определения примитива Порядок намотки ,

    Абстрактный патч

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

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

    Из-за этой дихотомии генератор примитивов работает над тем, что можно считать «абстрактным пятном». Это не смотрит на выход патча от TCS; он мыслит только с точки зрения тесселяции абстрактного четырехугольника, треугольника или блока «изолинии».

    В зависимости от типа абстрактного патча генератор примитивов оценивает различное количество уровней тесселяции и применяет разные алгоритмы тесселяции. Каждая сгенерированная вершина имеет нормализованную позицию (то есть координаты находятся в диапазоне [0, 1]) внутри абстрактного патча. Эта позиция состоит из двух или трех компонентов, в зависимости от типа патча. Координаты передаются в TES через встроенный вход vec3 gl_TessCoord.

    Уровни тесселяции

    Количество тесселяции, выполняемой над абстрактным типом патча, определяется внутренними и внешними уровнями тесселяции. Они, как указывалось ранее, предоставляются либо TCS, либо контекстными параметрами, указанными через glPatchParameter , Они представляют собой 4 вектора с плавающей точкой, определяющие «внешние уровни тесселяции», и 2 вектора с плавающей точкой, определяющие «внутренние уровни тесселяции».

    Конкретная интерпретация зависит от используемого типа абстрактного патча, но общая идея такова. В большинстве случаев каждый уровень тесселяции определяет количество сегментов, в которые ребро тесселяции; таким образом, уровень тесселяции 4 означает, что ребро станет 4 ребром (2 вершины станут 5). «Внешние» уровни тесселяции определяют тесселяцию для внешних краев примитива. Это позволяет двум или нескольким исправлениям правильно соединяться, при этом все еще имея разные уровни тесселяции внутри исправления. Внутренние уровни тесселяции соответствуют количеству тесселяций в абстрактном патче.

    Не все абстрактные патчи используют одинаковое количество значений в данных внешнего / внутреннего уровней тесселяции. Например, треугольники используют только один внутренний уровень и 3 внешних уровня. Остальные игнорируются.

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

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

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

    В нижеследующем обсуждении max - это максимально допустимый уровень тесселяции, определенный GL_MAX_TESS_GEN_LEVEL. Это должно быть не менее 64, так что у вас есть место для игры.

    Интервал влияет на эффективный уровень тесселяции следующим образом:

    equal_spacing Каждый уровень тесселяции индивидуально привязан к закрытому диапазону [1, макс.]. Затем оно округляется до ближайшего целого, чтобы получить эффективный уровень тесселяции. fraal_even_spacing Каждый уровень тесселяции индивидуально привязан к закрытому диапазону [2, макс.]. Затем оно округляется до ближайшего четного целого, чтобы получить эффективный уровень тесселяции. Fractional_odd_spacing Каждый уровень тесселяции индивидуально привязан к закрытому диапазону [1, макс. - 1]. Затем оно округляется до ближайшего нечетного целого числа, чтобы получить эффективный уровень тесселяции.

    Расстояние между краями тесселяции

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

    Если для spacing установлено значение equal_spacing, то все сегментированные сегменты на ребре будут иметь одинаковую длину. Поскольку equal_spacing округляет уровни тесселяции до следующего целого числа, это означает, что ребра будут «всплывать», когда уровни тесселяции переходят от одного целого числа к следующему.

    Поскольку equal_spacing округляет уровни тесселяции до следующего целого числа, это означает, что ребра будут «всплывать», когда уровни тесселяции переходят от одного целого числа к следующему

    Две другие схемы интервалов предназначены для обеспечения плавного поведения при изменении уровней тесселяции. Они полезны в случаях, когда количество тесселяции зависит от области, видимой с камеры.

    Сначала нам нужно определить два значения:

    • n должно быть эффективным уровнем тесселяции, вычисленным выше для рассматриваемого ребра.
    • f должно быть значением, вычисленным до шага округления выше. Таким образом, это потенциально дробное значение.

    Если n равно 1, то на этом ребре не происходит тесселяции. Если n равно 2, то будет два сегмента равной длины.

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

    Длина коротких сегментов относительно других основана на (n - f). Когда это значение равно 0, короткие отрезки будут иметь ту же длину, что и остальные. Когда это значение приближается к 2, длина коротких сегментов приближается к 0,0.

    Дробный нечетный интервал Дробный нечетный интервал

    Дробный равномерный интервал Дробный равномерный интервал

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

    • Чтобы короткие сегменты были расположены симметрично по краю мозаики.
    • Что размещение коротких сегментов будет инвариантным с f для * любого * сегментируемого сегмента.

    Обратите внимание, что нет гарантии, что размещение коротких сегментов не будет изменяться при изменении f. То есть нет гарантии гладкости при изменении f.

    Примитивный порядок генерации

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

    Примечание:

    этот порядок не означает, что вы можете использовать Магазин загрузки изображений читать из памяти, записанной вызовом родственного шейдера только потому, что этот вызов был из «предыдущего» примитива. Такие чтения / записи следуют Некогерентный доступ к памяти правила.

    Тесселяция делает вещи менее четкими. Хотя порядок вершин в примитиве четко определен (определяется настройками входного макета TES cw или ccw), порядок примитивов, сгенерированных относительно друг друга, не является. Реализации определяют этот порядок, поэтому вы не можете полагаться на какой-либо конкретный порядок.

    Опять же, большинство способов, которые вы могли бы сказать, основаны на некогерентных обращениях к памяти ...

    Тесселяция примитивов

    треугольники

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

    Каждая вершина, сгенерированная и отправленная в TES, будет Барицентрические координаты как входные данные gl_TessCoord. Эта координата определяет, где находится эта вершина в пятне абстрактного треугольника. Барицентрические координаты для 3 вершин абстрактного треугольного участка показаны на диаграмме. Все остальные вершины будут указаны относительно них.

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

    vec3 аккумулятор = vec3 (0.0 f) аккумулятор + = gl_TessCoord [0] * значение [0] аккумулятор + = gl_TessCoord [1] * значение [1] аккумулятор + = gl_TessCoord [2] * значение [2]

    Где значение - это массив (в данном случае vec3) значений, которые соответствуют трем вершинам, изображенным на диаграмме.

    Алгоритм тесселяции треугольников основан на тесселяции краев треугольника, а затем построении из них вершин и треугольников. Это делает поведение внутреннего уровня тесселяции немного неинтуитивным, поскольку оно не соответствует непосредственно числу внутренних треугольников.

    Шаг первый удаляет наиболее вырожденный случай. Если все эффективные внешние уровни (как вычислено выше) имеют ровно 1,0, а эффективный внутренний уровень также равен 1,0, то ничего не переселяется, и TES получит 3 вершины и один треугольник. И, таким образом, ни один из более поздних шагов не происходит.

    Затем, если эффективный внутренний уровень равен 1,0 (и, следовательно, по крайней мере один из внешних уровней равен> 1,0, в противном случае мы достигли бы вышеуказанного условия), тогда эффективный внутренний уровень пересчитывается так, как если бы пользователь указал значение 1,0 + е. для внутреннего уровня, где е - число, бесконечно близкое к нулю. Так что значение 1.0 + e чуть выше 1,0.

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

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

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

    Этот процесс повторяется, используя новый кольцевой треугольник для генерации следующего внутреннего кольца, пока не будет выполнено одно из двух конечных условий. Если треугольное кольцо не имеет подразделенных ребер (только 3 вершины), то процесс останавливается.

    Если треугольное кольцо имеет ровно 2 подразделенных ребра (всего 6 вершин), то генерируемое им «кольцо» вовсе не является треугольником. Это одна вершина:

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

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

    Затем он повторно составляется в соответствии с тремя эффективными внешними уровнями тесселяции

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

    • То, что площадь треугольника в пространстве (u, v, w) будет полностью покрыта сгенерированной триангуляцией.
    • То, что ни одна часть площади треугольника не будет покрыта сгенерированной триангуляцией более одного раза.
    • Это будут ребра между соседними вершинами каждого «кольца» треугольников. То есть темные линии на приведенной выше диаграмме гарантируются спецификацией.
    • Если вершина имеет соответствующие вершины в кольце, которое непосредственно предшествовало ей, то между этой вершиной и соответствующими ей будет ребро (углы кольцевых треугольников имеют 2 соответствующие вершины). Точно так же, если вершина имеет соответствующую вершину на кольце внутри нее, между ними будет ребро.

    Остальные ребра определяются реализацией.

    Квадроциклы

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

    Каждой вершине, сгенерированной и отправленной в TES, будет предоставлена ​​нормализованная 2D-координата в качестве входных данных gl_TessCoord, представляющая местоположение этой вершины в абстрактном патче. Третий компонент gl_TessCoord будет 0.0.

    Квадратная тесселяция работает скорее как треугольная тесселяция, только с 4 сторон. Тесселяция основана на подразделении ребер и построении вершин на основе подразделенных ребер.

    Шаг первый удаляет наиболее вырожденный случай. Если все эффективные внешние уровни (как вычислено выше) равны 1,0, а эффективные внутренние уровни также равны 1,0, то ничто не пересчитывается. TES получит 2 треугольника и четыре вершины (хотя он может быть вызван целых 6 раз). И, таким образом, ни один из более поздних шагов не происходит.

    Далее, если эффективный внутренний уровень равен 1,0 (и, следовательно, по крайней мере один из внешних уровней равен> 1,0, в противном случае мы достигли бы вышеуказанного условия), тогда этот эффективный внутренний уровень пересчитывается так, как если бы пользователь указал значение 1,0 + е. для уровня, где е - число, бесконечно близкое к нулю. Так что значение 1.0 + e чуть выше 1,0. Это относится к обоим внутренним уровням.

    Это гарантирует, что, если вдоль внешнего края будет происходить тесселяция, то внутри четырехугольника всегда будет хотя бы одна вершина.

    Следующим шагом в тесселяции является подразделение краев абстрактного квад-патча на основе эффективных внутренних уровней. Да, алгоритм начинается с игнорирования внешних уровней тесселяции; он применяет внутреннюю тесселяцию ко всем четырем внешним краям. Внутренний уровень 0 применяется к обоим горизонтальным краям, а уровень 1 применяется к вертикальным краям.

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

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

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

    То есть, вместо того, чтобы быть четырехугольником, это либо линия (использующая вершины длинной стороны для ее разделения), либо точка (если оба внутренних уровня идентичны):

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

    Каждый внешний край затем перераспределяется в соответствии с четырьмя эффективными внешними уровнями тесселяции

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

    • Что площадь четырехугольника в пространстве (u, v) будет полностью покрыта сгенерированной триангуляцией.
    • То, что ни одна часть площади четырехугольника не будет покрыта сгенерированной триангуляцией более одного раза.
    • Это будут ребра между соседними вершинами каждого "кольца" четырехугольников. То есть темные линии на приведенной выше диаграмме гарантируются спецификацией.
    • Если вершина имеет соответствующие вершины в кольце, которое непосредственно предшествовало ей, то между этой вершиной и соответствующими ей будет ребро (углы кольцевых квадратов имеют 2 соответствующие вершины). Точно так же, если вершина имеет соответствующую вершину на кольце внутри нее, между ними будет ребро.

    Остальные ребра определяются реализацией.

    Изолинии

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

    Каждой вершине, сгенерированной и отправленной в TES, будет предоставлена ​​нормализованная 2D-координата в качестве входных данных gl_TessCoord. gl_TessCoord.x представляет расстояние вдоль одной из линий, в то время как gl_TessCoord.y указывает, для какой линии вершина предназначена. Третий компонент gl_TessCoord будет 0.0.

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

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

    Если вы хотите сгенерировать одну изолинию, вы должны передать 1 для gl_TessLevelOuter [0]. Однако, если вам нужно больше тесселяционных вершин, чем это может быть сделано в одном значении внешнего уровня, TES прекрасно способен сшивать несколько отдельных строк вместе. Тесселлятор гарантирует, что первая и последняя точки для каждой линии будут точно 0,0 и 1,0.

    Помните: абстрактный патч является абстрактным ; TES может расположить вершины где угодно.

    Примеры

    Шейдер оценки тесселяции

    Шейдер оценки тесселяции (TES) отвечает за получение абстрактных координат, сгенерированных генератором примитивов, вместе с выходными данными TCS (или вершинного шейдера, если TCS не используется), и использует их для вычисления фактических значений для вершин. , Здесь вы кодируете алгоритм, который фактически используете для вычисления новых позиций / normal / texcoords / etc. TES является обязательной частью тесселяции; если его нет, тесселяции не происходит.

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

    Интерфейс патча и непрерывность

    Тестирование патчей так, чтобы между примитивами, генерируемыми соседними патчами, не было пробелов, очень важно. Это также не то, что просто происходит. Поскольку OpenGL слеп к тому, как работает фактическая тесселяция (генератор примитивов работает только с абстрактным патчем), есть определенные вещи, которые вы должны сделать, чтобы гарантировать отсутствие расхождений между патчами.

    Правило 1. Реализация интерполяции TES для вершин, относящихся к ребрам патчей, должна получать идентичные двоичные значения для этих ребер. TES определяет, что на самом деле означают различные данные патчей, так как он реализует интерполяцию. Таким образом, ваш TCS или данные патча на каждую вершину в целом должны убедиться, что данные, которые TES использует для генерации этих краевых позиций, одинаковы для общего ребра в двух (или более) патчах.

    К счастью, OpenGL правила инвариантности означает, что вычисления шейдера, которые выполняют одинаковое совпадение, дадут одинаковые результаты. Обычно это означает только то, что входы в TCS, которые вносят вклад в интерполяцию по краям, получают одинаковые значения от массивы вершин , как обрабатывается через Вершинный шейдер , Однако различные методы тесселяции и интерполяции, реализованные вашим TES, могут иметь определенные потребности.

    Правило 2: внешний уровень тесселяции для общих ребер должен быть двоичным идентичным. Хотя вы можете просто гарантировать, что «эффективный уровень тесселяции» ребер идентичен, в спецификации говорится, что инвариантность тесселяции гарантируется только в том случае, если заданные уровни идентичны. Поэтому лучше быть уверенным в том, что два ребра, которые должны объединиться, получат одинаковый уровень тесселяции.

    Приведенные выше два правила гарантируют, что TES получит двоичные идентичные значения для данных исправления, используемых для вычисления вершин общего ребра, а также точное совпадение значений gl_TessCoord для этих вершин вдоль общего ребра. Таким образом, единственное другое правило, которое необходимо соблюдать:

    Правило 3: TES должен вычислять вершины ребер, основываясь только на двоичных идентичных данных, используя точно такую же математику между вызовами шейдеров вдоль общих ребер. Стандарт OpenGL правила инвариантности шейдеров работать до тех пор, пока для обоих вызовов используется один и тот же код.

    Примечание.

    Если вы используете две разные программы (т. Е. Два разных вызова рендеринга генерируют патчи с общими краями), вам необходимо убедиться, что соответствующие этапы шейдеров также инвариантный между собой Поэтому вам может понадобиться использовать ключевое слово invariant там, где это необходимо.

    Полные правила инвариантности для тесселяции, от OpenGL 4.5, приложение A.4, стр. 632 объясните, как OpenGL предоставляет эти гарантии.

    Несмотря на кажущуюся сложность этих правил, им действительно нетрудно следовать. Правило № 1 может быть трудно выполнить при использовании необычных алгоритмов тесселяции, но для поверхностей Безье или NURBS, если контрольные точки непрерывны в соответствии с этими правилами поверхности, они будут выполнены.

    Наиболее трудным для выполнения, как правило, будет правило № 2, поскольку оно усложняет вычисления для внешних уровней тесселяции. Он не может просто основываться на расстоянии до общего патча; каждый патч должен знать, что использовали соседние патчи, чтобы все они могли совпадать. По сути, вам придется вычислять внешние уровни тесселяции для патча на основе расстояния для каждого края до камеры. Или какой-то похожий алгоритм, который будет инвариантным для разных патчей.

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

    Примеры

    Новости