Поэтому я занимаюсь разработкой DirectX, точнее используя SharpDX под .NET (но применимы решения DirectX / C ++ API). Я ищу самый быстрый способ визуализации линий в ортогональной проекции (например, имитация 2D-рисования линий для научных приложений) с использованием DirectX.
Снимок экрана с видами графиков, которые я пытаюсь сделать, выглядит следующим образом:
Подобные графики нередко имеют линии с миллионами сегментов, различной толщины, с сглаживанием или без него в каждой строке (или вкл / выкл полноэкранного АА). Мне нужно очень часто обновлять вершины для строк (например, 20 раз / секунду) и максимально разгрузить графический процессор.
До сих пор я пытался:
- Программное обеспечение рендеринга, например, GDI + на самом деле не плохая производительность, но, очевидно, сильно загружает процессор
- Direct2D API - медленнее, чем GDI, особенно с включенным сглаживанием
- Direct3D10 использует этот метод для эмуляции AA, используя цвета вершин и тесселяцию на стороне процессора. Также медленный (я профилировал его, и 80% времени уходит на вычисление позиций вершин)
Для третьего метода я использую Vertex Buffers для отправки треугольной полосы в GPU и обновляю каждые 200 мсек новыми вершинами. Я получаю частоту обновления около 5FPS для 100 000 сегментов линии. Мне нужны миллионы в идеале!
Теперь я думаю, что самым быстрым способом было бы сделать тесселяцию на GPU, например, в Geometry Shader. Я мог бы отправить вершины в виде списка строк или упаковать в текстуру и распаковать в Geometry Shader для создания четырехугольников. Или просто отправьте необработанные точки в пиксельный шейдер и полностью реализуйте рисование линии Брезенхема в пиксельном шейдере. Мой HLSL ржавый, модель шейдера 2 с 2006 года, так что я не знаю о сумасшедших вещах, которые могут делать современные графические процессоры.
Итак, вопрос: - кто-нибудь делал это раньше, и есть ли у вас какие-либо предложения, чтобы попробовать? - Есть ли у вас какие-либо предложения по улучшению производительности за счет быстрого обновления геометрии (например, новый список вершин каждые 20 мс)?
ОБНОВЛЕНИЕ 21 января
С тех пор я реализовал метод (3) выше, используя шейдеры Geometry, используя LineStrip и Dynamic Vertex Buffers. Теперь я получаю 100FPS в 100k очков и 10FPS в 1000000 очков. Это огромное улучшение, но теперь я ограничен по частоте заполнения и вычислениям, поэтому я подумал о других методах / идеях.
- Как насчет аппаратной реализации геометрии линейного сегмента?
- А как насчет Sprite Batch?
- А как насчет других (Pixel Shader) ориентированных методов?
- Могу ли я эффективно отбраковывать на GPU или CPU?
Ваши комментарии и предложения очень ценятся!
Ответы:
Если вы собираетесь визуализировать
Y = f(X)
только графики, я предлагаю попробовать следующий метод.Данные кривой передаются как данные текстуры , что делает их постоянными и позволяет, например, частичное обновление
glTexSubImage2D
. Если вам нужна прокрутка, вы можете даже использовать циклический буфер и обновлять только несколько значений на кадр. Каждая кривая отображается как полноэкранный квад, и вся работа выполняется пиксельным шейдером.Содержимое однокомпонентной текстуры может выглядеть так:
Работа пиксельного шейдера заключается в следующем:
41.3
было бы выбрать40
,41
,42
и43
.X,Y
пары в пространство экранаВы можете заменить 4 большими значениями в зависимости от потенциального уровня масштабирования.
Я написал очень быстрый и грязный шейдер GLSL, реализующий эту функцию . Я могу добавить версию HLSL позже, но вы сможете конвертировать ее без особых усилий. Результат можно увидеть ниже, с различными размерами линий и плотностями данных:
Одно очевидное преимущество заключается в том, что объем передаваемых данных очень низок, а количество вызовов - только один.
источник
Там была глава Gem Gem для рендеринга сглаженных линий: Fast Prefiltered Lines . Основная идея состоит в том, чтобы визуализировать каждый линейный сегмент в виде квадрата и рассчитать для каждого пикселя гауссову функцию расстояния центра пикселя от линейного сегмента.
Это означает рисование каждого линейного сегмента на графике в виде отдельного четырехугольника, но в D3D11 вы, безусловно, могли бы использовать геометрический шейдер и / или создание экземпляров для создания четырехугольников, уменьшая объем данных, передаваемых в графический процессор, до просто точек данных. самих себя. Я бы, вероятно, установил точки данных как StructuredBuffer для чтения вершинным / геометрическим шейдером, а затем сделал бы вызов отрисовки с указанием количества сегментов, которые нужно нарисовать. Там не будет никаких реальных буферов вершин; вершинный шейдер просто использовал бы SV_VertexID или SV_InstanceID, чтобы определить, на какие точки данных смотреть.
источник
@ Dr.ABT - Извинения за это вопрос, а не ответ. Я не нашел способа задать это в ответе Сэма Хочевара выше.
Не могли бы вы поделиться более подробной информацией о том, как вы наконец реализовали линии для своего графика? У меня такая же потребность в приложении WPF. Заранее благодарим за любые детали или код, которым вы можете поделиться на этом.
источник