Как фрагменты генерируются растеризатором в OpenGL

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

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

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

Итак, мне интересно, если это так, как проецирование 3 вершин треугольника определяет, какие пиксели покрыты стороной?

Рисует ли растеризатор сначала края треугольника, а затем сканирует каждый пиксель или двумерный массив пикселей (также известный как буфер кадра по умолчанию) и видит, находятся ли точки между линиями, используя какой-либо математический метод или какой-то другой более простой процесс?


person gettingfaster    schedule 12.04.2016    source источник
comment
Нет, он не рисует края в первую очередь. Это привело бы к перекрытию соседних треугольников на один пиксель, что вызвало бы проблемы с полупрозрачными треугольниками. Кроме того, это было бы медленно. Что он делает? Он, вероятно, сканирует наименьший прямоугольник, охватывающий треугольник, и использует три перекрестных произведения (или, возможно, точечные произведения), чтобы увидеть, находится ли пиксель внутри этого треугольника.   -  person HolyBlackCat    schedule 12.04.2016
comment
Я думаю, что-то вроде этого будет работать: bool inside(ivec2 a, ivec2 b, ivec2 c, ivec2 p) {return cross(p-a,b-a)>0 && cross(p-b,c-b)>0 && cross(p-c,a-c);}.   -  person HolyBlackCat    schedule 12.04.2016
comment
что, если бы он использовал линейную интерполяцию для определения точек на ребрах? а затем использовать эти точки, сканируя от одного края до другой стороны треугольника? это похоже на возможность?   -  person gettingfaster    schedule 12.04.2016
comment
Да, это еще один законный способ. Но насколько я знаю, он обычно используется в программном рендеринге. Для видеокарт намного быстрее выполнять параллельные попиксельные вычисления.   -  person HolyBlackCat    schedule 12.04.2016
comment
а параллельные попиксельные вычисления - это то, что вы описали? где ближайший край прямоугольника/квадрата окружает треугольник, а затем для каждой точки квадрата/прямоугольника каждый пиксель в пределах этого сегмента интервала/линии проверяется чем-то вроде теста точки треугольника скалярного произведения/перекрестного произведения?   -  person gettingfaster    schedule 12.04.2016
comment
@gettingfaster: OpenGL не указывает подробности того, как происходит преобразование сканирования треугольника. Делает ли он сначала края или строки сканирования или что-то еще, все зависит от реализации. OpenGL действительно указывает некоторые вещи о результатах (гарантии соединения и т.п.), но о тех вещах, о которых вы говорите, в спецификации ничего не сказано.   -  person Nicol Bolas    schedule 12.04.2016
comment
но наверняка у нас есть какое-то представление о том, что происходит, из того, что я понимаю, не так много способов сделать это? кажется, что это либо линейная интерполяция, либо параллельные попиксельные вычисления, различные учебные пособия по графике, кажется, не описывают никакого другого способа, в конце концов, это связано с существующими там математическими методами в сочетании с тем, как фреймбуфер хранит информацию о пикселях/ данные (т.е. линейно как массив)   -  person gettingfaster    schedule 12.04.2016
comment
@gettingfaster: Если кажется, что способов сделать это не так уж и много... поразмыслите над этим. Память в фреймбуфере организована нелинейно. Обычно для оптимизации существует какая-то иерархическая структура — например, буфер кадра делится на тайлы, а затем проверяется, в какие тайлы попадает фрагмент, а затем проверяются пиксели внутри каждого тайла. Если фрагмент заполняет всю плитку, то в качестве оптимизации буфер глубины для этой плитки можно вычислить, используя уравнение плоскости для этого треугольника. Предположения, основанные на том, как вы это сделаете в программном обеспечении, вероятно, неверны.   -  person Dietrich Epp    schedule 12.04.2016
comment
но даже если он разделен на плитки в структуре для, как вы говорите, оптимизации, он все равно не останавливает доступ к нему линейным образом от начала координат окна до конца, т.е. 0,0 -> N,N, все координаты окна расположены как это и еще больше усложняет, что в конечном итоге повлияет только на дорогие вещи и не кажется практичным, я не понимаю, зачем кому-то размещать буфер кадров в тайлах? это просто усложнило бы ситуацию и привело бы к очень дорогой обработке, у компьютеров есть свои ограничения и максимальные скорости, в абстракции все просто, но на самом деле нет   -  person gettingfaster    schedule 12.04.2016
comment
Описан новый алгоритм сканирования-преобразования на основе графического процессора, реализованный с использованием OpenGL. Вычислительная производительность этого нового алгоритма, работающего на модемном графическом процессоре, сравнивается с производительностью трех распространенных алгоритмов преобразования сканирования (ближайший сосед, линейная интерполяция и билинейная интерполяция), реализованных в программном обеспечении с использованием модемного ЦП. Качество изображений, полученных с помощью алгоритма, измеряемое по мощности сигнал-шум, также сравнивается с качеством изображений, полученных с использованием этих трех распространенных алгоритмов преобразования сканирования. www.ncbi.nlm.nih.gov/pubmed/21710829, похоже, я был прав   -  person gettingfaster    schedule 12.04.2016
comment
@gettingfaster: Эта статья посвящена объемному рендерингу, а не растеризации треугольников. Совершенно другой предмет.   -  person Dietrich Epp    schedule 12.04.2016
comment
cse.wustl.edu/~jain/cse567-08/ftp /scan, поэтому его линейная интерполяция, билинейная интерполяция и ближайший сосед   -  person gettingfaster    schedule 12.04.2016
comment
@gettingfaster: Опять же, речь идет об преобразовании ультразвукового сканирования, так как это метод, специфичный для оборудования, которое они используют в больницах, чтобы заглянуть внутрь пациентов.   -  person Dietrich Epp    schedule 12.04.2016
comment
да, но дело в том, что если его использовать здесь, там и везде, то это показывает, что существует не так много разных, иначе, если бы было так широко и просто получить эти результаты, то каждый имел бы какую-то свою собственную версию, которая бы отличаться от всех остальных. Если они используют его везде, то почему реализация OpenGL должна быть такой другой? только для того, чтобы быть другим? ясно, что он эффективен и хорошо работает, как показывает математика, поэтому он должен выполнять работу для дискретных значений, которые производят компьютеры.   -  person gettingfaster    schedule 12.04.2016
comment
алгоритмы связаны со скоростью и эффективностью, а не позволяют увидеть, насколько мы можем быть сложными и отличаться от всех остальных, это не содержание творчества, а скорость, простота и эффективность, ведь программы OpenGL должны обрабатывать тысячи вершин, а не только одну вершину за кадр.   -  person gettingfaster    schedule 12.04.2016
comment
@gettingfaster: Эти алгоритмы, которые вы связали, не соответствуют тому, как это делают графические процессоры. У вас неправильное представление о том, как графические процессоры реализуют растровое преобразование. Не выполняется какая-то программа; вся растеризация происходит очень параллельно, не по порядку, чисто аппаратно. Также память не организована линейно в графическом процессоре. Структуры данных и макеты полностью отличаются от того, что вы видите на графическом процессоре. Память адресуется не по линейному адресу, а по тайловой координате.   -  person datenwolf    schedule 13.04.2016


Ответы (3)


и я знаю, что OpenGL, вероятно, имеет свои собственные реализации этого процесса

OpenGL — это просто документ спецификации. На компьютере работает реализация OpenGL, в большинстве случаев являющаяся частью драйвера графического процессора. Фактическая рабочая нагрузка выполняется графическим процессором…

это также происходит с OpenGL из-за процесса «Сканирование-преобразование» вершин, который я прочитал в учебнике по OpenGL.

скорее всего нет. На самом деле, в прошлые выходные я присутствовал на мероприятии Khronos (группа, которая определяет OpenGL), организованном AMD, и один из инженеров AMD по графическим процессорам сетовал на то, что новички имеют в виду алгоритм строки сканирования с OpenGL, Direct3D, Mantel, Vulkan и т. д. , в то время как графические процессоры делают что-то совершенно другое.

2D-массив пикселей, также известный как буфер кадра по умолчанию, который является линейным.

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

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

Итак, мне интересно, если это так, как проецирование 3 вершин треугольника определяет, какие пиксели покрыты стороной?

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

person datenwolf    schedule 12.04.2016

Алгоритм сканирования — это то, что люди делали в программном обеспечении еще в 1990-х годах, до появления современных графических процессоров. Разработчики графических процессоров довольно быстро поняли, что алгоритмы, которые вы используете для программного рендеринга, сильно отличаются от алгоритмов, которые вы бы реализовали в реализации СБИС с миллиардами транзисторов. Алгоритмы, оптимизированные для аппаратной реализации, имеют тенденцию выглядеть довольно чуждыми любому, кто так или иначе имеет опыт работы с программным обеспечением.

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

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

Что мы знаем о преобразовании сканирования?

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

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

  • Каждый примитив должен пройти перспективную проекцию. Этот процесс берет каждую вершину с однородными координатами (X, Y, Z, W) и преобразует ее в (X/W, Y/W, Z/W).

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

Таким образом, вы можете видеть, что в программном обеспечении плитки «сложны и медленны», но в аппаратном обеспечении они «просты и быстры».

Некоторые примечания к руководству R5xx:

Серия R5xx определенно старая (2005 г.), но документация доступна в Интернете (ищите «R5xx_Acceleration_v1.5.pdf»). В нем упоминаются два преобразователя сканирования, поэтому конвейер выглядит примерно так:

primitive output -> coarse scan converter -> quad scan converter -> fragment shader

Преобразователь грубой развертки, по-видимому, работает с более крупными плитками настраиваемого размера (от 8x8 до 32x32) и имеет несколько выбираемых режимов, режим «на основе перехвата» и «на основе ограничивающей рамки».

Затем четырехканальный преобразователь берет выходные данные преобразователя грубой развертки и выводит отдельные четверки, которые представляют собой группы из четырех отсчетов. Значения глубины для каждого квадроцикла могут быть представлены в виде четырех дискретных значений или уравнения плоскости. Уравнение плоскости позволяет быстро отбросить весь четырехугольник, если соответствующий четырехугольник в буфере глубины также указан как уравнение плоскости. Это называется «ранняя Z» и является обычной оптимизацией.

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

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

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

person Dietrich Epp    schedule 12.04.2016
comment
в то время как вы правы, что имена для всех этих методов изменены, одна вещь не изменилась, и это математика, стоящая за этим, все все вычисления, которые происходят, основаны на математических идеях, поэтому независимо от того, называют ли они это PowerVR или отложенным на основе плитки рендеринг или что-то еще в этом отношении, в конце концов все сводится к старой школе математики, и в этой школе ничего не изменилось, методы все те же, те же и постоянные http://http.developer.nvidia.com/GPUGems3/gpugems3_ch34.html в конце они всегда используют математические модели для всех преобразований - person gettingfaster; 24.04.2016
comment
единственная разница в том, что графический процессор может выполнять все параллельно, но, в конце концов, делает то же самое, что и процессор, но с множеством потоков, где работа распределяется между различными транзисторами. - person gettingfaster; 24.04.2016

Цитата из GPU Gems: Параллельная сумма префиксов (сканирование) с CUDA, описывается как OpenGL выполняет преобразование сканирования и сравнивает его с CUDA, что, я думаю, достаточно для ответа на мой вопрос:

До внедрения CUDA несколько исследователей реализовывали сканирование с использованием графических API, таких как OpenGL и Direct3D (дополнительную информацию см. в Разделе 39.3.4). Чтобы продемонстрировать преимущества CUDA перед этими API для вычислений, таких как сканирование, в этом разделе мы кратко опишем эффективную реализацию OpenGL с инклюзивным сканированием Sengupta et al. (2006). Их реализация представляет собой гибридный алгоритм, который выполняет настраиваемое количество шагов сокращения, как показано в алгоритме 5. Затем он запускает версию алгоритма сканирования суммы с двойной буферизацией, ранее показанную в алгоритме 2, для результата шага уменьшения. Наконец, он выполняет развертку вниз, как показано в алгоритме 6.

Пример 5. Шаг сокращения алгоритма сканирования OpenGL

1: for d = 1 to log2 n do 
2:     for all k = 1 to n/2 d  – 1 in parallel do 
3:          a[d][k] = a[d – 1][2k] + a[d – 1][2k + 1]]
Example 6. The Down-Sweep Step of the OpenGL Scan Algorithm

1: for d = log2 n – 1 down to 0 do 
2:     for all k = 0 to n/2 d  – 1 in parallel do 
3:          if i > 0 then 
4:             if k mod 2 U2260.GIF 0 then 
5:                  a[d][k] = a[d + 1][k/2]
6:             else 
7:                  a[d][i] = a[d + 1][k/2 – 1]

Вычисление сканирования OpenGL реализовано с использованием пиксельных шейдеров, и каждый массив a[d] представляет собой двумерную текстуру на графическом процессоре. Запись в эти массивы выполняется с помощью рендеринга в текстуру в OpenGL. Таким образом, каждая итерация цикла в алгоритме 5 и алгоритме 2 требует чтения одной текстуры и записи в другую.

Основными преимуществами CUDA по сравнению с OpenGL являются встроенная общая память, функциональность синхронизации потоков и разбросанная запись в память, которая не подвергается воздействию пиксельных шейдеров OpenGL. CUDA делит работу большого сканирования на множество блоков, и каждый блок полностью обрабатывается на кристалле одним мультипроцессором, прежде чем какие-либо данные будут записаны во внешнюю память. В OpenGL все обновления памяти являются внешними обновлениями памяти. Таким образом, пропускная способность, используемая реализацией OpenGL, намного выше, и, следовательно, производительность ниже, как показано ранее на рис. 39-7.

person gettingfaster    schedule 23.04.2016
comment
Черт возьми, зачем вам публиковать и принимать ответ, который не отвечает на ваш собственный вопрос? Проблема, описанная в статье, никак не связана с тем, как растеризуются примитивы. - person Yakov Galka; 03.12.2019