Толщина линии Direct3D

Как изменить толщину линий при рисовании списков линий с помощью Direct3D?

В этом сообщении говорится, что ширина линии не поддерживается, и предлагается обходной путь. Другие варианты?

Пока мы обсуждаем эту тему, позволяют ли шейдеры рисовать линии штриховыми узорами?


person Agnel Kurian    schedule 17.02.2010    source источник


Ответы (4)


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

Если геометрический шейдер не подходит, временным решением может быть использование вершинного шейдера, но это потребует некоторой переделки вашего VB. Имейте в виду, что VS затем должен знать сегмент линии в целом, поэтому вы в конечном итоге сохраните p и p + 1 для каждого из ваших элементов VB, плюс стоимость дублирования индексов / вершин (в зависимости от используемой топологии и если вы отображаете свою строку как индексированный примитив или нет).

Если производительность не является проблемой, возможно, лучше всего будет расширить процессор.

РЕДАКТИРОВАТЬ:

О шаблонах штрихов: вы также можете использовать геометрический шейдер, чтобы имитировать glLineStipple поведение. Если у вас топология GL_LINES, то есть изолированные линии, шаблон перезапускается на каждом новом сегменте линии. Таким образом, вам просто нужно вычислить в геометрическом шейдере горизонтальное начало (или вертикальное начало, в зависимости от ориентации) вашего линейного сегмента в экранном пространстве и передать эту дополнительную информацию в пиксельный шейдер. Затем пиксельный шейдер будет отвечать за отбрасывание фрагментов в соответствии со значениями factor и pattern (целочисленные и побитовые инструкции DirectX 10/11 упрощают эту задачу).

Опять же, это хорошо работает, и вы можете комбинировать его с имитируемыми линиями ширины (с помощью первого упомянутого выше метода).

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

Вы можете добиться этого с помощью рендеринга линейной полосы во временном VB с использованием функции потокового вывода DirectX 10 (каждый элемент этого VB соответствует длине экранного пространства каждого сегмента). Затем вам нужно выполнить параллельную префиксную сумму (также известную как сканирование) этого VB (для накопления значений длины каждого сегмента линии).

Наконец, вы визуализируете линейную полосу, как для GL_LINES, но используете эту дополнительную информацию Scan VB в PS.

person Stringer    schedule 17.02.2010

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

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

Так что, вероятно, нет никакого способа создать экструдированные квадроциклы для этой цели. Как объяснил Стрингер Белл в своем ответе, есть несколько способов добиться этого.

Самый простой способ, который работает для меня, - это создать буфер вершин, содержащий каждую вершину дважды, с нормалями, указывающими «вправо» или «влево», в зависимости от того, являются ли они правым или левым краем линии. Затем очень простой вершинный шейдер может выполнить выдавливание (изменяя положение вершины на кратное ее вектору нормали). Таким образом, вы можете быстро изменить ширину линии, не пересчитывая геометрию на CPU. Это может быть полезно, если вы хотите настроить ширину линии в зависимости от размера объекта или расстояния.

person Pepor    schedule 18.02.2010
comment
Это интересное решение. Удалось ли вам получить те же результаты, что и при вызове glLineWidth (на попиксельной основе)? - person Stringer; 18.02.2010
comment
Я не проверял его на пиксель, но для нетекстурированных, сглаженных линий результаты должны быть достаточно похожими. Использование текстуры (например, для имитации штриховых узоров OpenGL) наверняка доставит вас в мир боли с нелинейной интерполяцией координат текстуры (с которой NVidia Quadros справляется на удивление плохо, даже по сравнению с почти идентичной частью Geforce). Шейдеру необходимо проделать много дополнительной работы, чтобы получить правильные текстовые координаты. - person Pepor; 15.03.2010
comment
Вы можете попробовать это сами, просто используйте какую-то длину линии в пикселях экрана для координат текстуры и нарисуйте линии с текстурой, на которой есть точечный узор. Вы удивитесь, насколько неровный узор. По крайней мере, был. ;-) - person Pepor; 15.03.2010


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

SamplerState wrapTriLinear {
    AddressU = WRAP;
    AddressV = WRAP;
}
person Justin R.    schedule 24.05.2013