Погружение при соединении смешанных линий сглаживания

У меня проблема при соединении двух линий сглаживания при использовании режима смешивания, я получаю провал в точке, где они соединяются. Под режимом наложения я подразумеваю, что я рисую свою сглаженную линию, вычисляя соотношение цвета линии к цвету фона, поэтому, когда отношение для пикселя составляет, например, 70%, новый пиксель составляет 0,7* цвет линии + 0,3* цвет фона. Моя функция сглаживания для строк в основном сделана из функции ошибок (хотя я предполагаю, что та же проблема возникает для большинства функций сглаживания), например так:

0,5 + 0.5erf (-x)

Таким образом, когда встречаются две линии, одна нарисованная за другой, вы получаете провал, соединение двух линий опускается до 75% от интенсивности, которой оно должно быть, потому что в этой точке 50% фона было сохранено для первой линии и затем 50% из этих 50% остались после рисования второй линии, когда нужно оставить 0%:

1 - (0,5 эрф (-х) * 0,5 эрф (х))

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

Также: просто чтобы было ясно, как нарисованы линии, по ширине линии создаются с помощью гауссовой функции (e^-x*x), и оба конца округляются с использованием повышенных функций ошибок. Вы можете увидеть пример того, как выглядит горизонтальная линия длиной 10 пикселей, введя "0.5erfc(-x-5) * 0.5erfc(x-5) * e^(-y*y)" в WolframAlpha.

4 ответа

Решение

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

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

image => (blend) line1 => (blend) line2 => (blend) line3

Я могу иметь:

image => (blend) [0 => (add) line1 => (add) line2 => (add) line3]

что достигается заменой использования значения одного пикселя на наличие массива значений для каждого уровня глубины скобок, поэтому в этом случае на v[0] у вас будет пиксель от imageтогда вы начнете с v[1] в 0 и добавьте каждую строку к нему, и когда все строки будут добавлены, закрытие скобки будет делать v[1] смешаться в v[0] и правильное значение результирующего пикселя будет там.

Вот и все, это довольно просто, это проблема, только если вы не позволяете себе использовать эквивалент группы слоев в Photoshop.

Делать хорошо выглядящие непрерывные линии, состоящие из смешанных сегментов, вообще невозможно, если вы думаете о них как о сегментах - если вы просто думаете о случае, когда имеется одна линия, а затем рисуете следующий сегмент либо под тем же углом, а затем под углом 90 градусов. Цвета пикселя для одной строки зависят от угла, с которым она соединяется со следующей строкой

То, о чем вы тогда должны думать, это сегменты с наклонными концами.

Чтобы нарисовать его, поищите литературу по митре конического линейного соединения (митра, вероятно, легче).

Если вы рисуете смежные линии со смешиванием, это довольно трудная проблема.

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

К сожалению, это означает, что вам нужно расстояние до каждой линии, которая может повлиять на пиксель. Это то, что делают некоторые текстовые растеризаторы.

В качестве альтернативы вы просто не весите линии. Они либо включены, либо выключены на пиксель. Тогда вы позволите супер выборке позаботиться об остальном. Это то, что делают программные векторные рендереры, такие как flash или svg.

Идея thang может быть хорошей отправной точкой: короче говоря, контролировать центр "кисти" вместо краев. В идеале с хорошими круглыми конечными точками вы могли бы видеть хорошие круглые углы при таком подходе.

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

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

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

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

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

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

Другие вопросы по тегам