Как делается кисть для рисования волос
Я Вам расскажу об общих принципах того, как в графическом редакторе можно сделать так называемые кисти, подходящие по получаемой текстуре для изображения прядей волос, и что из себя представляют алгоритмы, используемые для получения такого результата.
Интуитивно кажется всё ясно - наставим в неком круге точек, и протащим этот круг по плоскости рисования - пусть каждая точка оставляет свой след. Вот так мы за один раз нарисуем много волос - целую прядь.
Но, во-первых, этот алгоритм ещё и реализовать нужно, и с этим не так уж всё просто, а во-вторых, получается не очень похоже, и хотя мы в своих художествах к особой похожести не стремимся, но хотелось бы и такие возможности иметь.
Вот это всё мы с вами сейчас и обсудим.
Мне легче, чем вам. Я делаю свой собственный редактор для художественного рисования, и пришедшие в голову идеи могу тут же на нем испробовать. Это занятие творческое, очень интересное, и я вам об этом сейчас расскажу.
ЗАЧЕМ НУЖЕН КРУГ ИЗ ТОЧЕК
Итак, проблема первая - какой формы будет у нас кисть? Проще всего копировать точки с образца на поле для рисования из одной прямоугольной области в другую такую же область. Но тогда и кисть у нас получится прямоугольной формы. А удобнее было бы иметь форму круглую и иметь возможность размер кисти регулировать.
Но как узнать, принадлежит ли точка к кругу заданного диаметра, или она выпадает из него?
Возводить в квадрат X и Y каждой точки, складывать, извлекать квадратный корень, и сравнивать полученную величину с заданным радиусом? Это излишняя работа, замедляющая процесс рисования, и эту работу следует провести заранее.
В самом начале работы программы, сразу после её загрузки, делается так называемый круг из точек.
У меня это массив RXY(1400, 3), в нулевом столбце которого стоят значения радиуса, а в первом и втором столбцах - координаты X и Y для каждой точки.
Имеется также список R20(21) - это ссылки на адреса массива точек. Например, между индексами R20(R1) и R20(R2) в массиве RXY(1400, 3) находится информация о точках, отстоящих от центра на расстояние большее, чем R1, но не большее, чем R1. Пожалуйста - можете координаты этих точек находить, и копировать точки, если это нужно.
КАК ПРОХОДИТ ПРОЦЕСС РИСОВАНИЯ
Последовательно происходящие события мыши - нажатие кнопки (MouseDown), движение мыши, переводящее указатель с одного пикселя на другой (MouseMove), и отжатие кнопки (MouseUp) отслеживаются программой. При этом на процесс рисования влияют только первые два события - MouseDown позволяет подготовиться к рисованию и совершить некие предварительные действия (например, определить радиус закрашиваемого круга), а MouseMove приводит к непосредственному нанесению точек на поверхность рисунка.
При каждом перемещении мыши точки наносятся сообразно новому её положению.
А как они наносятся?
Обычно существуют некие запреты. В моей программе точки не наносятся на чёрный цвет или на цвет фона, если этот фон со своим цветом объявлен прозрачным. В Фотошопе и в других программах - свои примочки.
Кроме того и перекрашивать пиксель в новый цвет можно не совсем. Если смешивать старый цвет OldC и новый цвет C в некоторой наперёд заданной пропорции (установим эту пропорцию через число А, меньшее единицы, показывающее долю старого цвета в смеси), то тогда можно достичь зрительного эффекта прозрачности наносимого мазка. Разумеется, другого рода прозрачность будут создавать и незаполняемые места между наносимыми точками.
Вариантов много.
Такого рода окрас для кисти состоящей из разрозненных мелких точек, и из точек, объединённых в небольшие круги, можно видеть на двух первых примерах иллюстрации, в левой части каждого примера.
В первом случае получается "искрящаяся" прическа, во втором случае волосы курчавятся.
И то, и другое неплохо. Но как бы попробовать избавиться от "искрения" в первом примере? Избавиться от тех мелких точек, которые остаются незакрашенными. Нужно понять причину такого явления.
Причина мелкой незакрашенности заключается в том, что одиночные точки, проходя по поверхности, не всегда попадают на пиксели смежные по горизонтали или вертикали, а часто перескакивают и по диагонали.
А что, если закрасить эти смежные точки? Очень просто! Решил я, и попробовал ставить на рисунок точки размером не в один, а в два пикселя.
Эффект получился для меня неожиданным - рисунок сразу приобрёл свойства мокрой акварели.
См. правую часть первого и второго примеров.
Это интересно. Чем больше возможностей оказывается у метода, тем лучше, поскольку будет из чего выбирать.
Что касается "неожиданности", то её можно было бы и предвидеть - точку я наношу четырьмя пикселями (по два на каждую сторону), а считываю цвет пикселей по-прежнему, поодиночке. Следовательно, считываю я иногда не совсем старый цвет, а цвет уже мною изменённый, вот цвет и расползается по рисунку по мере того, как я ставлю на рисунке точки.
Ну чем не эффект мокрой акварели? Она самая и есть.
Прекрасно, сказал я себе, и привязал эту возможность к кнопочке, которая весьма кстати оказалась в моём редакторе - эта кнопка переключает режимы Гуашь-Акварель. Правда создавал я её для другого метода рисования. Но это ничего, пусть кнопочка послужит и здесь.
ОСОБЕННОСТИ семплированного и несемплированного рисования.
Картинки точек в круге, которые я использовал в первых двух опытах, я делал чёрным цветом на светло-сером фоне. А что, если разнообразить цвета этих точек? Или даже расположить в круге некую картинку, и затем репродуцировать её по поверхности рисунка, проводя по нему кистью.
Именно так работает Фотошоп. В нём мазок кистью семплирован - он состоит из отдельных, но близко расположенных семплов, своеобразных штампов, отпечатки которых, слегка, или сильно изменяясь, последовательно накладываются друг на друга в том направлении, в котором мы ведём линию.
В этом и состоит общая идеология рисования в фотошопе.
Я же делаю несколько по иному - при работе кистью отпечатки не разделяются семплированием, а тесно примыкают друг к другу. Можно, разумеется, назвать и эти отпечатки семплами, но какие же это семплы, когда расстояние между ними 1 пиксель. То есть, расстояния как бы и нет вовсе.
Оба этих подхода к рисованию кистью имеют и свои плюсы, и свои минусы.
Семплированный метод работает быстрее, зато метод непрерывного рисования проще. Кроме того я постарался освободить его от лишних нагрузок - в Фотошопе рисование кистями унифицировано, в частности, все кисти используют вот этот самый круг с чёрными точками, или с размещённой на круге картинкой - так называемый патерн. А я сделал кисти, не использующие патерн, и стало быть, работающие быстрее, и только кисть №5 этот патерн использует.
Эту кисть я сделал специально для рисования волос, хотя, создавая интересную фактуру, кисть может быть использована и в других целях. Как бы там ни было, но и эта кисть тоже должна работать быстро. Насколько быстро, это зависит от количества тёмных точек в патерне.
СТАТУС ТОЧЕК ПАТЕРНА
В связи со сказанным давайте вернёмся к вопросу - А стоит ли разнообразить цвета точек в патерне? Стоит ли дополнительно нагружать компьютер анализом цвета этих точек?
И как использовать эти разноцветные точки? Делать с них отпечатки, как это делается в Фотошопе? Или использовать различие в цвете как-то по иному?
И я нашёл оригинальное решение, помогающее кстати и основной цели - получить в приемлемом качестве пути для рисования прядей волос. Итак, рассказываю.
В тот момент, когда для рисования кистью №5 выбирается подходящий для этого патерн, компьютер не загружен непосредственно рисованием, и следовательно, вполне может провести некую подготовительную работу. Работа эта заключается в заполнении третьего столбца массива RXY(1400, 3) статусом точек патерна.
Статус точки определяется по степени её темноты в соответствии с порогами 47, 99, 151 и 203 для синей составляющей цвета.
Чёрные точки по этому принципу получают статус 4, а светло-серые точки фона и ярко-голубая точка в центре - статус 0. Точки со статусом 0 в рисовании не участвуют. Напротив того - точки со статусом 4 в рисовании участвуют всегда.
Как вы уже догадались, точки с промежуточной степенью темноты получают статус 1, 2 или 3. Для рисования всех этих точек на патерне вполне подходят цвета из набора программы msPaint. Эти цвета - чёрный, два серых и темно-зелёный, на палитре программы Paint показаны на иллюстрации стрелочками.
Как и заполнять патерн точками тоже очень удобно в стандартной программе Paint при увеличении 6х.
Поэтому специальных средств для создания патерна я в своей программе не делал.
И, наконец, для чего нужен этот самый статус точки? А нужен он вот для чего.
Когда мы ведём кистью сверху вниз, рисуя прядь волос, то вначале в процессе участвуют только чёрные точки. Затем, когда мы пройдём кистью небольшой участок, в рисование включаются темно-зелёные точки, затем подключаются тёмно-серые и просто серые. А через некоторое время всё это выключается, только в обратном порядке.
И что же получается? Получается готовый шиньон из почти натуральных волос. Когда более тёмные точки патерна сосредоточены поближе к центру, то получается очень естественно.
Для создания подобного патерна я взял вначале уменьшенное фото снежинки. Если статус точек не отслеживается, то при коротком движении мыши получается просто отпечаток снежинки, а затем след от кисти резко чернеет. Но если включить отслеживание статуса точек, то на первом отпечатке будет видна только самая тёмная часть снежинки, и такой кистью уже можно успешно рисовать волосы.
Последний пример на иллюстрации получен с использованием специально сделанного патерна. В нём точки собраны по три, наподобие маленьких букв Г, и эти буквы - чёрные, тёмно-зелёные и серые размещены на поверхности патерна в соответствии с описанными выше принципами - те, что потемнее, помещены поближе к центру. Результат вы видите.
___________
Если кому-нибудь интересно, как это всё реализовано, то фрагмент программы на языке Визуал Бейсик я привожу ниже.
Любопытно, я так долго говорил об особенностях рисования волос, так много текста размещено выше, а для реализации этого всего, смотрите, совсем немного нужно:
'=========общий раздел для всех кистей
If M = 2 Then Exit Sub 'MouseUp не отрабатывается
DW = Form1.Picture1.DrawWidth: Form1.Picture1.DrawWidth = 1: Cb = -2 'фон непрозрачен
A = Form1.Command34.Caption: If InStr(Form1.Text1.Text, "п") > 0 Then Cb = cBack 'фон прозрачен
R = Form1.Command9.Caption
If Fbra = 5 Then '===========кисть №5 для рисования волос
If M = 4 Then 'MouseDown
If L4 = 1 Then Ko = 3.5: dK = 1 / (DW + 8) Else Ko = 0.3: dK = 0
Form1.Picture1.DrawWidth = DW: Exit Sub
End If '========= далее отрабатывается событие MouseMove
If AG = 1 Then Form1.Picture1.DrawWidth = 2
If R > 5 Then Im = R20(2 * R - 4) Else Im = R20(R + 1)
If A > 6 Then A = A / 5 - 0.85 Else A = (A + 1) / 20
Ko = Ko - dK: If Ko < 0.2 Or Ko > 3.5 Then dK = -dK
For I = 1 To Im
K = RXY(I, 3)
If K > Ko Then '<====проверяется соответствие статуса точки
X = RXY(I, 1) + Xm: Y = RXY(I, 2) + Ym
C = Form1.Picture1.Point(X, Y): If C = Cb Then C = -1
If C > 0 Then C = ccRGB(OldC, C, A): C = C Or 1: Form1.Picture1.PSet (X, Y), C
End If
Next I
End If
Form1.Picture1.DrawWidth = DW
End Sub
_________________
Свидетельство о публикации №119071801919
Ирина Петал 18.07.2019 14:56 Заявить о нарушении
Моя внучка хочет и в моей программе работать, и в Фотошопе работать научиться. Но пока ей тоже некогда.
Маштаков 18.07.2019 18:13 Заявить о нарушении
Спасибо, Дмитрий, за программу!
Ирина Петал 18.07.2019 18:19 Заявить о нарушении
Маштаков 20.07.2019 10:46 Заявить о нарушении