Найшвидший спосіб візуалізації ліній з AA, різної товщини в DirectX


14

Тому я займаюся розробкою DirectX, використовуючи SharpDX під .NET для точності (але рішення API API DirectX / C ++ застосовні). Я шукаю найшвидший спосіб візуалізації ліній в ортогональній проекції (наприклад, моделювання двовимірного малювання рядків для наукових програм) за допомогою DirectX.

Скріншот видів сюжетів, які я намагаюся зробити: введіть тут опис зображення

Не рідкість у таких різновидів сюжетів є лінії з мільйонами сегментів, різної товщини, з антиліазінговою лінією або без неї (або ввімкнення / вимкнення повного екрану AA). Мені потрібно дуже часто оновлювати вершини для рядків (наприклад, 20 разів на секунду) і максимально завантажувати GPU.

Поки я намагався:

  1. Візуалізація програмного забезпечення, наприклад, GDI + насправді не є поганою продуктивністю, але, очевидно, є важкою для процесора
  2. Direct2D API - повільніше, ніж GDI, особливо з включеним Antialiasing
  3. Direct3D10 використовує цей метод для емуляції AA за допомогою вершинних кольорів та тесселяції на стороні процесора. Також повільно (я профілював це і 80% часу витрачається на обчислення вершинних позицій)

Для третього методу я використовую Vertex Buffers для надсилання трикутної смужки до GPU та оновлення кожні 200 м новими вершинами. Я отримую частоту оновлення в межах 5 FPS на 100 000 лінійних сегментів. Мені потрібні мільйони в ідеалі!

Зараз я думаю, що найшвидшим способом було б зробити tessellation на GPU, наприклад, у Geometry Shader. Я міг би надіслати вершини у вигляді списку рядків або упакувати з текстурою і розпакувати в Geometry Shader для створення квадратиків. Або просто надішліть необроблені точки на піксельний шейдер і реалізуйте малюнок Bresenham Line повністю у піксельному шейдері. Моя HLSL - іржава, шейдерна модель 2 з 2006 року, тому я не знаю про шалені речі сучасних графічних процесорів.

Отже, питання: - хтось робив це раніше, і чи є у вас якісь пропозиції спробувати? - Чи є якісь пропозиції щодо підвищення продуктивності за допомогою швидкого оновлення геометрії (наприклад, новий список вершин кожні 20 мс)?

ОНОВЛЕННЯ 21 січня

З тих пір я реалізував метод (3) вище, використовуючи шейдери геометрії, використовуючи буфери LineStrip та Dynamic Vertex. Тепер я отримую 100 FPS у 100k балів та 10FPS у 1000000 балів. Це величезне вдосконалення, але тепер я заповнена та обчислена обмежена, тому я задумалась про інші методи / ідеї.

  • А як щодо апаратного монтажу геометрії лінійного сегмента?
  • Що з Sprite Batch?
  • Що щодо інших (Pixel shader) орієнтованих методів?
  • Чи можу я ефективно працювати з графічним процесором чи процесором?

Ваші коментарі та пропозиції дуже оцінені!


1
Що про рідну AA в Direct3D?
API-Beast

5
Чи можете ви показати кілька прикладів кривих, які ви хочете побудувати? Ви згадуєте мільйон вершин, але ваш екран, мабуть, не має більше мільйона пікселів , чи потрібна ця кількість дійсно? Мені здається, вам не потрібно всю повну щільність даних скрізь. Ви розглядали ЛОД?
sam hocevar

1
Другий підхід, який ви пов’язали, здається гарним, ви використовуєте динамічний вершинний буфер, який ви оновлюєте, чи створюєте новий щоразу?

1
Ви, ймовірно, повинні перейти з динамічним вершинним буфером (не так багато роботи, просто скажіть, що ваш вершинний буфер динамічний, картографуйте буфер, скопіюйте свої дані, скапіруйте), але якщо вашим вузьким місцем є в першу чергу генерація вершин, це, ймовірно, виграло Зараз я не дуже допомагаю. Не думайте, що є щось скажене у використанні GS для полегшення навантаження на процесор

1
Якщо кількість вершин в кінцевому підсумку буде занадто великою для GPU, ви все одно можете спробувати зменшити розмір входів - вам не потрібно дійсно сотні мільйонів лінійних сегментів для однієї кривої, коли ваш екран буде шириною декількох тисяч пікселів щонайбільше

Відповіді:


16

Якщо ви збираєтеся візуалізувати Y = f(X)лише графіки, то пропоную спробувати наступний метод.

Дані кривої передаються як текстурні дані , роблячи їх стійкими та, наприклад, частковими оновленнями glTexSubImage2D. Якщо вам потрібна прокрутка, ви можете навіть застосувати круговий буфер і оновити лише кілька значень на кадр. Кожна крива відображається як повноекранний квадроцикл, а всю роботу виконує піксельний шейдер.

Вміст однокомпонентної текстури може виглядати так:

+----+----+----+----+
| 12 | 10 |  5 | .. | values for curve #1
+----+----+----+----+
| 55 | 83 | 87 | .. | values for curve #2
+----+----+----+----+

Робота піксельного шейдера така:

  • знайти координату X поточного фрагмента в просторі набору даних
  • взяти напр. 4 найближчих точки даних, які мають дані; Наприклад , якщо значення Х 41.3було б вибрати 40, 41, 42і 43.
  • запитайте текстуру для значень 4 Y (переконайтеся, що пробовідбірник не проводить ніякої інтерполяції)
  • перетворити X,Yпари на екранний простір
  • обчислити відстань від поточного фрагмента до кожного з трьох сегментів і чотирьох точок
  • використовувати відстань як значення альфа для поточного фрагмента

Ви можете замінити 4 більшими значеннями залежно від потенційного рівня збільшення.

Я написав дуже швидкий і брудний шейдер GLSL, реалізуючи цю функцію . Я можу додати версію HLSL пізніше, але ви повинні мати можливість її перетворити без особливих зусиль. Результат видно нижче, з різними розмірами рядків та щільністю даних:

криві

Однією явною перевагою є те, що обсяг переданих даних дуже низький, а кількість зворотних викликів - лише одна.


Це досить класна техніка - я робив GPGPU до того, як упакувати текстури з даними - це те, про що я знаю, але не те, що я вважав для цього. Який найбільший розмір (наприклад, найбільший набір даних, який ви можете завантажити?). Я завантажую ваш код, якщо ви не заперечуєте та пограйте з ним - я хочу побачити виставу.
Доктор ABT

@ Dr.ABT Розмір набору даних обмежений лише максимальним розміром текстури. Я не розумію, чому мільйони пунктів не спрацювали, якщо б не було правильного розміщення даних. Зауважте, що мій код, звичайно, не якість виробництва, але сміливо зв'яжіться зі мною приватно, якщо є якісь проблеми.
sam hocevar

Привіт @SamHocevar - я підкажу. Минув час, коли я склав розумний приклад OpenGL! :-)
Доктор ABT

Позначаючи як відповідь, так як, хоча я не використовую текстурне навантаження, ви представили справжній приклад OpenGL, який міг намалювати лінії на піксельній шейдері та поставити нас у правильному напрямку !! :)
Доктор ABT

4

Був розділ GPU Gems про рендеринг антиалізірованних ліній: Швидкі попередньо фільтрувані лінії . Основна ідея полягає в тому, щоб передати кожен відрізок рядка як квадроцикл і обчислити в кожному пікселі функцію Гаусса відстані піксельного центру від лінійного відрізка.

Це означає, що малювати кожен сегмент рядка в графі як окремий квадратик, але в D3D11 ви, звичайно, можете використовувати шейдер для геометрії та / або інстанцію для генерування квадратиків, зменшуючи кількість даних, що передаються в GPU, лише до точок даних себе. Я, мабуть, встановив точки даних як StructuredBuffer, який повинен читатися шейдером вершини / геометрії, а потім зробив виклик малювання із зазначенням кількості сегментів, які потрібно намалювати. Фактичних вершинних буферів не буде; вершинний шейдер просто використовує SV_VertexID або SV_InstanceID, щоб визначити, які точки даних слід подивитися.


Ей, дякую - так, я знаю про цю статтю, жодного вихідного коду з нею, на жаль :-( Примітка GeoShader + FragShader, здається, є переможцем для такого типу роботи. Ефективне отримання даних у GPU стане ефективною хитра частина!
Доктор ABT

Привіт @NathanReed, повертаючись до цього - якщо я використовував Geometry Shader або інстанцію для малювання квадратиків, то Point1 / Point2 - це протилежні вершини квадратика, то як у Pixel Shader можна обчислити відстань до лінії між Pt1 & Pt2? Чи має піксельний шейдер знання вхідної геометрії?
Доктор ABT

@ Dr.ABT Параметри математичної лінії повинні бути передані в піксельний шейдер через інтерполятори. Піксельний шейдер не має прямого доступу до геометрії.
Натан Рід

Я бачу, чи можна це зробити, надіславши висновки з GeometryShader або інстанції? Щоб отримати додатковий кредит (якщо вам цікаво), я додав тут питання: gamedev.stackexchange.com/questions/47831/…
доктор ABT

@ Dr.ABT Це точно так само, як координати текстури, звичайні вектори та всі подібні речі, як правило, надсилаються на піксельний шейдер - шляхом написання виходів з вершини / геометрії шейдера, які інтерполюються, та введення в піксельний шейдер.
Натан Рід

0

@ Dr.ABT - Вибачення за це питання, а не відповідь. Я не знайшов способу задати це питання у відповіді Сем Хочевар вище.

Чи можете ви поділитися детальнішою інформацією про те, як ви нарешті реалізували лінії для своєї діаграми? У мене така ж потреба в додатку WPF. Заздалегідь дякую за будь-які деталі чи код, якими ви можете поділитися цим.


як ви знаєте, це не відповідь, будь ласка, відредагуйте та поставте це як коментар
MephistonX

Я намагався це зробити, але в початковій публікації немає кнопки "Додати коментар".
ErcGeek

Привіт ErcGeek, Вибачте, я не можу поділитися остаточним рішенням, оскільки ця інформація є власником моєї компанії. Хоча наведені вище приклади та пропозиції ставлять нас на правильний шлях. Всього найкращого!
Доктор ABT

Ви не можете публікувати коментарі, перш ніж досягти певної репутації. І всі ці голоси, що точно не дадуть вам такої можливості.
Mathias Lykkegaard Lorenzen

Хлопець не повинен бути покараний за те, що він хоче знати кінцевий результат і просити його єдиним доступним для нього способом. Викликав відповідь.
Девід Чін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.